# UniDesk CLI Reference

UniDesk 的统一 CLI 实现入口是根目录 `scripts/cli.ts`，运行方式固定为 `bun scripts/cli.ts <command>`；普通根 CLI 子命令仍使用该入口。`trans <route> ...` 是 SSH/WSL/k3s 透传专用入口，wrapper 委托轻量 `scripts/ssh-cli.ts` 启动链路，避免被无关根 CLI 子命令模块的解析或语法错误拖垮；长期参考文档、AGENTS 索引、CLI help 和人工远端操作示例都必须优先写 `trans ...`，不得再把 `bun scripts/cli.ts ssh ...` 作为默认透传入口。面向人工的默认输出采用 Kubernetes 风格的简洁表格、短摘要和 drill-down 命令；JSON 只用于 `--json`、`--raw`、`--full`、`-o json` 或其他明确机器消费模式。所有成功和失败路径仍必须给出可判定状态，避免无输出造成不可观测。

- 高频 CLI 默认输出与帮助输出是直接阅读入口：
  - 必须保持有界、低噪声并直接展示，不得触发 `outputTruncated` 或 `/tmp/unidesk-cli-output` dump。
  - 面向人工的高频 `--help` 必须默认输出紧凑文本；机器 JSON 只能由显式 `--json`、`-o json` 或等价参数请求，不能把 JSON envelope 当作帮助页直接倾倒。
  - 顶层帮助只展示分组索引和可执行的下钻命令，详细合同通过 `<command> --help <operation>` 或等价 scoped help 获取。
  - 未知子命令、未知 help scope 和可预测 option 校验失败必须返回紧凑、结构化且无 stack 的输入错误；stack 只允许在显式 debug/raw 错误模式下披露，内部异常不得伪装成输入错误。
  - 默认输出或帮助输出触发 dump 视为 CLI 缺陷，必须收敛信息结构，禁止用提高 stdout 阈值掩盖。
  - 默认超限只返回语义化窄查询，不创建 `/tmp/unidesk-cli-output` dump；`--json` 只选择机器格式，不等同于完整披露。
  - dump 只允许用于用户显式请求的 `--full`、`--raw`、`UNIDESK_TRAN_STREAM_DUMP=1`，或确实无法预先界定的一次性异常证据。

- stdin 文本输入默认直接使用 quoted heredoc：
  - 单次使用的正文、评论、prompt、patch、脚本或 JSON 必须直接写成 `--*-stdin <<'EOF'` 或等价 stdin heredoc。
  - 禁止先把同一段文本写入 `/tmp` 或工作区临时文件，再用 `< file` 传给支持 stdin 的命令。
  - 只有内容需要复用、作为正式工件保留、属于二进制，或目标工具明确只接受文件路径时，才使用 `--*-file`、upload 或文件重定向。
  - heredoc delimiter 必须引用，避免 `$()`、反引号、变量和反斜杠被本地 shell 提前展开。
  - `apply-patch` 检测到交互 TTY 且没有 stdin 时必须立即返回 `apply-patch-stdin-required` 和 `trans <route> apply-patch <<'PATCH'`，不得等待短连接超时。

- 远端文本与文件传输边界：
  - 文本读取使用 `cat`、`head`、`tail` 或 `rg`；
  - 文本修改使用 `apply-patch <<'PATCH'`，不得先建临时 patch 文件；
  - 已知文本路径的 `upload` / `download` 默认在远端操作和本地目标写入前返回 `text-transfer-discouraged`；
  - 只有确需整体搬运文本生成物时才显式加 `--allow-text-transfer`，成功结果必须记录 override 并继续执行字节数和 SHA-256 校验。

主 server 必须在 PATH 上提供 `/root/.local/bin/trans` 可执行 wrapper，内容委托 repo 内版本化 `scripts/trans` 并执行 `bun scripts/ssh-cli.ts ssh "$@"`；交互 shell 可额外提供 alias，但非交互 Codex `exec` 和脚本不能依赖 alias 展开。

主 server 固定提供 PATH 可见的 `/usr/local/bin/unidesk`，委托版本化 `scripts/unidesk` 执行根 CLI；`/root/.local/bin/unidesk` 可以保留为用户级兼容链接，但不能作为非交互入口的唯一安装位置。高频人工入口优先写 `unidesk <command>`；仓库内验证和未安装 wrapper 的 checkout 使用等价的 `bun scripts/cli.ts <command>`。

`trans` wrapper 是 SSH/WSL/k3s 透传的唯一默认入口：人工/Codex 远端操作、长期参考文档、AGENTS 索引、CLI help、非交互脚本和非交互 `exec` 都必须直接调主 server PATH 上的 `/root/.local/bin/trans`；禁止把 `bun scripts/cli.ts ssh ...`、`bun scripts/cli.ts trans ...` 或任何带 `bun scripts/cli.ts` 前缀的透传写法作为默认入口。`bun scripts/cli.ts help`、`config`、`server`、`provider`、`microservice` 等普通根 CLI 子命令不受这条限制，仍使用 `bun scripts/cli.ts <command>`，避免透传命令和根子命令在调用前缀上互相混淆。

误写 `bun scripts/cli.ts trans ...` 或 `bun scripts/cli.ts tran ...` 时，根 CLI 必须在本地返回紧凑的 `trans-root-cli-entrypoint-moved` 输入错误、精确 `usage` 替代命令和 `Use: trans <route> <operation> [args...]` 迁移提示，不能连接运行面、披露 stack 或退化成通用 `Unknown command`。

- `trans` 的 cwd 与本地校验合同：
  - host/workspace 的 cwd 只写入 route，例如 `trans NC01:/root/unidesk exec git status --short` 或 `trans NC01:/root/unidesk bash <<'BASH'`；
  - k3s workload 的容器 cwd 使用 route 后缀或 `exec --cwd /absolute/path -- <command>`；
  - host/workspace 上误用 `exec|argv|sh|bash --cwd` 时，必须在选择 transport 和连接运行面前返回 `trans-host-cwd-belongs-in-route` 与精确替代命令；
  - `trans --help` 必须直接展示 host/workspace 与 k3s cwd 摘要，`trans --help exec|bash` 提供可执行示例。

- Code Agent 跨服务只读诊断合同：
  - `platform-infra observability diagnose-code-agent` 是 AgentRun durable authority、HWLAB projection/read model 与 OTel 服务覆盖的单命令聚合入口；
  - 默认 text 与显式 `--full|--raw` JSON 必须共同披露 `typed outcome`、`effectiveStatus`、`mutation=false`、durable authority 和 projection 状态；
  - AgentRun 权威终态与 HWLAB 投影不一致时，以权威终态作为有效结果，并将投影滞后或冲突标记为 `warning=true`、`blocking=false`；
  - 聚合入口只读，不得触发 mirror sync、PipelineRun、Argo refresh/sync 或运行面修补。

Windows `ps` 的参数语义分为两种：单个参数是完整 PowerShell source；多个参数是边界明确的 argv。后者对 native application 使用 Windows 命令行引用规则，必须保留 `python -c` 代码中的路径、`encoding="utf-8"`、字典 key 和嵌套引号，并继承 route 对应的 Windows workspace。PowerShell prelude 将 `Get-Content` 默认编码固定为 UTF-8；Windows fs helper 的 `head` / `tail` 同时支持 `-n N`、`-nN`、`--lines=N` 和 GNU `-N`，`wc -l` 必须把选项与路径分开解析。

- Windows `rg` / PowerShell 本地边界：
  - broad `rg` 超时必须先输出 `UNIDESK_WINDOWS_RG_SUMMARY ... timeout=true`，再输出 `UNIDESK_WINDOWS_RG_HINT code=timeout exitCode=124 action=narrow-scope-or-add-glob` 并返回 124；无匹配仍返回 1，二者不能混淆。
  - 一行 PowerShell source 必须用本地单引号，例如 `trans G14-WSL:win/d/Work/demo ps '$p = Start-Process python -PassThru; $p.Id'` 和 `trans G14-WSL:win/d/Work/demo ps 'Get-Process | Where-Object { $_.CPU -gt 0 }'`。
  - 多行 PowerShell 使用 `trans <route> ps <<'PS'`；quoted delimiter 保证 `$p`、`$_`、反斜杠和代码块不会被本地 shell 提前解释。
  - 源码因本地展开而以缺失左值的 `=` 开始时，CLI 必须在远端执行前返回 `ssh-windows-powershell-local-expansion`、单引号示例和 quoted heredoc 示例。

- Windows/WSL `apply-patch v2` 文本完整性合同：
  - localized replacement 必须保留纯 CRLF 文件的 CRLF 风格，不能把新增行写成 bare LF，也不能把整个文件静默改写为 LF。
  - original/final integrity mismatch 后必须重新只读采集当前文件，输出 adapter、stage、expected/current bytes、SHA-256、newline 和 encoding；摘要不得包含文件正文。
  - Windows 与 WSL route 对同一文件使用同一 replacement plan 和 payload 合同；失败不能自动或人工建议回退 Windows 不支持的 `apply-patch-v1`。

CLI 可以从 `master` 快速演进，但必须兼容 `deploy.json` 固定的 CI/CD server 和生产运行面。CLI/server 能力协商、unsupported-version 失败语义和 release-line 边界由 `docs/reference/release-governance.md` 与 [GitHub issue #6](https://github.com/pikasTech/unidesk/issues/6) 约束。

## CI/CD Control Boundary

CI/CD、GitOps、rollout、artifact 发布、PR 合并后的 runtime lane 滚动、PipelineRun 重跑/清理、Argo refresh、运行面 retention 和 legacy runtime 退役都必须由 UniDesk CLI 的高层子命令控制。稳定入口包括 `gh pr ...`、`hwlab g14 retirement ...`、`hwlab g14 monitor-prs --lane v02|v03`、`agentrun control-plane ...`、`deploy check|plan|apply`、`ci install|status|run|publish-*|logs`、`artifact-registry ...`、`server rebuild ...`、`dev-env ...` 和后续为特定运行面补充的同级命令。原生 `kubectl`、`argo`、`tkn`、`gh`、`curl` 或临时 shell 可以作为实现细节存在于 CLI 内部，但不能作为人工或 runner 的正式控制面。

GitHub 受控入口的命令用法由 `$unidesk-gh` 维护，长期模块边界以 [PJ2026-010606 GitHub入口](../../project-management/PJ2026-01/specs/PJ2026-010606-github-controlled-entry.md) 为权威。`scripts/src/gh.ts` 只保留 thin compatibility entry；具体实现必须按职责落在 `scripts/src/gh/` 子模块，新增能力不要把用法和实现细节复制到本参考文档。

`trans <route> kubectl|logs|get|describe` / `tran <route> ...` 仍是 CLI 介导的低层诊断底座，用于短查询、日志尾部、只读证据和一次性故障定位。它不应承载可重复的 CI/CD 写操作：创建/删除 PipelineRun、patch Pipeline/CronJob/RBAC、annotate Argo Application、触发/回滚 rollout、修改 retention 策略、确保 SecretRef 或清理运行面资源，都应该先落成 `bun scripts/cli.ts ...` 高层子命令，再由该子命令输出结构化 dry-run、执行摘要、保护对象、后续观察命令和失败分类。

当现有 CLI 对某个 CI/CD 操作缺字段、缺动作、缺状态或缺权限时，处理顺序是先补 CLI，再执行发布或治理动作。临时低层 route 写操作只允许用于一次性止血，并且必须随后把稳定能力补进 CLI 与本参考文档；不能把手工 `kubectl apply/delete/annotate`、原生 GitHub CLI、手写 REST 请求或 registry shell 脚本沉淀成长期流程。长时观察仍遵守 60 秒短查询和 submit-and-poll 语义，不用单个 `trans`/`tran` 等待完整 PipelineRun 或 Argo rollout 结束。

`hwlab nodes control-plane allow-endpoint-bridge --node G14 --lane v03 [--dry-run|--confirm]` 是 v03 platform PostgreSQL bridge 的受控收敛入口，用于让 Argo 跟踪固定 `EndpointSlice/g14-platform-postgres-host`，并清理旧 `Endpoints/g14-platform-postgres` 及其派生的随机 EndpointSlice。`hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 [--dry-run|--confirm]` 是 v03 迁移到 G14 platform PostgreSQL 后清理旧 repo-owned Postgres StatefulSet/Service/ConfigMap/Secret/PVC 的受控入口。迁移后的 `hwlab-cloud-api-v03-db` 和 `hwlab-v03-openfga` SecretRef 来自 G14 host platform DB 凭据文件，不再从 lane-local Postgres Secret 派生；`hwpod-v03-db`、`hwpod_v03`、`hwpod_v03_app` 是废弃残留，不是完成态 SecretRef。v03+ 的 `hwlab nodes secret ensure --name hwlab-cloud-api-v03-db|hwlab-v03-openfga` 旧路径已删除，status 只做 redacted SecretRef 与 `g14-platform-postgres` Service、固定 EndpointSlice 和旧 Endpoints 缺席观测；发现 HWPOD DB 残留时使用 `hwlab nodes secret cleanup-obsolete --node G14 --lane v03 --name hwpod-v03-db [--dry-run|--confirm]` 受控清理。平台 DB 运行、SecretRef 轮换边界和 health 验证见 `docs/reference/g14-platform-db.md`。

`hwlab nodes secret status|ensure --node G14 --lane v03 --name hwlab-v03-code-agent-provider` 是 v03 Code Agent / MoonBridge provider SecretRef 的受控 bootstrap 入口；`ensure` 只从集群内既有 `hwlab-v02/hwlab-v02-code-agent-provider` 复制 `openai-api-key`、`opencode-api-key` 到 lane-local Secret，输出仅披露 source/target Secret 名、key presence、decoded byte count、mutation 和后续命令，禁止打印 base64、解码值、完整 API key 或可复用凭据。OpenFGA 和 master admin API key 继续使用同一命名空间下的 `hwlab nodes secret ... --name hwlab-v03-openfga|hwlab-v03-master-server-admin-api-key`。

G14/D601 v03 的 bootstrap admin password 是 HWLAB runtime Secret 生命周期的一部分，必须收敛到 `config/hwlab-node-lanes.yaml` 的 `bootstrapAdmin` 声明与受控 `hwlab nodes secret status|ensure --node <node> --lane v03 --name hwlab-v03-bootstrap-admin` CLI。明文只能存在于 Git 忽略、owner-only 的 `.state/secrets/...` sourceRef 文件；CLI 在本地把明文转换为 HWLAB 兼容 password hash，只向运行面同步 `password-hash`，并在输出中只披露 sourceRef、sourceKey、target Secret/key、presence、byte count、fingerprint、mutation 与后续命令。`secret ensure --force` 只用于明确需要按 YAML sourceRef 重灌 bootstrap admin hash 并重启 Cloud API 的受控恢复场景，默认 ensure 不做强制重灌；不要把人工生成 hash、手工写 k8s Secret 或原生 `kubectl rollout` 沉淀为长期入口。

`web-probe run|script --node <node> --lane <lane>` 是 HWLAB Cloud Web 线上 DOM/Playwright 验收的受控入口；旧 `hwlab nodes web-probe` 已移除，调用方应迁移到 `bun scripts/cli.ts web-probe ...`。CLI 负责从 YAML 解析 workspace、public URL 和 bootstrap admin sourceRef，并只输出 redacted 凭据状态、artifact path/hash、readiness、`probe.summary` 和失败分类。`run` 使用 repo-owned 标准 DOM probe；`script` 不运行默认探针，必须通过 stdin heredoc 或 `--script-file <path>` 提供调用者脚本。`run --message ...` 未显式设置 trace 参数时会做轻量 trace 采样，`script` helper 可用 `recordStep` / `safeFetchJson` / `fetchApiMatrix` 保留失败前的结构化 partial evidence，完整 redacted 报告通过 `reportPath`/`reportSha256` 展开。具体 Web 开发、fake-server Playwright、fixture 脱敏、`web-probe script` helper、截图和 Workbench/Performance 判定口径统一见 `$unidesk-webdev`，本 CLI 参考不再维护第二套操作面。

`web-probe script` 的 issue closeout 优先引用顶层 `issueEvidence` 或 `summary.issueEvidence`，其中包含 redacted `result`、最近 steps、lastStep、script/report SHA 和截图摘要；完整调查才展开 `probe.script.result`、`probe.steps` 或 `reportPath`，避免把同一证据在 stdout、summary 和 report 多层重复粘贴。

`web-probe observe analyze` 的 duplicate final response 结论必须服从 `observe collect --view trace-frame` 的可见行事实。`trace-frame` renderer 固定追加的 `Final Response` summary 区块只是阅读摘要，不是第二条业务 assistant message；analyze 只能把同一 trace-frame 内重复出现的可见 assistant final rows 判为 duplicate，并在 finding 中保留 `finalResponseSummaryBlockCounted=false`、可见行数量、row index 和 traceId。

`hwlab nodes control-plane infra plan|status|apply --node D601 --lane v03` 是 D601 HWLAB v03 节点本地 k3s、CI/CD 与 git-mirror 前置控制面的 YAML 驱动入口，配置真相源是 `config/hwlab-node-control-plane.yaml`。`plan` 只读展示 YAML target、host k3s node config 摘要和将渲染的 control-plane 对象；`status` 只读观察 k3s systemd drop-in 与 node `capacity/allocatable.pods`、D601 Tekton、CI namespace、git-mirror、Argo、node-local registry 和 tools image readiness；`apply --dry-run` 只输出 manifest 与 host config 摘要；`apply --confirm` 按 YAML 收敛 D601 host k3s drop-in 和 control-plane bootstrap 对象，只有 host k3s 配置或 live pod capacity 未收敛时才重启 k3s，不触发 HWLAB runtime rollout，不创建 PK01 DB，也不修改 Caddy/FRP。D601 host 侧 k3s pre-start 修正也必须写成 YAML `execStartPre` argv，不做手工 systemd 热改；当 kube API 已不可用时，`apply` 可用同一 YAML 渲染出的 host 脚本经 node-local tools image/Docker fallback 恢复 systemd drop-in，输出仍只给对象名、SHA、exit code 和摘要。k3s pod capacity 等可调数值只以 YAML 为准，长期参考不复制具体数值；tools image 的 node-local registry 地址只能作为输出 artifact，输入 base image 必须由 YAML 声明为公开 registry 来源，缺少 output image 时应在 `status.next.blockers` 中体现，而不是把现有 node-local image 当成输入基础镜像。

`hwlab nodes control-plane infra ci-build-benchmark --node D601 --lane v03 --profile <profile> --confirm` 是 HWLAB v0.3 k3s CI/CD 全量无缓存构建出网测速入口，profile、cache policy、独立 catalog path 模板、PipelineRun prefix、必须输出的 timing 阶段和失败族都来自 `config/hwlab-node-control-plane.yaml`。confirmed benchmark 只创建一次唯一 PipelineRun，使用 node-lane YAML 中的实际 HWLAB v0.3 service set、git mirror read/write URL、registry prefix、base image 和 Tekton pipeline；`forbidBuildkitCache=true` 时会向 PipelineRun 传 `build-cache-mode=disabled`。status/logs 通过短连接轮询 PipelineRun/TaskRun 摘要和有界日志。成功的 benchmark 必须出现每个 `build-<service>` TaskRun；如果 PipelineRun 成功但缺少任一 service build task，CLI 必须把该 service 报为 `cache-hit-forbidden`，不能把 catalog/env reuse 当作 #1010 这类性能验收的通过证据。

`hwlab nodes git-mirror status|sync|flush --node <node> --lane <lane>` 是 node-scoped runtime lane 的 Git mirror 维护入口。对 legacy git-mirror source authority，`status` 的 `githubSource` / `githubGitops` 来自本地 mirror cache 的 `refs/mirror-stage/...`，不是实时 GitHub API；对 Gitea/PaC 迁移 lane，`status` 的 `mode` 为 `gitea-source+legacy-gitops-flush`，source head/snapshot 来自 Gitea controlled mirror，GitOps flush 仍读 legacy git-mirror refs。输出中的 `refSources` 给出来源和刷新命令。legacy `sync --confirm --wait` 的 k8s Job 是 upstream GitHub fetch 的唯一正式入口；Gitea/PaC 迁移 lane 的 source sync 必须走受控 Gitea mirror 入口；遇到 GitHub SSH transient 时按受控 retry/backoff 停止并输出下一步，不回退到 operator host git、目标 host fixed workspace 或第二套 source resolver。`flush --confirm --wait` 如果已经把 GitOps ref push 到 GitHub，但 post-push fetch/recheck 因 transient SSH 失败而无法刷新 mirror-stage，会标记 `partialSuccess=push-succeeded-fetch-failed`；CLI 应自动执行一次受控 sync 刷新 mirror-stage，若恢复后 `pendingFlush=false` 且 `githubInSync=true`，结果应为 `ok=true` 并输出 `partialSuccessRecovered` / `postPushRecovery`，否则才保留 `degradedReason=node-runtime-git-mirror-flush-post-push-fetch-failed` 和下一步 `sync --confirm --wait`。不要把这种 partial success 解读为需要连续盲目 flush。`hwlab nodes control-plane trigger-current --node <node> --lane <lane> --confirm --wait` 会先按 YAML `sourceAuthority` 执行 source snapshot sync：legacy lane 走 k8s git-mirror sync，Gitea/PaC 迁移 lane 走 platform-infra Gitea mirror sync 并读取 Gitea immutable snapshot；随后自动执行必要的 pre-flush，并在 PipelineRun terminal 后继续完成 post-flush、Argo refresh/status closeout、runtime readiness 和 YAML public `/health` 探测；同一条 CLI 的端到端预算是 120s，嵌套 source sync、git-mirror sync/flush 与 status 探测必须按剩余预算裁剪，不能每阶段各自等待一轮。progress/summary 必须显式输出 source snapshot、`git-mirror-pre-flush` / `git-mirror-post-flush` 的 executed/skipped、jobName、local/github source、local/github GitOps、`pendingFlush`、`githubInSync`、Argo observed/target revision、runtime/public readiness 和 pending TaskRun/Pod drill-down；PipelineRun 已成功但 Argo/runtime/public 仍在收敛时，状态原因应落在 Argo/runtime closeout，不再泛化成 CI TaskRun pending。`control-plane status` 仍是只读入口，只读受控 source snapshot 与 mirror cache 并暴露 compact `gitMirror` 摘要和下一步 flush 命令，不隐式执行写操作。

PR 合并后触发 node-scoped runtime lane 时，`control-plane status --pipeline-run <name>` 是某次 PipelineRun 的定点观察入口，但同一输出中的 `sourceHead` / `summary.sourceCommit` 仍可能反映当前分支最新 head；如果触发后又有后续 PR 合并，当前 head 可能已经不是该 PipelineRun 名称中的短 SHA。closeout 证据必须同时写明：PR merge commit、定点 PipelineRun 名称和状态、最终 runtime/GitOps revision、当前 branch tip，以及当前 branch tip 是否包含本次 PR merge commit。不要只凭 `summary.sourceCommit` 反推某个旧 PipelineRun 的源码身份。

`hwlab nodes control-plane status` 的 `publicProbe.ready` 表示控制面从公网用户入口访问 YAML 声明 public Web/API 成功；`publicProbe.targetHost` 只表示目标节点 host 自己访问同一公网 URL 的诊断结果。若 `publicProbe.ready=true` 且 `publicProbe.diagnostic.kind=target-host-public-egress-mismatch`，closeout 仍以 `publicProbe` 和 `web-probe` 用户入口证据为准，host 侧 `hwlab-cli` 访问公网失败应单独按目标 host egress/hairpin 问题跟踪。

非默认 node/lane 的 `hwlab nodes control-plane status --full` 是有界运行面 drill-down，不是完整 JSON dump：默认展示 PipelineRun/Argo/runtime/public/git-mirror 阶段、workload readiness、externalPostgres bridge 和 SecretRef presence，Secret 只显示对象名、key 名和 `valuesPrinted=false`。需要完整结构化 payload 时使用显式 `--raw`，不要把 `/tmp/unidesk-cli-output` dump 当作常规阅读入口。

PipelineRun 失败或长时间未完成时，先按定点 `control-plane status --pipeline-run <name>` 和 bounded 只读 k3s 诊断定位失败 TaskRun/Pod/container。env-reuse service build 常见失败点是 `build-<service>` 的 `step-publish` 日志，apt、npm、Go module 等外部依赖下载可能通过 lane YAML 注入的 egress proxy 出现瞬时 502、reset 或超时；先用 `platform-infra sub2api status|validate` 区分共享 proxy 整体故障和单个上游 transient。proxy 健康但单个依赖下载 transient 时，可以受控 `trigger-current --rerun`；重复失败应把对应 `artifact-publish`/envRecipe 下载步骤补成有限重试后重新合并发布。不要用原生 `kubectl delete/patch`、pod 内热补或盲目全量重跑替代持久化 recipe 修复。

`hwlab nodes control-plane infra tools-image status|build|logs --node D601 --lane v03` 是 D601 tools image 的受控入口。Dockerfile 必须由 `config/hwlab-node-control-plane.yaml` 的 `tekton.toolsImage.dockerfileInline` 声明，输入镜像必须列在 `publicBaseImages`，构建参数和网络模式也来自 YAML；confirmed build 只在 D601 后台异步构建并推送到 node-local registry，返回 status/logs 轮询命令。`hwlab nodes control-plane infra argo status|apply|logs --node D601 --lane v03` 是 D601 Argo CD 的声明式安装入口。Argo 版本、官方 manifest URL、镜像 rewrite/preload、field manager、imagePullPolicy、CRD 列表、期望 Deployment/StatefulSet 以及生成的 AppProject/Application 都必须来自同一个 YAML；`argo apply --confirm` 只执行可重复 server-side apply 和后台轮询，不把原生 `kubectl apply`、手工 Argo CLI 或临时 manifest 作为正式安装路径。

`hwlab nodes control-plane runtime-image status|preload|build --node G14 --lane v03` 是 G14 v0.3 runtime lane base image 的受控入口。输入公开来源来自 `config/hwlab-node-lanes.yaml` 的 `baseImageSource`，输出目标来自同一 lane 的 `baseImage`；`status` 只读检查 node-local registry tag 与 source/target image presence，`preload --confirm` 按 YAML 下载配置执行 source pull/tag/push，`build` 当前只是 preload 别名。这个入口用于 `trigger-current` 前置检查和 base image 缺失恢复；后续 service build 失败应按失败 TaskRun 单独分流。

## Command Model

- `help` 输出命令索引，适合作为交互式入口。
- 每个 CLI 命名空间必须支持 `help`、`--help` 或 `-h`；高频人工入口默认返回紧凑文本，只有显式 `--json`、`-o json` 或等价机器参数才返回 JSON。不得为了打印帮助而访问 runtime 服务、拉起交互会话或执行长时任务。
- `--main-server-ip <ip> <command>` 默认通过公网 frontend 登录态调用主 server 的同源 API 代理，不要求计算节点持有主 server SSH key；显式提供 `--main-server-key` 或 `--main-server-transport ssh` 时才使用旧 SSH 传输。远程 frontend 传输下的 `ssh <route> ...` 必须复用同一套结构化 route parser，支持 `D601`、`G14`、host workspace、`D601:win`、`D601:win/c/test`、`D601:k3s` 和 `D601:k3s:<namespace>:<workload>` 这类定位路径；它不向调用容器下发 provider token，也不要求调用容器能解析 backend-core 内网 DNS。
- `config show` 读取并校验根目录 `config.json`，不从环境变量、默认值或隐藏文件静默补配置。
- `check` 默认只执行轻量配置校验、Bun 版本检查和 Bun Transpiler 语法解析（覆盖 CLI 入口、主要 `scripts/` 模块和核心组件入口，不做类型推导）。除非用户明确要求，CLI 改动不运行单元测试、合同测试或新增测试脚本；默认最多做语法检查和必要的帮助/命令形态人工确认。关键文件存在性、`scripts/` TypeScript 类型检查、`src/components/` TypeScript 类型检查、Docker Compose config、日志轮转策略扫描和 D601 recovery guardrails 默认不启用，分别通过 `--files`、`--scripts-typecheck`、`--components`、`--compose`、`--logs`、`--recovery-guardrails` 开启，或用 `--full` 一次性开启。不得把裸 `tsc` / `bun --bun tsc` 或 `check --scripts-typecheck` 当作语法验证；它是重型类型检查，可能长时间卡住或超时。单文件语法确认使用 `bun --check <具体文件>`，入口级轻量自检使用 `bun scripts/cli.ts check` 默认 syntax transpile。`--scripts-typecheck` 只跑 scripts TypeScript 类型检查，不触发测试脚本或 GitHub issue/PR live API check。长命令项必须在 stderr 输出 `unidesk.check.progress` JSON lines，stdout 保持最终 JSON 结果，避免 post-task 或人工运行时长时间无可见进度。`typescript:scripts` 固定通过 `bun --bun tsc -p scripts/tsconfig.json --noEmit --pretty false` 执行，默认 `--scripts-typecheck-timeout-ms 120000`，可按目标运行面显式调小或调大但 CLI 会封顶；`--check-heartbeat-ms` 控制运行中心跳间隔，默认 `15000`。所有命令项的最终 item detail 必须包含 `durationMs`、`timeoutMs`、`heartbeatMs`、`exitCode`、`signal`、`timedOut`、stdout/stderr byte count、truncation flag 和有界 tail；超时必须返回 `timedOut=true`，不得只留下被外层命令杀死的空输出。不要把 `bun --check scripts/cli.ts` 当作低噪声 CLI 自检入口；它可能执行根 CLI help 并触发长 help dump。CLI 入口级自检使用 `bun scripts/cli.ts check`，单文件语法确认只针对具体模块文件运行。`check recovery-guardrails` 是同一诊断的低噪声直接入口，报告 malformed `/proc/mounts`、kubelet validation risk、stale CRI sandbox count、Code Queue worktree/symlink、Code Queue/MDTODO hostPath 和 `ContainerCreating` 分类；它不得重启 k3s、删除 CRI sandbox、修改 hostPath、deploy/rollout 或 prune/reset。`--rust` 只允许在 D601 CI/dev execution 中配合 `UNIDESK_D601_RUST_CHECK=1` 使用，长期规则见 `docs/reference/dev-environment.md` 和 `docs/reference/devops-hygiene.md`。
- `server start` 创建异步 job，在后台执行 Docker 构建和启动；命令默认只返回低噪声 async job 摘要、stdout/stderr 路径和 `job status` 后续命令，完整 JSON 只能通过 `--full`/`--raw` 显式展开。
- `server stop` 创建异步 job，在后台停止固定 Compose project 中的全部 UniDesk 服务；默认输出同样是 async job 摘要。
- `server status` 查询公开端口、受限宿主端口、内部端口、主机 swap 摘要、Compose 容器、core/frontend/dev-frontend/provider/database 健康检查和访问 URL；D601 Code Queue 使用的 PostgreSQL/OA Event Flow host mapping 必须出现在受限宿主端口而不是无条件公开入口中。低内存主 server 上 `swap.warning` 非空时，先执行 `server swap status` 或 `server swap ensure`。
- `server swap status|ensure [--path /swapfile] [--size 2GiB] [--dry-run]` 是主 server swap 管理入口。`status` 仅读 `/proc/meminfo`、`/proc/swaps` 和 `/etc/fstab` 并返回 JSON；`ensure` 在已有任何 active swap 时只报告 no-op，在无 active swap 时创建固定 swapfile、`chmod 600`、`mkswap`、`swapon` 并尽量写入 `/etc/fstab`。输出必须包含 `before`、`after`、total memory、active swap、持久化状态、关键动作和错误详情；若 swap 已启用但 fstab 写入失败，状态为 `degraded`，调用者需按返回的 detail 修复持久化。
- `server logs` 返回 `logs/` 文件日志和 Docker 容器日志的尾部，默认限制输出大小，避免日志爆炸。实现必须只读取文件末尾字节，不得为了 tail 先把巨大日志完整读入 CLI 内存。
- `server cleanup plan|run --confirm [--min-age-hours N] [--limit N]` 是主 server Docker 镜像高水位治理入口。`plan` 生成 dry-run 计划，不执行删除；`run --confirm` 只删除同一 classifier 选出的 stale Docker images，高风险候选必须额外 `--include-high-risk` 才会执行。默认 `--min-age-hours 24`，避免把刚发布或刚验证的镜像列为 stale。输出必须包含 active containers/images、受保护镜像、candidate stale images、估算释放空间、风险等级、执行/跳过结果和人工审批线索。计划必须保守白名单：保留 running containers 使用的 image ID，保留 stopped containers 引用的 image ID 直到人工先复核容器，保留 `deploy.json`/`CI.json` 当前 commit-pinned artifact、Compose stable image、上游 digest pin 和 provider-gateway runner image；`protectedStorage` 必须显式列出 PostgreSQL named volume、Baidu Netdisk `.state`、D601 registry storage 和 Docker volumes/host data policy。该入口禁止 `docker system prune`、`docker image prune`、`docker builder prune`、`docker volume rm`、`docker compose down -v`、数据库清理或 host data `rm` 命令。
- `gc plan|run --confirm|db-trace|policy|remote` 是主 server 和受控 provider 的磁盘高水位一次性缓解与长期防膨胀入口。`plan` 只读输出候选、风险、估算收益和保护对象；`run` 必须显式 `--confirm`；`gc remote <providerId> ...` 通过 UniDesk SSH 透传执行远端 GC，`--target-use-percent N` 会在 `summary.target` 中报告目标水位所需释放量、候选估算、预计水位、缺口和 safe-stop 决策。默认只包含 allowlisted `/tmp` 诊断目录；非 allowlist stale `/tmp` 直接子项必须显式 `--include-stale-tmp`，并只允许删除 `/tmp` 一级子项且避开系统 socket/session 前缀。G14/HWLAB registry retention、受限 core dump、保护对象、safe-stop 线和长期收益表的权威规则见 `docs/reference/gc.md`。
- `server rebuild <backend-core|frontend|dev-frontend-proxy|provider-gateway|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>` 创建异步 job，先构建目标服务镜像，随后在 `.state/locks/server-compose.lock` 串行保护下用 `--no-deps --force-recreate` 替换目标 service 并等待容器 `healthy/running`。Todo Note 的 CC01/旧 Compose 回退入口已在迁移验收后删除；正式发布只走 NC01 PaC/Argo。D601 Code Queue 执行面不由 `server rebuild` 管理；Rust backend-core 常规迭代不得用该命令在 master server 编译，只有明确的 backend-core 主 server 上线例外可以按限流、异步轮询和 health 证据执行，规则见 `docs/reference/dev-environment.md`。
- `provider attach <providerId> [--master-server URL] [--up] [--force]` 在新计算节点生成两项配置的 provider-gateway 挂载包：`.state/provider-<ID>.env` 默认只包含 `UNIDESK_MASTER_SERVER` 与 `PROVIDER_ID`，`provider-<ID>.yml` 固定 Docker socket、`pid: "host"`、`restart: always`、只读 `/workspace` 和 SSH 维护私钥挂载；`--up` 会立即执行生成的 `docker compose up -d --build`。`provider triage <providerId> [--observed-error text] [--observed-scope scope] [--microservice id ...] [--full|--raw]` 是只读多信号健康裁决入口，会把单路径 `provider is not online`、SSH 超时、registry 失败和 service proxy 失败归类成 `runner-local-observation-gap`、`service-degraded`、`provider-degraded` 或 `global-blocker`。默认输出只返回裁决、scope、失败/降级/未知信号和有界 evidence 摘要，完整 evidence 必须显式加 `--full` 或 `--raw`；推荐交叉验证命令仍包含 `debug health`、`debug dispatch <providerId> host.ssh --wait-ms 15000`、`trans <providerId> argv true`、`artifact-registry health --provider-id <providerId>`、`microservice health k3sctl-adapter`、`microservice health code-queue` 和 `codex tasks --view supervisor --limit 20`。
- `platform-db postgres plan|status|export-secrets|apply --config config/platform-db/postgres-pk01.yaml` 管理 YAML 声明的 PK01 host-native PostgreSQL。`plan` 和 `status` 只读采集远端 host、PostgreSQL、TLS、DNS alias 和 Secret 形态；`export-secrets --confirm` 只按 YAML 物化本地 Secret source/export 文件，不触碰远端 PostgreSQL；`apply --confirm` 默认创建本地异步 job，`apply --confirm --wait` 用远端 root-owned job 收敛 systemd PostgreSQL、TLS、`pg_hba`、role/database、Secret export 和备份 timer。输出不得打印密码或完整 `DATABASE_URL`。跨节点消费者使用 YAML 中的 `connectionHost` 直连 PK01 公网 endpoint，DNS alias 不作为 `sslmode=require` 切库 blocker，PK01 规则见 `docs/reference/pk01.md`。
- `trans <route> [operation args...]` / `tran <route> [operation args...]` 通过 backend-core 内网 WebSocket broker 和 provider-gateway 的 Host SSH / WSL SSH 维护桥连接目标节点：
  - `route` 基础形态是 provider id，例如 `D601` 或 `G14`；也可以扩展为纯定位路径 `provider:plane[:namespace:resource[:container]]`，例如 `D601:win`、`D601:win/c/test`、`G14:k3s`、`D601:k3s` 或 `G14:k3s:<namespace>:<workload>`。
  - WSL provider 的 Windows plane 固定使用 `win`，不得使用 `win32`；Windows route 中 `win` 只负责定位，operation 直接写 `ps`、`cmd`、`git` 或 fs helper。
  - Windows operation 中，`ps` 执行 PowerShell heredoc 或一行 PowerShell 命令，`cmd` 执行 cmd.exe/batch，`skills` 发现 Windows skill 目录；CLI 自动设置 UTF-8/Python 编码默认值，`cmd` 额外设置 `chcp 65001`。
  - 非交互远端命令优先使用 `trans <providerId> argv ...`；需要 POSIX shell 脚本、管道、变量或循环时，在 operation 位置显式写 `sh` 或 `bash`，并通过 quoted heredoc 传入正文。
  - 远端文本修改默认使用 `trans <route> apply-patch <<'PATCH'`；已知文本路径不得改走 `upload` / `download`，只有整体搬运生成文本产物时才显式加 `--allow-text-transfer`。
  - 非文本或二进制文件使用 `<route> upload <local-file> <remote-file>` 和 `<route> download <remote-file> <local-file>`，CLI 自动核对字节数与 SHA-256。
  - 只有人工确认需要旧 helper 时，才显式使用 `<provider>:k3s:<namespace>:<workload> apply-patch-v1` 或 `<providerId> apply-patch-v1`，输入仍使用 quoted heredoc。
  - ssh-like 命令遇到 timeout/kex/255 类失败时，CLI 在 stderr 追加 `UNIDESK_SSH_HINT` JSON，提示改用 `sh` / `bash` stdin heredoc、argv 或 provider triage 交叉验证。
- `trans <route> apply-patch <<'PATCH'` 是默认推荐的远端 patch 入口：
  - 本地 TypeScript line-based engine 解析并计算新文件内容，远端 route 只负责读写文件；支持 host workspace、k3s pod workspace、Windows workspace route 和 frontend transport。
  - quoted heredoc 中直接放置标准 `*** Begin Patch` / `*** End Patch` envelope，不先创建 patch 临时文件。
  - 成功 stdout 为 `Success. Updated the following files:`；失败 stdout 为空，stderr 写失败原因。多文件补丁中途失败时按 Codex 语义停止，保留失败前已提交的变更。
  - v2 可规范化常见非标准补丁输入并给出 canonical 写法 hint；parser 或上下文失败时，只提示修正 patch 文本或 hunk context，不自动重试或切换到 `apply-patch-v1`。
  - 大块替换因上下文过期失败时，重新读取当前目标块并缩小或拆分 Update File hunk；不得改走 `download` / `upload`、远端 Python/Perl/sed heredoc 或整文件重写。
  - Windows route 复用同一套 v2 核心算法，只把底层读写替换成 PowerShell 文件系统接口。
  - `trans <providerId> apply-patch-v1 [tool args...] <<'PATCH'` 是显式 legacy 入口，直接调用远端注入的 `apply_patch` sh/perl helper；默认 `apply-patch` 不把 v1 当 fallback。
- GitHub issue/PR 正文局部修补必须优先走 `trans gh:/owner/repo/issue/<number> apply-patch` 或 `trans gh:/owner/repo/pr/<number> apply-patch`，而不是人工优先整篇 `gh issue update --mode replace` 或底层 `gh issue patch`。`gh:/` 路由把 issue/PR body 暴露为一楼虚拟文件 `body.md`；route 未显式写 `/1` 时默认一楼正文，`apply_patch` 与 `patch-apply` 只作为兼容别名。典型补丁写法是 `*** Update File: body.md`；普通小补丁在已用 `trans gh:/... cat|rg|ls` 确认上下文后可以直接 apply，`--dry-run` 只作为高风险大段修改、关闭前验收文案或并发敏感正文的可选预览。写回仍通过 UniDesk `gh issue/pr update` guard 和 REST API，不使用原生 `gh`、手写 REST 或整篇 shell 拼接正文。单条 issue comment 的局部修补当前仍使用 `bun scripts/cli.ts gh issue comment patch <commentId> --body-patch-stdin`，直到评论楼层 route 成为稳定入口。
- `apply-patch` v2 每次结束都会在 stderr 追加一行 `UNIDESK_APPLY_PATCH_TIMING {json}`，字段包含 `durationMs`、`patchBytes`、`fileCount`、`hunkCount`、`changedCount`、`remoteOperationCount`、`remoteOperationCounts`、`remoteElapsedMs`、`remoteFailureCount`、`providerId`、`route` 和 `transport`（可得时）。普通 POSIX host/k3s 和 Windows workspace 远端的多文件 `Update File` patch 会优先合并成 bulk read/write，避免每个文件单独 stat/read/write 的 SSH 往返；Add/Delete/Move 等复杂 patch 保持原有逐步语义。timing 摘要只用于定位慢在 patch 解析、远端 stat/read/write 或 bulk read/write、provider session 还是传输层，不能替代 Codex 标准 stdout/stderr 成功失败文本，也不是门禁或自动判断。
- `trans <providerId> py [script-args...] < script.py` 把本地 stdin 落到远端临时 `.py` 文件后再以 `python3 -u` 执行并自动清理，避免再手写 `'python3 -'`、heredoc 或多层引号；`script-args` 会按 argv 安全透传给远端脚本。
- `trans <providerId> skills [--scope all|wsl|windows] [--limit N]` 发现目标节点上的 WSL/Linux skill 根目录；当 provider 是 WSL 时同一次调用还会扫描 Windows 用户目录下的 `.agents/skills` 与 `.codex/skills`。
- `trans <providerId>:k3s[:namespace:workload[:container]] <operation> ...` 是原生 k3s 结构化 route 入口，route 只定位控制面或 workload，`kubectl`、`logs`、`exec`、`sh`、`bash`、`apply-patch`、旧 `apply-patch-v1` fallback 和普通容器命令作为 operation 放在 route 之后；CLI 固定注入 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml` 并把 kubectl、workload exec、logs 和 pod workspace 读写参数组装成 argv，避免在 Host SSH、bash、kubectl exec 和容器 shell 之间反复手写多层引号；D601 与 G14 都有 provider-specific guard，分别校验 `d601` 和 G14 k3s 节点身份。
- Code Queue runner 镜像必须在 PATH 上提供 `/usr/local/bin/tran`。runner 内的 `tran` 检测到 `CODE_QUEUE_*` 或 `KUBERNETES_SERVICE_HOST` 后，默认执行 `bun /root/unidesk/scripts/cli.ts --main-server-ip <public-frontend> ssh ...`，其中 `<public-frontend>` 优先来自 `UNIDESK_MAIN_SERVER_IP` / `UNIDESK_MAIN_SERVER_HOST` / `CODE_QUEUE_DEV_CONTAINER_MASTER_HOST`。runner remote frontend HTTP 客户端默认使用 `curl` 后端，降低 Bun 在部分 runner 内读取非 SSH HTTP response body 时触发 native crash 的风险；显式 `UNIDESK_REMOTE_HTTP_CLIENT=fetch` 可用于诊断。runner 内跨 D601/G14 的分布式访问应优先使用结构化 route/operation，例如 `tran D601 argv ...`、`tran G14 argv ...`、`tran D601:k3s kubectl ...`、`tran D601:k3s:<namespace>:<workload> argv ...`、`tran G14:/absolute/workspace apply-patch ...` 和 `tran <route> upload|download ...`；`apply-patch`、`upload`、`download`、`sh`、`bash`、`py` 和旧 `apply-patch-v1` fallback 经 frontend `/ws/ssh` 通道执行，stdout/stderr 也必须完整直通，不得退回 `/api/dispatch` task JSON。非 UniDesk admin runner 可通过 `UNIDESK_SSH_CLIENT_TOKEN` 使用 scoped `/ws/ssh` client token，frontend 侧用 `UNIDESK_SSH_CLIENT_ROUTE_ALLOWLIST` 约束允许 route；该 token 只授予 ssh passthrough，不下发 provider token、主 server SSH key 或完整 frontend 登录态。
- `microservice list/status/health/diagnostics/tunnel-self-test/proxy` 通过 backend-core 内网 API 管理挂载在计算节点 Docker 或 k3s 控制面中的用户服务（底层命令名仍为 microservice）；`health`、`status` 和 `diagnostics` 默认返回 compact summary、body 字节数和 `--full|--raw` 展开命令，只有小 body 或无法抽取 summary 时才带有界 body preview，避免 Code Queue/k3s 诊断一次性输出爆炸；`tunnel-self-test` 和 `proxy` 会走真实 backend-core -> provider-gateway 或 k3sctl-adapter -> 节点服务链路。`microservice health code-queue` 使用 commander-safe 专用摘要，必须保留 ok/status、service id、running count、queue count、heartbeat freshness/risk、split-brain/live/degraded 解释和 raw drill-down 命令；需要完整健康 JSON 时显式加 `--raw` 或 `--full`，等价深挖路径是 `microservice proxy code-queue /health --raw --full`。`proxy` 支持受控 JSON 请求体并对超大响应 body 默认输出有界预览，规则见 `docs/reference/microservices.md`。
- `decision upload/list/show/health` 通过 `config/unidesk-host-k8s.yaml` 选择 NC01 k8s `unidesk/decision-center` 入口，用于上传会议记录/决议 Markdown、列出权威记录、查看详情和健康检查；持久化权威是 GitHub repo `pikasTech/decision-center-data` 的 `main:data`，PostgreSQL 只作为运行时索引/缓存。`decision list` 默认只返回摘要并省略完整 Markdown body，需要排查大正文时显式加 `--include-body`。正式文书字段通过 records 模型一等字段返回和查询：`--doc-no DC-...`、`--doc-type DCSN|GOAL|PLAN|RPRT|ACTN|ISSU|RETR|RQST|RESP|MINS`、`--doc-priority P0|P1|P2|P3`、`--year YYYY`、`--signer`、`--issued-at`、`--effective-scope`、`--supersedes`、`--superseded-by`；`show` 和 `requirement update` 可使用 `id` 或 `docNo`。`decision requirement list/create/upsert/update/show` 在同一 records 模型上管理 `goal|decision|blocker|debt|experiment` 需求记录，`docNo` 唯一，未传 `--doc-no` 但提供 `--doc-type/--doc-priority/--year` 时由服务分配下一个序号。它们不得直连 Service、NodePort、provider-gateway 业务 HTTP 或旧 D601 Decision Center 路径。
- `decision diary import <markdown-file>` 将带 `# YYYY年M月D日`、`# YYYY-MM-DD` 或 `# YYYY/M/D` 标题的工作日志拆成每天一篇 Markdown 日记，按 `YYYY-MM/YYYY-MM-DD.md` 虚拟路径写入 Decision Center GitHub 存储；`decision diary list/history` 默认只返回摘要，需要完整 Markdown 时显式加 `--include-body`；`decision diary show <YYYY-MM-DD|id> [--source-file path]` 查看单日正文，`--source-file` 用于同一天存在多个导入来源时精确选择；`decision diary edit|upsert <YYYY-MM-DD|id> --body-file <path> [--title text] [--source-file path] [--tag tag]` 通过 `PUT /api/diary/entries/:idOrDate` 创建当天或历史条目并编辑既有条目。
- `deploy check/plan/apply` 默认从根目录 `deploy.json` 读取服务 repo 与 commit 期望状态，join `config.json` 和现有 manifest 后使用 target-side build 或 reviewed artifact consumer 校验/更新已支持目标；`deploy plan --env dev|prod` 只从 `origin/master:deploy.json#environments.<env>` 读取 manifest 并输出 dry-run 环境计划，不使用本地 dirty worktree；当前 `deploy apply --env dev` 支持 `backend-core`、`frontend`、`baidu-netdisk`、`mdtodo`、`claudeqq` 和 dev-only `code-queue` artifact consumers，`findjob`/`pipeline`/`met-nonlinear` 为 D601 direct Compose artifact consumers，`k3sctl-adapter` 只提供 plan/dry-run；Decision Center 生产部署走 NC01 YAML-first k8s + GitHub repo storage，不再用 D601 artifact consumer 作为当前 closeout；dev desired-state smoke 使用 `ci run-dev-e2e`；规则见 `docs/reference/deploy.md`、`docs/reference/dev-environment.md` 和 `docs/reference/dev-ci-runner.md`。`deploy apply --env prod` 同时覆盖 `findjob` 和 `pipeline` 的 pull-only Compose CD，但 `met-nonlinear` 仍然只允许 dry-run/plan，`k3sctl-adapter` 只允许 plan/dry-run。
- `dev-env validate [--manifest path] [--kubectl-dry-run]` 离线校验 D601 `unidesk-dev` namespace、dev PostgreSQL 底座和 dev workload manifest。默认检查 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-foundation.k8s.yaml`；也可显式校验 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml` 或 `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml`。所有 namespaced 对象必须只落到 `unidesk-dev`，foundation manifest 必须包含 `postgres-dev` StatefulSet/Service、dev secret/config、迁移 Job 和 DB URL guard，core manifest 必须包含 `backend-core-dev`/`frontend-dev` Deployment/Service，Code Queue dev manifest 必须包含 `code-queue-scheduler-dev`、`code-queue-read-dev`、`code-queue-write-dev`、dev provider egress proxy，以及只读挂载宿主 `/home/ubuntu/.agents/skills` 到容器 `/root/.agents/skills` 的 `skills-dir` volume。加 `--kubectl-dry-run` 时额外以 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml` 执行 `kubectl apply --dry-run=client --validate=false -f <manifest>`，仍不 apply 资源；默认 `docker-desktop` kubeconfig 不得作为 D601 dry-run 目标。
- `dev-env prewarm-images [--image image] [--provider-id D601] [--no-pull] [--proxy-url URL] [--pull-timeout-ms N] [--dry-run]` 创建异步 job，通过 UniDesk SSH 维护桥在 D601 上把开发底座依赖镜像从 Docker 缓存导入原生 k3s containerd。默认镜像是 `postgres:16-alpine` 和 `rancher/mirrored-library-busybox:1.36.1`，用于避免 `postgres-dev` 与 local-path helper pod 卡在外部 registry 拉取。该命令固定验证 `/etc/rancher/k3s/k3s.yaml` 指向的 native k3s 上下文，并输出 `dev_env_containerd_image_ready=...` 作为成功判据；它不 apply manifest、不修改生产 `unidesk` namespace。
- `artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service` 管理 D601 host-managed CNCF Distribution registry 的声明、安装、只读检查和 pull-only artifact CD。该 registry 固定为 D601 loopback `127.0.0.1:5000`，由 systemd + Docker Compose 管理，位于 native k3s 故障域外；`deploy-service` 只拉取 CI 已发布的 commit-pinned 镜像、retag/recreate 或导入 native k3s，并做 live commit 验证，不构建 runtime source。`deploy-backend-core` 是 deprecated 兼容名，标准 backend-core prod CD 入口是 `deploy apply --env prod --service backend-core`。长期规则见 `docs/reference/artifact-registry.md`。
- `commander contract|plan --dry-run|smoke --dry-run|approval request --dry-run` 是 host Codex 指挥官直管微服务 skeleton 入口。当前命令返回 `phase=source-contract`、service/API/state/bridge/prompt/trace/#20/#46/ClaudeQQ 审批边界、.state/commander/ 状态模型、dev 无 daemon smoke plan 和 dry-run 计划，不接 live bridge、不注入 prompt、不发送 ClaudeQQ。`approval request --dry-run` 会生成 200 字以内中文纯文本 ClaudeQQ 审批草案、`notification-path-unavailable` blocker 和授权后唯一可用的 `bun scripts/cli.ts microservice proxy claudeqq /api/push/text --method POST --body-json '<payload>' --raw` 命令；不得提示使用本机 ClaudeQQ skill、powershell 或本地 server。AgentRun 新任务 payload 边界由指挥官直接审查，不再通过额外本地派单审查命令；legacy `codex submit` 已冻结，新任务走 AgentRun `create/apply` 资源原语。`plan`、`smoke` 与 `approval request` 必须带 `--dry-run`；缺少时返回 `error=dry-run-required`。长期规则见 `docs/reference/host-codex-commander.md`。
- `hwlab g14 retirement status|plan|execute --confirm [--wait]` 是 legacy G14 DEV/PROD 的受控退役入口。`status` 只读报告 `argocd/hwlab-g14-dev`、`argocd/hwlab-g14-prod`、`hwlab-dev`、`hwlab-prod`、bounded legacy resource preview、受保护的 `hwlab-g14-v02`/`hwlab-node-v03` 和 `hwlab-v02`/`hwlab-v03`，以及 `.state/hwlab-g14/legacy-g14-retirement.json` marker。`plan` 是 dry-run，只列出 destructive targets 和 protected targets。`execute --confirm` 删除 legacy Argo Applications 与 legacy namespaces，取消本地 active `hwlab_g14_pr_monitor` job，并写 retirement marker 记录执行证据；`hwlab g14 monitor-prs --lane g14` 按退役合同固定结构化失败并指向 `retirement status` 和 runtime lane monitor `--lane v02|v03`。该入口禁止触碰 v0.2/v0.3 Application、namespace、PipelineRun、Secret、Git mirror 或 FRP desired state。
- `hwlab g14 monitor-prs --lane v02` 是 HWLAB `v0.2` 的 PR -> CI -> CD 自动化入口。它只监控 base=`v0.2` 的 open PR：每轮先用 UniDesk `gh pr preflight` 读取 GitHub CI/checks、mergeability 和冲突状态；pending 时在 PR 下写等待评论，blocked/conflict 时写阻塞评论；ready 时直接用 UniDesk `gh pr merge` 合并，不因为其他 commit 的运行中 PipelineRun 阻塞 merge 或 CI 启动。合并后执行受控 `control-plane trigger-current --lane v02 --confirm --wait`、轮询定点 `control-plane status --lane v02 --source-commit <merge-sha>`，必要时执行 `git-mirror flush --confirm --wait`。v0.2 CD 采用 latest-only：旧 PipelineRun 不取消、不等待，但 promotion 写 `v0.2-gitops` 前必须重新确认 source head，stale commit 只能以 superseded/no-op 收口，不能回滚 runtime。不管 CD 成功、superseded、失败或超时，都在原 PR 下用 `gh pr comment create --body-stdin <<'EOF'` 追加语义化状态，正文固定包含起止时间、总耗时、冲突状态、CI/preflight conclusion、source commit、PipelineRun、targetValidation、Argo/webAssets 和 git mirror pendingFlush/githubInSync。评论去重状态写入 `.state/hwlab-g14/v02-pr-comment-signatures.json`，同一状态签名不会重复刷评论；v0.2 monitor 指针使用 `.state/hwlab-g14/latest-v02-monitor-job.json`、`latest-v02-once-job.json`、`latest-v02-dry-run-job.json` 和 `latest-v02-once-dry-run-job.json`，不会覆盖默认 G14 monitor 指针。`--lane v02 --once --dry-run` 只做单轮 preflight/merge/CD/comment plan，不写 GitHub、不触发 CD。
- `hwlab g14 monitor-prs --lane v03` 是 HWLAB `v0.3` 的 PR -> CI -> 自动合并 -> CD 入口。它只监控 base=`v0.3` 的 open PR：每轮先通过 UniDesk `gh pr preflight` 读取 GitHub checks、mergeability 和冲突状态；pending 时只在 PR 下写等待评论；失败 check、preflight blocker 或 conflict 时在 PR 下写阻塞评论，并按标题去重创建或更新 HWLAB failure issue。ready 时通过 UniDesk `gh pr merge` 合并，随后执行 runtime lane `control-plane trigger-current --lane v03 --confirm --wait`，轮询 `control-plane status --lane v03 --source-commit <merge-sha>`，判定 PipelineRun `True`、Argo `Synced/Healthy`、`hwlab-v03` runtime workload 可见、选中 node/lane 的 YAML public URL 探针通过；D601 `v0.3` 的正式入口是 `https://hwlab.pikapython.com`，裸 IP/FRP 端口只能作为边缘诊断证据，不能作为用户入口验收口径。必要时执行 `git-mirror flush --lane v03 --confirm --wait`。CD 成功、失败或超时都会在原 PR 下写语义化状态评论；失败和超时同时创建或更新 failure issue，正文必须包含 PR、base/head、commit、PipelineRun、失败阶段、preflight/CD 摘要和下一步 CLI。评论去重状态写入 `.state/hwlab-g14/v03-pr-comment-signatures.json`，monitor 指针使用 `.state/hwlab-g14/latest-v03-monitor-job.json`、`latest-v03-once-job.json`、`latest-v03-dry-run-job.json` 和 `latest-v03-once-dry-run-job.json`。`--lane v03 --once --dry-run` 只做单轮 preflight/merge/CD/comment/issue plan，不写 GitHub、不触发 CD。
- `agentrun control-plane status|trigger-current|refresh|cleanup-runs|cleanup-released-pvs [--dry-run|--confirm]` 是 AgentRun `v0.1` 在 G14 k3s 的受控 Tekton/Argo 入口。`status` 只读汇总固定 source worktree commit、对应 commit-pinned PipelineRun、GitOps latest、Argo Application、`agentrun-v01` manager source commit、`planArtifacts.summary`、env image result 和 git mirror 摘要，并报告 manager/Argo/GitOps 是否对齐当前 source commit。默认输出是 compact commander 视图：`summary` 给出 source、PipelineRun、Argo、manager image、git mirror 和 `aligned` 结论；`timings` 给出 `sourceMs`、`runtimeMs`、`gitMirrorMs` 和 `totalMs`；远端 stdout/stderr tail 默认省略，失败时仍展开必要 tail，完整 tail 用 `--full`，原始 git mirror cache 用 `--raw`。`status` 聚合 source 后会并行读取 runtime 和 git mirror，并向 stderr 输出 `agentrun.control-plane.status.progress` JSON 事件，覆盖 `source`、`runtime`、`git-mirror` 的 started/succeeded/failed 和 elapsedMs，避免 10s 以上状态聚合期间无可见进展；`trigger-current` 先快进 `G14:/root/agentrun-v01` 到 `origin/v0.1`，检查 `devops-infra` mirror 的 `localV01` 是否等于目标 source commit，必要时先执行受控 mirror sync，再创建 `agentrun-v01-ci-<short12>` PipelineRun。confirmed trigger 只提交 CI/CD 工作并返回后续 `status` 命令，不等待完整 PipelineRun；同名 PipelineRun 运行中或已成功时拒绝重复触发，只允许失败态重建或首次创建。`refresh` 只对 `argocd/agentrun-g14-v01` 执行 hard refresh，用于 GitOps promotion 已完成但 Argo 仍停留旧 revision 时的受控同步入口；它不直接 patch runtime workload。`cleanup-runs` 只清理 `agentrun-ci` 中已完成且超过 `--min-age-minutes` 的 `agentrun-v01-ci-*` PipelineRun，通过 Tekton ownerRef 回收临时 workspace PVC；dry-run 必须输出候选 PipelineRun、owned PVC、active mount 保护、local-path 实际估算 bytes 和 confirm 命令。`cleanup-released-pvs` 只处理 `agentrun-ci`、`local-path`、`Delete` reclaim policy 的 `Released` PV，用于 PipelineRun 删除后残留 PV 的二次回收；它不触碰 runtime namespace、业务 PVC、Secret、registry storage 或 GitOps desired state。AgentRun 实现事实来源在 AgentRun 仓库；HWLAB-facing SPEC 正文在 UniDesk OA，AgentRun 仓库 `spec-v01-*` 只保留交叉引用 stub。UniDesk CLI 只维护受控运维入口。
- `agentrun git-mirror status|sync|flush [--dry-run|--confirm]` 是 AgentRun `v0.1` 使用 `devops-infra` git mirror/relay 的受控维护入口。`status` 默认返回 read/write URL、`localV01`、`githubV01`、`localGitops`、`githubGitops`、`pendingFlush`、`githubInSync`、exact full-SHA shallow fetch 摘要和 Artificer bundle repo mirror 覆盖状态，不默认展开完整 cache stdout；需要探测 tail 时用 `--full`，需要原始 cache 输出时用 `--raw`。`sync` 创建 manual Job，把 GitHub `pikasTech/agentrun` 的 `v0.1` / `v0.1-gitops` refs 以及 Artificer 默认 bundle repo `pikasTech/unidesk`、`pikasTech/agent_skills` 的 `master` refs 拉入 `/cache/pikasTech/*.git`；`flush` 仍只把本地 `pikasTech/agentrun` 的 `v0.1-gitops` 快进推回 GitHub。AgentRun runner 的 `ResourceBundleRef` / AipodSpec 只写 GitHub URL，不写 `gitMirror` 字段；mirror 自动改写属于基础设施能力。confirmed `sync`/`flush` 默认创建 `.state/jobs/` 异步 job 并立刻返回 `job.id`、`statusCommand` 和日志路径；只有现场同步调试才显式加 `--wait`。该入口与 HWLAB v0.2 mirror 共用 `devops-infra` 服务和 cache PVC，但 repo path、refs、status 文件和 CLI 命令彼此独立。
- `hwlab g14 control-plane status|apply --lane v02 [--dry-run|--confirm]` 是 HWLAB `v0.2` 加法 lane 的受控 Tekton/Argo 控制面维护入口，source commit 只来自 G14 专用 bare repo `/root/hwlab-v02-cicd.git` 的 `refs/remotes/origin/v0.2`；`/root/hwlab-v02` 只作为人工开发和短连接源码工具 workspace 被观测，dirty/stale 状态必须输出为 isolated warning 而不能阻塞 CI/CD。该入口面向 branch `v0.2`、namespace `hwlab-ci` 和 Argo application `hwlab-g14-v02`；默认 `status` 只读汇总最新 source head 的 pipeline、RBAC/ServiceAccount、Argo、当前 commit PipelineRun、当前 PipelineRun 的 TaskRun 条件摘要、最近 PipelineRun 摘要、活跃 PipelineRun、遗留 v02 CronJob 清理状态、commit alignment，以及 19666/19667 的 Cloud Web 静态资源和 API live 探针。分支被后续提交推进后，要复查已完成 run 时使用 `status --lane v02 --pipeline-run hwlab-v02-ci-poll-<short-sha>`；已知完整 source SHA 但不想依赖最新 head 时使用 `status --lane v02 --source-commit <full-sha>`。定点 `status` 输出 `statusTarget.mode` 和 `targetValidation`，只检查指定 PipelineRun/source commit 的证据；`targetValidation.state=passed` 表示该目标已满足 PipelineRun succeeded、Argo `Synced/Healthy`、19666/19667 探针、Git mirror flushed，并且该 run 的 `planArtifacts.rolloutServices` 运行时 source commit 对齐；`planArtifacts.reusedServices` 作为 runtime/provenance 证据呈现，但不能被强制要求等于目标 source commit。`targetValidation.state=superseded` 表示该目标已成功且 runtime 已被同一分支后续成功 PipelineRun 取代，`falseGreenGuard` 在该状态下应标为 superseded/not-applicable。两种状态都不得因为 `origin/v0.2` 后续推进而把历史 run 判为失败；默认不带定点参数时仍严格判定最新 source head alignment。TaskRun 摘要的 `performance` 字段会把超过 120s 的 build TaskRun 标为慢任务、超过 180s 标为 critical warning，用于暴露 env reuse/git mirror 命中率回归，但不作为阻断门禁；CI/CD 性能验收应同时看 `planArtifacts.summary`、`taskRuns.performance.warningCount` 和 PipelineRun duration，纯 CLI/文档或无 runtime 重建需求的后续提交应稳定表现为 `build=0 reuse=<service-count>` 且无 build TaskRun warning，首次引入或切换 env image 时允许只构建必要 env image 一次。`webAssets` 必须直接给出 `readonly-rpc` 删除、sidebar/workspace/event panel 关键 CSS、`/app.js` 是否可读取和字节数、`/health/live` 与 API revision；`apiRevision` 是 cloud-api 服务自身 revision，Cloud Web 静态资源变更时允许它与 source commit 不同，不能把这种差异误判成 Cloud Web 未发布。默认只读取必要字段，禁止把完整 PipelineRun spec、Tekton 内联脚本、历史大对象或整份 CSS/HTML/JS 展开到默认输出；`apply` 先自动 fetch `/root/hwlab-v02-cicd.git` 并从 commit-pinned detached worktree 执行 render check，再经 `G14:k3s` server-side apply `tekton-v02/rbac.yaml`、`pipeline.yaml`、`argocd/project.yaml` 和 `argocd/application-v02.yaml`，confirmed apply 会删除遗留 v02 CronJob，但不会应用 runtime-v02 workload、Secret 或数据迁移。
- `hwlab nodes control-plane status|apply|refresh|trigger-current --node G14 --lane v03` 使用 `/root/unidesk/config/hwlab-node-lanes.yaml` 生成 runtime lane spec。该 YAML 同时声明 `nodes.G14`、`lanes.v02/v03`、`networkProfiles` 和 `downloadProfiles`；status 默认输出 `expected.configPath`、node、network/download profile、有效 `NO_PROXY`、Docker build proxy、Argo Application 和 runtime workload 摘要，confirmed trigger 创建的 PipelineRun annotation 记录 node/profile id。`apply` 和 `trigger-current` 的控制面 apply 只安装标准 node-scoped Argo Application，并通过同一受控入口清理旧式 `hwlab-g14-vNN` runtime lane Application，避免两个 Argo Application 同时管理同一 runtime namespace；该清理不删除 runtime workload、Secret 或 GitOps desired state。`refresh` 是受控 Argo 恢复入口，只终止 stale Application operation 并执行 hard refresh，不直接 patch runtime workload；用于 GitOps revision 已更新但 Argo 仍卡在旧 hook/operation 时让 Argo 重新从当前 desired state 自愈。新增 `v0.4+` lane 时应先加 YAML，再让 GitOps render、CI prepare-source/catalog fetch、runtime env 注入和 Secret/DB/bootstrap helper 消费同一 spec；不要在脚本、CI manifest 或 helper 默认值里新增散落的 G14 代理、下载源或端口硬编码。`hyueapi.com` / `.hyueapi.com` 是强制保留的 `NO_PROXY` 条目，lane 覆盖不得移除。
- `hwlab g14 control-plane trigger-current --lane v02 [--dry-run|--confirm]` 是 v02 标准手动触发入口：先自动 fetch `/root/hwlab-v02-cicd.git`，解析当前 `origin/v0.2` full SHA，创建 commit-pinned `hwlab-v02-ci-poll-<short12>` PipelineRun；读 Git 走 `git-mirror-http.devops-infra.svc.cluster.local`，GitOps promotion 写 `git-mirror-write.devops-infra.svc.cluster.local`；confirmed trigger 在创建 PipelineRun 前会先按当前 source commit 在 G14 临时 detached worktree 中 render，再 server-side apply v02 Tekton RBAC、Pipeline 与 Argo Application，避免 CI/CD 脚本或 runtime-ready 逻辑已合并但集群仍执行旧 Pipeline 定义；该 render 不要求固定 `/root/hwlab-v02` 工作树 clean，也不得因 `.worktree/` 或其他并行未提交修改阻塞；同名 PipelineRun 存在时默认复用现有状态，不删除重建，失败 run 的重试策略必须显式设计，不能恢复默认 delete/create。
  创建 PipelineRun 前会读取 `devops-infra` mirror refs，若 `localV02` 未等于当前 source commit，则自动执行一次受控 manual `git-mirror sync` Job 并复核 ref，复核失败时停止触发，避免 Tekton `prepare-source` 已知失败；services 参数只包含 v02 runtime service matrix，`hwlab-cli` 是固定 repo 短连接源码工具，不进入 PipelineRun service build。
  `--dry-run` 只报告是否会 pre-sync，不创建 Job；confirmed trigger 默认创建 `.state/jobs/` 异步 job 并立刻返回 `job.id`、`statusCommand`、stdout/stderr 路径，避免 git mirror pre-sync 或 PipelineRun 创建期间长时间阻塞；`--wait` 路径也必须向 stderr 输出 `hwlab.v02.trigger.progress` JSON 事件，覆盖 `control-plane-refresh`、`git-mirror-pre-sync` 和 `create-pipelinerun`，避免异步 job 长时间只有启动命令而无法判断卡点；默认 JSON 必须对 `manifest_b64`、长脚本和远端 stdout/stderr 做有界摘要，保留长度与 hash，最终 trigger 结果只返回阶段摘要和关键 tail，完整内容通过 job stdout/stderr 文件渐进披露；只有现场同步调试才显式加 `--wait`；旧 `rerun-current` 只作为输入别名保留。PipelineRun `Completed`、Argo `Synced/Healthy` 和 `webAssets.ok=true` 只证明 G14 runtime 已更新；交付收口还必须用 `hwlab g14 git-mirror status` 查看 `cache.summary.pendingFlush`，若为 true，继续执行受控 `hwlab g14 git-mirror flush --confirm` 并用 job status 轮询到 `pendingFlush=false`。
- `hwlab g14 control-plane runtime-migration --lane v02 [--dry-run|--allow-live-db-read --dry-run|--confirm]` 只通过 `hwlab-v02` namespace 当前 `deployment/hwlab-cloud-api -c hwlab-cloud-api` 内 repo-owned migration CLI 执行；不读取或打印 Secret 值、不触碰 PROD、不绕到手工 `psql`。
- `hwlab g14 secret status|ensure --lane v02 --name hwlab-v02-openfga|hwlab-v02-master-server-admin-api-key [--dry-run|--confirm]` 和 `hwlab nodes secret status|ensure --node G14 --lane v03 --name hwlab-v03-master-server-admin-api-key [--dry-run|--confirm]` 是 HWLAB runtime lane SecretRef bootstrap 的保留入口。v03+ Cloud API/OpenFGA datastore SecretRef 已迁移到 G14 platform PostgreSQL，`hwlab nodes secret status --node G14 --lane v03 --name hwlab-cloud-api-v03-db|hwlab-v03-openfga` 只做 redacted SecretRef 与 `g14-platform-postgres` bridge 观测；旧 `ensure` 路径已删除，不再从 `hwlab-v03-postgres` Secret 或 StatefulSet 派生。`hwpod-v03-db`、`hwpod_v03`、`hwpod_v03_app` 是废弃残留，不能作为 status 完成态保留，发现后用 `hwlab nodes secret cleanup-obsolete --node G14 --lane v03 --name hwpod-v03-db [--dry-run|--confirm]` 清理。平台库凭据、桥接 Service 和 SecretRef 轮换边界见 `docs/reference/g14-platform-db.md`。master server admin API key preset 确保本机 `/root/.config/hwlab-v0x/master-server-admin-api-key.env` 以 0600 保存 `HWLAB_API_KEY`，并同步到对应 lane 的 `*-master-server-admin-api-key/api-key`。`status` 只返回 key 是否存在、解码后字节数、key prefix、bridge 存在性和 runtime health 相关结果，永远不读取、不打印、不回传 secret 明文。`hwlab nodes secret cleanup-owned-postgres --node G14 --lane v03 [--dry-run|--confirm]` 是 v0.3+ 迁移到 G14 平台 Postgres 后的受控残留清理入口，精确删除旧 repo-owned `hwlab-v03-postgres` StatefulSet/Service/ConfigMap/Secret 和 `data-hwlab-v03-postgres-0` PVC；它要求 `g14-platform-postgres` Service 已存在，默认 dry-run，不触碰平台数据库、OpenFGA/Cloud API 当前 SecretRef 或 GitOps desired state。`hwlab g14 secret delete --lane v02 --name <obsolete-hwlab-v02-secret> [--dry-run|--confirm]` 只用于删除确认已不被 workload 引用的 v0.2 废弃 Secret，默认 dry-run，拒绝删除 OpenFGA/Postgres/master admin API key 等必需 Secret；共享 device-pod API key 已退出当前授权路径，不再提供 ensure/bootstrap 入口。
- `hwlab g14 control-plane cleanup-runs --lane v02|v03|g14|all [--min-age-minutes N] [--limit N] [--dry-run|--confirm]` 和 `hwlab nodes control-plane cleanup-runs --node <node> --lane <lane> [--min-age-minutes N] [--limit N] [--dry-run|--confirm]` 是完成态 PipelineRun 工作区 retention 入口；真实清理只删除已完成 PipelineRun 及其 Tekton TaskRun/Pod 链路，让 Tekton/local-path 回收临时 PVC，不触碰 registry storage、业务 PVC、Secret、runtime workload 或 GitOps desired state。带 `--pipeline-run <name>` 或 `--source-commit <full-sha>` 的定点清理必须先直接查询目标 PipelineRun，而不是只从全量列表过滤；不存在的目标返回 `target-pipelinerun-not-found`，未完成目标返回 `target-pipelinerun-not-terminal`，年龄保护仍返回 `below-min-age`。D601 等非默认 node 的 CI Pod capacity 被终态 TaskRun/Pod 占满时，先用 node-scoped `cleanup-runs --dry-run` 查看保护对象、候选 PipelineRun、owned TaskRun/Pod/PVC 和后续 `--confirm --wait` 命令；禁止用原生 `kubectl delete` 长期替代该入口。
- `hwlab g14 control-plane cleanup-released-pvs --lane all [--limit N] [--dry-run|--confirm]` 是 local-path 未自动回收后的补充 retention 入口；只列并删除 `Released`、`local-path`、`Delete`、`claimNamespace=hwlab-ci` 且 claim 名称形如 Tekton 临时 `pvc-*` 的 PV。
- `hwlab g14 git-mirror status|apply|sync|flush [--dry-run|--confirm]` 是 `devops-infra` git mirror/relay 的受控维护入口：`apply` 渲染并 server-side apply `devops-infra/git-mirror.yaml`，同时删除遗留 `git-mirror-hwlab-sync` CronJob；`sync` 创建一次性 manual Job，把 GitHub allowlist refs 拉入本地 mirror；`flush` 创建一次性 manual Job，把本地 `v0.2-gitops` 快进推回 GitHub。
  `status` 返回 read/write URL、last sync/write/flush、本地 ref、GitHub staging ref 和 pending flush 状态，并在 `cache.summary` 给出 `localV02`、`localGitops`、`githubGitops`、`pendingFlush`、`flushNeeded`、`githubInSync` 和下一条受控 `flushCommand`。confirmed `sync` 和 `flush` 默认创建 `.state/jobs/` 异步 job 并立刻返回可查询状态，只有现场同步调试才显式加 `--wait`；mirror 不设置 CronJob。
  如果 PipelineRun 的 `gitops-promote` 阶段报 git mirror 控制面漂移或 refs 不一致，先执行 `hwlab g14 git-mirror apply --confirm` 重新应用当前 `devops-infra/git-mirror.yaml` hook/ConfigMap，再执行 `hwlab g14 git-mirror sync --confirm --wait` 复核 refs；失败的同名 PipelineRun 只能通过 `hwlab g14 control-plane cleanup-runs --lane <lane> --pipeline-run <name> --confirm` 受控清理后重试，不要用原生 `kubectl delete` 或手工改 mirror hook。修复后仍必须用 `control-plane status --pipeline-run <name>` 和 `git-mirror status` 分别确认 runtime closeout 与 GitHub flush。
- `platform-infra sub2api|langbot|n8n|wechat-archive ...` 是 `platform-infra` namespace 内平台公共服务和公共工作流的受控入口；`sub2api` 支持 `plan|apply|status|validate|codex-pool`，`langbot` 和 `n8n` 支持各自 YAML-controlled `plan|apply|status|logs|validate` 等公共服务操作，`wechat-archive` 支持 `plan|apply|status|validate|pull`，用 `config/platform-infra/wechat-archive.yaml` 声明 LangBot/n8n/Baidu Netdisk 归档链路，以及 D601 Windows 隔离 PC 微信 + WeChatFerry host + D601 k3s 只读 collector 的 personal WeChat upstream；collector 必须复用 D601 已有 `platform-infra` namespace，`createNamespace=false`。`--target` 选择运行目标，默认 `G14` 为 active runtime，`D601` 为同一 YAML 控制的 standby predeploy target。镜像版本和 target 边界由 `config/platform-infra/*.yaml` 控制，Codex 上游池、统一 API key Secret、FRP 公网端口和 master `~/.codex` 消费端由 `config/platform-infra/sub2api-codex-pool.yaml` 控制；完整 Sub2API 日常部署、上游增删、FRP 暴露、local Codex 配置、验收和排障步骤统一见 `$unidesk-sub2api`（`.agents/skills/unidesk-sub2api/SKILL.md`）。`docs/reference/platform-infra.md` 保留 namespace、YAML-first、路由、Secret 脱敏、PK01 Caddy+FRP 和探针开发边界。
- `platform-infra observability plan|apply|status|validate|trace --target <node>` 是 `platform-infra` 内 OTel Collector 和 Tempo trace backend 的受控入口，`--target` 必须选择 trace 所属运行面节点；具体 trace 查询、噪声压制、Code Agent/AgentRun 排障和“先改进 OTel”的操作面统一见 `$unidesk-otel`（`.agents/skills/unidesk-otel/SKILL.md`）。
- `secrets plan|sync|status --config config/secrets-distribution.yaml --scope platform-infra` 是平台服务本地 Secret sourceRef 到 Kubernetes Secret key 的受控下发入口。`plan` 只读展示 sourceRef、必需 key、目标 Secret/key、missingKeys 和 fingerprint；`sync --confirm` 只按 YAML 声明创建允许生成的本地 key 并下发到声明的目标 Secret；`status` 只验证 live Secret key presence。该入口禁止从 live pod 或 Kubernetes Secret 反推密码、API key、JWT secret、n8n encryption key 或 `DATABASE_URL`，输出也不得打印 base64、解码值或远端 raw transcript；即使显式 `--raw` 也只返回脱敏 summary 和 raw omission 标记。LangBot/n8n Secret 轮换和缺 key 修复规则见 `docs/reference/platform-infra.md#secret-distribution-boundary`。
- `hwlab g14 observability status|apply|query|targets|boundary|closeout [--lane v02] [--promql <expr>] [--expect-count N] [--expect-value V] [--dry-run|--confirm]` 是 G14 `devops-infra` 共享监控基础设施和 HWLAB v0.2 监控 closeout 的受控入口。`apply` 固定安装 Prometheus Operator `v0.91.0`、Prometheus `v3.12.0`、Prometheus 发现 RBAC、`devops-infra` 内 Prometheus 实例和 ClusterIP query Service，并给被允许发现的 workload namespace 打低风险 label；它不把 Prometheus、Grafana 或 Alertmanager 部署到 `hwlab-v02`，也不接管 HWLAB runtime Deployment/Service。`status` 只读汇总 CRD、operator Deployment、Prometheus CR/pod/service、`hwlab-v02` ServiceMonitor/PrometheusRule 和 bounded `up` 查询；`query` 只通过 Kubernetes service proxy 查询 Prometheus，支持 `--expect-count` / `--expect-value` 输出 `assertion`、bad values 和 missing/extra series；`targets` 汇总 ServiceMonitor/PrometheusRule、metrics sidecar readiness/restart、三层指标值和 `metrics.k8s.io` 当前 CPU/内存资源快照；`boundary` 验证 workload namespace 没有 Prometheus/Alertmanager，并对 `19666/19667` 公网 `/metrics` 做负向验证；`closeout` 聚合平台 ready、scrape reachable、sidecar serving、business health probe、resource snapshot、namespace boundary 和 public metrics exposure 语义结论。长期边界见 `docs/reference/g14-observability-infra.md`。
- `hwlab g14 tools-image status|build --name ci-node-tools --tag <tag> [--dockerfile deploy/ci/hwlab-ci-node-tools.Dockerfile] [--dry-run|--confirm]` 是 G14 固定 HWLAB CI tools image 的受控 host build/push 入口；构建和 push 只发生在 G14 host 与本地 registry，不在 master server 构建，也不把 `apk add`/runtime install 塞进 Tekton PipelineRun。
- `trans gh:/owner/repo ...` 把 GitHub issue/PR 映射成只读、受控写入的虚拟文本目录：
  - `ls` 展示 PR / issue 目录和有界条目摘要；`cat` 直接读取一楼正文；`rg` 在正文内检索。
  - `apply-patch` 使用默认 v2 虚拟文件 executor，把正文一楼映射为 `body.md`，写回仍走 `bun scripts/cli.ts gh issue/pr update` 的 guard/concurrency 规则。
  - 普通小补丁不固定要求先跑 `--dry-run`；高风险正文可用 `--dry-run` 预览；`rm` 对正文一楼结构化拒绝。
  - 大正文默认不创建或依赖 dump；接口必须直接消费单份正文。超过显示预算时返回语义化窄查询，调用方继续用同一 `gh:` route 的 `rg`、`cat` 或 `apply-patch`，不得展开临时 dump 文件。
- `hwlab cd status|audit|preflight|apply --env dev [--dry-run]` 是旧 D601 HWLAB DEV CD 指挥侧 wrapper，仅用于显式 legacy 诊断和迁移对照。默认通过 UniDesk provider `host.ssh` 进入 D601，再调用 HWLAB repo-owned `scripts/dev-cd-apply.mjs`，不内嵌发布 kubectl 逻辑：`status` 汇总固定 CD mirror、Git clean/main/origin-main、`deploy/deploy.json`/artifact catalog/report、D601 native k3s guard 和 CD Lease lock，并用 `scripts/dev-cd-apply.mjs --status --skip-live-verify` 取得 target/promotion 摘要；`audit` 在 k3s/CD 恢复后做只读健康审计，返回有界 JSON 的 blocker 分类、D601 guard/node、SecretRef 存在性、registry 可达性、Lease phase/holder/staleness、deploy.json 与 artifact/workload image 收敛、current Deployment image/revision/rollout、16666/16667 public health commit/readiness 和 DB/runtime durability 摘要；`preflight` 进一步检查必需 SecretRef 对象/键存在性并运行 HWLAB `scripts/dev-cd-apply.mjs --dry-run --skip-live-verify` 受控事务摘要。完整远端 stdout/stderr 写入 D601 `~/.state/unidesk-hwlab-cd/<run-id>/` 和本地 `.state/hwlab-cd/<run-id>/` task dump，stdout 只返回有界摘要。默认 HWLAB CD repo 是 `/home/ubuntu/hwlab_cd`，`/home/ubuntu/hwlab` runner 历史目录不得作为发布真相。wrapper 强制 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml` 并只以这个显式目标作为 gate；显式目标出现 `docker-desktop`、`desktop-control-plane` 或 `127.0.0.1:11700` 信号会结构化拒绝，audit/preflight/apply --dry-run 都必须观察到 node `d601`。真实 apply 只暴露 `scripts/dev-cd-apply.mjs --apply --confirm-dev --confirmed-non-production --write-report` 命令形状并标注 host-commander-only，本 runner 不执行 live apply、rollout、Lease mutation 或 DEV deploy apply。长期规则见 `docs/reference/hwlab.md`。
- `gh auth status [--repo owner/name]` 探测 GitHub 操作前置条件并输出脱敏 JSON：是否存在 `gh` binary、是否存在 `GH_TOKEN`/`GITHUB_TOKEN` 或可用 `gh auth token` fallback、REST API 是否可达、目标 repo 是否可见、issue 是否可读。degraded reason 必须归类为 `missing-binary`、`missing-token`、`auth-failed`、`github-transient`、`network-proxy-failed`、`permission-denied`、`repo-not-found`、`repo-forbidden`、`issue-not-found`、`pr-not-found`、`scope-insufficient`、`validation-failed`、`invalid-response` 或 `unsupported-command`，不得打印 token；失败对象必须包含 `runnerDisposition=infra-blocked|business-failed`，runner 应优先用该字段分流。`github-transient` 表示 GitHub DNS/API 连接在收到 HTTP 状态前失败，输出应带 `retryable=true` 或等价 commander action；这不是缺 token、认证失败、权限不足或 PR 语义失败。
- `gh issue list [owner/repo] [--state open|closed|all] [--limit N] [--search text] [--title-prefix text] [--label label[,label...]]... [--repo owner/name] [--json number,title,state,url,updatedAt,createdAt,author,labels] [--raw|--full]` 通过 GitHub REST 列出 issue，默认 `state=open`、`limit=30`，输出稳定 JSON 且不依赖系统 `gh` binary。`owner/repo` 位置参数是 `--repo owner/repo` 的兼容别名；若位置 repo 与 `--repo` 冲突，或位置参数不是 `owner/repo`，必须结构化失败，禁止静默 fallback 到默认 repo。`--limit` 是 CLI 返回上限，不等同 GitHub 单页 `per_page`：当 `--limit > 100` 或默认页中混入 PR 时，CLI 必须分页抓取 GitHub REST/Search page，过滤 PR 后再返回 issue，并在输出中披露 `pagination.fetchedPages/rawCount/hasMore`；`hasMore=true` 时只能说明当前有界扫描未穷尽，禁止把它当作“仓库没有更多 issue”。`--search` 使用 GitHub Search Issues API，并自动追加 `repo:<owner>/<name>`、`type:issue` 和 state qualifier，用于创建新 issue 前做低摩擦查重；`--title-prefix` 在当前有界结果内按 issue 标题 `startsWith` 做本地过滤，输出 `titleFilter.inputCount/outputCount/filteredOut`，适合 `[FEEDBACK]` 等标题规范去重；未知 state 或未知 `--json` 字段必须结构化失败并带 `runnerDisposition=business-failed`。`--label` 是 GitHub REST `labels=label1,label2` 或 Search `label:` 服务端过滤，支持重复 `--label` 和逗号分隔；filter 不在本命令上下文中使用（如 `issue read`、`pr list`）必须结构化失败并指明 `gh issue create/list/stale-close` 才是合法作用域。GitHub issues API 可能混入 PR，CLI 会从 `.data.issues` 中过滤 pull request。`--raw|--full` 在 `gh issue list` 上是绕过 20 KiB stdout 截断的显式开关：响应结果会带 `noDump=true`，`output.ts` 据此跳过 head/tail 替换并把完整数据 inline 输出；当响应未超阈值时 `--raw|--full` 行为等价默认。
- `gh issue lifecycle`：
  - `--state` 只作为 `gh issue list` / `gh issue board-row list` / `gh pr list` 的过滤参数；`gh issue update` / `edit` 不接受 `--state` 改 open/closed，生命周期写入使用 `gh issue close|reopen`。
  - close/reopen 成功输出默认是 compact issue 摘要，不回显完整正文；人工正文读取使用 `trans gh:/owner/repo/issue/<number> cat`，定点检索使用同一路由的 `rg <pattern>`。
  - `readCommands.json/full/raw` 和 `gh issue view --json body|--full|--raw` 只用于显式机器结构化披露，不作为人工正文默认入口。
  - 生命周期评论只支持 `--comment-stdin <<'EOF'` quoted heredoc；内联 `--comment` 和生命周期 `--comment-file` 结构化拒绝。
  - 长篇验收证据先用 `gh issue comment create <n> --body-stdin <<'EOF'` 写证据评论，再用 `gh issue close <n> --comment-stdin <<'EOF'` 写简短中文收口。
  - issue 与 PR 都没有硬删除语义，生命周期终止使用 `close`。
- `gh issue comment create <number|owner/repo#number> --repo owner/name --body-stdin`、`gh issue comment update|edit <commentId> --repo owner/name --body-stdin`、`gh issue comment delete <commentId|owner/repo#number> --repo owner/name`、`gh issue close <number|owner/repo#number> --repo owner/name [--comment-stdin]`、`gh issue reopen <number|owner/repo#number> --repo owner/name [--comment-stdin]`、`gh issue update <number|owner/repo#number> --repo owner/name [--title ...] [--body-stdin]`、`gh issue edit <number|owner/repo#number> ...`、`gh issue board-row get|update|add|move|delete|upsert <number|owner/repo#number> --repo owner/name ...` 都接受与 `gh issue view|read`、`gh pr *` 一致的 `owner/repo#number` 位置 shorthand；shorthand 与显式 `--repo` 冲突时结构化失败并把两者都回显到错误对象里，避免静默改写目标 repo。`gh issue view|read`、`gh pr view|read|files|diff|preflight|closeout|comment create|comment update|comment edit|comment delete|close|reopen|merge|edit|update` 已长期支持该 shorthand；comment update/edit/delete 的 `--number` 表示 commentId，不是 issue/PR number。issue 写命令对齐后整个 `gh` 子命令在 shorthand 行为上保持一致，不再需要把 `pikasTech/HWLAB#621` 拆成 `621 --repo pikasTech/HWLAB`。来源：HWLAB #621 CLI 验收 `gh issue comment create pikasTech/HWLAB#621` 摩擦改进。

- `gh issue stale-close [--repo owner/name] [--inactive-hours N] [--limit N] [--label label[,label...]]... [--dry-run]` 是可复用批量生命周期清理入口，用于“超过 N 小时无回复或修改的 open issue 一律关闭”这类策略。判定基准固定为 GitHub `updatedAt < observedAt - inactiveHours`，issue comment、body/title 修改和 state 变化都会刷新 `updatedAt` 并视为活跃；PR 必须过滤，不参与 issue 关闭。默认 `inactive-hours=48`，默认扫描预算为 issue list 上限，输出必须包含 `observedAt`、`cutoffAt`、`scannedCount`、`staleCount`、`pagination.hasMore`、候选/关闭 issue 的 compact 摘要和失败列表，不得打印完整正文。正式关闭前建议先跑 `--dry-run`；真实执行后用同一命令加 `--dry-run` 验证 `staleCount=0`，且只有 `hasMore=false` 才能把当前扫描视为完整穷尽。HWLAB 当前长期策略使用 `bun scripts/cli.ts gh issue stale-close --repo pikasTech/HWLAB --inactive-hours 48 --dry-run` 观察，再移除 `--dry-run` 关闭。
- `gh issue view <number|url|owner/repo#number> [--repo owner/name] [--json body,title,state,comments] [--raw|--full]` 通过 GitHub REST 读取 issue：
  - 默认输出是有界 text/table/summary/Next/Disclosure，不回显完整正文，不创建或要求展开 dump。
  - 人工完整正文读取使用 `trans gh:/owner/repo/issue/<number> cat`；定点查找使用同一路由的 `rg <pattern>`；最近评论进展使用 bounded `gh issue comments <number>`。
  - `--json body,...`、`--full` 和 `--raw` 只用于显式机器结构化披露；正文稳定在 `.data.issue.body`，不复制到 `.data.json.body`。
  - 显式 full/raw 输出超出预算时可以创建受保护 dump；默认 view 和普通 `--json body` 超限只返回 cat/rg 语义窄路径，不创建 dump。
  - `read` 是兼容别名；位置参数接受正整数、GitHub issue URL 或 `owner/repo#number` shorthand；`--number N` 是单数字目标的兼容别名。
  - 字段白名单是 `body,title,state,comments,number,url,author,createdAt,updatedAt`；未知字段结构化失败并带 `runnerDisposition=business-failed`。
  - Issue create/update/comment/close/reopen/stale-close 都走 REST，不依赖原生 `gh`；多行 Markdown 使用 `--body-stdin` 或 `--comment-stdin` quoted heredoc。
  - `--body-file` 只用于已有复用文件；`--body` 只用于安全的短单行评论；日常评论修正使用 update/edit，硬删除 issue 不受支持。
- `gh issue update <number> --mode replace|append --body-stdin` 是正文更新主入口，`edit` 保留为兼容别名：
  - `replace` 用 heredoc/stdin 替换正文；`append` 读取当前正文后按 UTF-8 追加，保留真实换行、反引号和 Markdown 表格。
  - 默认拒绝字面量 `null`、空白正文和过短正文；只有真实需要短正文时才显式加 `--allow-short-body`。
  - `--body-profile` 继续执行 #20 看板和 commander brief 的既有 guard；非匹配 issue 使用 profile 时结构化失败。
  - `--dry-run` 只输出有界 preview、长度、SHA、guard、concurrency 和 wouldPatch，不 PATCH GitHub。
  - 正式写入先读取当前 issue，执行 guard 和显式 `--expect-*` 并发校验，再 PATCH；成功输出 compact 摘要和 `readCommands`，不回显完整正文。
  - 人工验收执行 `readCommands.body` / `readCommands.search`，对应 `trans gh:` cat/rg；`readCommands.json/full/raw` 只用于显式机器结构化披露。
- #20 只允许承担长期 UniDesk 指挥官 / Code Queue / CLI / infra 治理总看板职责；每日进展必须写入当天滚动指挥简报 issue，并由 #20 顶部“指挥简报索引”引用。HWLAB 用户反馈、Cloud Workbench、DEV-LIVE、M3 虚拟硬件可信闭环等产品 issue 必须写到 `pikasTech/HWLAB`；#20 只可记录 UniDesk 侧 commander/Code Queue/CLI/infra 支撑工作。`gh issue view/read 20` 会返回 `codeQueueBoardHint`；`gh issue update/edit 20` 的 body guard 会拒绝 `## 更新 YYYY-MM-DD HH:mm 北京时间`、`## YYYY-MM-DD HH:mm 北京时间指挥更新` 和 `### YYYY-MM-DD HH:mm CST：...` 这类简报段落；把 `pikasTech/HWLAB#N`、`HWLAB#N` 或 HWLAB 产品/live 验证行写入 #20 时只返回 warning 和 `codeQueueBoardHint`，不再拒绝正文 replace，以避免历史正文或治理交叉引用造成次生阻塞；`gh issue board-row list|get|update|add|move|delete|upsert --board-issue 20` 也会返回同一 hint，提醒不要把每日简报或 HWLAB 产品看板混入 #20。
- `gh issue edit 24 --body-stdin --notify-claudeqq-brief-diff [--dry-run] <<'EOF'` 是 legacy #24 指挥简报的通知入口。正式执行会先读取 GitHub 上 #24 旧正文并通过 #24 body profile guard，再从 heredoc/stdin 读取新正文；随后先 PATCH issue 主体，再把本次新增的 `## 更新 YYYY-MM-DD HH:MM 北京时间` 段落发送给 ClaudeQQ，ClaudeQQ 失败不会回滚 issue 正文，失败只体现在返回 JSON 的 `claudeqq.ok=false` 和结构化 `degradedReason`。每日滚动简报 issue 可用普通 `gh issue update <number> --body-profile commander-brief --dry-run` 和并发 guard 更新，但此通知 helper 仍只支持 #24。带通知 flag 的 `--dry-run` 不 PATCH、不发送；它按新正文做发送预览，并在输出中标明非 dry-run 才会读取旧正文做可靠 diff。默认 ClaudeQQ 目标是私聊 `645275593`，默认 base URL 是 UniDesk 受控入口 `http://backend-core:8080/api/microservices/claudeqq/proxy`；`UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_BASE_URL` 只接受 backend-core `/api/microservices/claudeqq/proxy` 等价路径，非 proxy URL 会结构化为 `notification-path-unavailable`。可用 `UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_ENABLED`、`UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_TARGET_TYPE`、`UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_USER_ID`、`UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_GROUP_ID` 和 `UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_TIMEOUT_MS` 调整开关、目标和超时。
- `gh issue board-audit [--repo owner/name] [--board-issue 20] [--limit N] [--known-meta-issue N[,N...]] [--ignore-issue N[,N...]] [--dry-run]` 是总看板只读结构审计入口，默认 repo 为 `pikasTech/unidesk`、board issue 为 `20`、输出 JSON 且不 PATCH/POST/DELETE GitHub。它只读取目标 board issue 正文，返回正文长度、行数、body SHA、可解析 Markdown board sections、section 行数和 parser warnings；不再拉取 GitHub open/closed issue 列表，也不再校验 OPEN/CLOSED 表是否覆盖全部 issue。兼容字段 `missingOpenIssues`、`closedInOpenRows`、`missingClosedRows`、`openInClosedRows`、`rowValidationWarnings`、`ignoredIssues` 和 `recommendedActions` 仍保留，但固定为空数组或 0，用于避免旧调用方因字段缺失失败。需要维护旧式 OPEN/CLOSED 明细表时，继续使用 `gh issue board-row list|get|update|add|move|delete|upsert` 的行级结构化入口。
- `gh issue board-row list --board-issue 20 [--state open|closed|all] [--dry-run]`、`gh issue board-row get <issueNumber> --board-issue 20` 和 `gh issue board-row update <issueNumber> --board-issue 20 --field progress|status|validation|branch|tasks|focus --value <text> [--dry-run] [--expect-updated-at ts|--expect-body-sha sha256]` 是 #20 看板表格单行结构化入口。list/get 复用 board-audit parser，只读返回 row、cells、fields、section、lineNumber、bodySha 和 rowValidationWarnings。update 只替换命中的一行里一个单元格，返回 old/new row、old/new body SHA、body guard、request plan 和 parser 结果；默认没有并发期望时即使不写 `--dry-run` 也只做 dry-run，正式 PATCH 必须带 `--expect-body-sha` 或 `--expect-updated-at`。字段映射固定为：`branch` -> Branch，`progress` -> 进度，`status`/`validation` -> 验收状态，`tasks` -> 相关 Code Queue 任务，`focus` -> 当前关注点。单元格值中的 Markdown 表格管道会转义为 `\|`，真实换行会折叠为空格，避免新增字面量 `\n` 污染。`gh issue board-row upsert <issueNumber> --board-issue 20 --section open|closed [--category text] --branch <branch> --tasks <task> --summary <text> --focus <text> --validation <text> --progress <text> [--status OPEN|CLOSED] [--dry-run] [--expect-body-sha|--expect-updated-at]` 是行级补齐入口：若 issue 已存在则只更新传入字段并返回 `operation=update`，未传字段保留原值；若不存在则按目标 section 表头生成完整行并返回 `operation=add`。新增时 `--section` 必需，且目标表头中的 category/branch/tasks/summary/focus/validation/progress 列都必须有对应值；若表没有独立 Summary/摘要列，`--summary` 会并入 Issue 单元格。upsert 不关闭、不删除、不重开 GitHub issue，也不做 OPEN/CLOSED 迁移；已存在行的 `--section` 或 `--status` 与当前 section 冲突时会结构化失败并提示使用 `board-row move`。`gh issue board-row add <issueNumber> --board-issue 20 --section open|closed --row-file <file> [--dry-run] [--expect-body-sha|--expect-updated-at]`、`move <issueNumber> --board-issue 20 --to open|closed [--status OPEN|CLOSED] [--dry-run] [--expect-body-sha|--expect-updated-at]` 和 `delete <issueNumber> --board-issue 20 [--dry-run] [--expect-body-sha|--expect-updated-at]` 是 row-scoped #20 结构化写入口。add 校验一行 `--row-file` 的 Issue 列、列数和 GitHub 状态列与目标 section 一致；move 允许跨 OPEN/CLOSED 表迁移并在需要时同步 GitHub 状态列；delete 仅删除匹配行。四类写入口默认 dry-run，非 dry-run 必须带 `--expect-body-sha` 或 `--expect-updated-at`，并返回 old/new row、body SHA、line/section 计划和 parser 结果；duplicate/ambiguous row、列数不匹配、缺少新增必填字段、section/status 冲突或 body SHA 不匹配都会结构化失败，不会 fallback 到整篇 body 手工替换。
- `gh issue scan-escape [--repo owner/name] [--limit N] [--dry-run]` 只读扫描 issue 主体和 comments 中的字面量 `\n`、可疑 `\t`、shell newline escape、escaped backtick、ANSI escape 字符串、短 body、blank body 和 null body。输出固定 JSON，`findings` 会带 `bodyKind=issue-body|comment-body`、`issueNumber`、`issueId`、`commentId`、`lineNumber`、`column`、`kind`、`snippet` 和 `classification=suspected-pollution|explanatory-mention|risk`，用于区分说明性提到 `\n` 和疑似污染；`cleanupSuggestions` 只给 dry-run 清理建议、body/comment 定位和 diff-like preview，不 PATCH、不 DELETE、不真实清理历史 comment。`gh issue cleanup-plan` 是同一只读能力的别名，默认 `dryRun=true`。`gh pr list [--state open|closed|all] [--json ...] [--raw|--full]` 提供 REST 列表，默认 `state=all` 以保持既有 UniDesk CLI 行为，字段白名单是 `body,title,state,number,url,author,head,base,draft,createdAt,updatedAt,headRefName,baseRefName`；未知 state 或未知 `--json` 字段必须结构化失败并带 `runnerDisposition=business-failed`。`--raw|--full` 在 `gh pr list` 上等价 `gh issue list --raw|--full`：响应带 `noDump=true`，inline 输出完整数据，绕开 20 KiB stdout 截断。`mergeable`、`mergeStateStatus` 和 `statusCheckRollup` 不属于 list 字段，请对具体 PR 使用 `gh pr view <number> --json headRefName,baseRefName,mergeable,mergeStateStatus,statusCheckRollup`，避免列表默认拉取 noisy/raw 状态汇总。`gh pr files <number> [--limit N]` 是 PR changed-file/stat summary 的稳定 REST 入口，返回 bounded `files`、`filesReturned`、`summary.files/additions/deletions/changes/commits`、`truncation` 和 `next.command`，默认不输出 raw diff 或 patch；`gh pr diff <number> --stat` 是兼容别名，返回同一 JSON，未带 `--stat` 的 raw diff 请求会结构化拒绝。`gh pr view|read <number|url|owner/repo#number> [--json ...] [--raw|--full]` 继续稳定返回这些字段，并额外支持 `stateDetail,closed,closedAt,merged,mergedAt,mergeCommit,headRefName,baseRefName,mergeable,mergeStateStatus,statusCheckRollup`。`owner/repo#number` shorthand 和冲突 `--repo` 规则与 issue view/read 相同。`stateDetail` 是 UniDesk 归一化生命周期值 `open|closed|merged`，用于区分 REST `state=closed` 中的普通关闭和已合并；`closed`、`closedAt`、`merged`、`mergedAt`、`mergeCommit`、`headRefName` 与 `baseRefName` 都来自 REST，不需要 GraphQL。`mergeable`、`mergeStateStatus` 和 `statusCheckRollup` 只在 view/read 明确请求这些字段或用 `--raw|--full` 显式完整披露时通过 GitHub GraphQL 查询，GraphQL 权限不足或网络失败会结构化失败；GitHub 暂未计算完成时仍保留原始 `UNKNOWN`/null，并额外返回 `closeoutMetadata.ok=false`、`missingOrUnknownFields`、advice 和 `mergeBoundary.unideskCliMergeSupported=true`。此时收口人员应优先重试一次；若仍缺失，应继续改进 UniDesk `gh` 子命令或使用人工 GitHub UI 做最终交叉确认，禁止原生 `gh` 或手拼 GitHub API 绕过。`gh pr preflight <number|owner/repo#number> [--repo owner/name] [--full|--raw]` 是低噪声 PR 收口入口，`gh preflight <number|owner/repo#number>` 和 `gh pr closeout <number|owner/repo#number>` 是兼容别名；shorthand 与 `gh pr view` 一致，已规范化为 `pikasTech/HWLAB#624` 这类形式时不需要再重复 `--repo`。它先输出脱敏 auth capability，再读取 PR state/draft/head/base、mergeable、mergeStateStatus 和 statusCheckRollup，默认只给 status check 计数与失败/等待预览，完整 contexts 和原始读取摘要必须显式加 `--full` 或 `--raw`。该命令固定 `readOnly=true`、`writesRemote=false`、`policy.mergesPr=false`，不会创建、评论、更新或 merge PR。`gh pr create --title <title> --body-stdin --base <branch> --head <branch> [--draft] [--dry-run]`、`gh pr edit <number> [--title ...] [--body-stdin|--body <text>] [--dry-run]`、`gh pr update <number> --mode replace|append [--body-stdin|--body <text>] [--title ...] [--dry-run]`、`gh pr comment create <number> (--body-stdin|--body <text>) [--dry-run]`、`gh pr comment delete <commentId> [--dry-run]`、`gh pr close|reopen <number> [--dry-run]` 和 `gh pr merge <number> [--merge|--squash|--rebase] [--delete-branch] [--dry-run]` 是 PR CRUD/生命周期入口。多行 PR 正文和评论推荐 `--body-stdin <<'EOF'`；`--body-file` 只在已有复用文件时使用，`--body` 只适合短单行内容。`pr create --dry-run` 只输出 planned operation，不访问 GitHub；非 dry-run 创建前会校验 repo、base、head 和 compare ahead 状态，成功时返回 PR number/url。`pr edit/update` 使用 REST `PATCH /repos/{owner}/{repo}/pulls/{number}`，只发送显式提供的 `title` 和/或 `body` 字段，完全避开 GitHub Projects Classic GraphQL/projectCards；输出低噪声 JSON：`ok`、`repo`、PR number、`changedFields`、`url`、body 长度/SHA/source 元数据和 request plan，不默认回显完整正文。`pr update --mode append` 会先读取当前 PR body 再追加正文。`pr merge` 会先执行同源 closeout 预检，拒绝非 open、draft、冲突、非 CLEAN、失败或 pending checks 的 PR，只有 ready 时才调用 GitHub REST merge；`--delete-branch` 只删除同 repo head ref。`gh pr delete <number>` 不开放，PR 生命周期删除语义请使用 `close`。
- `gh pr merge` 的 already-merged 终态是 guarded merge 的幂等成功例外：当目标 PR 已经处于 `merged` 状态时，命令返回 `ok=true`、`alreadyMerged=true`、`pullRequest.merged=true` 和 merge commit 摘要，不再把并发 monitor、GitHub UI 或人工合并后的 `closed` 状态误报为 validation-failed。
- `gh pr list` 与 `gh issue list` 一样接受单个位置参数 `owner/repo` 作为 `--repo owner/repo` 兼容别名；位置 repo 与显式 `--repo` 冲突时会结构化失败，输出里的 `repo` 始终反映真实请求目标。`--number N --repo owner/repo` 是单 PR/comment 数字目标命令的位置参数兼容别名，适用于 `view/read/files/diff/preflight/closeout/edit/update/comment create/comment delete/close/reopen/merge`，成功输出必须带 `standardSyntaxHint`；comment delete 中的 `--number` 表示 commentId，不是 PR number；`list/create` 不能静默忽略 `--number`。
- PR dry-run/probe 的最小手动序列：
  - `gh auth status` 只读检查 token 来源、GitHub REST egress 和 repo 可见性。
  - `gh pr create ... --dry-run <<'EOF'` 检查创建计划。
  - 人工正文使用 `trans gh:/pikasTech/unidesk/pr/<number> cat` 或 `rg <pattern>`；文件统计使用 bounded `gh pr files` / `review-plan`。
  - 状态观察使用 `gh pr view <number> --json state,stateDetail,closed,closedAt,merged,mergedAt,mergeCommit,head,base,headRefName,baseRefName,mergeable,mergeStateStatus,statusCheckRollup`，不混入 body。
  - `gh pr edit` / `comment create --dry-run` 检查写入计划；`gh pr merge --dry-run` 检查 guarded merge plan，真实 merge 只在任务边界允许且 preflight ready 后执行。
  - Code Queue runner 可用 `scripts/code-queue-pr-preflight-example.ts` 组合 auth 与 create/comment dry-run；不得输出 token，也不创建、评论或 merge PR。
- `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|send` 是当前 AgentRun 资源入口：
  - 日常查看使用 `get`、`describe`、`events`、`logs` 和 `result`；
  - session follow-up 只使用 `send session/<sessionId>`；
  - Artificer Target 派单使用 `create task --aipod Artificer`；
  - 同一命令必须提供 `--target`、`--target-workspace`、`--repo`、`--ref`、`--mdtodo-id` 和 prompt；
  - Target 模式在 submit 后自动 dispatch，并返回 task/run/session/attempt identity；
  - 用户级 `turn` 和 `steer` 已取消；
  - 兼容 group 只保留独立诊断。
- `agentrun explain session-policy --node <node> --lane <lane>`、`agentrun send session/<id> --node <node> --lane <lane> --dry-run` 和 `agentrun aipod-specs render <name> --node <node> --lane <lane>` 必须使用同一套目标 lane YAML 解析。非默认 lane 的短命令形态和 `--json-stdin -o json` 形态都应显示目标 `backendProfile`、`providerId`、`workspaceRef`、executionPolicy、provider credential SecretRef 和 tool credential SecretRef 摘要；Secret 输出只显示对象名、key 名、presence/fingerprint、projection 和 `valuesPrinted=false`。如果默认 human 输出触发 `/tmp/unidesk-cli-output` dump，应先把命令收敛为 summary/table/drill-down；机器完整输出留给显式 `--full`、`--raw`、`-o json` 或等价机器消费参数。`aipod-specs render` 的残余默认 dump 归 [#862](https://github.com/pikasTech/unidesk/issues/862) 跟踪。
- `agentrun` 资源原语 transport 来自 `config/agentrun.yaml`：
  - `client.transport=target-trans` 时，外层先经选中 Target 的 `trans` 重入；
  - marker、Target UniDesk 工作区和 CLI 路径全部来自 YAML；
  - Target 内部再经 `lane-k8s-service-proxy` 访问 manager；
  - dry-run 也必须走相同 Target 路径；
  - 代码不得补主机、绝对路径或第二条 transport 默认值；
  - 输出只披露 route、SecretRef、presence/fingerprint 和 `valuesPrinted=false`；
  - `agentrun control-plane ...` 与 `git-mirror ...` 仍属于 source/runtime 运维控制路径。
- `agentrun control-plane secret-sync --node <node> --lane <lane> --dry-run` 是 YAML SecretRef 配置维护的有界预检入口：
  - 默认文本、`-o json` 和 `-o yaml` 由同一个 compact payload 渲染；
  - payload 展示 YAML Secret ID、目标 Secret/key、source presence/fingerprint、activation fence identity/status 和关联资源 identity；
  - `--secret-id <yaml-secret-id>` 精确下钻单个声明；
  - `--full` 与 `--raw` 才展开 exhaustive probe/capture；
  - 全部输出固定 `valuesPrinted=false`，且该入口不得替代 source PR merge 的自动 CI/CD 链。
- `agentrun cancel ... --dry-run` 必须显示 `CancelLifecycle` 摘要：transport/authority、YAML lane、cascade scope、runner abort 窗口、cancel epoch 与 late-write fencing。取消策略来自 `config/agentrun.yaml` 的 `controlPlane.lanes.<lane>.deployment.runner.cancelLifecycle`；字段缺失或 lane 选择错误应暴露为配置错误，不得在 CLI、manifest 或服务里补隐式默认。操作非默认 lane 时先加 `--node <node> --lane <lane> --dry-run` 核对 policy，再移除 `--dry-run` 发起真实取消。
- `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。新任务、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 可用。
- `codex tasks [--view commander|supervisor|full] [--queue id] [--status succeeded|running|queued|failed|canceled|judging|retry_wait[,..]] [--unread|--unread-only] [--limit N] [--before-id id]` 通过同一私有代理输出渐进式披露视图。host commander 轮询应优先使用 `--view commander`：它是低噪声 polling 入口，只返回有界 action map，包含 `activeRunners.count` 及来源/处置、少量 active item、queued/retry_wait 精确计数、terminal-unread 总数和省略行数、关键风险计数、HWLAB#645/#99/#116/#164/#317 与 UniDesk#20/#118 命中、确定性分类计数和集中式 `codex task/trace/output/read` drill-down 命令。默认 commander 不展开历史 terminal unread item details，也不嵌入 prompt preview、final response preview、trace、output 或 raw overview；terminal unread 详情必须通过 `codex unread`、`codex tasks --unread --view supervisor`、`--view full`、`--full` 或 per-task `codex read <taskId>` 获取。默认 `supervisor` 保持旧低噪声分区视图，只返回 `activeRunning`、`running`、`completedUnread`、`recentCompleted`、`queued`、`activity`、`commanderConcurrency` 和 `executionDiagnostics` 的紧凑行；`activeRunning.count` 是 running+judging 的状态计数，`exact=true` 时来自 queue summary counts，`running.returned` 和 `activeRunning.rowPage.returned` 只是本次返回的紧凑行数。`commanderConcurrency.activeRunnerCount` 是并发策略应使用的 active/running 计数，等于 `activity.effectiveActiveTaskCount`；15 并发策略按 `15 - activeRunnerCount` 计算剩余窗口。`commanderConcurrency.splitBrainDisposition=live-count-as-active` 表示 split-brain 有 fresh heartbeat 证据，应继续监督并计入 active；`interventionRequired=true` 才提示介入。确定性分类只在有强基础设施故障信号时输出 `infrastructure-blocker`；普通 runner/CLI/治理上下文归入 `infra-governance`、`workflow` 或 `unknown`，避免把历史任务误报为基础设施阻塞。`supervisor` prompt/body 只给短预览和原始字符数，`running`/`completedUnread`/`queued` 默认只返回一个有界小页并通过 section `commands.next` 继续分页，`recentCompleted` 默认限量且不重复 `completedUnread` 未读终态，不嵌入完整 Trace、final response 或全量 overview。`--limit` 在 commander/supervisor 中主要是扫描/分页预算，不是返回几十条肥行的开关；CLI 安全上限是 100，输出会在 `filters.requestedLimit`、`filters.effectiveLimit`、`filters.limitCapped` 和 disclosure 中说明显式请求是否被 capped；底层 overview 拉取预算独立显示在 `source.requestedLimit` / `source.effectiveLimit`，所以 `--limit 260` 应显示 requested=260、effective=100、source requested/effective=200，而不是只露出一个含糊的 `limit`。`--unread` 是 `--unread-only` 的别名，必须只保留未读终态；`--status` 必须真实过滤支持的状态，并接受常见 alias：`completed|complete|success|successful -> succeeded`，`cancelled -> canceled`，`retry-wait|retrying -> retry_wait`，`pending -> queued`。未知参数或未知状态必须结构化失败并给出支持值和 alias 建议，预期参数错误默认不输出 stack trace；显式 `UNIDESK_CLI_DEBUG=1` 可保留完整诊断。需要更详细当前页任务行时显式使用 `--view full` 或 `--full`，仍受 `--limit` 和 `--before-id` 分页约束。
- `codex unread [summary|list|mark-read] [--queue id] [--repo owner/name] [--issue N] [--status succeeded|failed|canceled[,..]] [--limit N] [--before-id id] [--view summary|full] [--full] [--confirm]` 是完成未读积压的默认低噪声 triage 入口。默认只读返回总数、repo/issue/status/queue 计数、最新任务 id 小页和每行一条紧凑 `nextStep`，不拉取 per-task summary，不输出 raw prompt、final response、trace、output，也不为每个任务重复 `show/detail/trace/output/read` command block；完整 per-task 命令只在显式 `--full`、`--view full` 或 `list` 中展开。默认输出仍保留一次性的 `codex task <taskId>`、`codex read <taskId>`、分页和 full 展开模板命令。批量已读必须使用 `codex unread mark-read ... --confirm`，缺少 `--confirm` 时结构化失败且不 POST `/read`；单任务审阅仍优先 `codex read <taskId>`。
- `codex task <taskId> --trace --tail|--from-start|--after-seq N|--before-seq N --limit N` 按页拉取 Code Queue 的逻辑 trace；响应会返回 `nextAfterSeq`、`previousBeforeSeq`、`hasMore`、`hasBefore` 和下一页/上一页命令，默认 `--trace` 取最新一页，且仍以分页 trace 为主；需要完整 prompt/最终 response 时加 `--full`，需要详细 task 摘要时加 `--detail`。
- `codex output <taskId> --tail|--from-start|--after-seq N|--before-seq N --limit N [--full-text]` 按原始 output seq 分页读取底层记录；当 trace 行提示 `commandOmittedLines`、`bodyOmittedLines` 或 `rawSeqs` 时，用该命令按 seq 补取信息。默认是低噪声 raw-output 摘要：即使传入很大的 `--limit`，非 `--full-text` 也会限制返回行数和单条文本预览，并在 `disclosure.limitCapped`、`requestedLimit`、`effectiveLimit` 和 `commands.fullText` 中说明如何继续展开；显式 `--full-text` 才返回该页全文。
- `codex read <taskId>` 在人工审阅后标记单个终态任务已读，并在同一次响应中返回稳定任务身份、执行元数据、终态 attempt 摘要、最后错误或 judge 信息和最终 response，避免标记已读后还要额外 drill-down 才能确认结果。该命令不返回完整 prompt、tool logs 或 feedback prompt，只返回字符数、计数和 `codex task/detail/trace/output` 渐进披露命令；列表、overview 和 supervisor 视图只返回这个命令字段，不得自动执行，也不得批量清空未读状态。
- `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 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 资源原语。
- `job|jobs list [--limit N] [--include-command]` 与 `job status|get|read <jobId|latest> [--tail-bytes N]` 查询 `.state/jobs/` 文件系统状态，是异步命令的可观测入口。`jobs get/read` 是 `job status` 的兼容别名，不应引导调用者直接读取 `.state/jobs` 文件。`job list` 默认只返回最新 50 条摘要，并为已知异步工作流返回轻量 `progress.summary` 与后续查询命令；`job status` 默认返回结构化 `progress`、stdout/stderr 末尾 12000 字节、`tailPolicy` 与完整日志路径。已知工作流应从有界日志尾部抽取阶段、关键对象名和下一步命令，避免为了判断当前阶段而手工打开完整 stdout/stderr。`hwlab_g14_v02_trigger_current` 的 progress 必须暴露 trigger 阶段、source commit 和 PipelineRun；`hwlab_g14_v02_pr_monitor` 的 progress 必须暴露 preflight、merge、source-head、cd-trigger、cd-status、git-mirror-flush 和 pr-comment 阶段，以及 PR、source commit、PipelineRun、targetValidation/pendingFlush 摘要；`agentrun_vNN_trigger_current` 的 progress 必须识别 YAML lane 的 source-bootstrap、image-build、gitops-publish、git-mirror 阶段，暴露 source commit、PipelineRun、stage diagnostics、timing 和 `agentrun control-plane status --node <node> --lane <lane> --pipeline-run <name>`；`hwlab_g14_git_mirror_sync|flush` 与 `agentrun_v01_git_mirror_sync|flush` 的 progress 必须暴露 sync/flush 状态、Job 名、pendingFlush 与 fetch/push/total/SSH timing，并给出对应 repo 的 mirror status 命令。
- `debug health`、`debug ssh-pool <providerId>`、`debug dispatch` 与 `debug task` 走真实内部 core、WebSocket、数据库、provider、系统指标、Docker 状态和 Host SSH 维护桥流程，只用于开发调试，不写入 `TEST.md` 的正式验收步骤；`debug ssh-pool` 只裁剪单个 provider 的 `providerGatewaySshData*` labels，用于低噪声判断 tcp-pool 是否 ready、claimed、exhausted 或有 lastError。
- `e2e run [--only pattern[,pattern...]] [--skip pattern[,pattern...]]` 使用 publicHost 派生的公开 production frontend/dev frontend/provider ingress URL，并通过 Docker 内网验证 core API、PostgreSQL、provider self-connection、系统指标曲线、Docker 状态快照、provider.upgrade 预检和 Playwright 前端页面，是交付前的自动化 E2E 门禁；CLI 默认输出 check 状态摘要，完整诊断写入 `resultPath`，日常迭代应优先用 `--only` / `--skip` 跑最小必要集合。

## Web / Playwright

UniDesk/HWLAB Web 开发、HWLAB `web-probe run|script|observe|screenshot`、fake-server 回归、截图 artifact 和 node/lane 原入口验收统一见 `$unidesk-webdev`。本文件只保留 CLI 命名索引，不复制 Web 测试操作面，避免形成多路径和 fallback。

## Async Job State

长时操作采用 Fire-and-Forget 模式：CLI 创建 `.state/jobs/{jobId}.json`，后台进程执行真实命令，并将 stdout、stderr 分别写入 `.state/jobs/{jobId}.stdout.log` 与 `.state/jobs/{jobId}.stderr.log`。调用者通过 `bun scripts/cli.ts job status <jobId>` 或兼容别名 `bun scripts/cli.ts jobs get <jobId>` 查询进度和尾部输出。

异步 job 的返回值只表示控制动作已经排入后台执行，不表示目标运行面对象已经创建或收敛。所有带 `statusCommand` 的返回都必须先用 `job status <jobId>` 查看 `progress.stage`、`progress.stageStatus`、关键对象名和 `nextCommand`；只有 progress 已进入对应创建/完成阶段后，才进入更重的运行面 status。对于 `hwlab g14 control-plane trigger-current --lane v02 --confirm`，`progress.pipelineRun` 在 refresh 或 mirror pre-sync 阶段可能只是预期 PipelineRun 名称；在 `progress.stage=create-pipelinerun` 且 `progress.pipelineCreated=true` 前，`control-plane status --pipeline-run <name>` 返回 not found 只能说明 PipelineRun 尚未创建，不能当作 CI/CD 失败。对于 `git-mirror sync|flush --confirm`，先看 job progress 和 timing 摘要，再用对应 `git-mirror status` 确认 `pendingFlush`、local/github refs 和 `githubInSync`；node-scoped `flush` 的 progress 若出现 `partialSuccess=push-succeeded-fetch-failed`，先看是否同时有 `partialSuccessRecovered=true` 和 `postPushRecovery`，未恢复时再按 `nextCommand` 执行同 node/lane 的 `sync --confirm --wait` 刷新 mirror-stage cache。

定点状态查询优先使用后台 job 输出的稳定对象名：PipelineRun 用 `hwlab g14 control-plane status --lane v02 --pipeline-run <name>`，已知 source commit 用 `--source-commit <full-sha>`。不要在 source branch 可能继续推进时用默认最新 head status 判定历史 run 成败；默认最新 head 口径只适合判断当前 lane 是否整体最新。`control-plane status` 会汇总 source、mirror、Tekton、Argo、runtime workload 和公网探针，可能比普通只读命令慢；高频轮询应先用 `job status` 或更窄的 status，完整 status 留给阶段收口和异常定位。

`server rebuild` 与 `server start`、`server stop` 一样必须通过返回的 job id 确认结果；不要把连续 `server rebuild` 命令理解成“前一个重建已完成”，因为两个命令只是在快速创建异步 job。重建 frontend 只保留为维护/非标准路径；标准 frontend 发布必须先运行 `ci publish-user-service --service frontend --commit <full-sha>`，再运行 `deploy apply --env dev --service frontend` 和 `deploy apply --env prod --service frontend`，并验证 `/health.deploy.commit`。重建 dev 入口薄代理使用 `bun scripts/cli.ts server rebuild dev-frontend-proxy`。Todo Note 正式发布使用 `platform-infra pipelines-as-code --target NC01 --consumer unidesk-host`；旧 `server rebuild todo-note` 已删除。重建 Code Queue Manager、Project Manager、Baidu Netdisk 和 OA Event Flow 后端仍分别使用各自 `server rebuild` 与 `microservice health/proxy` 验证。D601 Code Queue 执行面由 D601 k3s/k8s 控制面代管；Decision Center 与 Todo Note 由 NC01 k8s 代管并写入同一个 GitHub repo 的独立 base path；persistent dev backend-core/frontend 仍走 artifact consumer，当前 Code Queue 仍不得通过维护通道直连 D601 做部署。不得把 `docker rm` 手工兜底当成正式交付步骤。

新部署入口优先使用受控 deploy path。`deploy apply --env dev --service backend-core` 是 D601 k3s artifact consumer，消费 `ci publish-backend-core` 产出的成品镜像；`deploy apply --env dev|prod --service frontend` 和 `deploy apply --env dev|prod --service baidu-netdisk` 是 artifact-consumer 样板；Decision Center 是 NC01 YAML-first + GitHub storage 样板，Todo Note 是 NC01 PaC/Argo + 同仓独立 base path 样板；旧的 `codex deploy` 已禁用。部署后必须用 live commit/digest 与存储验证证明不是旧服务。

## Output Contract

显式 JSON 或机器消费模式的最外层对象包含 `ok`、`command` 和 `data` 或 `error`。失败时 CLI 设置非零退出码；JSON 模式返回包含 `name`、`message` 和可用 `stack` 的错误对象，默认人工模式返回有界错误摘要和后续诊断命令。预期参数错误不得默认打印 stack trace。

诊断命令默认采用渐进披露：`server logs`、`job list/status`、`codex task/trace/output`、`microservice health code-queue`、`microservice proxy` 和 AgentRun control-plane/resource primitive 都必须有默认条数、字节数、表格或文本预览上限；用户显式传 `--limit`、`--tail-bytes`、`--full-text`、`--raw`、`--full`、`-o json` 或等价机器消费参数才扩大单次输出。AgentRun `control-plane plan|refresh|cleanup-runners|trigger-current` 默认输出短摘要、关键字段和下一步命令；`describe task -o json` 默认仍是 compact client schema，完整资源用 `--full -o json`；`result --raw` 属于显式 raw 路径，可以触发 dump 兜底。CLI stdout 遇到下游 pipe 关闭的 `EPIPE` 必须安静退出，不得打印 Bun stack trace。

`gh issue view/read --json comments` 是常用人工 drill-down，不得默认输出完整 comment body 或同时在顶层和 `.data.json.comments` 重复整组 comments。默认只返回 comment metadata、body 字符数/SHA 和短 preview；`--full` 仍保持评论列表有界，只把 issue 字段扩到完整元数据。单条完整评论正文通过 `gh issue comment view <commentId> --repo owner/name --full` 读取；`--raw` 才是显式展开所有评论正文的排障入口，可能触发 stdout dump。

人工 issue/PR 正文统一使用 `trans gh:` 虚拟文本路由：issue 和 PR 分别通过 `/issue/<number> cat|rg` 与 `/pr/<number> cat|rg` 读取。`gh issue/pr view --json body,...`、`--full` 和 `--raw` 只用于显式机器结构化披露；正文稳定路径分别是 `.data.issue.body` 与 `.data.pullRequest.body`，不复制到 `.data.json.body`。默认 bounded view 和普通 `--json body` 超预算时不创建 dump，只返回 cat/rg 窄路径；只有显式 full/raw 可以保留受保护的 dump metadata、SHA 与读取命令。

`microservice proxy` 是面向人工验证和受控调试的私有后端入口。默认 method 为 GET；使用 `--body-json JSON`、`--body-file path` 或 `--body-stdin` 时默认 method 切换为 POST，也可显式加 `--method POST|PUT|PATCH|DELETE`，但 GET/HEAD 不允许携带请求体。所有请求仍受 config 中的 `allowedMethods` 和 `allowedPathPrefixes` 限制。为了避免 Pipeline snapshot 这类超大业务 JSON 造成 CLI 输出爆炸，响应 body 超过默认阈值时会返回 `bodyOmitted=true`、`bodyPreview`、`bodyBytes` 和 `rawHint`；`--raw` 仍受默认硬限额保护，需要完整 body 时显式添加 `--raw --full`，或用 `--max-body-bytes <N>` 调整预览阈值。正式 frontend 展示仍应优先使用业务控件和 `__unideskArrayLimit` 这类展示级裁剪参数，而不是默认倾倒完整 JSON。

## Todo Note Resource CLI

Todo Note 的人工与秘书入口是 `unidesk todo-note`。命令内部通过 backend-core 私有代理访问 NC01 服务，调用者不拼 `/api/...` 或 JSON action body。默认输出是有界表格，显式 `--json` 才返回结构化对象：

```bash
unidesk todo-note list
unidesk todo-note show 大论文
unidesk todo-note show HWLAB --all --limit 80
unidesk todo-note add 大论文 --title "跟踪外审意见" [--parent <todo-id>]
unidesk todo-note update 大论文 <todo-id|精确标题> --title "新标题"
unidesk todo-note complete 大论文 <todo-id|精确标题>
unidesk todo-note reopen 大论文 <todo-id|精确标题>
unidesk todo-note remind 大论文 <todo-id|精确标题> --at 2026-07-31T18:00:00+08:00
unidesk todo-note remind 大论文 <todo-id|精确标题> --clear
unidesk todo-note delete 大论文 <todo-id|精确标题> --confirm
unidesk todo-note undo 大论文
unidesk todo-note redo 大论文
unidesk todo-note health
```

`complete` 和 `reopen` 是幂等命令：目标已经处于期望状态时返回 `CHANGED=false`，不会反向切换。列表支持名称或 instance id；todo 支持 id 或唯一精确标题，标题重名时必须使用 id。`microservice proxy todo-note ...` 仅保留底层诊断、迁移和尚未产品化的 API 调试，不是日常维护入口。

看到底层诊断返回 `404 {"error":"Todo Note is running in backend-only mode"}` 时**第一反应**是路径错（用了不存在的 REST 端点被 catch-all 兜底），不是 mode 锁了写；详见 `docs/reference/microservices.md` 的 Todo Note 段。

**Todo Note 错路径结构化诊断（issue #198）**：旧 Gitee/CC01 runtime 的 catch-all handler 会把未注册路径回成 `404 {"ok":false,"error":"Todo Note is running in backend-only mode"}`，与 `TODO_NOTE_BACKEND_ONLY=1` 的真实语义（只关 Vite 前端）混淆。当前 vendored NC01 服务直接返回明确 route-not-found；backend-core/CLI 仍保留旧特征改写作为迁移兼容兜底：

```json
{
  "ok": false,
  "error": "Todo Note route not found",
  "backendOnly": true,
  "method": "POST",
  "path": "/api/instances/<id>/todos",
  "writableApiEndpoints": [
    { "method": "POST", "path": "/api/instances", "hint": "Create a new todo list; body {name}." },
    { "method": "DELETE", "path": "/api/instances/:instanceId", "hint": "Delete a todo list." },
    { "method": "POST", "path": "/api/instances/:instanceId/actions", "hint": "Apply a typed action; body {action: {type, ...}}." },
    { "method": "POST", "path": "/api/instances/:instanceId/undo", "hint": "Undo the last applied action." },
    { "method": "POST", "path": "/api/instances/:instanceId/redo", "hint": "Redo the last undone action." }
  ],
  "actionTypes": ["addTodo", "updateTodoTitle", "toggleTodoCompleted", "toggleTodoExpanded", "setAllTodosExpanded", "moveTodo", "deleteTodo", "renameInstance", "setTodoReminder"],
  "hint": "...",
  "issueReference": "pikasTech/unidesk#198"
}
```

改写后的响应同时带 `bodyRewritten: true`、`rewriteReason` 和原始 `upstreamBody`（`{"ok":false,"error":"Todo Note is running in backend-only mode"}`），所以审计 / 排障仍能拿到上游真相；上游 PR 落地后这个特征 body 不再出现，backend-core proxy 和 CLI 兜底改写会自动退化为 no-op。

**`--check-path` 预检（同样针对 todo-note）**：在真正发请求前先校验 path/method 是否命中 CLI 侧 endpoint catalog，命中返回 `ok: true, matched: true, endpoint: {...}`，未命中返回与 rewrite 同源的结构化诊断且**不调用上游**。这能在 1 步内识别 typo、错端口、错 host 等引起的 catch-all 404。命令样例：

```sh
# 命中：POST /api/instances（创建清单）
bun scripts/cli.ts microservice proxy todo-note /api/instances --method POST --check-path

# 命中：POST /api/instances/<id>/actions（action 队列写）
bun scripts/cli.ts microservice proxy todo-note /api/instances/instance_xxx/actions --method POST --check-path

# 未命中：POST /api/todos（典型 REST 笔误，触发结构化诊断，不打 upstream）
bun scripts/cli.ts microservice proxy todo-note /api/todos --method POST --check-path

# 非 todo-note 服务：--check-path 当前只支持 todo-note，其他服务返回结构化 unsupported 错误（不阻塞现有 proxy 行为）
bun scripts/cli.ts microservice proxy code-queue /api/foo --method GET --check-path
```

`--check-path` 与默认 proxy 行为是正交的：默认 proxy 仍然打 upstream，并由 backend-core proxy 对误导 404 做 rewrite；`--check-path` 完全跳过 upstream 调用，只走 CLI 侧 catalog。详见 `src/components/backend-core/src/microservice_proxy.rs` 的 Todo Note route diagnostic、`scripts/src/microservices.ts` 的 `TODO_NOTE_WRITABLE_ENDPOINTS` / `matchTodoNoteEndpoint` / `rewriteTodoNoteMisleadingRouteNotFound` / `runTodoNoteCheckPath`，以及 `scripts/src/e2e.ts` 的 `microservice:todo-note-route-diagnostic` 门禁。

**复杂 JSON body 优先 `--body-file <path>` 而非 `--body-json '<inline>'`**（2026-06-01 摩擦改进验证）。`--body-json` 在 shell 里要把双引号 escape 成 `\"`，遇到 action 对象里有嵌套字段或中英文混排标题几乎必坏；`--body-file` 走文件直读，反引号、反斜杠、中文、嵌套 JSON 都安全，且支持 stdin（`--body-file -`）。推荐做法：先 `cat > /tmp/x.json <<'EOF' ... EOF`（heredoc quoted 防 shell 展开），再 `bun scripts/cli.ts microservice proxy todo-note .../actions --method POST --body-file /tmp/x.json`。已交互验证 200 OK 全套 write actions（addTodo / toggleTodoCompleted / deleteTodo），probe 写入 + 删除完整 lifecycle 通。

GitHub issue/PR 正文局部修补必须优先使用 `trans gh:/owner/repo/issue/<number> apply-patch <<'PATCH'` 或 `trans gh:/owner/repo/pr/<number> apply-patch <<'PATCH'`，虚拟文件固定为 `body.md`；底层 `bun scripts/cli.ts gh issue patch ... --body-patch-stdin` 只作为受控底座或兼容入口，不作为人工首选。普通小补丁在 `trans gh:/... cat|rg|ls` 读取确认后可以直接写回；`--dry-run` 只作为高风险预览，不是每次 patch 的必经步骤。新增 issue/PR 正文、整篇有意替换、评论创建和生命周期评论仍使用 `bun scripts/cli.ts gh issue|pr ... --body-stdin <<'EOF'` 或 `--comment-stdin <<'EOF'`。Issue/PR 的正式写入一律使用中文，包括标题、正文、评论、关闭/重开说明、PR 描述、PR 评论和 merge closeout 说明；命令、路径、trace/session/job id、API path、代码标识符、英文专有名词、原始日志摘录和外部错误原文可以保留原样，但解释性文字、结论、风险、计划和验收说明必须中文。不要把 Markdown 正文拼进 shell 参数或 `gh api -f body=...`；这些路径容易把真实换行污染成字面量 `\n`。推荐形态是 quoted heredoc，例如 `bun scripts/cli.ts gh issue comment create <number|owner/repo#number> --repo owner/name --body-stdin <<'EOF' ... EOF`，保证反引号、反斜杠和 Markdown 表格不被 shell 展开，也不需要临时正文文件；已有可复用正文文件时才使用 `--body-file <file|->`。`gh issue update/edit` 正式写入默认先读取当前 issue 元数据，执行 body guard 并在结果里返回旧 `bodySha`/`updatedAt` 与新正文摘要；一般看板和评论写入不需要人工先 `read` 再手填 `--expect-body-sha`。对高风险整篇替换仍可显式加 `--expect-body-sha` 或 `--expect-updated-at`，CLI 会在 PATCH 前校验，不匹配则结构化失败。`gh issue comment create --body <short-text>` 只适合人工短单行评论，默认输出只给 bounded preview、bodyChars、bodySha、source 和 readCommands，不回显长正文；同时传 `--body` 与 `--body-stdin` / `--body-file` 必须结构化失败。PR 安全写入口同样优先使用 `--body-stdin` heredoc；`--body` 只适合短单行内容。JSON 请求体场景使用各命名空间自己的 `--body-stdin` 或 `--body-file`，避免长 JSON 直接塞进 shell 参数。`update --mode append` 用 REST 读取旧正文后追加 stdin 字节，不引入 shell 拼接正文路径。`gh pr merge` 是 guarded write：先读 closeout metadata 并拒绝非 ready PR，`--dry-run` 只输出计划不写远端；没有 `--confirm` 之类绕过 preflight 的路径。CLI 会按 UTF-8 原样读取 stdin 或文件内容并用 JSON body 调用 REST API；issue/PR 写入输出不会默认回显完整正文。

`network perf` 用于生成组网性能前后对比数据。标准 Code Queue overview 读路径基准命令是 `bun scripts/cli.ts network perf --service code-queue --path /api/tasks/overview?limit=30 --count 30 --concurrency 1 --label before`，远程主 server 可用 `bun scripts/cli.ts --main-server-ip 74.48.78.17 network perf ...`。输出包含成功/失败数、状态码分布、`x-unidesk-cache`、`x-unidesk-proxy-mode`、`x-unidesk-upstream-proxy-mode` 分布和 min/p50/p90/p95/max；provider-gateway 长连接数据面验收应看到 `proxyModeCounts.provider-ws-http-tunnel`，adapter native Service 数据面验收应看到 upstream proxy mode 为 `kubernetes-native-service`，若出现 `kubernetes-api-service-proxy` 必须结合 `/api/control-plane.nativeServiceProxy.failedServices` 解释 fallback 原因。

## Debug Contract

`debug` 子命令必须复用真实模块与真实端点，禁止维护平行实现。`debug health` 会摘要展示 `/api/nodes/system-status` 和 `/api/nodes/docker-status`，避免输出完整快照造成信息爆炸。`debug ssh-pool <providerId>` 从 `/api/nodes` 裁剪单个 provider 的 `providerGatewaySshDataTransport`、host/port、desired、total、ready、claimed、connecting 和 lastError，并给出 `ssh-tcp-pool-ready`、`provider-gateway-upgrade-required`、`provider-data-pool-exhausted` 或 `provider-data-pool-not-ready` 分类；它是 `trans`/`tran` 出现 tcp-pool transient hint 后的首选低噪声探针。`debug dispatch` 会通过 backend-core 容器内置 helper 访问 backend-core `/api/dispatch`，core 再通过 WebSocket 将 `docker.ps`、`provider.upgrade`、`host.ssh`、`microservice.http` 或 `echo` 任务下发给 provider gateway，因此它可以验证核心调度闭环，同时不需要公开 core REST API，也不要求 frontend 容器携带调试 broker。`provider.upgrade` 默认使用 `mode: "plan"` 预检；需要验证一键升级时必须显式加 `--mode schedule`，并通过 `--wait-ms` 或 `debug task` 确认任务进入 `succeeded`、result 中包含 updater 容器信息和 `policy: "always-enabled"`。`host.ssh` 默认使用 `mode: "probe"` 做短超时维护桥自检；需要执行明确命令时使用 `--ssh-command` 进入 `mode: "exec"`，并配合 `--wait-ms` 和 `debug task` 查看 stdout、stderr、exitCode 与 probeLine。`microservice.http` 只用于开发调试 provider-gateway 私有 HTTP 代理，正式用户入口应使用 `microservice` CLI 或 frontend 的用户服务页面。

## SSH Command

`trans <providerId> [ssh-like args...]` 是面向人的终端透传入口，不包装 JSON 输出，默认由 `scripts/ssh-cli.ts` 只加载 SSH/route/远程前端转发相关模块。主 server 本地执行时会在宿主机启动 `docker exec -i unidesk-backend-core backend-core --ssh-broker ...`，broker 只连接 backend-core 的 Docker 内网 `/ws/ssh`；core 使用 provider WebSocket 下发 open/dispatch 控制消息，但 stdin/stdout/stderr 数据面必须走 provider 主动连接 main server 的 `host.ssh.tcp-pool` TCP warm pool，provider-gateway 最终执行维护用 SSH 连接宿主或 WSL sshd。TTY 策略固定为交互登录 shell 使用 `ssh -tt`，带远端命令的会话使用 `ssh -T`；`apply-patch`、脚本 stdin、`py` 和旧 `apply-patch-v1` fallback 这类命令模式不得被伪终端回显或注入控制字符。该入口不暴露 database，也不改变 frontend/dev frontend/provider ingress 之外的业务边界；provider data TCP port 是 provider 主动连入的数据面端口，不是计算节点入站要求。

`trans --help` 和 `trans <providerId> --help` 是本地紧凑文本帮助命令，必须快速返回；只有显式机器输出参数才能请求 JSON。不能把 `--help` 解析成 Provider ID，不能打开交互 shell，也不能等待 provider 会话。顶层只展示 route 语法、operation 分组和 scoped help 索引；operation 细节通过 `trans --help <operation>` 获取。任一默认帮助触发 `outputTruncated` 或 dump 都是缺陷，必须缩减顶层内容，禁止提高 stdout 阈值。

主 server 固定提供 `trans` 缩写，等价于 `bun scripts/ssh-cli.ts ssh "$@"` 的受控 UniDesk SSH 透传入口。这里必须同时保留两层入口：交互式 shell 可额外配置 alias；Codex `exec`、脚本和其他非交互 shell 不会自动展开 alias，所以还必须有 `/root/.local/bin/trans` 可执行 wrapper，内容固定为委托 repo 内版本化脚本：

```sh
#!/bin/sh
exec /root/unidesk/scripts/trans "$@"
```

主 server 上的人工/Codex 分布式敏捷操作必须直接写 `trans ...`，不要在 Codex 工具调用里退回完整 `bun scripts/cli.ts ssh ...` 前缀。例如 `trans D601:/home/ubuntu/workspace/hwlab-dev git status --short --branch`、`trans D601:k3s kubectl get pods -n hwlab-dev` 或 `trans D601:k3s:hwlab-dev:hwlab-cloud-web exec --cwd /tmp -- pwd`。`tran` 是历史兼容 wrapper 和 runner 固化入口；新写长期参考、AGENTS 索引和 CLI help 时优先写 `trans ...`。

`trans` 同样遵守 route/operation 解析器；route 后面的第一个 token 不是原生 ssh 命令字符串。带变量展开、管道、重定向或多条命令的远端逻辑，默认使用 `trans G14:/root/hwlab sh <<'SH'`；`sh` 走目标节点 `/bin/sh`，并继承 provider-gateway/G14 已长期化的 proxy 环境。需要 Bash 专有语法，例如 `set -o pipefail`、数组、`[[ ... ]]` 或 `${var:0:8}` 子串展开时，必须把 operation 写成 `bash`，例如 `trans D601:/home/ubuntu/workspace/hwlab-v03 bash <<'BASH'`。需要临时单步执行一行远端 shell 逻辑、且不想先创建脚本文件或 heredoc 时，使用 `trans G14:/root/hwlab sh -- 'sed -n "1,20p" a && sed -n "1,20p" b'` 或 `bash -- '<bash command>'`，CLI 会把单个字符串放进目标节点对应 shell 的 `-c`，第二个 `sed`、管道和重定向都会留在远端；`sh --` 与 `bash --` 只接受一个 shell command 字符串，多 argv 单进程命令必须走 `argv`、`exec` 或已知直接子命令。`script` 和 `shell` operation 已移除并会失败；失败 JSON 必须保留用户入口名（`trans`/`tran`/`ssh`）、route、operation 和 `replacementExamples`，其中包含 `trans <route> sh -- '<command>'` 与 `trans <route> bash -- '<command>'` 形态；不得用 `--shell bash` 或旧名绕过显式 shell 选择。`sh` 和 `bash` helper 会在用户 shell 文本前注入一个极小的 POSIX 兼容 `printf` wrapper，使 `printf "--- section ---\n"` 这类高频排障分隔标题在 dash/sh 与 bash 下行为一致；direct argv 形态不注入该 wrapper。单进程命令才直接写成 argv，例如 `trans G14:/root/hwlab git status --short --branch`。遇到分布式开发摩擦时，优先补强 `trans`/`tran` 的 route/operation、stdin helper 或目标节点环境，并把稳定解法写回长期参考文档，不要退回多层 shell 字符串拼接。

本地检索或引用 Markdown 命令片段时也要避免外层 shell 误解析。任何包含反引号的 pattern，例如文档里的 `` `trans ...` ``，都必须用单引号、`rg -F -e` 或 stdin/file 传入；禁止写进双引号参数，因为 shell 会先执行 backtick command substitution，可能在搜索旧文档时反而误触 `trans ... script` 这类已移除 operation。


### Standard Workspace-Prefixed Passthrough

- 长期参考、AGENTS 索引、CLI help、Codex 任务脚本、CI/CD 排障和人工远端操作必须统一把已知的远端 workspace 写在 route 的第一个 token，而不是塞进 `cd` 串。`route` 段只表达分布式定位，operation 段才执行命令；workspace 路径是定位信息，不是命令。
- 标准形态是 `trans <provider>:/absolute/workspace <operation> [args...]`：
  - 只读命令：`trans G14:/root/hwlab git status --short --branch`。
  - 单行 shell：`trans G14:/root/hwlab-v02 sh -- 'git fetch origin v0.2 && git pull --ff-only origin v0.2'`。
  - 多行 shell：`trans D601:/home/ubuntu/workspace/unidesk-dev sh <<'SH'` 或 `trans D601:/home/ubuntu/workspace/hwlab-v03 bash <<'BASH'`。
  - 文本修改：`trans G14:/root/hwlab apply-patch <<'PATCH'`。
  - 结构化检索：`trans G14:/root/hwlab glob --root . --pattern 'web/hwlab-cloud-web/*.ts' --contains session-tabs`。
- 反面形态必须删除或迁移：`trans G14 sh -- 'cd /root/hwlab && git status --short --branch'`、`trans G14 sh <<'SH' cd /root/hwlab-v02 git fetch origin v0.2 SH`、`tran G14 sh -- 'cd /home/ubuntu/workspace/unidesk-dev && ...'`、route 后继续写旧的 `script` / `shell` operation、`bun scripts/cli.ts ssh G14 -- 'cd /root/hwlab && ...'`。这些写法把已知 workspace 写进 command 字符串，破坏 route/operation 分离，引入本地 shell 二次解析、远端 cwd 漂移和并行 worktree 切换摩擦，或继续使用已移除的模糊 shell 旧名。
- 例外只限于一次性探测、临时 heredoc 草稿或旧文档复用；任何被复用第二次的 `cd <workspace> && ...` 都必须重写成 `trans <provider>:/absolute/workspace` 形式。
- 当远端存在多个并行 workspace（例如 `G14:/root/hwlab` 与 `G14:/root/hwlab-v02`）时，route 必须显式带 workspace，CLI 的 `pwd` 输出、后续 `apply-patch` 的相对路径和 `sh`/`bash` 的 cwd 全部跟随该 workspace；切换 workspace 必须切换 route，不允许在同一次 `trans` 链里再 `cd`。
- 当 host workspace 位于 `/mnt/<drive>` 且透传用户为 root 时，`trans` 会读取 route workspace owner uid，并仅在当前命令进程树中通过 `SUDO_UID` 让 Git 信任该 Windows 挂载工作区；不得为此写入全局 `safe.directory`。该桥接不授权不同 owner 的嵌套仓库，也不改变普通 Linux workspace；若大型 Windows 挂载仓库的 `git status` 等全树扫描超过 60 秒，应缩小查询或改用同 provider 的 `:win` route，而不是放宽短连接预算。通用 route 和 shell 规则见 `$unidesk-trans`。
- 本规则覆盖所有 host workspace 形态，包括 `G14:/root/hwlab`、`G14:/root/hwlab-v02`、`G14:/root/agentrun-v01`、`D601:/home/ubuntu/workspace/unidesk-dev`、`D601:/home/ubuntu/workspace/hwlab-dev`；provider-gateway 侧已经把它们注册为 host workspace route。
- 与 `k3s` route 的分工不变：定位控制面继续写 `trans G14:k3s`、定位 workload/container 继续写 `trans G14:k3s:<namespace>:<workload>[:<container>]`；pod/container 内 cwd 用 operation 参数 `--cwd /path`，或在已经明确选出 container 后才使用 `/path` route 后缀表达文件系统位置。host workspace 路径里的 `cd` 才需要被替换，控制面或 pod 内的多层 shell 不在本规则的清理范围。

非交互 `ssh`/`trans`/`tran` 不是登录 shell，不能依赖 `.bashrc`、`.profile` 或交互 alias。
CLI 会在 Host route、workspace route、k3s 控制面脚本和 pod route 的 `sh`/`bash` helper
前统一注入用户级工具 PATH：`$HOME/.bun/bin`、`$HOME/.local/bin`、`$HOME/bin`
和 `/root/.bun/bin`。因此 G14 这类节点只要已经安装了 `/root/.bun/bin/bun`，
`trans G14:/root/hwlab-v02 sh -- 'bun --version'` 应该直接可用，
不需要在任务里硬写绝对路径。direct argv 不经过 shell 初始化；如果某个 direct argv 工具找不到，
优先改用 `sh -- '<command>'` / `bash -- '<command>'` 或补强 CLI 的 argv PATH 处理，
不要在业务脚本里长期散落绝对路径 workaround。

本地 shell 运算符不是 `trans` 可以拦截的内容。`trans G14:/root/hwlab sed -n '1,20p' AGENTS.md && sed -n '1,20p' docs/reference/g14.md` 会先由 master server 的本地 shell 拆成两个命令，只有第一个 `sed` 进入 G14，第二个 `sed` 会在 master server 当前目录执行。需要把两个命令都放到目标节点时，必须写成 `trans G14:/root/hwlab sh -- 'sed -n "1,20p" AGENTS.md && sed -n "1,20p" docs/reference/g14.md'`，或者用 `trans G14:/root/hwlab sh <<'SH'` 把多行脚本送到远端；需要 Bash 专有语法时把 operation 改成 `bash`。

`trans`/`tran` 不做本地 provider/plane 串行锁；本地目录锁不是 G14 原生 k3s/Tekton/GitOps 的业务协调机制，stale lock 会阻塞所有后续短查询。以后不要在 wrapper 里恢复本地锁。业务并发、发布互斥和 rollout 协调必须交给 k8s/Tekton/Argo/Lease 等原生运行面机制；若 provider session allocator 需要限流，应在服务端实现带 TTL 的队列或 lease，而不是在客户端加目录锁。

非交互 `trans`/`tran`/`ssh` 有最外层运行时硬超时，默认和最大值都是 60 秒；`UNIDESK_TRAN_RUNTIME_TIMEOUT_SECONDS`、`UNIDESK_TRAN_RUNTIME_TIMEOUT_MS` 或 `UNIDESK_SSH_RUNTIME_TIMEOUT_MS` 只能把超时调小，不能调大超过 60 秒。到点后 wrapper、backend-core broker 或 frontend websocket 路径会主动断开并在 stderr 输出 `UNIDESK_TRAN_TIMEOUT_HINT` 或 `UNIDESK_SSH_RUNTIME_TIMEOUT`，提示改用短查询加轮询。长时间 CI/CD、Tekton/Argo 观察、trace/result、日志 tail、构建下载和硬件任务都必须按 submit-and-poll/短查询语义拆成多次 `trans` 调用；不得让单个 `trans` 挂着等待最终完成。本规则的跟踪 issue 是 [pikasTech/unidesk#187](https://github.com/pikasTech/unidesk/issues/187)。

长任务的标准形态是：用一次短 `trans <route> sh` 或 `trans <route> bash` 启动目标侧 job、后台进程、PipelineRun 或受控命令，并把 job id、日志路径、状态文件或 Kubernetes 对象名写到目标侧；后续用多次短 `trans` 查询 `status`、`logs --tail`、`kubectl get/describe`、trace result 或工具自带 job-status。不要为了观察 Docker build、镜像 push、Keil 下载、串口抓取或 Code Agent turn，把 `trans` 一直挂到结束；超过 60 秒的断开只说明调用方式需要改成轮询，不应立即归因成 provider session、CI/CD 或硬件失败。

HWLAB `hwlab-cli client agent` 端到端验证经 UniDesk `trans`/`tran`/`ssh` 进入 G14 时，也按短连接 submit-and-poll 执行：在目标 workspace 和锁定 runtime env 下先 `agent send` 提交 turn，避免在可能超过 60 秒的路径上使用 `--wait` 长挂；随后多次短查询 `agent result <traceId>`、`agent trace <traceId> --render web` 或 `agent inspect --trace-id <traceId>` 取证。关闭 context-loss、AgentRun 复用或多轮会话类 issue 时，证据至少应记录 `conversationId`、`sessionId`、`threadId`、`traceId`、`runId`、`commandId` 和关键 event label。需要验证“第二轮继承第一轮上下文”时，显式传入同一 conversation/session/thread 标识，不能依赖旧 Cloud Web workspace 历史或人工印象；`--no-workspace` 这类绕过恢复的实验只可作为定位证据，不能替代默认入口验收。

HWLAB Code Agent provider profile 的 `config.toml`、完整 Codex `auth.json` 写入、Secret 证据和真实 profile 试机规则统一见 `docs/reference/hwlab.md#code-agent-provider-profile-配置与验收`。本 CLI 参考只规定 `trans` 短连接和 submit-and-poll 边界，不重复维护 provider profile 凭证语义。

HWLAB Cloud Web Workbench 或 Code Agent 装配类 issue 的 CLI 验证必须贴近 Web 路径：优先使用会调用同一 Cloud API/Web dispatcher 的正式 `hwlab-cli client agent` 或等价 UniDesk 高层 CLI，再从 trace/inspect/result 中确认 runner job、AgentRun runtime assembly、`transientEnv`、`runId` 和 `commandId`。当前 HWLAB v0.2 资源装配需求以 UniDesk OA 的 [Runtime装配](../../project-management/PJ2026-01/specs/PJ2026-010202-runtime-assembly.md) 和 [HWLAB接入](../../project-management/PJ2026-01/specs/PJ2026-010205-hwlab-dispatch.md) 为权威：`ResourceBundleRef.kind="gitbundle"`，通过 `bundles[]` 装配 `tools/` 与 `.agents/skills`；不要在本 CLI 文档重复维护旧字段清单。直接调用 AgentRun manager、手写 `dispatchHwlabAgentRun()` 或临时 runner job 只可作为基础设施 canary；它不能替代 Web Workbench 原入口验收，也不能作为关闭 Web issue 的唯一证据。若缺少这种同路径 CLI，先补 CLI 可见性和 submit-and-poll 入口，再继续修复或关闭 issue。

`trans D518` 应表现为登录 D518 WSL 的 shell；`trans D518 hostname` 应像 `ssh D518 hostname` 一样只输出远端命令结果并返回远端 exit code。Provider ID 前的目标选择由 UniDesk 节点清单决定，`-p`、`-i`、`-l`、`-o` 等传统 ssh 传输参数由 provider-gateway 部署配置统一管理，CLI 会兼容性消费这些参数但不会覆盖节点侧维护桥配置。指挥官、CI 预检和其他非交互流程不要依赖 ssh-like 自由拼接；单进程标准写法是 `trans D601 argv true`，多行 shell 逻辑标准写法是 quoted heredoc 单步调用 `trans D601 sh <<'SH'`。

- UniDesk CLI/trans/tran 客户端改进属于 Master server 高频控制入口维护：
  - 可以直接在 `/root/unidesk` 轻量开发、提交并推送 `origin/master`；
  - 不为这类客户端小改强制迁移到 D601 worktree。
- 该例外不改变 Master server 禁止重型验证的规则：
  - 仓库级 check 和 Playwright/browser smoke 默认在 NC01、CI runner 或目标运行面执行；
  - 镜像构建、Rust/Go 编译和 Code Queue runner 实测遵循同一执行面边界；
  - 只有 owning pipeline 或目标运行面固定属于 D601 时才使用 D601；
  - backend-core 主服务上线的受控编译例外按 `docs/reference/dev-environment.md` 单独处理。
- `trans`/`tran`/SSH 文件传输出现 provider-gateway 单次 stdin、argv 或 stdout 限制时：
  - 先在 CLI 客户端实现分块、SHA-256 校验、失败可观测输出和最小真实闭环；
  - 只有客户端无法解决且已有证据时，才修改 provider-gateway；
  - 文件传输默认按 1 MiB raw chunk 读写；
  - 避免 100 MiB 文件被 45 KiB 小块和 base64 全量暂存拖慢；
  - `upload`/`download` 成功 JSON 的自动验证字段是端到端完整性证明；
  - 调用方不需要额外手写 `sha256sum` 比对。

`scripts/src/ssh.ts` 只承担 route/operation parser、共享远端命令构造、broker 调用和顶层 dispatch。新增或扩展高频 operation 不得继续把完整实现堆进 `ssh.ts`；应按能力拆到专门模块，例如整文件传输放在 `scripts/src/ssh-file-transfer.ts`，再由 `ssh.ts` 和 frontend remote transport 传入共享 command builder/bridge executor。后续新增 operation 也按 `scripts/src/ssh-<capability>.ts` 或等价专门模块组织，帮助文本、端到端 CLI 交互验证和 reference 与代码同一变更集更新。

core 只允许声明了 `host.ssh` capability 的 provider 使用 `host.ssh` dispatch；`trans`/`tran`/`ssh` 流式透传还必须要求 provider 声明 `host.ssh.tcp-pool`。旧 provider 不支持该能力时必须快速失败并输出 `provider-gateway-upgrade-required`，提示升级 provider-gateway；不得回落到旧 WebSocket 数据路径。provider 已升级但没有可用 data channel 时，错误应区分 `provider-data-pool-exhausted`、`provider-data-channel-missing` 或 data port 连接失败，并通过 provider labels 的 `providerGatewaySshData*` 字段定位。

本地 broker 默认等待 provider SSH 会话打开 60000ms，以便在目标节点同时有较多 microservice.http 任务时仍能建立维护会话；需要诊断慢连接时可用 `UNIDESK_SSH_OPEN_TIMEOUT_MS=<ms>` 临时调大，但最小有效值固定为 15000ms，避免把真实离线误判为长时间阻塞。注意 open timeout 只控制“会话打开”阶段，不能绕过 60 秒最外层运行时硬超时。

ssh-like 远端命令如果出现 `kex_exchange_identification`、`Connection closed by remote host`、provider session timeout 或 exit code 255，CLI 会在原始 stderr 后追加一行 `UNIDESK_SSH_HINT { ... }`。该 JSON 不回显原始远端命令，只包含 `code=ssh-like-command-friction`、`trigger`、`try` 和 `triage`；`try` 固定指向显式 `sh` stdin heredoc 形态，避免把一次 ssh-like 解析/握手摩擦误读成 D601 SSH 整体不可用。`ssh`/`trans`/`tran` 在失败路径识别到 tcp-pool 数据面问题时会追加 `UNIDESK_SSH_TCP_POOL_HINT { ... }`，`failureKind` 固定分为 `provider-data-channel-closed`、`provider-data-channel-missing` 和 `provider-data-pool-exhausted`；这类 hint 表示 transport/data-pool transient，幂等受控操作应先运行 `bun scripts/cli.ts debug ssh-pool <providerId>` 查看 labels，再重试原受控 CLI，不能单独定性为远端 runtime 配置失败。backend-core/provider 控制面返回结构化 `ssh.error` 时 broker 还会输出 `UNIDESK_SSH_ERROR { ... }`，供 `job status` 从旧日志或异步 job 日志中恢复 failureKind。`ssh`/`trans`/`tran` 运行时硬超时会输出 `UNIDESK_SSH_RUNTIME_TIMEOUT { ... }` 或 wrapper 层 `UNIDESK_TRAN_TIMEOUT_HINT { ... }`；这不是远端业务失败，而是调用方需要改成短查询/轮询。`ssh`/`trans`/`tran` 只有在运行耗时超过默认 10000ms 时才会在 stderr 追加一行 `UNIDESK_SSH_TIMING { ... }`，且 `level=warning`；正常短调用不输出 timing 噪声。慢成功命令也必须保留该 warning，因为它是 provider session、远端命令成本、helper bootstrap 和 `trans`/`tran`/远端 patch 性能回归的重要监控信号。warning 包含 `elapsedMs`、`elapsedSeconds`、`transport`、`invocationKind` 和 `exitCode`，提示优先排查 provider/session 延迟、远端命令自身耗时、helper bootstrap 或工具层回归。阈值可用 `UNIDESK_SSH_SLOW_WARNING_MS=<ms>` 临时调节，提示同样不回显原始远端命令。

非交互 `ssh` / `trans` / `tran` 远端命令的流式 stdout/stderr 使用统一的有界预览策略：

- 默认预览预算来自 `config/unidesk-cli.yaml#output.maxStdoutBytes`；超过预算后继续消费远端流以取得最终 exit code，但超出部分不落盘，`dumpPath=null`。
- 本地 stderr 追加 `UNIDESK_SSH_STDOUT_TRUNCATED { ... }` 或 `UNIDESK_SSH_STDERR_TRUNCATED { ... }`，披露 stream、阈值、已观察字节数、`dumpPath`、disclosure policy 和推荐的窄查询。
- 只有用户显式设置 `UNIDESK_TRAN_STREAM_DUMP=1` 时才把完整流写入受保护的 dump；`--full` / `--raw` 属于上层命令的显式完整披露，不应由默认 `trans` 静默推导。
- 需要一次性扩大预览预算时可显式设置 `UNIDESK_SSH_STDOUT_STREAM_MAX_BYTES` / `UNIDESK_TRAN_STDOUT_STREAM_MAX_BYTES` 或对应的 stderr 变量，仍受最小 4KiB、最大 16MiB 的工具保护。
- 看到截断 hint 时优先改成 `rg -m`、`sed -n`、`tail`、`--limit` 或 `--tail-bytes` 等更窄的结构化 drill-down；交互登录 shell 不套该上限。

`trans <providerId>` 透传只在当前 operation 需要 helper 时才注入 `/tmp/unidesk-ssh-tools`，普通 `argv`、`sh`/`bash`、`kubectl`、`logs` 和默认 `apply-patch` 等路径不得传输无关工具源码。`apply-patch-v1` 只注入 `apply_patch`；`glob` 只注入 `glob`；`skills`/`skill discover` 只注入 `skill-discover`。`apply_patch` 接受标准 `*** Begin Patch` / `*** End Patch` patch 格式，便于通过 SSH 透传编辑远端仓库文件；远端存在 `perl` 时必须走快速精确匹配路径，避免大文件 hunk 被 sh 模式匹配拖成几十秒，缺少 `perl` 时才退回 sh-only 实现。`glob` 和 `skill-discover` 需要远端 `python3`。注入工具只写 `/tmp/unidesk-ssh-tools`，不修改目标仓库。

远端文本 patch 默认使用 `apply-patch` 的 v2 引擎：它不把 hunk 解析交给远端 shell/perl helper，而是在本地按行序列匹配，支持长中文/Unicode 行、纯新增 hunk、低上下文插入和 `@@` 上下文定位，再把完整新内容写回远端。v2 的文件操作提交顺序按 Codex 标准 `apply_patch` 语义执行：空 patch 会失败；删除不存在的文件会失败；`Add File` 可覆盖已有文件；`Move to` 可覆盖目标文件；当大 patch 后续 hunk 不匹配时，已成功提交的前序文件操作会保留，并在错误详情中记录 `partialChanges`，调用方应基于当前文件内容继续补一个更小的 patch，而不是期待全量事务回滚。若 stderr 报 `failed to find expected lines` 且显示 partial context match，尤其是大块/函数替换，调用方必须先重读目标文件当前块，再用更少稳定上下文、`@@ <unique anchor>` 或多个小 hunk 重试；该失败不构成改用 `download`/`upload`、远端脚本整文件替换或 `apply-patch-v1` 的理由。`apply_patch` 旧 helper 默认拒绝低上下文 update hunk：空搜索/纯插入无锚点、只在插入点前有上下文而没有插入点后上下文、或同一 hunk search 在目标文件中匹配多个位置时，都会结构化失败并提示补充上下文。成功应用时每个 hunk 会在 stderr 输出 `apply_patch: hunk N matched path:line`，用于复核实际落点；只有人工确认确实需要旧 helper 行为或 `--allow-loose` 时，才显式调用 `apply-patch-v1 --allow-loose`。

远端文本补丁统一通过 stdin quoted heredoc 直送，不先创建、下载或上传 patch 临时文件：

- host workspace 使用 `trans D601:/absolute/workspace apply-patch <<'PATCH'`。
- k3s workload 使用 `trans D601:k3s:<namespace>:<workload>[:<container>] apply-patch --cwd /workspace <<'PATCH'`。
- Windows workspace 使用 `trans D601:win/c/test apply-patch <<'PATCH'`。
- 旧 helper 只有 `apply-patch-v1` 一个显式入口；附加参数原样透传，补丁正文仍使用 quoted heredoc，例如 `trans D601 apply-patch-v1 --allow-loose <<'PATCH'`。

标准单命令用法如下：

pod 内文本热修的反面案例是：先在 host/source worktree 生成 `git diff`，再用本地 `sed` 改路径、拼 `*** Begin Patch` 包头，最后管道到 `G14:k3s:<namespace>:<pod>`。这种做法把 source workspace、local shell、远端 shell 和 pod workspace 四层混在一起，容易出现 patch 格式错误、路径漂移、部分成功后误判、以及“看起来在热修 pod，实际主要在搬运 host diff”的错误行为。正确做法是把第一个 route token 直接定位到目标 pod/container，容器内 cwd 用 `--cwd /path` 表达，然后在同一条 route 上写标准 Codex patch：

```bash
trans G14:k3s:hwlab-dev:pod:hwlab-cloud-web-abc:hwlab-cloud-web apply-patch --cwd /app/web/hwlab-cloud-web <<'PATCH'
*** Begin Patch
*** Update File: app.mjs
@@
-const value = "old";
+const value = "new";
*** End Patch
PATCH
```

如果运行面实际加载 `dist/` 产物，同样直接定位到 `...:hwlab-cloud-web apply-patch --cwd /app/web/hwlab-cloud-web/dist` 再改 `app.mjs`，不要从源码 worktree 生成 diff 后改路径上传。热修后立即用同一个 pod route 做 `grep`/`sha256sum`/语法检查或浏览器 smoke 确认落点；若热修内容已经等同于上传一份较大源码，优先停止热修，改走 PR/CI/CD。

```bash
trans D601:/home/ubuntu/pipeline apply-patch <<'PATCH'
*** Begin Patch
*** Update File: scripts/src/nodeControl.ts
@@
-const value = "old";
+const value = "new";
*** End Patch
PATCH
```

旧 helper fallback 示例：

```bash
trans D601:/home/ubuntu/pipeline apply-patch-v1 <<'PATCH'
*** Begin Patch
*** Update File: scripts/src/nodeControl.ts
@@
-const value = "old";
+const value = "new";
*** End Patch
PATCH
```

如果只是想远端执行 Python 脚本，不要再手写 `trans D601 'python3 -' < script.py`。正式入口是 `trans D601 py < script.py`；CLI 会先把本地 stdin 写入远端临时 `.py` 文件，再以无缓冲模式执行并自动清理，同时对额外脚本参数逐个做 shell quoting，避免字符串转义问题。典型用法：

```bash
printf 'import sys\nprint(sys.argv)\n' | trans D601 py foo '--bar=baz'
```

`trans <providerId> py` 的附加参数是脚本参数，不是 Python 解释器参数；如需 `-m`、`-X` 或多条 shell 命令，仍使用原始远端命令入口。为了保证 CLI 输出及时可见，helper 固定采用“临时文件 + `python3 -u`”模式；provider 命令模式不分配 TTY，因此脚本内容不应被远端回显。

如果远端逻辑需要 shell 特性，不要再把整段脚本作为原生 ssh-like 命令字符串传入。正式入口必须在 operation 位置显式声明 shell 方言：`trans D601 sh` 表示目标 `/bin/sh`，`trans D601 bash` 表示目标 Bash。脚本正文从 stdin 进入；operation 后的普通参数会作为脚本参数传入。`sh`/`bash` helper 会在用户脚本文本前注入用户级工具 PATH 和兼容前缀，让 `bun`、`tsx` 等用户级工具在非交互 shell 中可见，也让 `printf "--- section ---\n"` 这类分隔标题不再因目标 `/bin/sh` 方言失败；已有 `printf '%s\n' value`、`printf -- ...` 和 bash 的 `printf -v` 仍按原语义工作。临时单步执行优先用 quoted heredoc；只有命令很短、明确希望一行内完成时才用 `sh -- '<command && command>'` 或 `bash -- '<bash command>'`，它会把单个字符串按所选远端 shell one-liner 执行且不等待 stdin；`sh --` / `bash --` 后出现多个 argv token 会失败，单进程命令必须改用 `argv` 或直接子命令；复用脚本时才用 `< script.sh` 文件重定向。`script` 和 `shell` operation 已移除并会失败，不能用 `--shell bash` 或旧名绕过显式 shell 选择。典型用法：

```bash
cat <<'BASH' | trans D601 bash alpha
set -euo pipefail
printf 'arg=%s\n' "$1"
hostname
BASH
```

这个入口的目标是分布式调试的“0 shell-command-string”路径：本地 shell 只负责 heredoc/stdin，UniDesk 只负责 provider 路由，远端 shell 只解释脚本正文。脚本正文里仍然要遵守 shell 语言自身的规则，但不再穿过本地 shell、远端 shell、kubectl exec 和容器 shell 的多重字符串转义。

一行远端 shell 逻辑同样必须用显式方言：POSIX 写 `trans <providerId> sh -- '<command>'`，Bash 专有语法写 `trans <providerId> bash -- '<command>'`。它的输入必须作为一个 quoted argv 到达 CLI，适合 `sed ... && sed ...`、`kubectl get ... | head` 或一次性环境探测；它仍然只穿过一次目标 shell，不能解决本地 shell 已经拆开的外层 `&&`、`|`、`>`。k3s 控制面同样支持 `trans G14:k3s sh -- 'kubectl get nodes && kubectl get pods -A'`，并默认注入 `/etc/rancher/k3s/k3s.yaml`；pod route 需要 cwd 时使用 workload route 的 `sh`/`bash` operation 或 `exec --cwd /path -- sh -c '<command>'`，例如 `trans D601:k3s:hwlab-dev:hwlab-cloud-api sh --cwd /app -- 'pwd && ls'`。

`trans <providerId> skills` 是远端 skill 发现入口，也可写作 `trans <providerId> skill discover`。输出固定为 JSON，包含 `node`、`roots`、`counts` 和 `skills`：`roots` 会显示每个候选 skill 根目录是否存在、扫描到多少 skill 以及错误；`skills` 会给出 `scope`、`name`、`description`、`path`、`skillMd` 和可转换时的 `windowsPath`。默认扫描远端用户的 `~/.agents/skills`、`~/.codex/skills`、可访问的 `/root/.agents/skills`、`/root/.codex/skills`；如果目标是 WSL，还会扫描 `/mnt/c/Users/*/.agents/skills` 与 `/mnt/c/Users/*/.codex/skills`，从而一次性看清 WSL 和 Windows 两套 skill。常用参数是 `--scope wsl`、`--scope windows`、`--limit N`、`--max-depth N`、`--root <path>` 和 `--windows-root <path>`；不要用宽泛的 Linux `find /mnt/*` 扫 Windows 盘，优先用这个结构化入口避免卡在 Windows 挂载层。

```bash
trans D601 skills --limit 80
trans D601 skills --scope windows --limit 40
```

Windows 工具链透传的 wrapper、路径转换、是否修改 skill、是否额外安装依赖等长期规则见 `docs/reference/windows-passthrough.md`；`trans skills` 本身只负责发现，不会修改远端 skill。

`trans <providerId> find` 是常用远端搜索的结构化入口，避免在 Host SSH / WSL SSH 透传里手写 `find \( ... \)`、`*`、管道和多层引号。它会把路径、谓词和 pattern 作为 argv 安全拼接，并支持重复 `--name`、`--iname`、`--path` 或 `--ipath`，重复 pattern 默认按 OR 组合。稳定参数包括 `--max-depth`/`-maxdepth`、`--min-depth`/`-mindepth`、`--type`/`-type`、`--contains`、`--icontains`、`--name`/`-name`、`--iname`/`-iname`、`--path`/`-path`、`--ipath`/`-ipath`、`--mtime`/`-mtime`、`--mmin`/`-mmin`、`--size`/`-size`、`--sort` 和 `--limit N`。典型用法：

```bash
trans D601 find /home/ubuntu --max-depth 4 --type d --icontains pika --limit 50 --sort
```

`trans <providerId> glob` 是远端 glob 匹配入口，支持 `--root DIR`、`--pattern PATTERN`、`--contains TEXT`、`--icontains TEXT`、`--type any|f|d`、`--limit N`、`--sort` 和 `--absolute`。`--contains` 与 `--icontains` 可避免在本地 shell 中输入 `*`；若显式使用 `--pattern '**/*.ts'` 这类 pattern，仍应按本地 shell 规则加引号，防止参数到达 CLI 前已被本地 shell 展开。典型用法：

```bash
trans D601 glob --root /home/ubuntu/pikapython --pattern '**/*-test.cpp' --limit 20 --sort
```

`ssh` 的 route 语法是 `{provider}:{plane}[:{scope...}] {operation} [operation-args...]`。第一个 argv token 只负责定位分布式目标，不表达操作；第一个 token 后面的所有 token 才进入 operation 解析器。Host workspace route 使用 `<provider>:/absolute/workspace`，例如 `D601:/home/ubuntu/workspace/hwlab-dev`，CLI 会把该路径作为远端 cwd 传给 Host SSH 维护桥，后续 `pwd`、`git`、`sh`、`bash`、`apply-patch` 和旧 `apply-patch-v1` fallback 等操作仍按同一套 operation parser 执行。`<provider>:host:/absolute/workspace` 是等价长写法；workspace 必须是绝对路径，远端是否存在由维护桥实际 `cd` 失败或成功证明。显式 host workspace 进入失败必须返回 `UNIDESK_SSH_CWD_FAILED` 和非零退出，不得静默落回默认目录；完整 provider-gateway 语义见 `docs/reference/provider-gateway.md`。

当前稳定 plane 包括 `win` 和 `k3s`。`win` plane 的 operation 是 Windows 操作，不是 POSIX shell 别名：`<provider>:win ps` 在 WSL provider 上启动 Windows PowerShell，stdin heredoc 会被写入临时 `.ps1` 后执行；`<provider>:win cmd` 启动 Windows host 的 `cmd.exe`，stdin heredoc 会被写入临时 `.cmd` 后执行；`<provider>:win skills` 发现 Windows skill 目录。需要 Windows 当前目录时使用 slash 路由 `<provider>:win/<drive>/<path>`，例如 `D601:win/c/test ps` 会先在 PowerShell 内 `Set-Location -LiteralPath 'C:\test'`，`D601:win/c/test cmd cd` 会先在 cmd 内执行 `cd /d "C:\test"`。`cmd`、`git` 和 host direct argv 会逐 token 保留调用端已经形成的参数边界，包括空格与中文；会打开编辑器或需要 shell 审阅的命令仍用 `ps` 或 `cmd` heredoc 包装。`win32` 不是合法 plane，调用者必须改用 `win`。

Windows workspace 中依赖 Windows PATH、解释器、SDK 或编译工具链的操作必须优先在 `win` plane 执行，而不是先进入同一 provider 的 WSL `/mnt/<drive>` host workspace。WSL/host plane 与 Windows plane 是两套命令环境：前者出现 `python: command not found` 只证明 WSL PATH 中没有该命令，禁止据此判断 Windows 未安装 Python。Windows Python 的最小探测入口是 `trans G14-WSL:win/d/Work/CONSTAR_workspace cmd python --version`；需要 PowerShell 变量、管道或多步逻辑时改用同一路由的 `ps`。

`<provider>:win ps` 是 Windows PowerShell 专用入口，适合管道、变量、`Get-ChildItem`、`Start-Process`、`Test-Path` 和 Windows 路径脚本；不要用 host/k3s 的 `sh`/`bash` operation 表示 PowerShell。`ps` 和 `cmd` 都注入 UTF-8/Python 编码默认值；`cmd` 额外执行 `chcp 65001>nul`。典型用法：

```bash
trans D601:win ps <<'PS'
$ErrorActionPreference = 'Stop'
Get-ChildItem -LiteralPath 'F:\Work' -Directory -Filter '*HWLAB*' | Select-Object -ExpandProperty FullName
PS
```

`<provider>:win skills [--scope agents|codex|all] [--limit N] [--name <精确名称>|--filter <文本>]` 是 Windows 用户 skill 发现入口，默认只读取当前 Windows 用户的 `%USERPROFILE%\.agents\skills`，输出 JSON 中包含 `roots`、`counts`、`query` 和每个 skill 的 `name`、`path`、`skillFile`、`description`。查单个 skill 时优先 `--name`，模糊查找时使用 `--filter`，避免全量结果触发 stdout dump；需要同时检查 `%USERPROFILE%\.codex\skills` 时显式加 `--scope all`。

- Windows `rg`：
  - `<provider>:win/<drive>/<path> rg` 调用 Windows PATH 中的原生 `rg.exe`。
  - 支持一个或多个 `-e|--regexp`，以及 `--files`、`-g|--glob`、`--max-count`、`--max-files` 和 `--timeout-ms`。
  - 搜索强制输出文件名，`UNIDESK_WINDOWS_RG_SUMMARY` 披露 `matched`、`fileCount`、`elapsedMs`、`timeout`、`encoding` 和截断状态。
  - legacy 或无效 UTF-8 输出必须标记 `encoding=legacy-or-invalid-utf8`，不能静默当作 UTF-8 正常文本。
  - 默认预算由 `config/unidesk-cli.yaml#trans.windowsFs.rg` 唯一控制。
  - 超时返回 124，无匹配返回 1，缺少 `rg.exe` 返回 127 和可执行替代提示。
- Windows 有界读取：
  - `wc` 支持 `-l|--lines`、`-w|--words`、`-m|--chars` 与 `-c|--bytes`。
  - `head` 和 `tail` 在行裁剪阶段使用流式读取，不得先以整文件大小门禁拒绝已经有界的 `-n N` 请求。
- `apply-patch v2` legacy 文本：
  - bulk read、plan 和 apply 必须共享同一原始字节 fingerprint。
  - 非 UTF-8 单字节文本标记为 `legacy-single-byte`。
  - ASCII localized replacement 必须保持原 legacy 字节和换行风格。
  - legacy replacement 包含无法用单字节保持的新字符时必须显式拒绝，不能转码整个文件。

`D601:k3s` 或 `G14:k3s` 定位到对应 provider 的原生 k3s 控制面；`<provider>:k3s:<namespace>:<workload>[:container]` 定位到 namespace 下的一个默认 deployment workload；若目标是具体 Pod，标准 workload 段写成 `pod:<podid>`，例如 `D601:k3s:hwlab-v03:pod:hwlab-cloud-api-abc:hwlab-cloud-api`。`pod/<podid>` 不是合法 route 写法，因为 `:` 是分布式路由分隔符，`/` 只表示目标容器里的文件系统 cwd；如果调用者写成 `pod/<podid>/<container>`，CLI 必须在连接运行面前报错并提示改用 `pod:<podid>:<container>` 或 `--container <container>`。若目标是 Deployment，也可以显式写 `deployment:<name>` 或简写 `<name>`；容器选择写 `:<container>` 或 operation 参数 `--container <container>`。pod 内 cwd 推荐用 operation 参数 `--cwd /path`，例如 `D601:k3s:hwlab-dev:hwlab-cloud-api:hwlab-cloud-api exec --cwd /app -- pwd`。`kubectl`、`logs`、`sh`、`bash`、`apply-patch`、旧 `apply-patch-v1` fallback、`exec` 和普通容器命令都是 route 后面的 operation，这样路由子模块和操作子模块可以独立扩展。

`k3s` 必须出现在 route 的 plane 段里，禁止使用 `trans G14 k3s ...` 或 `trans D601 k3s ...` 这类 post-provider shorthand；正确形态是 `trans G14:k3s kubectl ...` 或 `trans D601:k3s kubectl ...`。定位和操作必须保持分离，`kubectl`、`logs`、`sh`、`bash`、`apply-patch`、旧 `apply-patch-v1` fallback、`exec` 等 operation 名也不得放进任何 colon route 段，包括 namespace、workload 或 container 段；新增分布式目标时按 `{provider}:{plane}:{scope}` 扩展 route，而不是在 operation args 中新增另一套定位语法。

该入口解决运行面调试中最常见的多层 shell 引号问题。它不要求升级 provider-gateway，也不新增业务 API，只复用现有 Host SSH 维护桥；CLI 在本地把 Kubernetes 目标、namespace、container、log 限制、容器命令、`sh`/`bash` stdin、pod cwd `apply-patch` 读写和旧 `apply-patch-v1` fallback 组装成 kubectl argv，并固定远端 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml`。`<provider>:k3s` 无后续参数时执行 native k3s guard；`<provider>:k3s kubectl ...` 接收原始 kubectl argv；`<provider>:k3s sh` 或 `bash` 执行带 native kubeconfig 的 host stdin 脚本；`<provider>:k3s:<namespace>:<workload>[:container] logs` 读取有界日志；`<provider>:k3s:<namespace>:<workload>[:container] exec ...` 和 `<provider>:k3s:<namespace>:<workload>[:container] <command> ...` 进入目标 workload/container；`<provider>:k3s:<namespace>:<workload>[:container] sh` 或 `bash` 把本地 stdin 作为 pod 内 shell 脚本执行；`<provider>:k3s:<namespace>:<workload>[:container] apply-patch --cwd /workspace` 是 pod 内文本 patch 默认入口；旧 helper 仅通过 `<provider>:k3s:<namespace>:<workload> apply-patch-v1` 显式调用。典型用法：

```bash
trans D601:k3s
trans D601:k3s kubectl get pods -n hwlab-dev
trans D601:/home/ubuntu/workspace/hwlab-dev git status --short --branch
trans D601:win ps <<'PS'
$PSVersionTable.PSVersion.ToString()
PS
trans D601:win cmd ver
trans D601:win/c/test cmd cd
trans D601:win skills --limit 20
trans G14:k3s
trans G14:k3s kubectl get pipelineruns -n hwlab-ci
printf 'kubectl get deploy -n hwlab-dev\n' | trans D601:k3s sh
trans D601:k3s:hwlab-dev:hwlab-cloud-api logs --tail 80
trans D601:k3s:hwlab-v03:pod:hwlab-cloud-api-abc:hwlab-cloud-api sh -- 'curl -fsS http://user-billing/health'
trans G14:k3s logs --namespace=devops-infra --deployment=git-mirror-http --tail=80
trans G14:k3s logs -n agentrun-ci -l tekton.dev/pipelineRun=agentrun-v01-ci-xxxx --tail=120
trans D601:k3s:hwlab-dev:hwlab-cloud-api node -e 'console.log(process.version)'
trans D601:k3s:hwlab-dev:hwlab-cloud-api exec --cwd /app -- pwd
printf 'printf "pod=%s\n" "$HOSTNAME"\n' | trans D601:k3s:hwlab-dev:hwlab-cloud-api sh
tar -C /tmp/patched-files -cf - . | trans D601:k3s:unidesk:code-queue exec --cwd /root/unidesk --stdin -- tar -xf - -C /root/unidesk
trans D601:k3s:hwlab-dev:hwlab-cloud-api:hwlab-cloud-api apply-patch --cwd /app <<'PATCH'
*** Begin Patch
*** Update File: /tmp/example.txt
@@
-old
+new
*** End Patch
PATCH
```

`logs` operation 默认是有界读取；`--follow`/`-f` 会被拒绝，防止 CLI 长时间占用维护桥。目标 route 后面直接跟普通命令时，CLI 会把 argv 放到 `kubectl exec --` 后；显式 `exec` operation 可用于让命令边界更清晰。`exec --stdin -- <command> ...` 是 workload route 的通用 stdin 流入口，适合把 tar、patch 以外的任意字节流直接送进容器命令；operation 选项必须放在 `--` 前，容器命令从 `--` 后开始。需要 shell 语法时优先改用 `sh` 或 `bash` operation，把脚本走 stdin，而不是把 `kubectl exec ... -- sh -c ...` 放进远端命令字符串。pod 内文本热修默认使用 workspace route 加 `apply-patch`，不要求目标容器自带 `python3`、`node` 或仓库里的工具脚本；旧 `apply-patch-v1` operation 仍使用同一个 sh helper，只作为显式 legacy fallback，不用于二进制改写。

`trans <providerId> argv <command> [args...]` 是通用 argv 安全拼接入口；`exec` 是同义入口。它是非交互远端单进程命令的默认成功路径，不需要 shell 管道时直接传命令和参数，例如 `trans D601 argv true`。直接写未列入专用 helper 的单进程命令时也会逐 token shell quote，不再把已形成的多词参数重新按空格拆分。需要管道、重定向、变量展开或多条命令时，优先改用 `trans <providerId> sh <<'SH'`。`apply-patch`、`find`、`glob` 和旧 `apply-patch-v1` fallback 有专用入口；`git`、`rg`、`grep`、`sed`、`nl`、`stat`、`du`、`ls`、`cat`、`head`、`tail`、`wc` 和 `pwd` 可以直接作为 `trans` 子命令使用，CLI 会对每个 argv token 做 shell quoting。`/mnt/<drive>` workspace 上的命令若以 127 和 `command not found` 失败，stderr 会给出同 provider 对应 `:win/<drive>/... cmd` 的 `UNIDESK_SSH_HINT`，用于核对 Windows PATH；原退出码保持不变。

通过 `trans <providerId>` 执行多行脚本时，优先使用结构化 helper，例如 `trans G14 py < script.py`、`trans G14 sh <<'SH'` 或 `trans G14:k3s sh <<'SH'`。不要在远端命令字符串里再嵌套 heredoc、复杂引号或 `ssh 'python3 - <<EOF ...'` 形态；多层 shell 解析容易把 stdin 绑定到错误进程，结果会打开远端交互解释器并留下悬挂的 broker/SSH 会话。长脚本需要复用时，优先提交到 repo 或通过 stdin 传输到目标节点执行。

- Windows 固定脏 worktree 精确提交入口：
  - `trans <route>:win/... git exact-commit status` 只读披露对象数量与安全停止边界；
  - `plan --path <repo-relative-path>` 使用临时 index 生成待提交 tree，不更新 ref；
  - `run --path <path> --message <message> --confirm` 使用 HEAD old-value CAS 更新当前分支，只刷新选中路径的 index，并验证未选中路径的 staged/unstaged 状态不变；
  - 多文件必须重复传入 `--path`，禁止把当前 index 当作隐式提交范围；
  - `gc-auto --confirm` 只运行 `git gc --auto`，不得直接 prune active、recent 或受 reflog 保护的 unreachable objects。

## Remote Main Server Passthrough

`--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 `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`、`sh`/`bash` stdin、`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 自测，不能视为交付完成。

远程透传的安全边界是公网 frontend 登录态和 frontend 到 backend-core 的内网代理；不要把 provider token、数据库端口或 backend-core REST API 暴露给计算节点。旧 SSH 传输只作为兼容路径保留，不得把“必须提供主 server SSH key”作为计算节点自测的前置条件。
