From 774c32515e70b8def6abb1015423311e316df34f Mon Sep 17 00:00:00 2001 From: Codex Date: Sat, 23 May 2026 00:16:20 +0000 Subject: [PATCH] fix: reduce codex submit success noise --- AGENTS.md | 2 +- docs/reference/cli.md | 2 +- docs/reference/code-queue-supervision.md | 2 +- ...e-queue-cli-submit-prompt-contract-test.ts | 31 ++++++ scripts/src/code-queue.ts | 102 ++++++++++++++++-- scripts/src/help.ts | 4 +- 6 files changed, 132 insertions(+), 11 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 70cf76e7..92c9bef0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,7 +49,7 @@ UniDesk 是一个以主 server 为统一入口的分布式工作平台;本文 - `bun scripts/cli.ts commander contract|plan --dry-run|smoke --dry-run|approval request --dry-run`:查看 host Codex 指挥官直管微服务 skeleton 的 source/contract、无 daemon smoke 验证计划、.state/commander/ 状态模型、trace summary 聚合和 ClaudeQQ 高风险请示草案;当前只返回 dry-run 计划,不接 live bridge、不接管人工指挥官,不发送消息,规则见 `docs/reference/host-codex-commander.md`。 - `bun scripts/cli.ts ci install/status/run/publish-backend-core/publish-user-service/run-dev-e2e/logs`:在 D601 原生 k3s 上安装和运行 Tekton CI,支持每 commit 检查、Code Queue 只读性能门禁、`CI.json` catalog 驱动的 backend-core 与 user-service commit-pinned 镜像发布和手动触发的 `origin/master:deploy.json#environments.dev` 临时 namespace e2e;catalog/producer/consumer 分工见 `docs/reference/cicd-standardization.md`,`run-dev-e2e` 的 Git 控制 runner、短 launcher 和 no-CD 边界见 `docs/reference/dev-ci-runner.md`,Tekton 规则见 `docs/reference/ci.md`。 - `bun scripts/cli.ts codex deploy `:旧 Code Queue 兼容部署入口已禁用,原因是它会绕过受控部署边界直连 D601 部署 Code Queue;规则见 `docs/reference/codex-deploy.md`。 -- `bun scripts/cli.ts codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue ]` / `codex pr-preflight [--remote]`:前者通过 backend-core 私有代理提交 Code Queue 任务,`--dry-run` 会给出 MiniMax/GPT/人工路由建议但不改写 payload;后者只读检查 D601 scheduler/runner 的 GitHub token、egress 和 PR 能力,PR 型派单前必须使用,规则见 `docs/reference/cli.md` 和 `docs/reference/code-queue-supervision.md`。 +- `bun scripts/cli.ts codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue ]` / `codex pr-preflight [--remote]`:前者通过 backend-core 私有代理提交 Code Queue 任务,`--dry-run` 会给出 MiniMax/GPT/人工路由建议但不改写 payload,真实提交成功只返回写入确认、task id 和后续查看命令,不回显 prompt;后者只读检查 D601 scheduler/runner 的 GitHub token、egress 和 PR 能力,PR 型派单前必须使用,规则见 `docs/reference/cli.md` 和 `docs/reference/code-queue-supervision.md`。 - `bun scripts/cli.ts codex task `:按 Code Queue 任务 ID 查询默认审阅摘要,只返回原始 prompt、最终 response、最后错误和渐进披露命令;需要工具调用、attempt/judge 和详细耗时时显式加 `--detail`;`codex queues [--full] [--limit N] [--page N|--offset N]` 默认分页低噪声输出队列摘要,完整 upstream 只通过 raw command 显式获取。 - `bun scripts/cli.ts codex judge --attempt [--dry-run]`:按指定 task/attempt 用与队列 worker 相同的上下文构建和 MiniMax judge 调用路径单步复现完成判定;`--dry-run` 只输出 prompt/payload 诊断。 - `bun scripts/cli.ts codex steer [prompt|--prompt-file path|--prompt-stdin] [--dry-run]`:通过 Code Queue 私有代理向运行中的 active turn 注入纠偏提示,正式替代底层 `microservice proxy ... /steer` 调用。 diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 3b7650aa..b95f1909 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -44,7 +44,7 @@ CLI 可以从 `master` 快速演进,但必须兼容 `deploy.json` 固定的 CI - `ci install|status|run|publish-backend-core|publish-user-service|run-dev-e2e|logs` 管理 D601 原生 k3s 上的 Tekton CI。`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`。 -- `codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--reasoning-effort effort] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run]` 通过 backend-core 私有代理向稳定 `code-queue` 用户服务路径提交任务;prompt 必须且只能来自位置参数、文件或 stdin 之一,`--dry-run` 只返回结构化请求且不实际入队。长 prompt、多行 prompt、含引号/反引号/Markdown 表格/JSON/反斜杠的 prompt 必须优先用 `--prompt-stdin` 或 `--prompt-file`,不要拼进 shell 单个参数;位置参数只适合短单行 smoke prompt。stdin 推荐用 quoted heredoc:`cat <<'PROMPT' | bun scripts/cli.ts codex submit --prompt-stdin --queue --dry-run`,文件路径推荐 `bun scripts/cli.ts codex submit --prompt-file /tmp/code-queue-prompt.md --queue --dry-run`,确认 dry-run 后移除 `--dry-run` 提交同一 payload。dry-run 会额外输出 `routingRecommendation`,包含推荐 route、runner、model、风险信号、prompt 自包含/issue 非唯一来源/prod-secret-DB 禁止/运行态或 release 禁止/证据要求/中等复杂度候选等 guard 状态;同时输出 `policyContract`,固定暴露 GPT-5.5、DeepSeek、MiniMax 的风险分层、并发上限和外部 provider 429 退避处置。该建议只用于指挥官 preflight,不会改写 payload,不改变 runtime admission,也不假设生产 MiniMax 或 DeepSeek 可用。提交确认和 dry-run 必须返回完整 prompt、字符数和 `truncated=false`,不能套用任务详情的预览截断策略,否则长任务 prompt 无法被人工验收。真实提交会经过本机本地串行化保护和短节流,避免同一指挥端并发 submit 把低内存主机或 `code-queue-mgr` 控制面打抖;返回值会附带 `submitConcurrencyGuard` 说明本次提交的锁与等待信息。backend-core 默认把提交、队列 CRUD、已读状态、历史摘要和轻量 Trace 读取分流到主 server `code-queue-mgr`,由它写入主 PostgreSQL;D601 scheduler 只轮询并执行已入库任务。 +- `codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--reasoning-effort effort] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run]` 通过 backend-core 私有代理向稳定 `code-queue` 用户服务路径提交任务;prompt 必须且只能来自位置参数、文件或 stdin 之一,`--dry-run` 只返回结构化请求且不实际入队。长 prompt、多行 prompt、含引号/反引号/Markdown 表格/JSON/反斜杠的 prompt 必须优先用 `--prompt-stdin` 或 `--prompt-file`,不要拼进 shell 单个参数;位置参数只适合短单行 smoke prompt。stdin 推荐用 quoted heredoc:`cat <<'PROMPT' | bun scripts/cli.ts codex submit --prompt-stdin --queue --dry-run`,文件路径推荐 `bun scripts/cli.ts codex submit --prompt-file /tmp/code-queue-prompt.md --queue --dry-run`,确认 dry-run 后移除 `--dry-run` 提交同一 payload。dry-run 会额外输出 `routingRecommendation`,包含推荐 route、runner、model、风险信号、prompt 自包含/issue 非唯一来源/prod-secret-DB 禁止/运行态或 release 禁止/证据要求/中等复杂度候选等 guard 状态;同时输出 `policyContract`,固定暴露 GPT-5.5、DeepSeek、MiniMax 的风险分层、并发上限和外部 provider 429 退避处置。该建议只用于指挥官 preflight,不会改写 payload,不改变 runtime admission,也不假设生产 MiniMax 或 DeepSeek 可用。`--dry-run` 必须返回完整 prompt、字符数和 `truncated=false` 用于人工验收;真实提交是写入操作,默认只返回 `accepted=true`、task id、队列、写入保护摘要和后续查看命令,必须标记 `promptOmitted=true` 且不得回显 prompt 或 promptPreview。真实提交会经过本机本地串行化保护和短节流,避免同一指挥端并发 submit 把低内存主机或 `code-queue-mgr` 控制面打抖;返回值会附带低噪声 `submitConcurrencyGuard` 说明本次提交的锁与等待信息。backend-core 默认把提交、队列 CRUD、已读状态、历史摘要和轻量 Trace 读取分流到主 server `code-queue-mgr`,由它写入主 PostgreSQL;D601 scheduler 只轮询并执行已入库任务。 - `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]` 通过稳定 `code-queue` proxy 请求 D601 scheduler `/api/runtime-preflight`,用于 PR 型派单 admission。输出会压缩展示 scheduler/runner 的 token 覆盖、Auth Broker source/capability/nextAction、工具、agent port、Git worktree、GitHub egress、repo/issue/PR 只读探测、可选 push dry-run,以及可选 PR body/create dry-run guard;只报告 `GH_TOKEN`/`GITHUB_TOKEN` 是否存在和来源 key,不打印值。当 auth-broker 配置存在时,`tokenCoverage.source="auth-broker"`、`credentialSource="broker-issued-token"` 且 runner env token 不是成功前提;当仅 env token 存在时,`credentialSource="env-token"` 且 `preflight.authBroker.nextAction="use-env-token-until-auth-broker-live"`;两者都缺失时顶层 `ok=false`、`runnerDisposition=infra-blocked`、`degradedReason=auth-broker-needed`,`tokenCoverage.missing` 同时列出 `GH_TOKEN` 与 `GITHUB_TOKEN`,并输出 `preflight.authBroker.source="broker/auth-broker-needed"`、`capability.source="missing-token"`。该 `auth-missing` 的 scope 是 `scheduler-runner-env`,不能简化成“当前 active runner/dev container 不能创建 PR”;输出必须带 `scopeBoundary` 和 `activeRunnerDevContainer`,要求调用方另跑 `bun scripts/cli.ts gh auth status --repo pikasTech/unidesk` 与 PR dry-run 来确认当前 dev container 能力。`preflight.prCapabilityContract` 是 runner-facing 合同摘要,必须包含目标分支、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 授权和 `gh pr merge` 的 `unsupported-command` 边界;系统 `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`;需要完整 prompt/response 文本时加 `--full`;需要工具调用、judge、attempt 全量摘要时使用 `--detail --full --tool-limit N`。该摘要读取默认由主 server `code-queue-mgr` 从 PostgreSQL 返回,不依赖 D601 `code-queue-read` Service 可用。 - `codex tasks [--view supervisor|full] [--queue id] [--status succeeded|running|queued|failed|canceled|judging|retry_wait[,..]] [--unread|--unread-only] [--limit N] [--before-id id]` 通过同一私有代理输出渐进式披露视图。默认 `supervisor` 是低噪声指挥官视图,只返回 `running`、`completedUnread`、`recentCompleted`、`queued` 和 `executionDiagnostics` 的紧凑行;prompt/body 只给短预览和原始字符数,`running`/`completedUnread`/`queued` 默认只返回一个有界小页并通过 section `commands.next` 继续分页,`recentCompleted` 默认最多返回 5 条且不重复 `completedUnread` 未读终态,不嵌入完整 Trace、final response 或全量 overview。每个条目只保留 task id、队列、状态、issue、分类和短摘要,`show/detail/trace/output/full/read` 放在 section template 中避免重复噪声,并带 `kind` 标记直接推进、部署修复、验证/报告噪声等类别,帮助指挥官按 #131 聚焦真实推进而不是被 Gate/报告/审查任务牵引。`--unread` 是 `--unread-only` 的别名,必须只保留未读终态;`--status` 必须真实过滤支持的状态,未知参数或未知状态必须结构化失败,不能静默忽略。需要更详细当前页任务行时显式使用 `--view full` 或 `--full`,仍受 `--limit` 和 `--before-id` 分页约束。 diff --git a/docs/reference/code-queue-supervision.md b/docs/reference/code-queue-supervision.md index 8ab70005..cfdf0f99 100644 --- a/docs/reference/code-queue-supervision.md +++ b/docs/reference/code-queue-supervision.md @@ -55,7 +55,7 @@ Code Queue 派单模型按成本、可信度和 blast radius 分层:GPT-5.5/Codex 处理高风险和复杂任务,DeepSeek/OpenCode 处理中等复杂度且边界清晰的任务,MiniMax/OpenCode 处理简单、低权限、可复核任务,生产重启、密钥、数据库手工写入和运行中任务控制保留给指挥官或人工。 -当前提交合同由 `bun scripts/cli.ts codex submit` 暴露:prompt 必须来自位置参数、`--prompt-file` 或 `--prompt-stdin`;可选字段包括 `--queue/--queue-id`、`--provider-id/--provider`、`--cwd/--workdir`、`--model`、`--reasoning-effort`、`--execution-mode/--mode`、`--max-attempts` 和 `--reference-task-id/--reference/--ref`。长 prompt、多行 prompt、含引号/反引号/Markdown 表格/JSON/反斜杠的 prompt 应使用 `--prompt-stdin` 或 `--prompt-file`,例如 `cat <<'PROMPT' | bun scripts/cli.ts codex submit --prompt-stdin --queue --dry-run` 或 `bun scripts/cli.ts codex submit --prompt-file /tmp/code-queue-prompt.md --queue --dry-run`;位置参数只适合短单行 smoke prompt。提交前先用 `--dry-run` 检查完整 payload,确认后移除 `--dry-run`。这些字段写入任务 payload 后由 `code-queue-mgr` 入 PostgreSQL,核心任务字段包括 `queue_id`、`provider_id`、`execution_mode`、`model`、`cwd`、`prompt/base_prompt`、`reference_task_ids`、`reasoning_effort`、`max_attempts` 和 `task_json`;队列记录至少有 `id/name/created_at/updated_at`。模型治理应优先看任务 payload 和数据库字段,不靠 worker final response 自报。 +当前提交合同由 `bun scripts/cli.ts codex submit` 暴露:prompt 必须来自位置参数、`--prompt-file` 或 `--prompt-stdin`;可选字段包括 `--queue/--queue-id`、`--provider-id/--provider`、`--cwd/--workdir`、`--model`、`--reasoning-effort`、`--execution-mode/--mode`、`--max-attempts` 和 `--reference-task-id/--reference/--ref`。长 prompt、多行 prompt、含引号/反引号/Markdown 表格/JSON/反斜杠的 prompt 应使用 `--prompt-stdin` 或 `--prompt-file`,例如 `cat <<'PROMPT' | bun scripts/cli.ts codex submit --prompt-stdin --queue --dry-run` 或 `bun scripts/cli.ts codex submit --prompt-file /tmp/code-queue-prompt.md --queue --dry-run`;位置参数只适合短单行 smoke prompt。提交前先用 `--dry-run` 检查完整 payload,确认后移除 `--dry-run`。真实提交成功只返回低噪声写入确认、task id、队列和后续查看命令,必须标记 `promptOmitted=true` 且不得回显 prompt;需要复核正文时用返回的 `codex task ` 渐进展开。这些字段写入任务 payload 后由 `code-queue-mgr` 入 PostgreSQL,核心任务字段包括 `queue_id`、`provider_id`、`execution_mode`、`model`、`cwd`、`prompt/base_prompt`、`reference_task_ids`、`reasoning_effort`、`max_attempts` 和 `task_json`;队列记录至少有 `id/name/created_at/updated_at`。模型治理应优先看任务 payload 和数据库字段,不靠 worker final response 自报。 运行态默认模型仍是 `gpt-5.5`。`CODE_QUEUE_MODELS` 当前长期合同至少包含 GPT-5.5、GPT-5.4、GPT-5.4 Mini、DeepSeek Chat 和 MiniMax M2.7;`deepseek`/`deepseek-chat` 与 `minimax-m2.7` 会走 OpenCode port,其余模型走 Codex port。只有当执行面 `/health` 或等价配置已经显示 DeepSeek 模型可用、并完成轻量 runner smoke 后,才允许真实提交 `--model deepseek-chat`。 diff --git a/scripts/code-queue-cli-submit-prompt-contract-test.ts b/scripts/code-queue-cli-submit-prompt-contract-test.ts index 2823256a..e9e52bd6 100644 --- a/scripts/code-queue-cli-submit-prompt-contract-test.ts +++ b/scripts/code-queue-cli-submit-prompt-contract-test.ts @@ -2,6 +2,7 @@ import { spawnSync } from "node:child_process"; import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; +import { compactSubmitSuccessResponseForTest } from "./src/code-queue"; type JsonRecord = Record; @@ -91,6 +92,35 @@ export function runCodeQueueCliSubmitPromptContract(): JsonRecord { const duplicateMessage = String(nestedRecord(duplicateSource.json, ["error"]).message || ""); assertCondition(duplicateMessage.includes("exactly one prompt source"), "duplicate prompt source error should be explicit", { duplicateMessage }); + const longSubmittedPrompt = `${multilinePrompt}${"submitted prompt body must not be echoed\n".repeat(80)}`; + const submitSuccess = compactSubmitSuccessResponseForTest({ + tasks: [{ + id: "codex_submit_success_contract", + queueId: "prompt-contract", + status: "queued", + providerId: "D601", + model: "gpt-5.5", + cwd: "/workspace", + prompt: longSubmittedPrompt, + maxAttempts: 99, + createdAt: "2026-05-22T00:00:00.000Z", + updatedAt: "2026-05-22T00:00:00.000Z", + }], + queue: { + total: 1, + queueCount: 1, + counts: { queued: 1 }, + queuedTaskIds: ["codex_submit_success_contract"], + }, + }, { ok: true, status: 200 }, { mode: "local-atomic-directory-submit-serialization", acquiredAfterMs: 1, heldMs: 2, throttleMs: 2000 }); + const submitSuccessJson = JSON.stringify(submitSuccess); + const submitted = nestedRecord(submitSuccess, ["submitted"]); + assertCondition(submitted.accepted === true, "submit success should confirm accepted write", submitSuccess); + assertCondition((submitted.taskIds as unknown[]).includes("codex_submit_success_contract"), "submit success should expose task id", submitSuccess); + assertCondition(submitSuccessJson.includes("promptOmitted"), "submit success should explicitly mark prompt omitted", submitSuccess); + assertCondition(!submitSuccessJson.includes("submitted prompt body must not be echoed"), "submit success must not echo prompt text", submitSuccess); + assertCondition(!submitSuccessJson.includes("promptPreview"), "submit success must not include promptPreview", submitSuccess); + const help = runCli(["codex", "submit", "--help"]); assertCondition(help.status === 0 && help.json?.ok === true, "codex submit help should succeed", help.json ?? { stdout: help.stdout }); const data = nestedRecord(help.json?.data, []); @@ -113,6 +143,7 @@ export function runCodeQueueCliSubmitPromptContract(): JsonRecord { "submit --prompt-file preserves reviewed file contents", "submit positional prompt is redacted from the outer command envelope", "duplicate submit prompt source fails explicitly", + "submit success confirms write without echoing prompt", "codex submit help documents stdin/file recommendations and copyable examples", ], }; diff --git a/scripts/src/code-queue.ts b/scripts/src/code-queue.ts index 3f1be55d..24a5ad8d 100644 --- a/scripts/src/code-queue.ts +++ b/scripts/src/code-queue.ts @@ -2773,6 +2773,101 @@ function compactTaskMutationResponse(task: unknown, options: CompactTaskMutation }; } +function compactSubmitTaskConfirmation(task: unknown): Record { + const record = asRecord(task) ?? {}; + const taskId = asString(record.id); + const prompt = asString(record.displayPrompt ?? record.basePrompt ?? record.prompt); + return { + id: taskId || null, + queueId: record.queueId ?? null, + status: record.status ?? null, + queuedReason: record.queuedReason ?? null, + providerId: record.providerId ?? null, + model: record.model ?? null, + reasoningEffort: record.reasoningEffort ?? null, + cwd: record.cwd ?? null, + executionMode: record.executionMode ?? null, + maxAttempts: record.maxAttempts ?? null, + createdAt: record.createdAt ?? null, + updatedAt: record.updatedAt ?? null, + promptChars: prompt.length, + promptOmitted: true, + commands: taskId.length === 0 ? null : { + show: `bun scripts/cli.ts codex task ${taskId}`, + detail: `bun scripts/cli.ts codex task ${taskId} --detail`, + trace: `bun scripts/cli.ts codex task ${taskId} --trace --tail --limit ${defaultTraceLimit}`, + }, + }; +} + +function compactSubmitQueueConfirmation(value: unknown): Record | null { + const record = asRecord(value); + if (record === null) return null; + return { + total: record.total ?? null, + queueCount: record.queueCount ?? null, + counts: record.counts ?? null, + activeQueueIds: boundedUniqueStringList(record.activeQueueIds, 8), + activeTaskIds: boundedUniqueStringList(record.activeTaskIds ?? record.databaseActiveTaskIds, 8), + queuedTaskIds: boundedUniqueStringList(record.queuedTaskIds, 8), + executionDiagnostics: compactQueueExecutionDiagnostics(record.executionDiagnostics), + }; +} + +function compactSubmitConcurrencyGuard(value: Record): Record { + return { + mode: value.mode ?? null, + acquiredAfterMs: value.acquiredAfterMs ?? null, + heldMs: value.heldMs ?? null, + throttleMs: value.throttleMs ?? null, + staleMs: value.staleMs ?? null, + }; +} + +function compactSubmitSuccessResponse(body: Record, upstream: Record, lock: Record): Record { + const allTasks = asArray(body.tasks).map(compactSubmitTaskConfirmation); + const tasks = allTasks.slice(0, defaultTasksLimit); + const allTaskIds = allTasks.map((task) => asString(task.id)).filter(Boolean); + const taskIds = allTaskIds.slice(0, defaultTasksLimit); + const queueIds = Array.from(new Set(tasks.map((task) => asString(task.queueId)).filter(Boolean))).sort(); + const firstTaskId = taskIds[0] ?? null; + const firstQueueId = queueIds[0] ?? null; + return { + ok: true, + upstream, + submitted: { + accepted: true, + taskCount: allTasks.length, + returnedTaskCount: tasks.length, + taskIds, + taskIdsCount: allTaskIds.length, + taskIdsTruncated: allTaskIds.length > taskIds.length, + queueIds, + tasks, + tasksTruncated: allTasks.length > tasks.length, + promptOmitted: true, + outputPolicy: { + default: "write-confirmation", + promptEchoed: false, + reason: "codex submit is a write operation; default output confirms persistence and provides drill-down commands without echoing prompt text.", + }, + }, + queue: compactSubmitQueueConfirmation(body.queue), + submitConcurrencyGuard: compactSubmitConcurrencyGuard(lock), + commands: { + firstTask: firstTaskId === null ? null : `bun scripts/cli.ts codex task ${firstTaskId}`, + firstTaskDetail: firstTaskId === null ? null : `bun scripts/cli.ts codex task ${firstTaskId} --detail`, + queue: firstQueueId === null ? null : `bun scripts/cli.ts codex tasks --queue ${firstQueueId} --limit ${defaultTasksLimit}`, + supervisor: `bun scripts/cli.ts codex tasks --view supervisor --limit ${defaultTasksLimit}`, + queues: "bun scripts/cli.ts codex queues", + }, + }; +} + +export function compactSubmitSuccessResponseForTest(body: Record, upstream: Record = { ok: true, status: 200 }, lock: Record = {}): Record { + return compactSubmitSuccessResponse(body, upstream, lock); +} + function codexReadTask(taskId: string): unknown { const response = unwrapCodexResponse(coreInternalFetch(codeQueueProxyPath(`/api/tasks/${encodeURIComponent(taskId)}/read`), { method: "POST", body: {} })); return { @@ -3728,12 +3823,7 @@ function codexSubmitTask(args: string[]): unknown { } const locked = runWithSubmitLock(() => unwrapCodexResponse(coreInternalFetch(codeQueueProxyPath("/api/tasks"), { method: "POST", body: payload }))); const response = locked.result; - return { - upstream: response.upstream, - tasks: asArray(response.body.tasks).map((task) => compactTaskMutationResponse(task, { fullPrompt: true })), - queue: compactQueueMutationSummary(response.body.queue), - submitConcurrencyGuard: locked.lock, - }; + return compactSubmitSuccessResponse(response.body, response.upstream, locked.lock); } function codexInterruptTask(taskId: string): unknown { diff --git a/scripts/src/help.ts b/scripts/src/help.ts index 2e97ad24..dea7d08a 100644 --- a/scripts/src/help.ts +++ b/scripts/src/help.ts @@ -52,7 +52,7 @@ export function rootHelp(): unknown { { 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 [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run]", description: "Submit a Code Queue task through backend-core -> code-queue proxy; --dry-run shows the structured request without enqueueing." }, + { command: "codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run]", description: "Submit a Code Queue task through backend-core -> code-queue proxy; --dry-run shows the structured request, while real success only confirms the write and task id." }, { 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]", description: "Read-only PR admission check against the D601 scheduler/runner token, GitHub egress, repo visibility, optional push dry-run, and PR body/create dry-run guard." }, { command: "codex task [--detail] [--trace --tail|--from-start|--after-seq N|--before-seq N --limit N] [--full]", description: "Fetch the bounded review view by default: original prompt, final response, and drill-down commands; detail and trace are opt-in." }, { command: "codex tasks [--view supervisor|full] [--queue id] [--status status[,status]] [--unread|--unread-only] [--limit N] [--before-id id]", description: "Show the low-noise supervisor view by default: compact task rows, capped recent completions, diagnostics, and drill-down commands; use --view full for detailed rows." }, @@ -278,7 +278,7 @@ function codexHelp(): unknown { file: "bun scripts/cli.ts codex submit --prompt-file /tmp/code-queue-prompt.md --queue --dry-run", dryRunThenSubmit: "Run with --dry-run first; remove --dry-run to submit exactly the same payload.", }, - description: "Operate Code Queue through the stable backend-core private proxy path.", + description: "Operate Code Queue through the stable backend-core private proxy path. Real submit success is a low-noise write confirmation and does not echo prompt text.", }; }