diff --git a/.doc/README.md b/.doc/README.md index 63e5c83c..99ed93ef 100644 --- a/.doc/README.md +++ b/.doc/README.md @@ -42,6 +42,7 @@ | 架构设计 | [system-design/README.md](system-design/README.md) | | 测试报告 | [test-reports/](test-reports/) | | 历史功能设计 | [archive/design/superpowers/](archive/design/superpowers/) | +| Herdr 角色、审批与备援 | [ops/2026-09-13-herdr-agent-roster.md](ops/2026-09-13-herdr-agent-roster.md) | --- diff --git a/.doc/archive/ops/2026-09-13-herdr-agent-governance.md b/.doc/archive/ops/2026-09-13-herdr-agent-governance.md new file mode 100644 index 00000000..eca91c56 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-herdr-agent-governance.md @@ -0,0 +1,62 @@ +--- +title: "Herdr Agent 角色、备援与自动审批治理" +status: done +created: 2026-09-13 +updated: 2026-09-13 +owner: Codex +branch: feature/herdr-agent-governance +worktree: .worktrees/feature-herdr-agent-governance +mutex: ops-governance +--- + +# Herdr Agent 角色、备援与自动审批治理 + +## 目标 + +建立可审计的 Herdr Agent 能力分工、额度保护、故障接管和免人工工具审批入口,并明确 Herdr PI 与产品容器 PI Agent Runner 不是同一执行体。 + +## 范围 + +- 持久化主责、备份顺序、任务泳道和接管条件。 +- 为已安装的 Claude、Codex、Cursor、Antigravity、PI、Kimi、Cline CLI 提供统一启动入口。 +- 自动审批仍受仓库、worktree、mutex、集成槽和破坏性操作红线约束。 +- 提供保守的自动派发:只向同工作目录、空闲的规范命名实例投递;明确失败时降级,超时停止重复投递。 + +## 非目标 + +- 不重启或接管当前正在执行 DOCREV/CHAT/INTENT 的实例。 +- 不修改容器内 PI Agent Runner 的模型、凭证、配置或运行状态。 +- 不操作共享 Docker 或推送远端。 +- 不将删库、强推、密钥读取/外传等不可逆动作纳入无条件许可。 + +## 步骤 + +1. [x] 盘点 Herdr 0.9.0、在线实例、集成状态、CLI 版本和审批参数。 +2. [x] 写入项目级角色与备援 SSOT,并在 AGENTS/PROJECT 建立入口。 +3. [x] 实现统一自动审批启动脚本和保守派发脚本。 +4. [x] 完成静态检查、脚本 dry-run 与路由验收。 +5. [x] 更新任务状态、提交 feature 分支并合入 `dev`。 + +## 验收标准 + +- [x] 每种当前可调用 CLI 都有明确角色、主备关系和自动审批启动参数。 +- [x] Codex/Claude 的高成本推理与 Cursor/Flash 模型的实施负载分离。 +- [x] 明确禁止因 timeout/unknown 状态盲目重复派发。 +- [x] Herdr PI 与产品容器 PI 在名称、职责和动作上不会混淆。 +- [x] 启动和派发脚本通过 `bash -n`,dry-run 不启动实例、不执行任务。 + +## 相关链接 + +- Agent roster: [../../ops/2026-09-13-herdr-agent-roster.md](../../ops/2026-09-13-herdr-agent-roster.md) +- Handoff: [../../ops/handoffs/2026-09-13-herdr-agent-governance.md](../../ops/handoffs/2026-09-13-herdr-agent-governance.md) +- Test report: 本任务文“证据 / 备注” + +## 证据 / 备注 + +- `herdr status`: client/server 0.9.0,protocol 22,兼容。 +- `herdr integration status`: Claude/Codex/Cursor/Antigravity/PI/Kimi integration current;Cline CLI 3.0.61 可调用。 +- CLI 版本:Claude 2.1.270、Codex 0.154.0、Cursor 2026.09.10、Antigravity 1.2.2、PI 0.85.1、Kimi 0.41.0、Cline 3.0.61。 +- `bash -n scripts/herdr-agent-start.sh scripts/herdr-agent-dispatch.sh`: PASS。 +- 七种启动 profile dry-run:PASS;未启动或重启实例。 +- 七条 lane `--explain`:PASS。 +- 非法标准名:exit 2;无在线标准实例:逐级跳过并 exit 69,未误投任务。 diff --git a/.doc/ops/2026-09-13-herdr-agent-roster.md b/.doc/ops/2026-09-13-herdr-agent-roster.md new file mode 100644 index 00000000..da311783 --- /dev/null +++ b/.doc/ops/2026-09-13-herdr-agent-roster.md @@ -0,0 +1,94 @@ +# Herdr Agent 角色、审批与备援 SSOT + +**更新**: 2026-09-13 +**owner**: `orchestrator_codex` +**status**: active + +本文只管理工程协作终端,不管理产品运行时智能体。通用分支、worktree、mutex、集成槽、密钥和破坏性操作规则仍以仓库根 [AGENTS.md](../../AGENTS.md) 为准。 + +## 1. 身份边界 + +| 名称 | 唯一含义 | 禁止混称 | +|------|----------|----------| +| Herdr PI / `context_pi` | Herdr pane 内运行的 PI CLI,当前目标模型 MiniMax M3,负责工程调研与长上下文分析 | 不代表后端 runner,不作为产品 E2E 证据 | +| 产品 PI Agent Runner | Compose/服务端调用的产品执行器;模型与验收要求见 PROJECT | 不参与 Herdr 工程任务路由 | + +文档、提示词和 handoff 中禁止只写“PI”;必须写 `context_pi` 或“产品 PI Agent Runner”。 + +## 2. 稳定角色 + +| 逻辑名 | 客户端 / 目标模型 | 主责 | 工作量策略 | 首选备援 | +|--------|-------------------|------|------------|----------| +| `orchestrator_codex` | Codex / GPT Sol 5.6 | 需求澄清、系统方案、任务拆解、调度、跨模块风险、代码终审、发布判断 | 保留推理容量,原则上不承担大批量机械实现 | `context_kimi`;关键争议才用 `reserve_claude` | +| `implementer_cursor` | Cursor / Auto | 前后端实施、测试补齐、重构、浏览器验证、按 checklist 收口 | 主力实施席,承担最大常规工作量 | `implementer_cline` → `verifier_antigravity` → `orchestrator_codex` | +| `verifier_antigravity` | Antigravity / Gemini 3.8 Flash | 快速只读排查、测试设计、文档核对、日志归纳、低风险小修 | 低成本高频;不得单独作安全或发布终审 | `implementer_cline` → `implementer_cursor` | +| `context_pi` | PI CLI / MiniMax M3 1M | 全仓长上下文扫描、文档/代码交叉研究、候选清单、handoff 压缩 | 长材料首选;结论由 Codex 或 reviewer 复核 | `context_kimi` → `orchestrator_codex` | +| `context_kimi` | Kimi Code / Kimi K3 1M | PI 备援、长文档审查、跨文件一致性检查、方案反证 | 额度有限,优先作长上下文备援而非日常实现 | `context_pi` → `orchestrator_codex` | +| `implementer_cline` | Cline / GLM 5.3 Flash | 机械实现、测试修复、格式化、重复性迁移、Cursor 备援 | CLI 已可调用;进入主路由前需完成一次隔离 worktree 写验收 | `implementer_cursor` → `verifier_antigravity` | +| `reserve_claude` | Claude Code / Sonnet 5 | P0/P1 架构争议、安全关键复核、Codex 失败后的第二强意见 | 额度极少,禁止日常调研、批量实现和首轮测试 | `orchestrator_codex` → `context_kimi` | +| `reserve_devin` | Devin / 尚未接入 | 预留长任务自治席 | `standby`,不得派发 | 无 | + +模型名称来自当前工作区约定;启动脚本不猜测各 CLI 的模型别名。每次新会话由 orchestrator 在首条状态回报中确认实际模型,不一致则停止高风险任务并记录 handoff。 + +## 3. 任务泳道与自动备援顺序 + +| lane | 适用任务 | 路由顺序 | +|------|----------|----------| +| `governance` | 方案、拆解、跨模块决策、普通 review | Codex → Kimi → Cursor → Claude | +| `critical-review` | 鉴权、安全、迁移、发布 blocker 终审 | Codex → Claude → Kimi | +| `implementation` | Go/React/SQL 实施与测试 | Cursor → Cline → Antigravity → Codex | +| `ui` | React、交互、Playwright | Cursor → Antigravity → Cline | +| `test` | 单测、集成测试、失败定位 | Cursor → Cline → Antigravity | +| `fast-check` | 日志、静态核对、文档一致性、小修 | Antigravity → Cline → Cursor | +| `long-context` | 全仓/全量文档审读、证据汇总 | PI → Kimi → Codex | + +Claude 只在 `critical-review` 中作为前排备援;其他 lane 放在最后或不进入路由,以保护额度。Codex 的实现兜底只用于阻塞交付的关键路径。 + +## 4. 自动派发和接管协议 + +1. Orchestrator 先创建 short-term、认领 mutex、建立独立 worktree;之后才启动或选择 agent。 +2. 实例必须使用上表逻辑名,且 `cwd` 必须与任务 worktree 完全相同。派发器不会占用名称不规范或其他目录的实例。 +3. 只向 `idle` / `done` 实例投递。同一 mutex 同时只允许一个执行者写入。 +4. 以下情况可自动尝试下一个备援:实例不存在、启动前已 blocked、认证失败、明确额度耗尽、客户端在写入前失败。 +5. Agent 只有在尚未写文件、未运行有副作用命令时,才可返回派发器给出的本次唯一 `HERDR_RETRY::` 行触发降级。 +6. `timeout`、`agent_prompt_stalled`、`unknown` 或无终态标记均不能证明任务未执行;派发器必须停止,不得盲目重投。先读取 pane,必要时写 handoff。 +7. 接管前确认原实例不再 `working`;有部分改动时由原实例或 orchestrator 写 handoff,备援串行续作,不得并发覆盖。 +8. Review 可由不同 worktree 的多个只读实例并行;写任务仍受 mutex 单写者约束。 + +## 5. 自动审批不是无限授权 + +统一入口为 [`scripts/herdr-agent-start.sh`](../../scripts/herdr-agent-start.sh)。当前安装版本验证过的参数如下: + +| profile | 自动审批参数 | 保留的边界 | +|---------|--------------|------------| +| Claude | `--dangerously-skip-permissions` | 仍受本规范和任务提示约束 | +| Codex | `--ask-for-approval never --sandbox workspace-write` | 保留 workspace 沙箱;失败回传模型,不询问人工 | +| Cursor | `--force --sandbox enabled --approve-mcps --trust` | 保留 Cursor 沙箱和显式 deny | +| Antigravity | `--dangerously-skip-permissions --sandbox` | 保留其终端沙箱 | +| PI | `--approve` | 信任项目本地文件;该 CLI 没有独立的逐工具审批开关 | +| Kimi | `--auto` | Never Ask 模式 | +| Cline | `--tui --auto-approve true` | 所有工具自动批准 | + +即使客户端不弹确认框,Agent 也不得自行执行:删库/清空数据、强推、删除主干或 worktree、停止 Herdr server、覆盖其他 Agent 未合并改动、泄露密钥、未获用户授权的外部写入。需要新权限时写 handoff/blocker,不把确认框转交给用户逐条点击。 + +## 6. 操作入口 + +在任务 worktree 的 Herdr pane 中启动标准实例: + +```bash +./scripts/herdr-agent-start.sh codex orchestrator_codex +./scripts/herdr-agent-start.sh cursor implementer_cursor +``` + +预览某泳道路由,或自动投递: + +```bash +./scripts/herdr-agent-dispatch.sh --explain implementation +./scripts/herdr-agent-dispatch.sh implementation "读取任务文并完成已认领范围,验证后写 handoff。" +``` + +派发器只处理规范命名且已在线的实例,不擅自创建 pane、不重启 agent、不抢集成槽。缺少实例时由 orchestrator 用启动脚本补齐。 + +## 7. 当前可用性基线 + +2026-09-13 现场基线:Herdr client/server 0.9.0、协议 22;Claude/Codex/Cursor/Antigravity/PI/Kimi 集成已安装且 current;Cline CLI 3.0.61 可调用,但尚无在线标准命名实例;Devin 尚未接入。在线状态是瞬时信息,派发前必须重新运行 `herdr agent list`。 diff --git a/.doc/ops/handoffs/2026-09-13-herdr-agent-governance.md b/.doc/ops/handoffs/2026-09-13-herdr-agent-governance.md new file mode 100644 index 00000000..aadd86d4 --- /dev/null +++ b/.doc/ops/handoffs/2026-09-13-herdr-agent-governance.md @@ -0,0 +1,63 @@ +--- +title: "Herdr Agent 治理分支待集成交接" +created: 2026-09-13 +from: Codex +to: next-integration-holder +status: closed +--- + +# 交接:Herdr Agent 治理分支待集成 + +## 目标(下一位 Agent 应完成什么) + +治理规范已完成并准备合入 `dev`;本文件保留为集成证据。 + +## 已完成 + +- 已建立角色、任务泳道、额度保护、自动审批和故障接管 SSOT。 +- 已提供七种 profile 的统一启动脚本和保守派发脚本。 +- 已验证脚本语法、全部 profile dry-run、全部 route、错误标准名和无实例安全退出。 + +## 未完成 / 后续 + +- 未推送远端(用户未要求)。 +- Cline 已安装且可调用,但标准命名 Herdr 实例仍需一次只读和一次隔离 worktree 写验收后才能升为 active。 + +## 认领 / 槽位状态 + +| 项 | 值 | +|----|-----| +| mutex 已释放 | yes | +| 集成槽位 holder | 未操作共享容器 | +| branch | `feature/herdr-agent-governance` | +| worktree | `.worktrees/feature-herdr-agent-governance` | + +## 关键文件 + +| 路径 | 说明 | +|------|------| +| `.doc/ops/2026-09-13-herdr-agent-roster.md` | 角色与路由 SSOT | +| `scripts/herdr-agent-start.sh` | 免人工审批启动入口 | +| `scripts/herdr-agent-dispatch.sh` | 主备派发与防重复策略 | +| `AGENTS.md` / `PROJECT.md` | 强制入口与 PI 身份边界 | + +## 如何验证 + +```bash +bash -n scripts/herdr-agent-start.sh scripts/herdr-agent-dispatch.sh +./scripts/herdr-agent-start.sh --dry-run codex orchestrator_codex w1:p1 +./scripts/herdr-agent-dispatch.sh --explain implementation +git diff --check +``` + +## 风险 / Blocker + +- `CURRENT.md` 是活文档;合并时以最新 `dev` 的 holder、phase、scope 为准,仅保留本任务认领或完成记录。 +- 不要因为 `timeout` / `agent_prompt_stalled` 自动重投任务。 +- 不要为验证本分支重启现有 DOCREV 实例或操作共享 Docker。 + +## 相关链接 + +- CURRENT: [CURRENT.md](../CURRENT.md) +- Task: [2026-09-13-herdr-agent-governance.md](../../archive/ops/2026-09-13-herdr-agent-governance.md) +- Checklist: 任务文中的验收标准 diff --git a/AGENTS.md b/AGENTS.md index 8c91bccc..0fdaafa6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -164,6 +164,15 @@ curl -sf http://127.0.0.1:8080/health - **不覆盖**:发现冲突先 handoff/blocker - **交接优先**:口头转述不可代替 handoff 文件 +### 6.6 Herdr 角色、自动审批与备援 + +- 本仓库 Herdr 角色、任务泳道、额度保护和备援顺序以 [Herdr Agent roster](./.doc/ops/2026-09-13-herdr-agent-roster.md) 为准。 +- Herdr 实例统一通过 [`scripts/herdr-agent-start.sh`](./scripts/herdr-agent-start.sh) 启动;自动派发使用 [`scripts/herdr-agent-dispatch.sh`](./scripts/herdr-agent-dispatch.sh)。 +- 自动审批只消除客户端逐条确认,不扩大任务授权;分支、worktree、mutex、集成槽和破坏性操作红线继续生效。 +- 自动接管仅允许发生在未开始写入且明确的额度、认证、客户端或启动失败。`timeout` / `unknown` 不证明任务未执行,必须停止重复投递并先检查 pane 与 handoff。 +- 名称 `context_pi` / “Herdr PI”专指协作终端内的 PI CLI;产品容器中的执行器统一称“产品 PI Agent Runner”,两者禁止混称或互相代替验收。 +- 未进入 roster 的新模型(包括尚未接入的 Devin)默认 `standby`,通过一次只读任务和一次隔离 worktree 写任务验证后再进入路由。 + --- ## 7. 文档生命周期 diff --git a/PROJECT.md b/PROJECT.md index 5c840aa0..0e7d1996 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -34,7 +34,8 @@ - **后端**:Go HTTP API(~110 路由) - **前端**:React + Vite - **数据库**:PostgreSQL + pgvector(Goose 迁移) -- **智能体**:PI Agent Runner(真实 / stub) +- **产品执行器**:容器内 PI Agent Runner(真实 / stub) +- **工程协作**:Herdr 管理的 Claude / Codex / Cursor / Antigravity / PI / Kimi / Cline;其中 Herdr PI 与产品 PI Agent Runner 无关 - **工作流**:main、product_manager、test_manager 三套正式定义 --- @@ -68,6 +69,7 @@ | 整改方案 | [.doc/remediation/INDEX.md](./.doc/remediation/INDEX.md) | | 测试报告归档 | [.doc/test-reports/](./.doc/test-reports/) | | 测试报告规范 | [.cursor/rules/test-reports-standard.mdc](./.cursor/rules/test-reports-standard.mdc) | +| Herdr 角色与备援 | [.doc/ops/2026-09-13-herdr-agent-roster.md](./.doc/ops/2026-09-13-herdr-agent-roster.md) | --- @@ -130,7 +132,13 @@ cd web && npm test && npm run build --- -## 10. 语言与提交 +## 10. Herdr 工程协作 + +- `orchestrator_codex` 负责拆解、方案、调度、风险控制和终审;主力实现默认交给 `implementer_cursor`。 +- 启动实例用 `scripts/herdr-agent-start.sh`,派发与安全降级用 `scripts/herdr-agent-dispatch.sh`。 +- 角色和备援 SSOT 见 [Herdr Agent roster](./.doc/ops/2026-09-13-herdr-agent-roster.md)。 + +## 11. 语言与提交 - 对用户:**简体中文** - 提交:Conventional Commits;在 `feature/*` 或 `fix/*` 上渐进式分批提交,合回 `dev` 用 `--no-ff`(禁止在三大主干直接 commit) diff --git a/scripts/herdr-agent-dispatch.sh b/scripts/herdr-agent-dispatch.sh new file mode 100755 index 00000000..8cb76dd7 --- /dev/null +++ b/scripts/herdr-agent-dispatch.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env bash +# Dispatch to a standard live Herdr agent, with conservative failover. +set -euo pipefail + +usage() { + cat <<'EOF' +用法: + scripts/herdr-agent-dispatch.sh --explain + scripts/herdr-agent-dispatch.sh [--timeout-ms N] + +lane: governance | critical-review | implementation | ui | test | fast-check | long-context +EOF +} + +route_for() { + case "$1" in + governance) printf '%s\n' orchestrator_codex context_kimi implementer_cursor reserve_claude ;; + critical-review) printf '%s\n' orchestrator_codex reserve_claude context_kimi ;; + implementation) printf '%s\n' implementer_cursor implementer_cline verifier_antigravity orchestrator_codex ;; + ui) printf '%s\n' implementer_cursor verifier_antigravity implementer_cline ;; + test) printf '%s\n' implementer_cursor implementer_cline verifier_antigravity ;; + fast-check) printf '%s\n' verifier_antigravity implementer_cline implementer_cursor ;; + long-context) printf '%s\n' context_pi context_kimi orchestrator_codex ;; + *) return 1 ;; + esac +} + +if [[ "${1:-}" == "--explain" ]]; then + [[ $# -eq 2 ]] || { usage >&2; exit 2; } + if ! route_for "$2"; then + printf '[错误] 未知 lane: %s\n' "$2" >&2 + exit 2 + fi + exit 0 +fi + +timeout_ms=120000 +if [[ "${1:-}" == "--timeout-ms" ]]; then + [[ $# -ge 4 ]] || { usage >&2; exit 2; } + timeout_ms="$2" + shift 2 +fi + +if [[ $# -ne 2 ]]; then + usage >&2 + exit 2 +fi + +lane="$1" +prompt="$2" +if ! routes="$(route_for "${lane}")"; then + printf '[错误] 未知 lane: %s\n' "${lane}" >&2 + exit 2 +fi + +if [[ ! "${timeout_ms}" =~ ^[1-9][0-9]*$ ]]; then + printf '[错误] timeout 必须是正整数毫秒。\n' >&2 + exit 2 +fi +if [[ "${HERDR_ENV:-}" != "1" ]]; then + printf '[错误] 当前进程不在 Herdr 管理的 pane 中。\n' >&2 + exit 1 +fi +command -v jq >/dev/null 2>&1 || { printf '[错误] 缺少 jq。\n' >&2; exit 1; } + +repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)" +if [[ -z "${repo_root}" || ! -f "${repo_root}/AGENTS.md" || ! -f "${repo_root}/PROJECT.md" ]]; then + printf '[错误] 必须从 Agent-System 任务 worktree 派发。\n' >&2 + exit 1 +fi +branch="$(git branch --show-current)" +if [[ "${branch}" != feature/* && "${branch}" != fix/* ]]; then + printf '[错误] 只允许从 feature/* 或 fix/* 分支派发,当前为 %s。\n' "${branch}" >&2 + exit 1 +fi +current_cwd="$(realpath -m "${repo_root}")" +agent_json="$(herdr agent list)" +dispatch_id="${BASHPID:-$$}-${SECONDS}" +retry_prefix="HERDR_RETRY:${dispatch_id}" +protocol="$(printf '\n\n[Herdr failover protocol]\n只有在尚未写文件、未运行有副作用命令,且仅因额度、认证或客户端故障无法开始时,回复独占一行 %s:quota、%s:auth 或 %s:client。已经开始工作时不得返回该标记;请写 handoff 并说明当前状态。' "${retry_prefix}" "${retry_prefix}" "${retry_prefix}")" + +while IFS= read -r target; do + row="$(jq -c --arg name "${target}" '.result.agents[] | select(.name == $name)' <<<"${agent_json}" | head -n 1)" + if [[ -z "${row}" ]]; then + printf '[跳过] %s 未在线。\n' "${target}" >&2 + continue + fi + + status="$(jq -r '.agent_status' <<<"${row}")" + agent_cwd="$(jq -r '.cwd' <<<"${row}")" + if [[ "${agent_cwd}" != "${current_cwd}" ]]; then + printf '[跳过] %s cwd=%s,不是当前任务 worktree。\n' "${target}" "${agent_cwd}" >&2 + continue + fi + if [[ "${status}" != "idle" && "${status}" != "done" ]]; then + printf '[跳过] %s 状态为 %s。\n' "${target}" "${status}" >&2 + continue + fi + + printf '[派发] lane=%s target=%s\n' "${lane}" "${target}" >&2 + set +e + result="$(herdr agent prompt "${target}" "${prompt}${protocol}" --wait --timeout "${timeout_ms}" 2>&1)" + rc=$? + set -e + + if [[ ${rc} -ne 0 ]]; then + if rg -q 'agent_blocked|agent_not_found|agent_not_ready' <<<"${result}"; then + printf '[降级] %s 在投递前不可用。\n' "${target}" >&2 + continue + fi + printf '%s\n' "${result}" >&2 + printf '[停止] 结果可能已投递;为避免重复执行,不自动切换备援。\n' >&2 + exit 75 + fi + + transcript="$(herdr agent read "${target}" --source recent-unwrapped --lines 120 2>/dev/null || true)" + if rg -q "^${retry_prefix}:(quota|auth|client)$" <<<"${transcript}"; then + printf '[降级] %s 明确报告写入前失败。\n' "${target}" >&2 + agent_json="$(herdr agent list)" + continue + fi + + printf '%s\n' "${result}" + exit 0 +done <<<"${routes}" + +printf '[错误] lane=%s 无可用实例;请用 herdr-agent-start.sh 启动标准实例。\n' "${lane}" >&2 +exit 69 diff --git a/scripts/herdr-agent-start.sh b/scripts/herdr-agent-start.sh new file mode 100755 index 00000000..8b40e725 --- /dev/null +++ b/scripts/herdr-agent-start.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +# Start a standard Herdr agent with non-interactive tool approvals. +set -euo pipefail + +usage() { + cat <<'EOF' +用法: + scripts/herdr-agent-start.sh [--dry-run] + +profile: claude | codex | cursor | antigravity | pi | kimi | cline +标准名称见 .doc/ops/2026-09-13-herdr-agent-roster.md。 +EOF +} + +dry_run=0 +if [[ "${1:-}" == "--dry-run" ]]; then + dry_run=1 + shift +fi + +if [[ $# -ne 3 ]]; then + usage >&2 + exit 2 +fi + +profile="$1" +agent_name="$2" +pane_id="$3" +shift 3 + +case "${profile}" in + claude) + kind="claude" + expected_name="reserve_claude" + native_args=(--dangerously-skip-permissions) + ;; + codex) + kind="codex" + expected_name="orchestrator_codex" + native_args=(--ask-for-approval never --sandbox workspace-write) + ;; + cursor) + kind="cursor" + expected_name="implementer_cursor" + native_args=(--force --sandbox enabled --approve-mcps --trust) + ;; + antigravity) + kind="agy" + expected_name="verifier_antigravity" + native_args=(--dangerously-skip-permissions --sandbox) + ;; + pi) + kind="pi" + expected_name="context_pi" + native_args=(--approve) + ;; + kimi) + kind="kimi" + expected_name="context_kimi" + native_args=(--auto) + ;; + cline) + kind="cline" + expected_name="implementer_cline" + native_args=(--tui --auto-approve true) + ;; + *) + printf '[错误] 未知 profile: %s\n' "${profile}" >&2 + usage >&2 + exit 2 + ;; +esac + +if [[ "${agent_name}" != "${expected_name}" ]]; then + printf '[错误] profile %s 的标准名称必须是 %s\n' "${profile}" "${expected_name}" >&2 + exit 2 +fi + +if [[ ! "${pane_id}" =~ ^w[[:alnum:]]+:p[[:alnum:]]+$ ]]; then + printf '[错误] 非法 pane id: %s\n' "${pane_id}" >&2 + exit 2 +fi + +command=(herdr agent start "${agent_name}" --kind "${kind}" --pane "${pane_id}" -- "${native_args[@]}") + +if [[ ${dry_run} -eq 1 ]]; then + printf '%q ' "${command[@]}" + printf '\n' + exit 0 +fi + +if [[ "${HERDR_ENV:-}" != "1" ]]; then + printf '[错误] 当前进程不在 Herdr 管理的 pane 中。\n' >&2 + exit 1 +fi + +repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)" +if [[ -z "${repo_root}" || ! -f "${repo_root}/AGENTS.md" || ! -f "${repo_root}/PROJECT.md" ]]; then + printf '[错误] 必须从 Agent-System 任务 worktree 启动。\n' >&2 + exit 1 +fi +branch="$(git branch --show-current)" +if [[ "${branch}" != feature/* && "${branch}" != fix/* ]]; then + printf '[错误] 自动审批实例只能在 feature/* 或 fix/* 分支启动,当前为 %s。\n' "${branch}" >&2 + exit 1 +fi +command -v jq >/dev/null 2>&1 || { printf '[错误] 缺少 jq。\n' >&2; exit 1; } +workspace_id="${pane_id%%:*}" +pane_json="$(herdr pane list --workspace "${workspace_id}")" +target_cwd="$(jq -r --arg pane "${pane_id}" '.result.panes[] | select(.pane_id == $pane) | .cwd' <<<"${pane_json}" | head -n 1)" +if [[ -z "${target_cwd}" || "$(realpath -m "${target_cwd}")" != "$(realpath -m "${repo_root}")" ]]; then + printf '[错误] 目标 pane 不存在或不在当前任务 worktree: %s\n' "${pane_id}" >&2 + exit 1 +fi + +exec "${command[@]}"