From 3d0faf557e5ef7b16fbb753a89aeec788a393d26 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 11 Jun 2026 14:29:46 +0000 Subject: [PATCH] fix: unify agentrun session send cli --- .agents/skills/unidesk-code-queue/SKILL.md | 11 +- docs/reference/cli.md | 8 +- docs/reference/code-queue-supervision.md | 14 +- scripts/src/agentrun.ts | 234 +++++++++++++-------- scripts/src/help.ts | 12 +- 5 files changed, 163 insertions(+), 116 deletions(-) diff --git a/.agents/skills/unidesk-code-queue/SKILL.md b/.agents/skills/unidesk-code-queue/SKILL.md index 3ec9b518..dc624ff9 100644 --- a/.agents/skills/unidesk-code-queue/SKILL.md +++ b/.agents/skills/unidesk-code-queue/SKILL.md @@ -1,11 +1,11 @@ --- name: unidesk-code-queue -description: UniDesk AgentRun-backed Code Queue CLI — Skill(cli-spec)。legacy `codex` 子命令只保留历史只读和残留停止;新任务提交、Aipod/Artificer 派单、steer/send、events/logs/result、ack/cancel、dispatch、run/command/runner 状态 drill-down 和 HWLAB Code Agent/CaseRun follow-up 必须使用 `agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send` 资源原语。用户提到 codex、Code Queue、submit、steer、resume、tasks、unread、code-queue、aipod、Artificer、HWLAB Code Agent 时使用。 +description: UniDesk AgentRun-backed Code Queue CLI — Skill(cli-spec)。legacy `codex` 子命令只保留历史只读和残留停止;新任务提交、Aipod/Artificer 派单、session follow-up、events/logs/result、ack/cancel、dispatch、run/command/runner 状态 drill-down 和 HWLAB Code Agent/CaseRun follow-up 必须使用 `agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|send` 资源原语。用户提到 codex、Code Queue、submit、send、resume、tasks、unread、code-queue、aipod、Artificer、HWLAB Code Agent 时使用。 --- # UniDesk Code Queue / AgentRun CLI -旧 Code Queue 已冻结新任务和写入口。`bun scripts/cli.ts codex ...` 现在只作为历史归档、只读排障和残留任务停止入口;新的指挥官派单、Aipod/Artificer 执行、events/logs/result、ack/cancel、dispatch、steer/send 必须走 AgentRun 资源原语,并按 cli-spec 渐进披露。UniDesk 是 render-only client:默认输出是低噪声 human 表格/摘要,脚本读取显式使用 `-o json|yaml` 的稳定客户端 schema,`--raw` 只用于查看直连 AgentRun REST envelope。 +旧 Code Queue 已冻结新任务和写入口。`bun scripts/cli.ts codex ...` 现在只作为历史归档、只读排障和残留任务停止入口;新的指挥官派单、Aipod/Artificer 执行、events/logs/result、ack/cancel、dispatch、session follow-up 必须走 AgentRun 资源原语,并按 cli-spec 渐进披露。UniDesk 是 render-only client:默认输出是低噪声 human 表格/摘要,脚本读取显式使用 `-o json|yaml` 的稳定客户端 schema,`--raw` 只用于查看直连 AgentRun REST envelope。 **固定入口前缀**: `cd /root/unidesk && bun scripts/cli.ts agentrun ...` @@ -55,11 +55,10 @@ bun scripts/cli.ts agentrun logs session/ --tail 100 bun scripts/cli.ts agentrun ack session/ bun scripts/cli.ts agentrun dispatch task/ bun scripts/cli.ts agentrun send session/ --aipod Artificer --prompt-stdin -bun scripts/cli.ts agentrun steer session/ --prompt-stdin bun scripts/cli.ts agentrun cancel session/ --reason --dry-run ``` -日常 task manifest 优先使用 YAML heredoc:`agentrun apply -f -`;单 prompt 派单优先 `agentrun create task --aipod Artificer --prompt-stdin`。UniDesk 客户端按 `config/agentrun.yaml` 直连 AgentRun REST API,不经过 HWLAB runtime、SSH official CLI 或旧 bridge wrapper;`--json-file`、`--prompt-file` 和 `--runner-json-file` 只是客户端输入来源,用于已审阅且可复用的受控文件。它不是旧 Code Queue adapter,不双写,也不迁移旧历史。 +日常 task manifest 优先使用 YAML heredoc:`agentrun apply -f -`;单 prompt 派单优先 `agentrun create task --aipod Artificer --prompt-stdin`;同 session 续跑只使用 `agentrun send session/`。UniDesk 客户端按 `config/agentrun.yaml` 直连 AgentRun REST API,不经过 HWLAB runtime、SSH official CLI 或旧 bridge wrapper;`send` 是唯一用户级 session follow-up 写入口,服务端按 durable session/run/command 状态自动决定内部 `steer` 或新 `turn`,旧 CLI `turn/steer` 路径不保留兼容。`--json-file`、`--prompt-file` 和 `--runner-json-file` 只是客户端输入来源,用于已审阅且可复用的受控文件。它不是旧 Code Queue adapter,不双写,也不迁移旧历史。 `AipodSpec` 是 AgentRun v0.1 的声明式 agent 装配:模型 profile、gitbundle、skills/tools、SecretRef 和 tool credential 都从 YAML 规格渲染。`Artificer` 默认用于 UniDesk 分布式开发任务,使用 `sub2api` provider、`gpt-5.5`、`reasoningEffort=xhigh`,并通过 SecretRef 注入 GitHub PR token、GitHub SSH 和 UniDesk SSH 透传能力。更新规格时使用 `agentrun aipod-specs apply --yaml-stdin --dry-run` 先看计划,确认后再去掉 `--dry-run`;不得把 API key、SSH key 或 token 写入 prompt、payload、YAML 或 issue。 @@ -74,14 +73,14 @@ AgentRun queue 生命周期不是一个单独的 `queue lifecycle` 命令,而 3. Run 级状态用 `events run/` 和 `result run/ --command `,判断 terminalClassification、failureKind、provider interruption、timeoutBudget 和 recoveryActions。 4. Command 级状态用 `describe command/ --run ` 和 `result command/ --run `,确认 command state、ack、terminal status 和结果摘要。 5. Runner job 只读状态用 `describe runnerjob/ --run `,确认 env image reuse、jobName、namespace、phase、exitCode、retention 和 `valuesPrinted=false`。不要为了这些字段手动调用 `trans G14:k3s kubectl ...`。 -6. Session trace/output 只在 `describe task` 或 result 里有实际 `sessionId` 时使用 `logs|ack|steer|send|cancel session/`;`sessionRef=null` 时不要猜 session 命令。 +6. Session trace/output 只在 `describe task` 或 result 里有实际 `sessionId` 时使用 `logs|ack|send|cancel session/`;`sessionRef=null` 时不要猜 session 命令。 7. 已创建但尚未运行的 task 使用 `dispatch task/` 派发,不再退回旧 bridge `queue dispatch`。 默认视图必须低噪声且不是 JSON envelope,`-o json|yaml` 才输出稳定机器结构,`--raw` 才保留直连 AgentRun REST envelope;命令返回里的下一步应优先是 `bun scripts/cli.ts agentrun ...` 资源原语,不得把人工 k8s 查询作为日常下一步。 ## HWLAB Code Agent 入口整合 -HWLAB Code Agent / CaseRun follow-up 的日常派单也归入 AgentRun 资源原语:新任务用 `create task --aipod Artificer` 或包含 HWLAB gitbundle 的 `apply -f -`;运行中纠偏用 `steer session/` 或 `send session/ --aipod Artificer`。需要验证 HWLAB Web/Cloud API 原入口时,仍按 `$hwlab-code-agent` 使用 G14 `/root/hwlab-v02` 的 `hwlab-cli client agent ...` 拉取同一 trace/result/inspect;不要回到旧 `codex submit/resume/steer`。 +HWLAB Code Agent / CaseRun follow-up 的日常派单也归入 AgentRun 资源原语:新任务用 `create task --aipod Artificer` 或包含 HWLAB gitbundle 的 `apply -f -`;运行中纠偏用 `send session/ --aipod Artificer`。需要验证 HWLAB Web/Cloud API 原入口时,仍按 `$hwlab-code-agent` 使用 G14 `/root/hwlab-v02` 的 `hwlab-cli client agent ...` 拉取同一 trace/result/inspect;不要回到旧 `codex submit/resume/steer`。 --- diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 9690e0d9..17e8a7bf 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -92,10 +92,10 @@ CI/CD、GitOps、rollout、artifact 发布、PR 合并后的 runtime lane 滚动 - `ci install|install-status|status|run|publish-backend-core|publish-user-service|run-dev-e2e|logs` 管理 D601 原生 k3s 上的 Tekton CI。`install` 默认创建 `.state/jobs` 异步 job 并立即返回,`install-status ` 读取阶段化 progress 和 bounded log tail;只有现场同步调试才显式加 `--wait`。`run` 手动创建每 commit 检查和 Code Queue 只读性能门禁;`publish-backend-core` 与 `publish-user-service` 从 pushed Git commit 构建并发布 `127.0.0.1:5000/unidesk/:` commit-pinned artifacts,输出 `artifactSummary`(含 `serviceId`、`sourceCommit`、`sourceRepo`、`dockerfile`、`imageRef`、`tag`、`digest`、`digestRef`),但不部署生产;`run-dev-e2e` 的 Git 控制 runner、短 launcher、host fetch 边界、临时 smoke namespace 和 no-CD 规则只在 `docs/reference/dev-ci-runner.md` 定义;Tekton CI 通用规则见 `docs/reference/ci.md`。 - `schedule list|get|runs|run|retry-run|delete|upsert-pgdata-backup` 管理 backend-core 定时任务和运行历史。`schedule list`、`schedule get`、`schedule runs --limit N` 和 `schedule runs --limit N` 是只读观察入口;`schedule run`、`schedule retry-run`、`schedule delete` 和 `schedule upsert-pgdata-backup` 会触发运行或写入配置,生产恢复时必须有明确授权。`schedule runs --limit N` 是全局历史视图,返回 `scope=global` 和 `scheduleId=null`;`schedule runs --limit N` 是指定 schedule 历史视图,返回 `scope=schedule` 和对应 `scheduleId`。CLI 必须拒绝 `schedule runs 50` 这类纯数字位置参数,并提示使用 `schedule runs --limit 50`,避免把空数组误判成“没有历史 run”。`schedule run --wait-ms N` 触发同一 schedule,并且即使 wait 超时也必须返回 `newRunId` 和 `observeCommand`;`schedule retry-run ` 只接受 failed run,从原 run 反查 `scheduleId` 后重触发同一 schedule,并输出 `originalRunId`、`scheduleId`、`newRunId` 和 `observeCommand`。当 backend-core 目标容器缺失或只观察到 verify-only 容器时,schedule/microservice 命令必须以非零退出并返回 `failureKind=target-stack-not-running`、`runnerDisposition=infra-blocked`、`readOnlyCommands` 和 `authorizationRequiredForRecovery`,不得把 Docker 的 `No such container` 当成成功的空历史。 - `codex deploy ` 是旧 Code Queue 兼容部署入口,已禁用以防止维护通道直连 D601 部署 Code Queue;当前 dev 自动化只做 `ci run-dev-e2e` smoke,不提供 Code Queue CD,详细规则见 `docs/reference/codex-deploy.md`。 -- `agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send` 是当前指挥官新任务和 AgentRun session 控制入口。UniDesk CLI 是 render-only client:客户端保留 k8s 风格命令解析、human 表格、生命周期摘要、下一步命令、分页、`-o json|yaml` 稳定客户端 schema 和错误展示;AgentRun 服务端只提供稳定 RESTful API、鉴权和业务事实,不承载 UniDesk CLI 渲染。日常查看用 `get tasks --queue commander`、`describe task/`、`events run/`、`logs session/`、`result run/ --command `;日常写入用 `create task --aipod Artificer --prompt-stdin`、`apply -f -`、`dispatch task/`、`steer/send session/`、`ack/cancel task|session/`。兼容 group `queue|runs|commands|runner|sessions|aipod-specs` 也走同一 direct HTTP transport,`--raw` 只披露直连 AgentRun REST envelope。 +- `agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|send` 是当前指挥官新任务和 AgentRun session 控制入口。UniDesk CLI 是 render-only client:客户端保留 k8s 风格命令解析、human 表格、生命周期摘要、下一步命令、分页、`-o json|yaml` 稳定客户端 schema 和错误展示;AgentRun 服务端只提供稳定 RESTful API、鉴权和业务事实,不承载 UniDesk CLI 渲染。日常查看用 `get tasks --queue commander`、`describe task/`、`events run/`、`logs session/`、`result run/ --command `;日常写入用 `create task --aipod Artificer --prompt-stdin`、`apply -f -`、`dispatch task/`、`send session/`、`ack/cancel task|session/`。用户级 CLI 取消 `turn` 和 `steer` 路径;`send session/` 是唯一 session follow-up 写入口,AgentRun 服务端按 durable session/run/command 状态自动决定内部 `steer` 或新 `turn`,dry-run 必须真实返回这个 decision 且不写状态。兼容 group `queue|runs|commands|runner|sessions|aipod-specs` 也走同一 direct HTTP transport,`--raw` 只披露直连 AgentRun REST envelope。 - `agentrun` 资源原语的默认 transport 是直连 AgentRun REST API,配置来源是 UniDesk 自有 YAML `config/agentrun.yaml`。鉴权可以复用 `HWLAB_API_KEY` 的环境变量/固定文件发现风格,但不得依赖 HWLAB runtime、HWLAB backend-core、HWLAB frontend 代理或 SSH official CLI;多一层转发会增加故障面,不能作为正式路径。`agentrun control-plane ...` 和 `git-mirror ...` 仍属于 G14 source/runtime 运维控制路径,可以继续使用 UniDesk SSH capture bridge;这些控制面路径不得反向成为 queue/session 资源原语的默认 transport。 - `agentrun control-plane expose --dry-run|--confirm` 按 `config/agentrun.yaml` 维护 AgentRun 公网 HTTPS 入口,模式与 Sub2API 暴露一致:G14 AgentRun runtime 通过 frpc 出到 master `127.0.0.1:`,master Caddy 提供 `https://agentrun.74-48-78-17.nip.io/`。该命令只补 master `frps` allow port 和 Caddy vhost;G14 frpc Deployment/ConfigMap 必须由 AgentRun `deploy/deploy.json` + GitOps render 管理,不能在 UniDesk 侧手写 Kubernetes manifest。 -- `codex submit/enqueue`、`codex steer`、`codex resume`、`codex queue create`、`codex queue merge`、`codex move`、旧 Web 提交表单、旧队列管理和旧 workdir 管理是冻结的 legacy Code Queue 写入口。CLI 必须返回 `ok=false`、`frozen=true`、`degradedReason=legacy-code-queue-frozen` 和 AgentRun 替代命令;服务端旧 API 写入口必须返回 410。新任务、steer/send、events/logs/result、ack 和 cancel 走 AgentRun 资源原语。 +- `codex submit/enqueue`、`codex steer`、`codex resume`、`codex queue create`、`codex queue merge`、`codex move`、旧 Web 提交表单、旧队列管理和旧 workdir 管理是冻结的 legacy Code Queue 写入口。CLI 必须返回 `ok=false`、`frozen=true`、`degradedReason=legacy-code-queue-frozen` 和 AgentRun 替代命令;服务端旧 API 写入口必须返回 410。新任务、session follow-up、events/logs/result、ack 和 cancel 走 AgentRun 资源原语,其中 session follow-up 只用 `agentrun send session/`。 - 旧 Code Queue 只保留历史归档、只读排障和残留任务停止。`codex task/tasks/output/read/unread/queues` 继续通过 backend-core 私有代理读取旧 PostgreSQL 历史;`codex interrupt|cancel ` 只用于停止旧运行面残留任务。旧 `steer-confirm` 只作为历史 trace confirmation 查询,不是新任务控制入口。 - `codex pr-preflight [--remote] [--push-dry-run --push-dry-run-ref refs/heads/probe/] [--pr-create-dry-run --pr-create-dry-run-head ] [--issue N] [--full|--raw]` 通过稳定 `code-queue` proxy 请求 D601 scheduler `/api/runtime-preflight`,用于 PR 型派单 admission。默认输出是紧凑 commander 视图,显式分出 `schedulerPreflight` 与 `activeRunnerPrCapability`,并附带 `commands` 和 `disclosure`,方便先看 scheduler auth 缺口、再看当前 runner/dev container 的 `gh auth status` 与 `gh pr create --dry-run` 能力;`--full` 或 `--raw` 才展开完整 `preflight`、工具、agent port、Git worktree、GitHub egress、repo/issue/PR 只读探测和观测原文。只报告 `GH_TOKEN`/`GITHUB_TOKEN` 是否存在和来源 key,不打印值。当 auth-broker 配置存在时,`tokenCoverage.source="auth-broker"`、`credentialSource="broker-issued-token"` 且 runner env token 不是成功前提;当仅 env token 存在时,`credentialSource="env-token"` 且 `authBroker.nextAction="use-env-token-until-auth-broker-live"`;两者都缺失时顶层 `ok=false`、`runnerDisposition=infra-blocked`、`degradedReason=auth-broker-needed`,`tokenCoverage.missing` 同时列出 `GH_TOKEN` 与 `GITHUB_TOKEN`,并输出 `authBroker.source="broker/auth-broker-needed"`、`capability.source="missing-token"`。该 `auth-missing` 的 scope 是 `scheduler-runner-env`,不能简化成“当前 active runner/dev container 不能创建 PR”;默认视图必须带 `scopeBoundary` 和 `activeRunnerPrCapability`。GitHub DNS/API 连接失败应归类为 `failureKind=github-transient`、`degradedReason=github-dns-api-transient`,并带 `retryable=true`、`commanderAction=retry-backoff-or-keep-running-if-heartbeat-fresh` 和有界 `githubTransient.failedProbes`;调用方应重试/退避,且在任务 heartbeat/trace 新鲜时继续监督,不把它当成 auth 缺失或 PR 语义失败。`prCapability` 是 runner-facing capability 摘要,必须包含目标分支、token/auth 来源、`systemGhBinaryRequiredForWrites=false`、UniDesk REST `bun scripts/cli.ts gh` 可用性、push dry-run/PR create dry-run 的 `writesRemote=false`、expected PR handoff、真实 PR 创建需要 commander 授权,以及 guarded `gh pr merge --dry-run` 预检路径;系统 `gh` binary 缺失只进入 `tools.systemGhBinary`,不得误判为 UniDesk REST `gh` CLI 不可用。`--remote` 在 runner-like 环境里不再依赖本地 `unidesk-backend-core`、`unidesk-database`、`baidu-netdisk-backend` 容器存在;这些缺失只作为本地观测证据。若远程控制面可达,则继续走远程控制面结果;若远程控制面不可达,则结构化返回 `failureKind=control-plane-missing` / `degradedReason=remote-control-plane-unreachable`,而不是把本地 `backend-core-container-missing` 当作最终阻塞。`--pr-create-dry-run` 不 POST GitHub,只证明 runner 内 PR body 生成、`scripts/cli.ts gh pr create --dry-run` 和 branch 参数形态可用;服务端创建权限仍以 token/auth broker、repo/issue/PR read、push dry-run 和最终授权后的真实 PR 创建结果为准。 - `codex task ` 通过 Code Queue 私有代理按任务 ID 查询结构化审阅摘要;默认只返回任务身份、执行 Provider、工作目录、attempt 计数、原始 prompt、最终 response、最后错误和渐进披露命令,适合指挥官审阅完成未读任务且避免上下文爆炸。`--detail` 仍是有界详细摘要:默认只返回少量 attempt/tool 行、短 prompt/response/stderr/feedback 预览和 omitted/truncated 元数据;需要完整 prompt/response 文本或更多 tool/attempt 细节时再显式加 `--full`、`--tool-limit N`、`--trace` 或 `codex output`。该摘要读取默认由主 server `code-queue-mgr` 从 PostgreSQL 返回,不依赖 D601 `code-queue-read` Service 可用。 @@ -107,7 +107,7 @@ CI/CD、GitOps、rollout、artifact 发布、PR 合并后的 runtime lane 滚动 - `codex dev-ready` 查询 Code Queue `/api/dev-ready` 并返回有界 readiness 摘要,包括工具、Docker、Codex config、SSH 和 `devReady.skills`。`devReady.skills` 只暴露 `UNIDESK_SKILLS_PATH`、是否存在、是否只读、skillCount、`cli-spec` 是否可见和修复建议,不输出宿主 auth/token 文件内容。 - `codex judge --attempt N [--dry-run] [--include-prompt]` 通过 Code Queue 私有代理按指定 attempt 单步复现 judge;这是执行面诊断入口,仍依赖 D601 scheduler/runner 侧的真实 judge builder、MiniMax 调用路径和执行环境。默认会真实调用 MiniMax,`--dry-run` 只返回 prompt/payload 大小、attempt 窗口和重建来源诊断,`--include-prompt` 仅用于本地深度排查。 - `codex steer-confirm --steer-id [--raw]` 是只读 trace confirmation lookup。默认输出 `traceConfirmation.found/accepted/deliveryState/trace.seq/trace.at/promptChars/promptHash` 和 `delivery.status`,不回显 prompt;`--raw` 才附带原始 backend confirmation body。该命令用于处理 stable-proxy abort 后的 `deliveryUnconfirmed`,不要用重复 prompt 代替确认查询。 -- 旧 `codex steer` 已冻结;`codex steer-confirm` 只作为历史 trace confirmation lookup。新运行中纠偏使用 `bun scripts/cli.ts agentrun steer session/ --prompt-stdin`,并用 `logs session/`、`events run/`、`result run/ --command ` 和 `ack session/` 观察。 +- 旧 `codex steer` 已冻结;`codex steer-confirm` 只作为历史 trace confirmation lookup。新运行中纠偏使用 `bun scripts/cli.ts agentrun send session/ --prompt-stdin`,并用 `logs session/`、`events run/`、`result run/ --command ` 和 `ack session/` 观察。 - `codex interrupt|cancel ` 通过 Code Queue 私有代理请求中断;running/judging 任务会请求 D601 当前 agent run 停止,queued/retry_wait 任务的取消也必须保持与 WebUI 相同代理路径,返回有界 task 摘要和后续查询命令。任何需要接触 active run 的动作仍属于 D601 执行面。 - 旧 Code Queue 多队列 lane 现在是归档视图:`codex queues [--full|--all] [--limit N] [--page N|--offset N]` 只读展示历史 queue 摘要、activity、commanderConcurrency、counts 和 execution diagnostics。`queue create`、`queue merge`、`move` 等旧队列写入口冻结并返回 `legacy-code-queue-frozen`;AgentRun 新任务的排队、派发和取消必须使用 `agentrun create|apply|get|cancel`。 - 所有旧 `codex` 历史查询、已读和残留 interrupt/cancel 命令必须走与 WebUI 相同的 backend-core 私有代理路径 `/api/microservices/code-queue/proxy/...`。旧 submit/steer/resume/queue mutation/move/workdir mutation 不得绕过冻结;若需要新任务或新 session 控制,使用 AgentRun 资源原语。 @@ -445,7 +445,7 @@ PATCH `--main-server-ip` 是一个全局前缀,必须放在需要透传的命令同一次调用中,例如 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug health`。默认传输是公网 frontend:本地 CLI 读取本仓库 `config.json` 中的 frontend 登录账号密码,登录 `http://:/` 获取 HttpOnly session cookie,然后通过 frontend 的 `/api/*` 同源代理访问 backend-core 内网 API;因此计算节点只需要能访问公网 frontend,不需要主 server SSH key,也不需要打开 backend-core REST API 或 PostgreSQL 端口。 -默认 frontend 传输支持 `debug health`、`debug dispatch`、`debug task`、`artifact-registry status|health`、`ci publish-user-service --dry-run`、`microservice list/status/health/diagnostics/tunnel-self-test/proxy`、`decision upload/list/show/health`、`decision requirement list/upsert`、`decision diary import/list/history/months/show/edit/upsert`、`codex task `、`codex tasks`、`codex unread`、`codex queues`、`codex output `、`codex judge --attempt N` 和 `ssh `。`microservice status/health/diagnostics` 经 frontend 远程传输时也复用本地 CLI 的默认 compact summary,`microservice health code-queue` 只有显式 `--raw` 或 `--full` 才返回完整健康 body。运行中纠偏已切到 AgentRun `steer session/`;旧 `codex steer` 属于冻结写入口,不应通过 frontend 远程传输或旧 proxy 绕过。其中 `ssh` 的 remote frontend 传输使用 authenticated frontend `/ws/ssh` WebSocket 代理接入 backend-core SSH bridge,stdout/stderr 按字节流直通到调用端,不经过 `/api/dispatch`、`/api/tasks` 或 task JSON compact;frontend 运行时必须通过 `PROVIDER_TOKEN`/`UNIDESK_PROVIDER_TOKEN` 或 `PROVIDER_TOKEN_FILE`/`UNIDESK_PROVIDER_TOKEN_FILE` 读取 provider token,并且不能把 token 下发给 runner。因此 D601 Code Queue runner 内的 `tran G14 ...` 应与主 server 本机 `trans G14 ...` / `tran G14 ...` 在输出完整性上保持同一语义。非交互单进程命令优先 `trans D601 argv true`;`apply-patch`、stdin script、`py` 和旧 `apply-patch-v1` fallback 也走同一条 `/ws/ssh` 流式通道。交互式登录 shell 仍应在主 server 本机 CLI 使用,或显式切换到旧 SSH 传输后在主 server 上执行。当 backend-core、database、provider-dispatch 或 provider-host-ssh 缺失时,这些 read-only 预检必须返回结构化 `runnerDisposition=infra-blocked` 和缺失通道列表,而不是裸 `No such container`。若确实需要旧行为,可使用 `--main-server-key ` 或 `--main-server-transport ssh`,这时 CLI 会通过 SSH 登录主 server 的 `--main-server-root` 目录执行同一个 `bun scripts/cli.ts `。 +默认 frontend 传输支持 `debug health`、`debug dispatch`、`debug task`、`artifact-registry status|health`、`ci publish-user-service --dry-run`、`microservice list/status/health/diagnostics/tunnel-self-test/proxy`、`decision upload/list/show/health`、`decision requirement list/upsert`、`decision diary import/list/history/months/show/edit/upsert`、`codex task `、`codex tasks`、`codex unread`、`codex queues`、`codex output `、`codex judge --attempt N` 和 `ssh `。`microservice status/health/diagnostics` 经 frontend 远程传输时也复用本地 CLI 的默认 compact summary,`microservice health code-queue` 只有显式 `--raw` 或 `--full` 才返回完整健康 body。运行中纠偏已切到 AgentRun `send session/`;旧 `codex steer` 属于冻结写入口,不应通过 frontend 远程传输或旧 proxy 绕过。其中 `ssh` 的 remote frontend 传输使用 authenticated frontend `/ws/ssh` WebSocket 代理接入 backend-core SSH bridge,stdout/stderr 按字节流直通到调用端,不经过 `/api/dispatch`、`/api/tasks` 或 task JSON compact;frontend 运行时必须通过 `PROVIDER_TOKEN`/`UNIDESK_PROVIDER_TOKEN` 或 `PROVIDER_TOKEN_FILE`/`UNIDESK_PROVIDER_TOKEN_FILE` 读取 provider token,并且不能把 token 下发给 runner。因此 D601 Code Queue runner 内的 `tran G14 ...` 应与主 server 本机 `trans G14 ...` / `tran G14 ...` 在输出完整性上保持同一语义。非交互单进程命令优先 `trans D601 argv true`;`apply-patch`、stdin script、`py` 和旧 `apply-patch-v1` fallback 也走同一条 `/ws/ssh` 流式通道。交互式登录 shell 仍应在主 server 本机 CLI 使用,或显式切换到旧 SSH 传输后在主 server 上执行。当 backend-core、database、provider-dispatch 或 provider-host-ssh 缺失时,这些 read-only 预检必须返回结构化 `runnerDisposition=infra-blocked` 和缺失通道列表,而不是裸 `No such container`。若确实需要旧行为,可使用 `--main-server-key ` 或 `--main-server-transport ssh`,这时 CLI 会通过 SSH 登录主 server 的 `--main-server-root` 目录执行同一个 `bun scripts/cli.ts `。 计算节点可以用该入口测试自身的远程升级闭环,而不需要在计算节点公开 core REST API 或 database。标准顺序是:先运行 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug health` 确认主 server 看到当前 Provider 在线,且该 Provider labels 中 `unideskCapabilities` 包含 `host.ssh`、`hostSshConfigured=true`、`hostSshKeyPresent=true`;再运行 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug dispatch provider.upgrade --mode schedule --wait-ms 15000` 触发真实 `provider.upgrade`;随后再次运行 `debug health` 确认节点重新上线;最后运行 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug dispatch host.ssh --wait-ms 15000` 和 `bun scripts/cli.ts --main-server-ip 74.48.78.17 ssh hostname` 验证 SSH 透传能力。provider-gateway 新部署或升级后没有完成这组 remote CLI 自测,不能视为交付完成。 diff --git a/docs/reference/code-queue-supervision.md b/docs/reference/code-queue-supervision.md index 272a1473..eeeeb844 100644 --- a/docs/reference/code-queue-supervision.md +++ b/docs/reference/code-queue-supervision.md @@ -93,7 +93,7 @@ HWLAB M3 口径使用同一分级:只读报告、fixture、LOCAL/DRY-RUN 和 d AgentRun 新派单和历史 Code Queue 审阅都按成本、可信度和 blast radius 分层:GPT-5.5/Codex 处理高风险和复杂任务,DeepSeek/OpenCode 处理中等复杂度且边界清晰的任务,MiniMax/OpenCode 处理简单、低权限、可复核任务,生产重启、密钥、数据库手工写入和运行中任务控制保留给指挥官或人工。 -当前新任务派发合同由 `bun scripts/cli.ts agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send` 资源原语暴露:`get tasks --queue commander` 查看指挥官队列,`create task --aipod Artificer --prompt-stdin` 或 `apply -f -` 创建任务,`dispatch task/` 派发,`events/logs/result/ack/cancel/steer/send` 读取和控制 AgentRun task、run 与 session。UniDesk 是 render-only client:日常一次性 YAML/JSON 和 prompt 输入优先用 quoted heredoc/stdin,客户端按 `config/agentrun.yaml` 直连 AgentRun REST API 并保留 k8s 风格渲染;`--json-file`、`--prompt-file` 和 `--runner-json-file` 只是客户端输入来源。该路径不经过 HWLAB runtime、SSH official CLI 或旧 bridge wrapper,不做旧 Code Queue 双写,也不迁移旧历史。 +当前新任务派发合同由 `bun scripts/cli.ts agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|send` 资源原语暴露:`get tasks --queue commander` 查看指挥官队列,`create task --aipod Artificer --prompt-stdin` 或 `apply -f -` 创建任务,`dispatch task/` 派发,`events/logs/result/ack/cancel/send` 读取和控制 AgentRun task、run 与 session。UniDesk 是 render-only client:日常一次性 YAML/JSON 和 prompt 输入优先用 quoted heredoc/stdin,客户端按 `config/agentrun.yaml` 直连 AgentRun REST API 并保留 k8s 风格渲染;`send session/` 是唯一用户级 session follow-up 写入口,服务端按 durable session/run/command 状态自动决定内部 `steer` 或新 `turn`,旧 CLI `turn/steer` 路径不保留兼容。`--json-file`、`--prompt-file` 和 `--runner-json-file` 只是客户端输入来源。该路径不经过 HWLAB runtime、SSH official CLI 或旧 bridge wrapper,不做旧 Code Queue 双写,也不迁移旧历史。 旧 `codex submit/enqueue`、`codex steer`、`codex resume`、旧 queue mutation、task move 和旧 workdir mutation 已冻结。CLI 必须返回 `ok=false`、`frozen=true`、`degradedReason=legacy-code-queue-frozen` 和 AgentRun 替代命令;服务端旧 API 写入口必须返回 410。旧 `codex task/tasks/output/read/unread/queues` 继续作为历史归档和只读排障入口,`codex interrupt|cancel` 只用于停止残留旧任务。 新任务模型由 AgentRun task payload 和 AgentRun runtime 配置决定;旧 Code Queue 的 `CODE_QUEUE_MODELS` 只作为历史任务审阅和残留运行面配置参考,长期合同至少包含 GPT-5.5、GPT-5.4、GPT-5.4 Mini、DeepSeek Chat、MiniMax M3 和 MiniMax M2.7 两路并行配置;`deepseek`/`deepseek-chat`、`minimax-m3` 与 `minimax-m2.7` 会走 OpenCode port,其余模型走 Codex port。PROD 集群把 `MINIMAX_MODEL` 切到 `MiniMax-M3`(M3 是新任务的默认 provider model),judge 与 opencode 跟随;M2.7 仍然作为并行配置存在,切换只需把 `MINIMAX_MODEL` 改成 `MiniMax-M2.7` 后 rollout restart。两者不存在自动 fallback 关系:M3 任务失败不会自动改派 M2.7,task 要用 M2.7 必须显式 `--model minimax-m2.7`。只有当执行面 `/health` 或等价配置已经显示 DeepSeek 模型可用、并完成轻量 runner smoke 后,才允许真实提交 `--model deepseek-chat`。 @@ -268,15 +268,15 @@ bun scripts/cli.ts codex pr-preflight --remote --issue ### Runner Resume 收口 -PR 小修、冲突、rebase、补测和 reviewer feedback 的新执行入口是 AgentRun 资源原语。仍在 AgentRun session 内的工作优先使用 `bun scripts/cli.ts agentrun steer session/ --prompt-stdin` 或 `send session/`;已沉淀成新工作项时使用 `bun scripts/cli.ts agentrun create task --aipod Artificer --prompt-stdin` 或 `agentrun apply -f -`。旧 `codex resume` 已冻结,不再作为 follow-up turn 入口。 +PR 小修、冲突、rebase、补测和 reviewer feedback 的新执行入口是 AgentRun 资源原语。仍在 AgentRun session 内的工作只使用 `bun scripts/cli.ts agentrun send session/ --prompt-stdin`;已沉淀成新工作项时使用 `bun scripts/cli.ts agentrun create task --aipod Artificer --prompt-stdin` 或 `agentrun apply -f -`。旧 `codex resume` 已冻结,不再作为 follow-up 入口。 旧 Code Queue task 只保留历史审阅和残留停止;需要基于旧任务产出继续推进时,在 AgentRun payload 中显式引用旧 task id、PR/branch 和审阅结论,而不是把旧 task 重新入队、resume 或 double-write。 AgentRun turn 的 timeout 监督按无响应空闲时间处理,而不是固定 wall-clock `backend-timeout`。只要 result/session liveness 的 `lastActivityAt`、`lastActivitySeq` 或 events 仍在刷新,指挥官应继续轮询,不应 interrupt、重派或判定 backend 死亡。若 command 因 idle timeout、provider stream disconnect、runner stdio inactive 或其他非业务终态停止,指挥官本人必须先读 `result`、`events` 或 `logs/trace`,确认最后有效工具输出、已完成修改、失败原因和下一步,再把这个摘要作为后续 prompt 发送给 Artificer;不能要求 Artificer 自己去猜旧 trace,也不能因为一次 timeout 就停止整个交付。 -Artificer 默认应携带可续跑 `sessionRef`。仍有 `sessionId` 的 follow-up、补测、reviewer feedback 和 timeout 恢复,优先使用 `bun scripts/cli.ts agentrun send session/ --aipod Artificer --prompt-stdin` 或 `steer session/` 继续同一个 session;只有历史任务没有 `sessionRef`、session 已 evicted、或同 session 已证明不可恢复时,才创建新 AgentRun task。新 task 必须在 prompt 中写明“这是基于旧 task/trace 的 manager-read continuation”,并记录旧 task/run/branch、管理者读 trace 得出的当前状态和下一步。 +Artificer 默认应携带可续跑 `sessionRef`。仍有 `sessionId` 的 follow-up、补测、reviewer feedback 和 timeout 恢复,只使用 `bun scripts/cli.ts agentrun send session/ --aipod Artificer --prompt-stdin` 继续同一个 session;只有历史任务没有 `sessionRef`、session 已 evicted、或同 session 已证明不可恢复时,才创建新 AgentRun task。新 task 必须在 prompt 中写明“这是基于旧 task/trace 的 manager-read continuation”,并记录旧 task/run/branch、管理者读 trace 得出的当前状态和下一步。 -replacement runner 只用于方向明显错误、质量不可接受、原 task 上下文不可恢复、原分支/PR 已废弃,或 AgentRun reuse/steer 已证明无法继续的情况。关闭或替换旧 PR 时必须在 PR/body/final response 中说明 superseded/replacement 关系,避免 competing branch 扩散。 +replacement runner 只用于方向明显错误、质量不可接受、原 task 上下文不可恢复、原分支/PR 已废弃,或 AgentRun 同 session `send` 已证明无法继续的情况。关闭或替换旧 PR 时必须在 PR/body/final response 中说明 superseded/replacement 关系,避免 competing branch 扩散。 ## 监控 @@ -294,7 +294,7 @@ replacement runner 只用于方向明显错误、质量不可接受、原 task - `bun scripts/cli.ts codex tasks --status succeeded --unread --limit N`:按具体终态过滤监督结果;不支持的 status filter 必须显式失败,不能扩大为未过滤结果。 - `bun scripts/cli.ts codex task `:默认只查看原始 prompt、最终 response、最后错误和 drill-down 命令,这是完成未读任务审阅的第一步。 - 当默认审阅摘要不足时,再逐级使用 `bun scripts/cli.ts codex task --detail`、`bun scripts/cli.ts codex task --trace --limit N` 或 `codex output`。 -- `bun scripts/cli.ts agentrun steer session/ --prompt-stdin`:对 AgentRun 中仍可继续的 session 追加修正;旧 `codex resume` 已冻结。 +- `bun scripts/cli.ts agentrun send session/ --prompt-stdin`:对 AgentRun 中仍可继续的 session 追加修正;服务端按运行状态决定内部 `steer` 或新 `turn`,旧 `codex resume` 已冻结。 - 当 master 控制面状态和 D601 scheduler 状态看起来分裂时,使用 `docs/reference/observability.md` 中的活性规则判断。 默认 commander/supervisor 视图必须保持低噪声。commander 视图用于回答“现在需要处理什么”,supervisor 视图用于看分区小页和红线细节。commander 的 `activeRunners.count` 是指挥官 active runner 计数,supervisor 的 `activeRunning.count` 是 running+judging 状态计数;两者都必须标明 exact/source,不能把返回行数当成并发总数。`activeRunning.count` 来源是 queue summary 的 status counts 时 `activeRunning.exact=true`,用于 redline 判断;`activeRunning.rowPage.returned` / `running.returned` 只表示本次返回的紧凑任务行。`activeRunning.redline` 必须写明 `countField`、routine target、burst redline、hard redline、`state` 和 `decisionReady`;只有 `decisionReady=true` 时,才能直接用该 count 做红线/补派判断。commander 的 `attention.items` 只返回最需要处理的有界任务,`attention.total/returned/omitted` 必须保留省略计数;`sections.recentCompleted` 不得重复 `sections.terminalUnread` 的未读终态。`running`、`completedUnread` 和 `queued` 即使传入较大的 `--limit`,默认也只返回一个很小的有界页,并通过 section `commands.next` 继续分页;`--limit` 保留为扫描/分页预算和 full view 返回预算,不得让一次 commander/supervisor 调用输出几十条肥行。每个任务行只应带 task id 和必要摘要,`show`、`detail`、`trace`、`output`、`full`、`read` 使用 section template 或 row commands 表达,让下一步渐进披露动作明确且不重复;默认不得嵌入完整 queue 列表、完整 final response、raw output 页或完整 trace 行。`recentCompleted` 必须默认限量,且不得重复 `completedUnread` 里的未读终态,避免完成历史把当前 running、阻塞和未读审阅挤出视野;需要完整当前页时显式使用 `--view full`。`executionDiagnostics` 只能展示有界 task-id/reason 预览、总数、截断标记和 omitted counts;需要全量诊断时使用输出中的 raw command。`commands.read` 只是在人工审阅后的建议命令,listing 命令绝不能自动执行。 @@ -373,8 +373,8 @@ D601 artifact registry 的 systemd unit inactive 不等于 D601 全局离线。 只有存在明确理由时才干预。 - 如果任务还在运行且 trace 或 scheduler heartbeat 新鲜,应引导而不是 interrupt。 -- 对 AgentRun 运行中 session 的引导应优先使用正式 CLI:`bun scripts/cli.ts agentrun steer session/ --prompt-stdin`,再用 `logs/events/result/ack` 确认。旧 `codex steer` 已冻结,只保留历史 trace confirmation 查询。 -- 真实 steer 输出必须保持低噪声:成功显示 `steer.status`、`steer.deliveryState`、`steer.steerId`、有界 `traceConfirmation` 和后续命令,不回显 prompt 或完整 task state;失败默认不带 request body、不带 upstream body preview,也不带 raw response,需要上游预览或原始失败对象时显式重跑 `--full` 或 `--raw`。`deliveryState=accepted` 表示 backend 已接受;`not_accepted` 表示任务状态/权限/输入未接受;`accepted_response_timeout` 表示 stable proxy 响应超时但 trace confirmation 找到该 `steerId`;`unknown` 表示响应路径失败且确认查询仍未证明接受。 +- 对 AgentRun 运行中 session 的引导只使用正式 CLI:`bun scripts/cli.ts agentrun send session/ --prompt-stdin`,再用 `logs/events/result/ack` 确认。旧 `codex steer` 已冻结,只保留历史 trace confirmation 查询。 +- 真实 `send` 输出必须保持低噪声并直接显示 `dryRun`、`mutation`、`decision`、`internalCommandType`、run/command/runnerjob 摘要和后续命令,不回显 prompt 或完整 task state;失败默认不带 request body、不带 upstream body preview,也不带 raw response,需要上游预览或原始失败对象时显式重跑 `--full` 或 `--raw`。 - 旧 Code Queue 的 provider tunnel 失败只作为历史运行面诊断线索;新任务控制面失败优先按 AgentRun `describe task`、`events`、`logs`、`result`、G14 `agentrun-v01` manager 和 runner job 证据分流。 - 新 AgentRun 任务失败分流以 AgentRun queue/session/runner-job 返回字段为准。旧 Code Queue `.data.diagnostics.reason` 只用于历史任务和残留运行面,不再引导新 `codex submit/steer/resume`。 - 如果任务进入终态但缺少必要验收证据,应使用聚焦 continuation prompt retry 同一任务。 diff --git a/scripts/src/agentrun.ts b/scripts/src/agentrun.ts index 7d4b383c..3e2c7025 100644 --- a/scripts/src/agentrun.ts +++ b/scripts/src/agentrun.ts @@ -39,7 +39,7 @@ const gitMirrorRepositories: readonly GitMirrorRepositorySpec[] = [ export function agentRunHelp(): unknown { return { - command: "agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send|explain", + command: "agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|send|explain", output: "human by default; use -o json|yaml or --raw for machine/debug output", usage: [ "bun scripts/cli.ts agentrun get tasks --queue commander --limit 20", @@ -54,7 +54,6 @@ export function agentRunHelp(): unknown { "bun scripts/cli.ts agentrun dispatch task/", "bun scripts/cli.ts agentrun create task --aipod Artificer --prompt-stdin --idempotency-key ", "bun scripts/cli.ts agentrun apply -f - --dry-run", - "bun scripts/cli.ts agentrun steer session/ --prompt-stdin", "bun scripts/cli.ts agentrun send session/ --aipod Artificer --prompt-stdin", "bun scripts/cli.ts agentrun explain task", "bun scripts/cli.ts agentrun control-plane status", @@ -78,7 +77,7 @@ export function agentRunHelp(): unknown { ], resources: ["task/qt", "run", "command/cmd", "runnerjob/rjob", "session/ses", "aipodspec/aps"], description: "Operate AgentRun v0.1 through Kubernetes-style resource verbs. Human output is compact by default; -o json|yaml returns the UniDesk render-only client schema, and --raw exposes the direct AgentRun REST envelope.", - legacyCompatibility: "queue/runs/commands/runner/sessions/aipod-specs remain as compatibility groups backed by direct HTTP; new commander work should use get/describe/events/logs/result/ack/cancel/dispatch/create/apply/steer/send.", + legacyCompatibility: "queue/runs/commands/runner/sessions/aipod-specs remain as compatibility groups backed by direct HTTP; new commander work should use get/describe/events/logs/result/ack/cancel/dispatch/create/apply/send. sessions turn/steer are removed; use send only.", }; } @@ -150,7 +149,6 @@ function isResourceVerb(value: string | undefined): value is AgentRunResourceVer || value === "dispatch" || value === "create" || value === "apply" - || value === "steer" || value === "send" || value === "explain"; } @@ -211,11 +209,8 @@ function agentRunHelpText(args: string[]): string { if (verb === "apply") { return "Usage: bun scripts/cli.ts agentrun apply -f task.yaml|json|- [--dry-run]\nTask manifests use kind: Task and spec: ."; } - if (verb === "steer") { - return "Usage: bun scripts/cli.ts agentrun steer session/ --prompt-stdin"; - } if (verb === "send") { - return "Usage: bun scripts/cli.ts agentrun send session/ --aipod Artificer --prompt-stdin"; + return "Usage: bun scripts/cli.ts agentrun send session/ --aipod Artificer --prompt-stdin\nThe server decides whether this becomes an internal steer or a new turn from session state."; } if (verb === "explain") return agentRunExplain(kind ?? "task"); if (verb === "control-plane") { @@ -254,7 +249,7 @@ function agentRunHelpText(args: string[]): string { return [ "Usage: bun scripts/cli.ts agentrun [options]", "", - "Verbs: get, describe, events, logs, result, ack, cancel, dispatch, create, apply, steer, send, explain", + "Verbs: get, describe, events, logs, result, ack, cancel, dispatch, create, apply, send, explain", "Resources: task/qt, run, command/cmd, runnerjob/rjob, session/ses, aipodspec/aps", "", "Common:", @@ -299,8 +294,7 @@ async function runAgentRunResourceCommand(config: UniDeskConfig | null, verb: Ag if (verb === "dispatch") return await resourceDispatch(config, command, action, bridgeActionArgs, options); if (verb === "create") return await resourceCreate(config, command, action, bridgeActionArgs, options); if (verb === "apply") return await resourceApply(config, command, bridgeActionArgs, options); - if (verb === "steer") return await resourceSessionPromptCommand(config, command, "steer", action, bridgeActionArgs, options); - if (verb === "send") return await resourceSessionPromptCommand(config, command, "turn", action, bridgeActionArgs, options); + if (verb === "send") return await resourceSessionPromptCommand(config, command, action, bridgeActionArgs, options); } catch (error) { if (error instanceof AgentRunRestError) return renderAgentRunRestError(command, error, options); return renderedCliResult(false, command, `Error: ${error instanceof Error ? error.message : String(error)}`); @@ -620,12 +614,12 @@ async function resourceApply(config: UniDeskConfig | null, command: string, args return renderMutationSummary(command, result, options, `${options.dryRun ? "Dry-run applied" : "Applied"} task manifest`, options.dryRun ? [rerunWithoutDryRun(command)] : undefined); } -async function resourceSessionPromptCommand(config: UniDeskConfig | null, command: string, officialAction: "steer" | "turn", action: string | undefined, args: string[], options: AgentRunResourceOptions): Promise { +async function resourceSessionPromptCommand(config: UniDeskConfig | null, command: string, action: string | undefined, args: string[], options: AgentRunResourceOptions): Promise { const ref = parseResourceRef(action, args, "session"); - if (ref.kind !== "session") throw new Error(`${officialAction === "steer" ? "steer" : "send"} requires session/`); - const sessionArgs = [officialAction, ref.name, ...stripLeadingResource(args, ref.name)]; + if (ref.kind !== "session") throw new Error("send requires session/"); + const sessionArgs = ["send", ref.name, ...stripLeadingResource(args, ref.name)]; const result = await runAgentRunRestCommand(config, "sessions", sessionArgs); - return renderMutationSummary(command, result, options, officialAction === "steer" ? "Steer submitted" : "Session turn submitted"); + return renderMutationSummary(command, result, options, options.dryRun ? "Session send plan" : "Session send submitted"); } function renderedCliResult(ok: boolean, command: string, renderedText: string, contentType: RenderedCliResult["contentType"] = "text/plain"): RenderedCliResult { @@ -675,7 +669,20 @@ function renderResultSummary(command: string, raw: Record, opti `State: ${displayValue(data.state ?? data.status ?? data.terminalStatus ?? "-")}`, `OK: ${String(raw.ok !== false)}`, ]; - const final = stringOrNull(data.finalResponse) ?? stringOrNull(data.output) ?? stringOrNull(data.summary) ?? stringOrNull(data.result); + const authority = stringOrNull(data.finalResponseAuthority); + const fallback = typeof data.finalResponseFallback === "boolean" ? data.finalResponseFallback : null; + const needsContinuation = typeof data.needsContinuation === "boolean" ? data.needsContinuation : null; + if (authority !== null) lines.push(`Authority: ${authority}`); + if (fallback !== null) lines.push(`Fallback: ${String(fallback)}`); + if (needsContinuation !== null) lines.push(`NeedsContinuation: ${String(needsContinuation)}`); + const finalRecord = record(data.finalResponse); + const final = stringOrNull(data.finalResponse) + ?? stringOrNull(finalRecord.content) + ?? stringOrNull(finalRecord.text) + ?? stringOrNull(finalRecord.message) + ?? stringOrNull(data.output) + ?? stringOrNull(data.summary) + ?? stringOrNull(data.result); if (final !== null) lines.push("", truncateMultiline(final, options.fullText ? 8000 : 1600)); else { const failure = renderFailureLines(data); @@ -694,6 +701,12 @@ function renderMutationSummary(command: string, raw: Record, op `OK: ${String(raw.ok !== false)}`, ]; if (id !== null) lines.push(`Name: ${id}`); + const decision = stringOrNull(data.decision); + const internalCommandType = stringOrNull(data.internalCommandType); + if (data.dryRun !== undefined) lines.push(`DryRun: ${String(data.dryRun)}`); + if (data.mutation !== undefined) lines.push(`Mutation: ${String(data.mutation)}`); + if (decision !== null) lines.push(`Decision: ${decision}`); + if (internalCommandType !== null) lines.push(`InternalCommandType: ${internalCommandType}`); const next = record(raw.next ?? data.next); const nextLines = (overrideNextLines ?? Object.values(next).map(String)).filter((line) => line.length > 0).slice(0, 5); if (nextLines.length > 0) lines.push("", "Next:", ...nextLines.map((line) => ` ${line}`)); @@ -3342,8 +3355,7 @@ async function runAgentRunSessionsRest(action: string | undefined, id: string | if (agentRunHasFlag(args, "dry-run")) return agentRunDryRunPlan("session-cancel", `/api/v1/sessions/${encodeURIComponent(id)}/control`, body, `bun scripts/cli.ts agentrun sessions cancel ${id}`); return await agentRunRestRequest("agentrun sessions cancel", "POST", `/api/v1/sessions/${encodeURIComponent(id)}/control`, body); } - if (action === "steer" && id) return await sessionSteerRest(id, args); - if (action === "turn") return await sessionTurnRest(id ?? null, args); + if (action === "send" && id) return await sessionSendRest(id, args); throw new AgentRunRestError("validation-failed", `unsupported sessions command: ${[action, id].filter(Boolean).join(" ") || "(empty)"}`); } @@ -3436,64 +3448,85 @@ async function mutateQueueTaskRest(action: string, taskId: string, suffix: strin return await agentRunRestRequest(`agentrun queue ${suffix}`, "POST", pathValue, body); } -async function sessionSteerRest(sessionId: string, args: string[]): Promise> { - const session = record(innerData(await agentRunRestRequest("agentrun sessions show", "GET", `/api/v1/sessions/${encodeURIComponent(sessionId)}${agentRunQuery(args, ["reader-id"])}`))); - const runId = stringOrNull(session.activeRunId) ?? stringOrNull(session.lastRunId); - if (runId === null) throw new AgentRunRestError("validation-failed", `session ${sessionId} has no run to steer`); - const prompt = readPromptFromArgs(args, 2); - const body: Record = { type: "steer", payload: { prompt } }; - const idempotencyKey = agentRunOption(args, "idempotency-key"); - if (idempotencyKey) body.idempotencyKey = idempotencyKey; - const command = await agentRunRestRequest("agentrun sessions steer", "POST", `/api/v1/runs/${encodeURIComponent(runId)}/commands`, body); - return { ok: command.ok !== false, command: "agentrun sessions steer", data: { action: "session-steer", sessionId, runId, command: innerData(command) }, bridge: command.bridge }; +async function sessionSendRest(sessionId: string, args: string[]): Promise> { + const aipod = agentRunOption(args, "aipod") ?? agentRunOption(args, "aipod-spec"); + if (aipod) return await sessionSendWithAipodRest(sessionId, aipod, args); + const input = await optionalJsonBody(args); + const prompt = optionalPromptFromArgs(args, 2); + const sendBody = await sessionSendBodyFromRunInput(sessionId, args, input, sessionSendPayloadFromInput(input, prompt)); + const response = await agentRunRestRequest("agentrun sessions send", "POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/send`, sendBody); + return { ok: response.ok !== false, command: "agentrun sessions send", data: innerData(response), bridge: response.bridge }; } -async function sessionTurnRest(positionalSessionId: string | null, args: string[]): Promise> { - const aipod = agentRunOption(args, "aipod") ?? agentRunOption(args, "aipod-spec"); - if (aipod) return await sessionTurnWithAipodRest(positionalSessionId, aipod, args); - const sessionId = positionalSessionId ?? agentRunOption(args, "session-id") ?? newAgentRunSessionId(); - const body = await optionalJsonBody(args); - const profile = agentRunOption(args, "profile") ?? agentRunOption(args, "backend-profile") ?? stringOrNull(body.backendProfile) ?? "codex"; - const prompt = readPromptFromArgs(args, positionalSessionId ? 2 : 1); - body.tenantId = agentRunOption(args, "tenant-id") ?? stringOrNull(body.tenantId) ?? "unidesk"; - body.projectId = agentRunOption(args, "project-id") ?? stringOrNull(body.projectId) ?? "default"; +function sessionSendPayloadFromInput(input: Record, prompt: string | null): Record { + const payload = record(input.payload); + if (Object.keys(payload).length > 0) return payload; + const text = prompt ?? stringOrNull(input.prompt) ?? stringOrNull(input.message) ?? stringOrNull(input.text); + if (text === null) throw new AgentRunRestError("validation-failed", "send requires payload or non-empty prompt/message/text; use --prompt-stdin, --prompt-file, --prompt, a trailing prompt, or JSON payload"); + return { prompt: text }; +} + +async function sessionSendBodyFromRunInput(sessionId: string, args: string[], input: Record, payload: Record): Promise> { + const fullSendBody = isExplicitSessionSendBody(input); + const runInput = fullSendBody ? record(input.run ?? input.runBase) : input; + const runBody = await sessionRunBodyFromArgs(sessionId, args, runInput); + const runnerDefaults = fullSendBody ? record(input.runnerJob) : {}; + const runnerJob = await sessionRunnerJobBody(args, runnerDefaults); + const body: Record = fullSendBody ? { ...input } : {}; + body.run = runBody; + body.payload = record(input.payload); + if (Object.keys(record(body.payload)).length === 0) body.payload = payload; + body.createRunnerJob = agentRunHasFlag(args, "no-runner-job") ? false : input.createRunnerJob !== false; + body.runnerJob = runnerJob; + body.dryRun = agentRunHasFlag(args, "dry-run"); + const commandIdempotencyKey = agentRunOption(args, "command-idempotency-key") ?? agentRunOption(args, "idempotency-key"); + if (commandIdempotencyKey) body.commandIdempotencyKey = commandIdempotencyKey; + return body; +} + +function isExplicitSessionSendBody(input: Record): boolean { + return isRecord(input.run) + || isRecord(input.runBase) + || isRecord(input.payload) + || isRecord(input.runnerJob) + || input.createRunnerJob !== undefined + || input.commandIdempotencyKey !== undefined; +} + +async function sessionRunBodyFromArgs(sessionId: string, args: string[], input: Record): Promise> { + const existing = await fetchAgentRunSessionOrNull(sessionId, args); + const profile = agentRunOption(args, "profile") + ?? agentRunOption(args, "backend-profile") + ?? stringOrNull(input.backendProfile) + ?? stringOrNull(existing?.backendProfile) + ?? "codex"; + const body: Record = { ...input }; + body.tenantId = agentRunOption(args, "tenant-id") ?? stringOrNull(body.tenantId) ?? stringOrNull(existing?.tenantId) ?? "unidesk"; + body.projectId = agentRunOption(args, "project-id") ?? stringOrNull(body.projectId) ?? stringOrNull(existing?.projectId) ?? "default"; body.providerId = agentRunOption(args, "provider-id") ?? stringOrNull(body.providerId) ?? "G14"; body.backendProfile = profile; body.workspaceRef = jsonObjectOption(args, "workspace-json") ?? record(body.workspaceRef); if (Object.keys(record(body.workspaceRef)).length === 0) body.workspaceRef = { kind: "opaque", path: "." }; body.executionPolicy = jsonObjectOption(args, "execution-policy-json") ?? record(body.executionPolicy); if (Object.keys(record(body.executionPolicy)).length === 0) body.executionPolicy = defaultAgentRunExecutionPolicy(profile); - const sessionRef = record(body.sessionRef); - const metadata = record(sessionRef.metadata); + const inheritedSessionRef = existing === null ? {} : { + conversationId: existing.conversationId, + threadId: existing.threadId, + metadata: existing.metadata, + }; + const sessionRef = { ...inheritedSessionRef, ...record(body.sessionRef) }; + const metadata = { ...record(inheritedSessionRef.metadata), ...record(sessionRef.metadata) }; const title = agentRunOption(args, "title"); if (title) metadata.title = title; body.sessionRef = { ...sessionRef, sessionId, metadata }; - await ensureAgentRunSession(sessionId, body); - const run = await agentRunRestRequest("agentrun runs create", "POST", "/api/v1/runs", body); - const runData = record(innerData(run)); - const runId = stringOrNull(runData.id) ?? requiredContext("session turn", "run id returned by AgentRun server"); - const commandBody: Record = { type: "turn", payload: { prompt } }; - const commandIdempotencyKey = agentRunOption(args, "command-idempotency-key") ?? agentRunOption(args, "idempotency-key"); - if (commandIdempotencyKey) commandBody.idempotencyKey = commandIdempotencyKey; - const command = await agentRunRestRequest("agentrun commands create", "POST", `/api/v1/runs/${encodeURIComponent(runId)}/commands`, commandBody); - const commandId = stringOrNull(record(innerData(command)).id); - let runnerJob: Record | null = null; - if (!agentRunHasFlag(args, "no-runner-job") && commandId !== null) { - const runnerBody = await optionalRunnerJsonBody(args); - runnerBody.commandId = commandId; - copyAgentRunOptions(args, runnerBody, ["image", "namespace", "attempt-id", "runner-id", "source-commit", "service-account-name"]); - runnerJob = await agentRunRestRequest("agentrun runner job", "POST", `/api/v1/runs/${encodeURIComponent(runId)}/runner-jobs`, runnerBody); - } - return { ok: true, command: "agentrun sessions turn", data: { action: "session-turn", sessionId, profile, run: innerData(run), command: innerData(command), runnerJob: runnerJob ? innerData(runnerJob) : null, valuesPrinted: false }, bridge: runnerJob?.bridge ?? command.bridge ?? run.bridge }; + return body; } -async function sessionTurnWithAipodRest(positionalSessionId: string | null, aipod: string, args: string[]): Promise> { - const sessionId = positionalSessionId ?? agentRunOption(args, "session-id") ?? newAgentRunSessionId(); - const rendered = await agentRunRestRequest("agentrun aipod-specs render", "POST", `/api/v1/aipod-specs/${encodeURIComponent(aipod)}/render`, await aipodRenderInputFromArgs(args, positionalSessionId ? 2 : 1, { sessionId })); +async function sessionSendWithAipodRest(sessionId: string, aipod: string, args: string[]): Promise> { + const rendered = await agentRunRestRequest("agentrun aipod-specs render", "POST", `/api/v1/aipod-specs/${encodeURIComponent(aipod)}/render`, await aipodRenderInputFromArgs(args, 2, { sessionId })); const renderedData = record(innerData(rendered)); const task = record(renderedData.queueTask); if (Object.keys(task).length === 0) throw new AgentRunRestError("schema-mismatch", `aipod-spec ${aipod} render did not return queueTask`); - await ensureAgentRunSession(sessionId, task); const sessionRef = record(task.sessionRef); const metadata = record(sessionRef.metadata); const title = agentRunOption(args, "title") ?? stringOrNull(task.title); @@ -3509,37 +3542,38 @@ async function sessionTurnWithAipodRest(positionalSessionId: string | null, aipo resourceBundleRef: task.resourceBundleRef, traceSink: { kind: "aipod-session", aipod, sessionId, valuesPrinted: false }, }; - const run = await agentRunRestRequest("agentrun runs create", "POST", "/api/v1/runs", runBody); - const runId = stringOrNull(record(innerData(run)).id) ?? requiredContext("session turn", "run id returned by AgentRun server"); - const commandBody: Record = { type: "turn", payload: task.payload }; + const runnerDefaults = record(record(renderedData.dispatchDefaults).runnerJob); + const sendBody: Record = { + run: runBody, + payload: task.payload, + createRunnerJob: !agentRunHasFlag(args, "no-runner-job"), + runnerJob: await sessionRunnerJobBody(args, runnerDefaults), + dryRun: agentRunHasFlag(args, "dry-run"), + }; const commandIdempotencyKey = agentRunOption(args, "command-idempotency-key") ?? agentRunOption(args, "idempotency-key"); - if (commandIdempotencyKey) commandBody.idempotencyKey = commandIdempotencyKey; - const command = await agentRunRestRequest("agentrun commands create", "POST", `/api/v1/runs/${encodeURIComponent(runId)}/commands`, commandBody); - const commandId = stringOrNull(record(innerData(command)).id); - let runnerJob: Record | null = null; - if (!agentRunHasFlag(args, "no-runner-job") && commandId !== null) { - const runnerDefaults = record(record(renderedData.dispatchDefaults).runnerJob); - const runnerBody = { ...runnerDefaults, ...(await optionalRunnerJsonBody(args)), commandId }; - copyAgentRunOptions(args, runnerBody, ["image", "namespace", "attempt-id", "runner-id", "source-commit", "service-account-name"]); - runnerJob = await agentRunRestRequest("agentrun runner job", "POST", `/api/v1/runs/${encodeURIComponent(runId)}/runner-jobs`, runnerBody); - } - return { ok: true, command: "agentrun sessions turn", data: { action: "session-turn", aipod, sessionId, profile: String(task.backendProfile ?? ""), run: innerData(run), command: innerData(command), runnerJob: runnerJob ? innerData(runnerJob) : null, valuesPrinted: false }, bridge: runnerJob?.bridge ?? command.bridge ?? run.bridge }; + if (commandIdempotencyKey) sendBody.commandIdempotencyKey = commandIdempotencyKey; + const response = await agentRunRestRequest("agentrun sessions send", "POST", `/api/v1/sessions/${encodeURIComponent(sessionId)}/send`, sendBody); + const data = record(innerData(response)); + return { ok: response.ok !== false, command: "agentrun sessions send", data: { ...data, aipod, profile: String(task.backendProfile ?? ""), valuesPrinted: false }, bridge: response.bridge }; } -async function ensureAgentRunSession(sessionId: string, source: Record): Promise { +async function fetchAgentRunSessionOrNull(sessionId: string, args: string[]): Promise | null> { try { - await agentRunRestRequest("agentrun sessions storage", "GET", `/api/v1/sessions/${encodeURIComponent(sessionId)}/storage`); - return; - } catch { - // Missing storage is recovered by creating the session; other failures will surface on create. + return record(innerData(await agentRunRestRequest("agentrun sessions show", "GET", `/api/v1/sessions/${encodeURIComponent(sessionId)}${agentRunQuery(args, ["reader-id"])}`))); + } catch (error) { + if (error instanceof AgentRunRestError && error.httpStatus === 404) return null; + throw error; } - await agentRunRestRequest("agentrun sessions create", "POST", "/api/v1/sessions", { - sessionId, - tenantId: source.tenantId ?? "unidesk", - projectId: source.projectId ?? "default", - backendProfile: source.backendProfile ?? "codex", - expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), - }); +} + +async function sessionRunnerJobBody(args: string[], defaults: Record = {}): Promise> { + const runnerBody = { ...defaults, ...(await optionalRunnerJsonBody(args)) }; + copyAgentRunOptions(args, runnerBody, ["image", "namespace", "attempt-id", "runner-id", "source-commit", "service-account-name"]); + const managerUrl = agentRunOption(args, "runner-manager-url"); + if (managerUrl !== null) runnerBody.managerUrl = managerUrl; + const runnerIdempotencyKey = agentRunOption(args, "runner-idempotency-key"); + if (runnerIdempotencyKey !== null) runnerBody.idempotencyKey = runnerIdempotencyKey; + return runnerBody; } async function agentRunRestRequest(command: string, method: AgentRunHttpMethod, pathValue: string, body?: unknown): Promise> { @@ -3967,12 +4001,26 @@ function jsonInputDisclosureFromArgs(args: string[]): Record { }; } -function newAgentRunSessionId(): string { - return `sess_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`; -} - function defaultAgentRunExecutionPolicy(profile: string): Record { - return { backendProfile: profile, valuesPrinted: false }; + const keys = profile === "sub2api" || profile === "codex" ? ["auth.json", "config.toml"] : ["auth.json", "config.toml"]; + return { + sandbox: "workspace-write", + approval: "never", + timeoutMs: 900000, + network: "enabled", + secretScope: { + allowCredentialEcho: false, + providerCredentials: [ + { + profile, + secretRef: { + name: `agentrun-v01-provider-${profile}`, + keys, + }, + }, + ], + }, + }; } function safeAgentRunEnvelope(envelope: Record): Record { @@ -4046,7 +4094,7 @@ type AgentRunHttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; type AgentRunFailureKind = "auth-missing" | "auth-failed" | "agentrun-unreachable" | "schema-mismatch" | "unsupported-version" | "validation-failed"; type AgentRunRestCompatGroup = "queue" | "sessions" | "aipod-specs" | "aipods" | "runs" | "commands" | "runner"; -type AgentRunResourceVerb = "get" | "describe" | "events" | "logs" | "result" | "ack" | "cancel" | "dispatch" | "create" | "apply" | "steer" | "send" | "explain"; +type AgentRunResourceVerb = "get" | "describe" | "events" | "logs" | "result" | "ack" | "cancel" | "dispatch" | "create" | "apply" | "send" | "explain"; type AgentRunResourceKind = "task" | "run" | "command" | "runnerjob" | "session" | "aipodspec"; type AgentRunOutputMode = "human" | "wide" | "name" | "json" | "yaml"; @@ -4471,7 +4519,7 @@ function unsupported(args: string[]): RenderedCliResult { `Error: unsupported AgentRun command: ${command}`, "", "Supported resource commands:", - " agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send", + " agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|send", "", "Compatibility bridge groups:", " agentrun aipod-specs|queue|runs|commands|runner|sessions", diff --git a/scripts/src/help.ts b/scripts/src/help.ts index 1742c643..5bc507b6 100644 --- a/scripts/src/help.ts +++ b/scripts/src/help.ts @@ -57,14 +57,14 @@ export function rootHelp(): unknown { { command: "commander contract|plan --dry-run|smoke --dry-run|approval request --dry-run", description: "Host Codex commander skeleton contract, no-daemon smoke plan, and dry-run approval preview without live bridges or message sends." }, { command: "hwlab nodes control-plane|git-mirror|secret --node G14 --lane v03", description: "Manage HWLAB node/lane runtime prerequisites for v0.3+ with the node identity passed as data instead of a command family." }, { command: "hwlab g14 monitor-prs | hwlab g14 control-plane status|apply|trigger-current|runtime-migration|cleanup-runs|cleanup-released-pvs | hwlab g14 git-mirror status|apply|sync|flush | hwlab g14 tools-image status|build", description: "Start the legacy G14 PR monitor, run bounded v0.2 Tekton/Argo control-plane, manual PipelineRun trigger, runtime migration, CI workspace retention, manual devops-infra git mirror/relay maintenance, or fixed HWLAB CI tools image actions; long confirmed trigger/sync/flush actions return async jobs by default." }, - { command: "agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send|control-plane|git-mirror", description: "Use AgentRun v0.1 resource primitives with low-noise human output by default; legacy bridge groups remain available for raw compatibility." }, + { command: "agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|send|control-plane|git-mirror", description: "Use AgentRun v0.1 resource primitives with low-noise human output by default; session follow-up uses send only and the server decides internal steer vs turn." }, { command: "platform-infra sub2api plan|apply|status|validate|codex-pool", description: "Deploy Sub2API in G14 platform-infra, manage the YAML-controlled Codex upstream pool, expose the unified API, and inspect marker sentinel state with low-noise reports without printing API keys." }, { command: "hwlab cd audit --env dev | hwlab cd status --env dev | hwlab cd apply --env dev --dry-run", description: "Legacy D601 HWLAB DEV CD wrapper kept for explicit old-path diagnostics; current HWLAB rollout uses G14 GitOps." }, { command: "code-agent-sandbox", description: "Independent Code Agent Sandbox service skeleton for adapter, mode, and credential-boundary diagnostics." }, { command: "schedule list|get|runs|run|retry-run|delete", description: "Manage backend-core scheduled tasks and run history; schedule run supports --wait-ms N and retry-run reuses the failed run's schedule." }, { command: "schedule upsert-pgdata-backup [--time HH:MM] [--remote-base /SERVER_DATA/UNIDESK_PG_DATA]", description: "Create or update the daily PGDATA physical backup task that uploads monthly rotated archives to Baidu Netdisk." }, { command: "codex deploy [--provider-id D601] [--timeout-ms N]", description: "Disabled legacy Code Queue deploy path; use the dev-only artifact consumer instead." }, - { command: "codex submit|steer|resume|queue create|queue merge|move", description: "Frozen legacy Code Queue write commands; use agentrun create/apply/steer/send for new commander work. Historical codex task/tasks/output/read/unread/queues remain available for archive troubleshooting." }, + { command: "codex submit|steer|resume|queue create|queue merge|move", description: "Frozen legacy Code Queue write commands; use agentrun create/apply/send for new commander work. Historical codex task/tasks/output/read/unread/queues remain available for archive troubleshooting." }, { command: "codex skills-sync --dry-run [--full]", description: "Inspect the controlled runner skills hostPath lifecycle contract without copying files, restarting services, reading secrets, or mutating live runner paths." }, { command: "codex execution-plane [--full|--raw]", description: "Read-only D601 native k3s Code Queue execution-plane inspection; compares formal deployments, deprecated Compose residuals, commit markers, pod digest, and mounted worktree HEAD." }, { command: "codex pr-preflight [--remote] [--push-dry-run --push-dry-run-ref refs/heads/probe/] [--pr-create-dry-run --pr-create-dry-run-head ] [--issue N] [--full|--raw]", description: "Read-only PR admission check with compact commander output by default; use --full or --raw to expand the full runtime preflight, tool, and observation payload." }, @@ -75,7 +75,7 @@ export function rootHelp(): unknown { { command: "codex read ", description: "Mark one reviewed terminal task read and return terminal metadata plus final response; prompt/tool logs stay behind drill-down commands." }, { command: "codex dev-ready", description: "Fetch execution-container readiness, including sanitized skill injection status from /api/dev-ready." }, { command: "codex judge --attempt N [--dry-run] [--include-prompt]", description: "Replay one stored Code Queue attempt through the same judge context builder and MiniMax judge call path used by the live queue worker." }, - { command: "codex steer / codex resume ", description: "Frozen legacy execution mutation entries; use agentrun steer/send/logs/events/result/ack/cancel against AgentRun resources instead." }, + { command: "codex steer / codex resume ", description: "Frozen legacy execution mutation entries; use agentrun send/logs/events/result/ack/cancel against AgentRun resources instead." }, { command: "codex steer-confirm --steer-id [--raw]", description: "Read-only lookup for a steerId in task trace so deliveryUnconfirmed can be resolved without resending the corrective prompt." }, { command: "codex interrupt|cancel ", description: "Request interrupt for a running Code Queue task, or cancel a queued/retry_wait task, through the same private proxy." }, { command: "codex queues [--full|--all] [--limit N] [--page N|--offset N]", description: "Read legacy Code Queue archive summaries. Legacy queue create/merge and move are frozen; use agentrun create/apply/get/cancel for new work." }, @@ -391,7 +391,7 @@ function codexHelp(): unknown { "bun scripts/cli.ts codex execution-plane [--full|--raw]", "bun scripts/cli.ts codex pr-preflight [--remote] [--push-dry-run --push-dry-run-ref refs/heads/probe/] [--pr-create-dry-run --pr-create-dry-run-head ] [--issue N] [--full|--raw]", "bun scripts/cli.ts codex judge --attempt N [--dry-run] [--include-prompt]", - "bun scripts/cli.ts agentrun steer session/ --prompt-stdin", + "bun scripts/cli.ts agentrun send session/ --prompt-stdin", "bun scripts/cli.ts codex steer # frozen legacy write entry", "bun scripts/cli.ts codex resume # frozen legacy write entry", "bun scripts/cli.ts codex steer-confirm --steer-id [--raw]", @@ -463,7 +463,7 @@ function codexHelp(): unknown { redline: "data.supervisor.activeRunning.redline names the count field, routine target, burst redline, hard redline, and decisionReady flag.", limitSemantics: "filters.requestedLimit preserves the user input; filters.limit/effectiveLimit shows the capped query budget; section outputBudget/rowPage show returned-row caps.", }, - description: "Operate legacy Code Queue as a read-only archive through bounded task/output/read/unread/queues views. New task dispatch, retry/resume, steer, queue mutation, move, and workdir mutation are frozen and replaced by AgentRun resource primitives via bun scripts/cli.ts agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send.", + description: "Operate legacy Code Queue as a read-only archive through bounded task/output/read/unread/queues views. New task dispatch, retry/resume, queue mutation, move, and workdir mutation are frozen and replaced by AgentRun resource primitives via bun scripts/cli.ts agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|send.", }; } @@ -578,7 +578,7 @@ function artifactRegistryHelp(): unknown { function agentRunHelpSummary(): unknown { return { - command: "agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send|control-plane|git-mirror", + command: "agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|send|control-plane|git-mirror", output: "human by default; use -o json|yaml or --raw", usage: [ "bun scripts/cli.ts agentrun get tasks --queue commander --limit 20",