fix: unify agentrun session send cli
This commit is contained in:
@@ -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/<sessionId> --tail 100
|
||||
bun scripts/cli.ts agentrun ack session/<sessionId>
|
||||
bun scripts/cli.ts agentrun dispatch task/<taskId>
|
||||
bun scripts/cli.ts agentrun send session/<sessionId> --aipod Artificer --prompt-stdin
|
||||
bun scripts/cli.ts agentrun steer session/<sessionId> --prompt-stdin
|
||||
bun scripts/cli.ts agentrun cancel session/<sessionId> --reason <text> --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/<sessionId>`。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/<runId>` 和 `result run/<runId> --command <commandId>`,判断 terminalClassification、failureKind、provider interruption、timeoutBudget 和 recoveryActions。
|
||||
4. Command 级状态用 `describe command/<commandId> --run <runId>` 和 `result command/<commandId> --run <runId>`,确认 command state、ack、terminal status 和结果摘要。
|
||||
5. Runner job 只读状态用 `describe runnerjob/<runnerJobId> --run <runId>`,确认 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/<sessionId>`;`sessionRef=null` 时不要猜 session 命令。
|
||||
6. Session trace/output 只在 `describe task` 或 result 里有实际 `sessionId` 时使用 `logs|ack|send|cancel session/<sessionId>`;`sessionRef=null` 时不要猜 session 命令。
|
||||
7. 已创建但尚未运行的 task 使用 `dispatch task/<taskId>` 派发,不再退回旧 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/<sessionId>` 或 `send session/<sessionId> --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/<sessionId> --aipod Artificer`。需要验证 HWLAB Web/Cloud API 原入口时,仍按 `$hwlab-code-agent` 使用 G14 `/root/hwlab-v02` 的 `hwlab-cli client agent ...` 拉取同一 trace/result/inspect;不要回到旧 `codex submit/resume/steer`。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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 <jobId|latest>` 读取阶段化 progress 和 bounded log tail;只有现场同步调试才显式加 `--wait`。`run` 手动创建每 commit 检查和 Code Queue 只读性能门禁;`publish-backend-core` 与 `publish-user-service` 从 pushed Git commit 构建并发布 `127.0.0.1:5000/unidesk/<service>:<commit>` 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 <scheduleId> --limit N` 是只读观察入口;`schedule run`、`schedule retry-run`、`schedule delete` 和 `schedule upsert-pgdata-backup` 会触发运行或写入配置,生产恢复时必须有明确授权。`schedule runs --limit N` 是全局历史视图,返回 `scope=global` 和 `scheduleId=null`;`schedule runs <scheduleId> --limit N` 是指定 schedule 历史视图,返回 `scope=schedule` 和对应 `scheduleId`。CLI 必须拒绝 `schedule runs 50` 这类纯数字位置参数,并提示使用 `schedule runs --limit 50`,避免把空数组误判成“没有历史 run”。`schedule run <id> --wait-ms N` 触发同一 schedule,并且即使 wait 超时也必须返回 `newRunId` 和 `observeCommand`;`schedule retry-run <failedRunId>` 只接受 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 <commitId>` 是旧 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/<taskId>`、`events run/<runId>`、`logs session/<sessionId>`、`result run/<runId> --command <commandId>`;日常写入用 `create task --aipod Artificer --prompt-stdin`、`apply -f -`、`dispatch task/<taskId>`、`steer/send session/<sessionId>`、`ack/cancel task|session/<id>`。兼容 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/<taskId>`、`events run/<runId>`、`logs session/<sessionId>`、`result run/<runId> --command <commandId>`;日常写入用 `create task --aipod Artificer --prompt-stdin`、`apply -f -`、`dispatch task/<taskId>`、`send session/<sessionId>`、`ack/cancel task|session/<id>`。用户级 CLI 取消 `turn` 和 `steer` 路径;`send session/<sessionId>` 是唯一 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:<remotePort>`,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/<sessionId>`。
|
||||
- 旧 Code Queue 只保留历史归档、只读排障和残留任务停止。`codex task/tasks/output/read/unread/queues` 继续通过 backend-core 私有代理读取旧 PostgreSQL 历史;`codex interrupt|cancel <taskId>` 只用于停止旧运行面残留任务。旧 `steer-confirm` 只作为历史 trace confirmation 查询,不是新任务控制入口。
|
||||
- `codex pr-preflight [--remote] [--push-dry-run --push-dry-run-ref refs/heads/probe/<name>] [--pr-create-dry-run --pr-create-dry-run-head <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 <taskId>` 通过 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 <taskId> --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 <taskId> --steer-id <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/<sessionId> --prompt-stdin`,并用 `logs session/<sessionId>`、`events run/<runId>`、`result run/<runId> --command <commandId>` 和 `ack session/<sessionId>` 观察。
|
||||
- 旧 `codex steer` 已冻结;`codex steer-confirm` 只作为历史 trace confirmation lookup。新运行中纠偏使用 `bun scripts/cli.ts agentrun send session/<sessionId> --prompt-stdin`,并用 `logs session/<sessionId>`、`events run/<runId>`、`result run/<runId> --command <commandId>` 和 `ack session/<sessionId>` 观察。
|
||||
- `codex interrupt|cancel <taskId>` 通过 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://<ip>:<frontendPort>/` 获取 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 <taskId>`、`codex tasks`、`codex unread`、`codex queues`、`codex output <taskId>`、`codex judge <taskId> --attempt N` 和 `ssh <PROVIDER_ID> <remote-command>`。`microservice status/health/diagnostics` 经 frontend 远程传输时也复用本地 CLI 的默认 compact summary,`microservice health code-queue` 只有显式 `--raw` 或 `--full` 才返回完整健康 body。运行中纠偏已切到 AgentRun `steer session/<sessionId>`;旧 `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 <key>` 或 `--main-server-transport ssh`,这时 CLI 会通过 SSH 登录主 server 的 `--main-server-root` 目录执行同一个 `bun scripts/cli.ts <command>`。
|
||||
默认 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 <taskId>`、`codex tasks`、`codex unread`、`codex queues`、`codex output <taskId>`、`codex judge <taskId> --attempt N` 和 `ssh <PROVIDER_ID> <remote-command>`。`microservice status/health/diagnostics` 经 frontend 远程传输时也复用本地 CLI 的默认 compact summary,`microservice health code-queue` 只有显式 `--raw` 或 `--full` 才返回完整健康 body。运行中纠偏已切到 AgentRun `send session/<sessionId>`;旧 `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 <key>` 或 `--main-server-transport ssh`,这时 CLI 会通过 SSH 登录主 server 的 `--main-server-root` 目录执行同一个 `bun scripts/cli.ts <command>`。
|
||||
|
||||
计算节点可以用该入口测试自身的远程升级闭环,而不需要在计算节点公开 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_ID> provider.upgrade --mode schedule --wait-ms 15000` 触发真实 `provider.upgrade`;随后再次运行 `debug health` 确认节点重新上线;最后运行 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug dispatch <PROVIDER_ID> host.ssh --wait-ms 15000` 和 `bun scripts/cli.ts --main-server-ip 74.48.78.17 ssh <PROVIDER_ID> hostname` 验证 SSH 透传能力。provider-gateway 新部署或升级后没有完成这组 remote CLI 自测,不能视为交付完成。
|
||||
|
||||
|
||||
@@ -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/<taskId>` 派发,`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/<taskId>` 派发,`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/<sessionId>` 是唯一用户级 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 <issue-number>
|
||||
|
||||
### Runner Resume 收口
|
||||
|
||||
PR 小修、冲突、rebase、补测和 reviewer feedback 的新执行入口是 AgentRun 资源原语。仍在 AgentRun session 内的工作优先使用 `bun scripts/cli.ts agentrun steer session/<sessionId> --prompt-stdin` 或 `send session/<sessionId>`;已沉淀成新工作项时使用 `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/<sessionId> --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/<sessionId> --aipod Artificer --prompt-stdin` 或 `steer session/<sessionId>` 继续同一个 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/<sessionId> --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 <taskId>`:默认只查看原始 prompt、最终 response、最后错误和 drill-down 命令,这是完成未读任务审阅的第一步。
|
||||
- 当默认审阅摘要不足时,再逐级使用 `bun scripts/cli.ts codex task <taskId> --detail`、`bun scripts/cli.ts codex task <taskId> --trace --limit N` 或 `codex output`。
|
||||
- `bun scripts/cli.ts agentrun steer session/<sessionId> --prompt-stdin`:对 AgentRun 中仍可继续的 session 追加修正;旧 `codex resume` 已冻结。
|
||||
- `bun scripts/cli.ts agentrun send session/<sessionId> --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/<sessionId> --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/<sessionId> --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 同一任务。
|
||||
|
||||
+141
-93
@@ -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/<taskId>",
|
||||
"bun scripts/cli.ts agentrun create task --aipod Artificer --prompt-stdin --idempotency-key <key>",
|
||||
"bun scripts/cli.ts agentrun apply -f - --dry-run",
|
||||
"bun scripts/cli.ts agentrun steer session/<sessionId> --prompt-stdin",
|
||||
"bun scripts/cli.ts agentrun send session/<sessionId> --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: <AgentRun task payload>.";
|
||||
}
|
||||
if (verb === "steer") {
|
||||
return "Usage: bun scripts/cli.ts agentrun steer session/<sessionId> --prompt-stdin";
|
||||
}
|
||||
if (verb === "send") {
|
||||
return "Usage: bun scripts/cli.ts agentrun send session/<sessionId> --aipod Artificer --prompt-stdin";
|
||||
return "Usage: bun scripts/cli.ts agentrun send session/<sessionId> --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 <verb> <resource> [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<RenderedCliResult> {
|
||||
async function resourceSessionPromptCommand(config: UniDeskConfig | null, command: string, action: string | undefined, args: string[], options: AgentRunResourceOptions): Promise<RenderedCliResult> {
|
||||
const ref = parseResourceRef(action, args, "session");
|
||||
if (ref.kind !== "session") throw new Error(`${officialAction === "steer" ? "steer" : "send"} requires session/<sessionId>`);
|
||||
const sessionArgs = [officialAction, ref.name, ...stripLeadingResource(args, ref.name)];
|
||||
if (ref.kind !== "session") throw new Error("send requires session/<sessionId>");
|
||||
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<string, unknown>, 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<string, unknown>, 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<Record<string, unknown>> {
|
||||
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<string, unknown> = { 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<Record<string, unknown>> {
|
||||
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<Record<string, unknown>> {
|
||||
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<string, unknown>, prompt: string | null): Record<string, unknown> {
|
||||
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<string, unknown>, payload: Record<string, unknown>): Promise<Record<string, unknown>> {
|
||||
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<string, unknown> = 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<string, unknown>): 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<string, unknown>): Promise<Record<string, unknown>> {
|
||||
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<string, unknown> = { ...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<string, unknown> = { 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<string, unknown> | 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<Record<string, unknown>> {
|
||||
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<Record<string, unknown>> {
|
||||
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<string, unknown> = { type: "turn", payload: task.payload };
|
||||
const runnerDefaults = record(record(renderedData.dispatchDefaults).runnerJob);
|
||||
const sendBody: Record<string, unknown> = {
|
||||
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<string, unknown> | 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<string, unknown>): Promise<void> {
|
||||
async function fetchAgentRunSessionOrNull(sessionId: string, args: string[]): Promise<Record<string, unknown> | 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<string, unknown> = {}): Promise<Record<string, unknown>> {
|
||||
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<Record<string, unknown>> {
|
||||
@@ -3967,12 +4001,26 @@ function jsonInputDisclosureFromArgs(args: string[]): Record<string, unknown> {
|
||||
};
|
||||
}
|
||||
|
||||
function newAgentRunSessionId(): string {
|
||||
return `sess_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
||||
}
|
||||
|
||||
function defaultAgentRunExecutionPolicy(profile: string): Record<string, unknown> {
|
||||
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<string, unknown>): Record<string, unknown> {
|
||||
@@ -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",
|
||||
|
||||
+6
-6
@@ -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 <id> 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 <commitId> [--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/<name>] [--pr-create-dry-run --pr-create-dry-run-head <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 <taskId>", 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 <taskId> --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 <taskId> / codex resume <taskId>", description: "Frozen legacy execution mutation entries; use agentrun steer/send/logs/events/result/ack/cancel against AgentRun resources instead." },
|
||||
{ command: "codex steer <taskId> / codex resume <taskId>", description: "Frozen legacy execution mutation entries; use agentrun send/logs/events/result/ack/cancel against AgentRun resources instead." },
|
||||
{ command: "codex steer-confirm <taskId> --steer-id <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 <taskId>", 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/<name>] [--pr-create-dry-run --pr-create-dry-run-head <head>] [--issue N] [--full|--raw]",
|
||||
"bun scripts/cli.ts codex judge <taskId> --attempt N [--dry-run] [--include-prompt]",
|
||||
"bun scripts/cli.ts agentrun steer session/<sessionId> --prompt-stdin",
|
||||
"bun scripts/cli.ts agentrun send session/<sessionId> --prompt-stdin",
|
||||
"bun scripts/cli.ts codex steer <taskId> # frozen legacy write entry",
|
||||
"bun scripts/cli.ts codex resume <taskId> # frozen legacy write entry",
|
||||
"bun scripts/cli.ts codex steer-confirm <taskId> --steer-id <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",
|
||||
|
||||
Reference in New Issue
Block a user