Files
pikasTech-unidesk/docs/reference/cli.md
T
2026-06-18 14:22:33 +00:00

168 KiB
Raw Blame History

UniDesk CLI Reference

UniDesk 的统一 CLI 实现入口是根目录 scripts/cli.ts,运行方式固定为 bun scripts/cli.ts <command>;普通根 CLI 子命令仍使用该入口。trans <route> ...bun scripts/cli.ts ssh <route> ... 的短 alias,只用于 SSH/WSL/k3s 透传,用于避免远端操作里反复输出过长前缀;长期参考文档、AGENTS 索引、CLI help 和人工远端操作示例都必须优先写 trans ...,不得再把 bun scripts/cli.ts ssh ... 作为默认透传入口。CLI 默认输出 JSON,所有成功和失败路径都必须向 stdout 写出结构化对象,避免无输出造成状态不可观测。

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

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 helpconfigserverprovidermicroservice 等普通根 CLI 子命令不受这条限制,仍使用 bun scripts/cli.ts <command>,避免透传命令和根子命令在调用前缀上互相混淆。

CLI 可以从 master 快速演进,但必须兼容 deploy.json 固定的 CI/CD server 和生产运行面。CLI/server 能力协商、unsupported-version 失败语义和 release-line 边界由 docs/reference/release-governance.mdGitHub issue #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|v03agentrun control-plane ...deploy check|plan|applyci install|status|run|publish-*|logsartifact-registry ...server rebuild ...dev-env ... 和后续为特定运行面补充的同级命令。原生 kubectlargotknghcurl 或临时 shell 可以作为实现细节存在于 CLI 内部,但不能作为人工或 runner 的正式控制面。

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-dbhwlab-v03-openfga SecretRef 来自 G14 host platform DB 凭据文件,不再从 lane-local Postgres Secret 派生;hwpod-v03-dbhwpod_v03hwpod_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-keyopencode-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.yamlbootstrapAdmin 声明与受控 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 沉淀为长期入口。

hwlab nodes web-probe run|script --node <node> --lane <lane> 是 HWLAB Cloud Web 线上 DOM/Playwright 验收的受控入口;CLI 负责从 YAML 解析 workspace、public URL 和 bootstrap admin sourceRef,并只输出 redacted 凭据状态、artifact path/hash、readiness、probe.summary 和失败分类。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 参考不再维护第二套操作面。

hwlab nodes control-plane infra plan|status|apply --node D601 --lane v03 是 D601 HWLAB v03 节点本地 CI/CD 与 git-mirror 前置控制面的 YAML 驱动入口,配置真相源是 config/hwlab-node-control-plane.yamlplan 只读展示 YAML target 和将渲染的 control-plane 对象;status 只读观察 D601 Tekton、CI namespace、git-mirror、Argo、node-local registry 和 tools image readinessapply --dry-run 只输出 manifest 摘要;apply --confirm 只收敛 D601 control-plane bootstrap 对象,不触发 HWLAB runtime rollout,不创建 PK01 DB,也不修改 Caddy/FRP。tools image 的 node-local registry 地址只能作为输出 artifact;输入 base image 必须由 YAML 声明为公开 registry 来源,缺少 output image 时应在 status.next.blockers 中体现,而不是把现有 node-local image 当成输入基础镜像。

hwlab nodes git-mirror status|sync|flush --node <node> --lane <lane> 是 node-scoped runtime lane 的 Git mirror 维护入口。statusgithubSource / githubGitops 来自本地 mirror cache 的 refs/mirror-stage/...,不是实时 GitHub API;输出中的 refSources.githubFieldsAreMirrorStageCache=truerefSources.cacheRefresh 给出这一来源和刷新命令。sync --confirm --wait 的 k3s Job 遇到 GitHub SSH transient 时,应通过目标 workspace fallback 拉取 GitHub source/gitops 并写回 node-local mirror,输出只披露 commit、mirror write URL 和 fallback 状态。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=falsegithubInSync=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 会在 source sync 后自动执行必要的 pre-flush,在 PipelineRun terminal 后自动执行必要的 post-flushprogress 事件必须显式输出 git-mirror-pre-flush / git-mirror-post-flush 的 executed/skipped、jobName、local/github source、local/github GitOps、pendingFlushgithubInSync,且已恢复的 partial success 不能让顶层 trigger-current false-fail。control-plane status 仍是只读入口,只暴露 compact gitMirror 摘要和下一步 flush 命令,不隐式执行写操作。

hwlab nodes control-plane infra tools-image status|build|logs --node D601 --lane v03 是 D601 tools image 的受控入口。Dockerfile 必须由 config/hwlab-node-control-plane.yamltekton.toolsImage.dockerfileInline 声明,输入镜像必须列在 publicBaseImages,构建参数和网络模式也来自 YAMLconfirmed 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 都必须来自同一个 YAMLargo 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.yamlbaseImageSource,输出目标来自同一 lane 的 baseImagestatus 只读检查 node-local registry tag 与 source/target image presencepreload --confirm 按 YAML 下载配置执行 source pull/tag/pushbuild 当前只是 preload 别名。这个入口用于 trigger-current 前置检查和 base image 缺失恢复;后续 service build 失败应按失败 TaskRun 单独分流。

Command Model

  • help 输出命令索引,适合作为交互式入口。

  • 每个 CLI 命名空间必须支持 help--help-h 并返回 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,支持 D601G14、host workspace、D601:winD601:win/c/testD601:k3sD601: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 一次性开启。--scripts-typecheck 只跑 scripts TypeScript 类型检查,不触发测试脚本或 GitHub issue/PR live API check。长命令项必须在 stderr 输出 unidesk.check.progress JSON linesstdout 保持最终 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 必须包含 durationMstimeoutMsheartbeatMsexitCodesignaltimedOut、stdout/stderr byte count、truncation flag 和有界 tail;超时必须返回 timedOut=true,不得只留下被外层命令杀死的空输出。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.mddocs/reference/devops-hygiene.md

  • server start 创建异步 job,在后台执行 Docker 构建和启动;命令本身只负责返回 job id、日志路径和启动命令。

  • server stop 创建异步 job,在后台停止固定 Compose project 中的全部 UniDesk 服务。

  • server status 查询公开端口、受限宿主端口、内部端口、主机 swap 摘要、Compose 容器、core/frontend/dev-frontend/provider/database 健康检查和访问 URLD601 Code Queue 使用的 PostgreSQL/OA Event Flow host mapping 必须出现在受限宿主端口而不是无条件公开入口中。低内存主 server 上 swap.warning 非空时,先执行 server swap statusserver swap ensure

  • server swap status|ensure [--path /swapfile] [--size 2GiB] [--dry-run] 是主 server swap 管理入口。status 仅读 /proc/meminfo/proc/swaps/etc/fstab 并返回 JSONensure 在已有任何 active swap 时只报告 no-op,在无 active swap 时创建固定 swapfile、chmod 600mkswapswapon 并尽量写入 /etc/fstab。输出必须包含 beforeafter、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 imageprotectedStorage 必须显式列出 PostgreSQL named volume、Baidu Netdisk .state、D601 registry storage 和 Docker volumes/host data policy。该入口禁止 docker system prunedocker image prunedocker builder prunedocker volume rmdocker compose down -v、数据库清理或 host data rm 命令。

  • gc plan|run --confirm|db-trace|policy|remote 是主 server 和受控 provider 的磁盘高水位一次性缓解与长期防膨胀入口。plan 只读输出候选、风险、估算收益和保护对象;run 必须显式 --confirmgc 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|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow> 创建异步 job,先构建目标服务镜像,随后在 .state/locks/server-compose.lock 串行保护下用 --no-deps --force-recreate 替换目标 service 并等待容器 healthy/running;该命令用于替代手工删除容器的兜底流程,其中 dev-frontend-proxy 只更新主 server dev 入口薄代理,todo-notecode-queue-mgrproject-managerbaidu-netdiskoa-event-flow 只重建主 server 承载的对应后端,不会重建或删除 database 命名卷。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_SERVERPROVIDER_IDprovider-<ID>.yml 固定 Docker socket、pid: "host"restart: always、只读 /workspace 和 SSH 维护私钥挂载;--up 会立即执行生成的 docker compose up -d --buildprovider triage <providerId> [--observed-error text] [--observed-scope scope] [--microservice id ...] [--full|--raw] 是只读多信号健康裁决入口,会把单路径 provider is not online、SSH 超时、registry 失败和 service proxy 失败归类成 runner-local-observation-gapservice-degradedprovider-degradedglobal-blocker。默认输出只返回裁决、scope、失败/降级/未知信号和有界 evidence 摘要,完整 evidence 必须显式加 --full--raw;推荐交叉验证命令仍包含 debug healthdebug dispatch <providerId> host.ssh --wait-ms 15000trans <providerId> argv trueartifact-registry health --provider-id <providerId>microservice health k3sctl-adaptermicroservice health code-queuecodex 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。planstatus 只读采集远端 host、PostgreSQL、TLS、DNS alias 和 Secret 形态;export-secrets --confirm 只按 YAML 物化本地 Secret source/export 文件,不触碰远端 PostgreSQLapply --confirm 默认创建本地异步 jobapply --confirm --wait 用远端 root-owned job 收敛 systemd PostgreSQL、TLS、pg_hba、role/database、Secret export 和备份 timer。输出不得打印密码或完整 DATABASE_URL。跨节点消费者使用 YAML 中的 connectionHost 直连 PK01 公网 endpointDNS alias 不作为 sslmode=require 切库 blockerPK01 规则见 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,例如 D601G14,也可以扩展为纯定位路径 provider:plane[:namespace:resource[:container]],例如 D601:winD601:win/c/testG14:k3sD601:k3sG14:k3s:<namespace>:<workload>。WSL provider 的 Windows plane 固定使用 win,不得使用 win32Windows operation 必须显式区分:ps 执行 Windows PowerShell heredoc 或一行 PowerShell 命令,cmd 执行 cmd.exe/batchskills 发现 Windows skill 目录。需要 Windows cwd 时用 trans D601:win/c/test pstrans D601:win/c/test cmd cdCLI 自动设置 UTF-8/Python 编码默认值;cmd 额外设置 chcp 65001。非交互远端命令优先使用 trans <providerId> argv ...;需要 POSIX shell 脚本、管道、变量或循环时必须在 operation 位置显式写 shbash,例如 trans G14 sh <<'SH'trans G14:k3s sh <<'SH'trans G14:k3s:<namespace>:<workload> sh <<'SH'trans D601:/workspace bash <<'BASH'sh 明确表示目标 /bin/shbash 明确表示目标 Bashscriptshell operation 已移除并会失败,避免隐藏 shell 方言。Windows PowerShell 必须写 trans <provider>:win ps <<'PS'。一行远端 shell 逻辑使用 sh -- '<单个字符串>'bash -- '<单个字符串>';顶层 remote option parser 必须保留命令已经开始后的 --,不得把它吞成全局选项结束符。需要远端改文本文件时默认优先使用 <route> apply-patch < patch.diff;需要可靠传输非文本或整文件时使用 <route> upload <local-file> <remote-file><route> download <remote-file> <local-file>CLI 会按字节数与 SHA-256 自动校验并在 provider-gateway stdin/argv 限制下切换客户端分块策略;需要旧 helper 时显式使用 <provider>:k3s:<namespace>:<workload> apply-patch-v1<providerId> apply-patch-v1。ssh-like 命令遇到 timeout/kex/255 类失败时,CLI 会在 stderr 追加一行 UNIDESK_SSH_HINT JSON,提示改用 sh/bash stdin heredoc、argv 或 provider triage 交叉验证。

  • trans <route> apply-patch < patch.diff 是默认推荐的远端 patch 入口:本地 TypeScript line-based engine 解析和计算新文件内容,远端 route 只负责读写文件;支持 host workspace、k3s pod workspace、Windows workspace route(例如 D601:win/c/test)和 frontend transport,并优先处理长中文/Unicode、低上下文插入、重复块 @@ 定位等旧 helper 容易失败的场景。apply-patch 输出按 Codex 标准文本口径,不套 UniDesk JSON 限制:成功 stdout 为 Success. Updated the following files:,失败 stdout 为空、stderr 写失败原因;多文件补丁中途失败时,stderr 只列出第一个失败前已成功执行的 hunk 和失败 hunk,随后按 Codex 语义停止,不继续尝试后续 hunk。v2 兼容常见 MiniMax/MXCX 非标准补丁输入,例如重复 nested *** Begin Patch / *** End Patch envelope、unified-diff hunk header、Add/Delete 误加 @@、Update context 漏掉前导空格,并在 stderr 给出 canonical 写法 hintparser 或上下文失败时仍坚持唯一 v2 引擎,只提示修正 patch 文本或 hunk context,不自动重试或切换到 apply-patch-v1;大块/函数替换因上下文过期失败时,正确动作是重新读取当前目标块、缩小或拆分 Update File hunk 后继续用 apply-patch,不得改走 download/upload、远端 Python/Perl/sed heredoc 或整文件重写。Windows route 复用同一套 v2 核心算法,只把底层读写替换成 PowerShell 文件系统接口;trans <providerId> apply-patch-v1 [tool args...] < patch.diff 保留为显式 legacy 入口,直接调用远端注入的 apply_patch sh/perl helper;默认 apply-patch 不把 v1 当 fallback。

  • GitHub issue/PR 正文局部修补必须优先走 trans gh:/owner/repo/issue/<number> apply-patchtrans gh:/owner/repo/pr/<number> apply-patch,而不是人工优先整篇 gh issue update --mode replace 或底层 gh issue patchgh:/ 路由把 issue/PR body 暴露为一楼虚拟文件 body.mdroute 未显式写 /1 时默认一楼正文,apply_patchpatch-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},字段包含 durationMspatchBytesfileCounthunkCountchangedCountremoteOperationCountremoteOperationCountsremoteElapsedMsremoteFailureCountproviderIdroutetransport(可得时)。普通 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 只定位控制面或 workloadkubectllogsexecshbashapply-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-patchuploaddownloadshbashpy 和旧 apply-patch-v1 fallback 经 frontend /ws/ssh 通道执行,stdout/stderr 也必须完整直通,不得退回 /api/dispatch task JSON。非 UniDesk admin runner 可通过 UNIDESK_SSH_CLIENT_TOKEN 使用 scoped /ws/ssh client tokenfrontend 侧用 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);healthstatusdiagnostics 默认返回 compact summary、body 字节数和 --full|--raw 展开命令,只有小 body 或无法抽取 summary 时才带有界 body preview,避免 Code Queue/k3s 诊断一次性输出爆炸;tunnel-self-testproxy 会走真实 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 --fullproxy 支持受控 JSON 请求体并对超大响应 body 默认输出有界预览,规则见 docs/reference/microservices.md

  • decision upload/list/show/health 通过 backend-core 用户服务代理访问 D601 k3s Decision Center,用于上传会议记录/决议 Markdown、列出权威记录、查看详情和健康检查;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-byshowrequirement update 可使用 iddocNodecision requirement list/create/upsert/update/show 在同一 records 模型上管理 goal|decision|blocker|debt|experiment 需求记录,docNo 唯一,未传 --doc-no 但提供 --doc-type/--doc-priority/--year 时由服务分配下一个序号。它们不得直连 D601 Service、NodePort 或 provider-gateway 业务 HTTP。

  • decision diary import <markdown-file> 将带 # YYYY年M月D日# YYYY-MM-DD# YYYY/M/D 标题的工作日志拆成每天一篇 Markdown 日记,按 YYYY-MM/YYYY-MM-DD.md 虚拟路径写入 Decision Center PostgreSQLdecision diary list/history 默认只返回摘要,需要完整 Markdown 时显式加 --include-bodydecision 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-corefrontendbaidu-netdiskdecision-centermdtodoclaudeqq 和 dev-only code-queue artifact consumersfindjob/pipeline/met-nonlinear 为 D601 direct Compose artifact consumersk3sctl-adapter 只提供 plan/dry-rundev desired-state smoke 使用 ci run-dev-e2e;规则见 docs/reference/deploy.mddocs/reference/dev-environment.mddocs/reference/dev-ci-runner.mddeploy apply --env prod 同时覆盖 findjobpipeline 的 pull-only Compose CD,但 met-nonlinear 仍然只允许 dry-run/plank3sctl-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.yamlsrc/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml。所有 namespaced 对象必须只落到 unidesk-devfoundation manifest 必须包含 postgres-dev StatefulSet/Service、dev secret/config、迁移 Job 和 DB URL guardcore manifest 必须包含 backend-core-dev/frontend-dev Deployment/ServiceCode Queue dev manifest 必须包含 code-queue-scheduler-devcode-queue-read-devcode-queue-write-dev、dev provider egress proxy,以及只读挂载宿主 /home/ubuntu/.agents/skills 到容器 /root/.agents/skillsskills-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-alpinerancher/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 资源原语。plansmokeapproval 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-devargocd/hwlab-g14-prodhwlab-devhwlab-prod、bounded legacy resource preview、受保护的 hwlab-g14-v02/hwlab-node-v03hwlab-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 headstale 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.jsonlatest-v02-once-job.jsonlatest-v02-dry-run-job.jsonlatest-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/Healthyhwlab-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.jsonmonitor 指针使用 .state/hwlab-g14/latest-v03-monitor-job.jsonlatest-v03-once-job.jsonlatest-v03-dry-run-job.jsonlatest-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 给出 sourceMsruntimeMsgitMirrorMstotalMs;远端 stdout/stderr tail 默认省略,失败时仍展开必要 tail,完整 tail 用 --full,原始 git mirror cache 用 --rawstatus 聚合 source 后会并行读取 runtime 和 git mirror,并向 stderr 输出 agentrun.control-plane.status.progress JSON 事件,覆盖 sourceruntimegit-mirror 的 started/succeeded/failed 和 elapsedMs,避免 10s 以上状态聚合期间无可见进展;trigger-current 先快进 G14:/root/agentrun-v01origin/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-minutesagentrun-v01-ci-* PipelineRun,通过 Tekton ownerRef 回收临时 workspace PVCdry-run 必须输出候选 PipelineRun、owned PVC、active mount 保护、local-path 实际估算 bytes 和 confirm 命令。cleanup-released-pvs 只处理 agentrun-cilocal-pathDelete reclaim policy 的 Released PV,用于 PipelineRun 删除后残留 PV 的二次回收;它不触碰 runtime namespace、业务 PVC、Secret、registry storage 或 GitOps desired state。AgentRun 实现事实来源在 AgentRun 仓库;HWLAB-facing SPEC 正文在 UniDesk OAAgentRun 仓库 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、localV01githubV01localGitopsgithubGitopspendingFlushgithubInSync、exact full-SHA shallow fetch 摘要和 Artificer bundle repo mirror 覆盖状态,不默认展开完整 cache stdout;需要探测 tail 时用 --full,需要原始 cache 输出时用 --rawsync 创建 manual Job,把 GitHub pikasTech/agentrunv0.1 / v0.1-gitops refs 以及 Artificer 默认 bundle repo pikasTech/unideskpikasTech/agent_skillsmaster refs 拉入 /cache/pikasTech/*.gitflush 仍只把本地 pikasTech/agentrunv0.1-gitops 快进推回 GitHub。AgentRun runner 的 ResourceBundleRef / AipodSpec 只写 GitHub URL,不写 gitMirror 字段;mirror 自动改写属于基础设施能力。confirmed sync/flush 默认创建 .state/jobs/ 异步 job 并立刻返回 job.idstatusCommand 和日志路径;只有现场同步调试才显式加 --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.gitrefs/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.modetargetValidation,只检查指定 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.summarytaskRuns.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 revisionapiRevision 是 cloud-api 服务自身 revisionCloud 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.yamlpipeline.yamlargocd/project.yamlargocd/application-v02.yamlconfirmed 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.G14lanes.v02/v03networkProfilesdownloadProfilesstatus 默认输出 expected.configPath、node、network/download profile、有效 NO_PROXY、Docker build proxy、Argo Application 和 runtime workload 摘要,confirmed trigger 创建的 PipelineRun annotation 记录 node/profile id。applytrigger-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.localGitOps promotion 写 git-mirror-write.devops-infra.svc.cluster.localconfirmed 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 matrixhwlab-cli 是固定 repo 短连接源码工具,不进入 PipelineRun service build。 --dry-run 只报告是否会 pre-sync,不创建 Jobconfirmed trigger 默认创建 .state/jobs/ 异步 job 并立刻返回 job.idstatusCommand、stdout/stderr 路径,避免 git mirror pre-sync 或 PipelineRun 创建期间长时间阻塞;--wait 路径也必须向 stderr 输出 hwlab.v02.trigger.progress JSON 事件,覆盖 control-plane-refreshgit-mirror-pre-synccreate-pipelinerun,避免异步 job 长时间只有启动命令而无法判断卡点;默认 JSON 必须对 manifest_b64、长脚本和远端 stdout/stderr 做有界摘要,保留长度与 hash,最终 trigger 结果只返回阶段摘要和关键 tail,完整内容通过 job stdout/stderr 文件渐进披露;只有现场同步调试才显式加 --wait;旧 rerun-current 只作为输入别名保留。PipelineRun Completed、Argo Synced/HealthywebAssets.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 PostgreSQLhwlab 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-dbhwpod_v03hwpod_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-keystatus 只返回 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 入口;只列并删除 Releasedlocal-pathDeleteclaimNamespace=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 CronJobsync 创建一次性 manual Job,把 GitHub allowlist refs 拉入本地 mirrorflush 创建一次性 manual Job,把本地 v0.2-gitops 快进推回 GitHub。 status 返回 read/write URL、last sync/write/flush、本地 ref、GitHub staging ref 和 pending flush 状态,并在 cache.summary 给出 localV02localGitopsgithubGitopspendingFlushflushNeededgithubInSync 和下一条受控 flushCommand。confirmed syncflush 默认创建 .state/jobs/ 异步 job 并立刻返回可查询状态,只有现场同步调试才显式加 --waitmirror 不设置 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-poollangbotn8n 支持各自 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 upstreamcollector 必须复用 D601 已有 platform-infra namespacecreateNamespace=false--target 选择运行目标,默认 G14 为 active runtimeD601 为同一 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 和探针开发边界。

  • secrets plan|sync|status --config config/secrets-distribution.yaml --scope platform-infra 是平台服务本地 Secret sourceRef 到 Kubernetes Secret key 的受控下发入口。plan 只读展示 sourceRef、必需 key、目标 Secret/key、missingKeys 和 fingerprintsync --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 seriestargets 汇总 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 映射成只读/受控写入的虚拟文本目录,适合日报、PR 正文和 issue 正文的小补丁维护:trans gh:/pikasTech/HWLAB ls 展示 pr/issue/trans gh:/pikasTech/HWLAB/pr ls [--state open|closed|all] [--limit N] [--full] 展示 PR 条目状态、楼层数、正文长度、URL 和标题,trans gh:/pikasTech/HWLAB/issue ls [--state open|closed|all] [--limit N] [--search TEXT] [--label L] [--full] 替代常见 gh issue list --search/--state 读取并输出 URLtrans gh:/pikasTech/HWLAB/pr/507 ls 展示单个 PR 的一楼正文文件,trans gh:/pikasTech/HWLAB/issue/1236 cat 读取 issue 正文,trans gh:/pikasTech/HWLAB/issue/1236 rg 'API_KEY|YAML-first' 在正文内检索,trans gh:/pikasTech/HWLAB/505/1 cat|rg|patch-apply 兼容旧式 issue/PR number route。apply-patch 使用 UniDesk 默认 apply-patch v2 的虚拟文件 executor,把正文一楼映射为 body.md,写回仍走 bun scripts/cli.ts gh issue/pr update 的 guard/concurrency 规则;普通小补丁不需要固定先跑 --dry-run,高风险正文可用 --dry-run 预览。rm 对正文一楼结构化拒绝,避免误删 issue/PR 正文。大正文读取必须展开 UniDesk gh dump 文件,否则 cat/rg/apply-patch 会误读为空,这是 gh: 虚拟文件接口的 P0 可见性契约。

  • 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 dumpstdout 只返回有界摘要。默认 HWLAB CD repo 是 /home/ubuntu/hwlab_cd/home/ubuntu/hwlab runner 历史目录不得作为发布真相。wrapper 强制 KUBECONFIG=/etc/rancher/k3s/k3s.yaml 并只以这个显式目标作为 gate;显式目标出现 docker-desktopdesktop-control-plane127.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-binarymissing-tokenauth-failedgithub-transientnetwork-proxy-failedpermission-deniedrepo-not-foundrepo-forbiddenissue-not-foundpr-not-foundscope-insufficientvalidation-failedinvalid-responseunsupported-command,不得打印 token;失败对象必须包含 runnerDisposition=infra-blocked|business-failedrunner 应优先用该字段分流。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=openlimit=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/hasMorehasMore=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 readpr list)必须结构化失败并指明 gh issue create/list/stale-close 才是合法作用域。GitHub issues API 可能混入 PRCLI 会从 .data.issues 中过滤 pull request。--raw|--fullgh issue list 上是绕过 20 KiB stdout 截断的显式开关:响应结果会带 noDump=trueoutput.ts 据此跳过 head/tail 替换并把完整数据 inline 输出;当响应未超阈值时 --raw|--full 行为等价默认。

  • gh issue lifecycle--state 只能作为 gh issue list / gh issue board-row list / gh pr list 的过滤参数;gh issue update / gh issue edit 只写 body/title不接受 --state 改 open/closed。把 gh issue update <n> --state closed 落到错命令上时,CLI 必须返回 validation-failed 并显式提示 gh issue close <n> / gh issue reopen <n>PR 用 gh pr close|reopen <n>),并把 5 条受支持命令放进 supportedCommands,禁止把"无 --state 改 issue 状态"的命令升级为"接受 --state"。gh issue close|reopen 成功输出默认是 compact issue 摘要,不得回显完整 issue.body;人工正文读取优先使用 trans gh:/owner/repo/issue/<number> cat|rg,需要 JSON 结构化元数据时再使用返回的 readCommandsgh issue view --json body|--full|--raw。生命周期 close/reopen 的评论推荐用 --comment-stdin <<'EOF' 直接写 heredoc/stdin;短单行可用 --comment,已有复用文件才用 --comment-file。需要附长篇 CLI 验收证据时,先用 gh issue comment create <n> --body-stdin <<'EOF' 写证据评论,再用 gh issue close <n> --comment <短引用> 关闭。issue 硬删除走 closePR 硬删除走 close,两者都没有"delete"语义。

  • gh issue comment create <number|owner/repo#number> --repo owner/name --body-stdingh issue comment update|edit <commentId> --repo owner/name --body-stdingh issue comment delete <commentId|owner/repo#number> --repo owner/namegh issue close <number|owner/repo#number> --repo owner/name [--comment <text>|--comment-stdin]gh issue reopen <number|owner/repo#number> --repo owner/name [--comment <text>|--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|readgh pr * 一致的 owner/repo#number 位置 shorthandshorthand 与显式 --repo 冲突时结构化失败并把两者都回显到错误对象里,避免静默改写目标 repo。gh issue view|readgh pr view|read|files|diff|preflight|closeout|comment create|comment update|comment edit|comment delete|close|reopen|merge|edit|update 已长期支持该 shorthandcomment 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 - inactiveHoursissue comment、body/title 修改和 state 变化都会刷新 updatedAt 并视为活跃;PR 必须过滤,不参与 issue 关闭。默认 inactive-hours=48,默认扫描预算为 issue list 上限,输出必须包含 observedAtcutoffAtscannedCountstaleCountpagination.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 title/body/state/url 和 comments,默认输出 JSONread 只保留为 UniDesk 兼容别名。view 对齐 GitHub CLI 标准位置参数:接受正整数、https://github.com/owner/repo/issues/<number> URL 或 owner/repo#number shorthand。--number N 也作为低摩擦兼容别名用于单 issue/comment 数字目标命令,并在成功响应里返回 standardSyntaxHint 提示标准位置参数写法;comment update/edit/delete 中的 --number 表示 commentId,不是 issue numberlist/create/scan-escape/cleanup-plan/board-audit/board-row list 这类没有单数字目标的命令仍拒绝 --number。URL 和 shorthand 会自动派生 --repo owner/repo 与 issue number;若同时提供冲突的显式 --repoCLI 必须结构化失败并给出 gh issue view <number> --repo owner/repo --json body,title,state,comments 与 shorthand raw 的可执行命令。兼容旧脚本的 --json body--json body,title,state,comments 字段选择,且正文仍稳定暴露在 .data.issue.body,避免调用方因为 JSON 路径变化把空值当成正文。字段白名单是 body,title,state,comments,number,url,author,createdAt,updatedAt,未知字段必须结构化失败并带 runnerDisposition=business-failed--raw--full 是显式完整披露别名:view/read 会选择完整支持字段集;issue update/edit 只有显式传入时才在成功响应里包含完整 .data.issue.body。当最终 gh JSON 超过 20 KiB 时,CLI 必须把完整 JSON 写入 /tmp/unidesk-cli-output/*.jsonstdout 只返回 outputTruncated=true、dump path、总 bytes/lines 和 head/tail 预览。默认 list/view 输出仍不得扩散到无界非 JSON 文本。gh issue create --title <title> --body-stdin [--label label[,label...]]... [--dry-run]gh issue update <number> --mode replace|append --body-stdin [--title ...] [--dry-run] [--full|--raw]gh issue comment create <number> (--body-stdin|--body <short-text>) [--dry-run]gh issue comment update|edit <commentId> (--body-stdin|--body <short-text>) [--dry-run]gh issue comment delete <commentId> [--dry-run]gh issue close|reopen <number> [--comment <short-text>|--comment-stdin] [--dry-run]gh issue stale-close [--inactive-hours N] [--dry-run] 都走 REST,不依赖 gh binary。--body-stdin--comment-stdin 是多行 Markdown 的第一等 heredoc/stdin 入口;--body-file / --comment-file 只在已有复用文件时使用。--body 仅用于 issue comment 的短单行文本;空白、多行、疑似 shell 污染、secret-like 或过长 inline body 必须结构化失败。comment update/edit 使用 GitHub issue comment PATCH 端点并保留评论 ID,日常修正文案优先用 update/edit,delete 只用于确实需要删除的评论。--label 用于 issue createissue listissue stale-close,支持重复传入和逗号分隔;issue create --dry-run 会展示解析后的 labels 与 request plan,正式创建时把 labels 放入 GitHub REST create-issue payloadGitHub 返回不存在 label 等 422 校验失败时 CLI 结构化返回 validation-failed,不静默成功。gh issue delete <number> 是结构化 unsupported-command,因为 GitHub REST 不支持 issue 硬删除;生命周期删除语义请使用 close

  • gh issue update <number> --mode replace|append --body-stdin 是正文更新主入口,edit 保留为兼容别名。replace 用 heredoc/stdin 正文替换现有 bodyappend 先读取当前 body,再按 UTF-8 stdin 字节追加,保留真实换行、反引号和 Markdown 表格。更新默认拒绝字面量 null、空白正文和过短正文;只有真实需要写短正文时才允许显式加 --allow-short-body,返回 JSON 会报告该风险。#20 总看板和指挥简报类 issue 是长期 body-only issue--body-profile auto 会按 issue number 自动启用 #20/#24 legacy guard#20 必须包含 ## 看板(OPEN,#24 legacy 指挥简报必须包含 ## 常驻观察与长期建议。显式 --body-profile commander-brief 不再固定 #24;#24 仍兼容,标题为 YYYY-MM-DD 指挥简报(北京时间) 或既有正文首行/关键 heading 表明为每日滚动指挥简报的 issue 也合法,并仍必须包含 ## 常驻观察与长期建议。对非简报 issue 显式使用 commander-brief 会结构化失败为 profile-issue-mismatch--dry-run 不 PATCH GitHub,输出有界 bodyPreview/bodyPreviewLines、新正文长度、SHA、关键标题检查结果、字面量 \n、反引号、Markdown 表格、shell 污染信号、guardconcurrencybodyOnlySafetywouldPatch;若环境里有 GH_TOKENGITHUB_TOKEN,dry-run 还会只读抓取旧正文长度、SHA 和 updatedAt 作为更新前对照。正式写入默认先读取当前 issue,执行 guard 和显式 --expect-* 并发校验,再 PATCH;成功输出 compact issue 摘要、old/new body SHA、updatedAt、bodySource 和 drill-down readCommands,不包含完整 issue.body。完整正文必须显式 --full|--raw 或后续执行 readCommands.body/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 会返回 codeQueueBoardHintgh issue update/edit 20 的 body guard 会拒绝 ## 更新 YYYY-MM-DD HH:mm 北京时间## YYYY-MM-DD HH:mm 北京时间指挥更新### YYYY-MM-DD HH:mm CST... 这类简报段落;把 pikasTech/HWLAB#NHWLAB#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 北京时间 段落发送给 ClaudeQQClaudeQQ 失败不会回滚 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/proxyUNIDESK_COMMANDER_BRIEF_CLAUDEQQ_BASE_URL 只接受 backend-core /api/microservices/claudeqq/proxy 等价路径,非 proxy URL 会结构化为 notification-path-unavailable。可用 UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_ENABLEDUNIDESK_COMMANDER_BRIEF_CLAUDEQQ_TARGET_TYPEUNIDESK_COMMANDER_BRIEF_CLAUDEQQ_USER_IDUNIDESK_COMMANDER_BRIEF_CLAUDEQQ_GROUP_IDUNIDESK_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。兼容字段 missingOpenIssuesclosedInOpenRowsmissingClosedRowsopenInClosedRowsrowValidationWarningsignoredIssuesrecommendedActions 仍保留,但固定为空数组或 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 20gh 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 -> Branchprogress -> 进度,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 movegh 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。输出固定 JSONfindings 会带 bodyKind=issue-body|comment-bodyissueNumberissueIdcommentIdlineNumbercolumnkindsnippetclassification=suspected-pollution|explanatory-mention|risk,用于区分说明性提到 \n 和疑似污染;cleanupSuggestions 只给 dry-run 清理建议、body/comment 定位和 diff-like preview,不 PATCH、不 DELETE、不真实清理历史 comment。gh issue cleanup-plan 是同一只读能力的别名,默认 dryRun=truegh 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|--fullgh pr list 上等价 gh issue list --raw|--full:响应带 noDump=true,inline 输出完整数据,绕开 20 KiB stdout 截断。mergeablemergeStateStatusstatusCheckRollup 不属于 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 filesfilesReturnedsummary.files/additions/deletions/changes/commitstruncationnext.command,默认不输出 raw diff 或 patchgh 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,statusCheckRollupowner/repo#number shorthand 和冲突 --repo 规则与 issue view/read 相同。stateDetail 是 UniDesk 归一化生命周期值 open|closed|merged,用于区分 REST state=closed 中的普通关闭和已合并;closedclosedAtmergedmergedAtmergeCommitheadRefNamebaseRefName 都来自 REST,不需要 GraphQL。mergeablemergeStateStatusstatusCheckRollup 只在 view/read 明确请求这些字段或用 --raw|--full 显式完整披露时通过 GitHub GraphQL 查询,GraphQL 权限不足或网络失败会结构化失败;GitHub 暂未计算完成时仍保留原始 UNKNOWN/null,并额外返回 closeoutMetadata.ok=falsemissingOrUnknownFields、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=truewritesRemote=falsepolicy.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;输出低噪声 JSONokrepo、PR number、changedFieldsurl、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=truealreadyMerged=truepullRequest.merged=true 和 merge commit 摘要,不再把并发 monitor、GitHub UI 或人工合并后的 closed 状态误报为 validation-failed。

  • gh pr listgh 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,成功输出必须带 standardSyntaxHintcomment delete 中的 --number 表示 commentId,不是 PR numberlist/create 不能静默忽略 --number

  • PR dry-run/probe 的最小手动序列是:bun scripts/cli.ts gh auth status --repo pikasTech/unidesk 只读检查 token 来源、GitHub REST egress、repo 可见性和 issue readbun scripts/cli.ts gh pr create --repo pikasTech/unidesk --title <title> --body-stdin --base master --head <head> --dry-run <<'EOF' ... EOF 检查创建计划;bun scripts/cli.ts gh pr list --repo pikasTech/unidesk --state open --limit 5 --json number,title,state,url,head,basebun scripts/cli.ts gh pr files <number> --repo pikasTech/unidesk --limit 30bun scripts/cli.ts gh pr view <number> --repo pikasTech/unidesk --json body,title,state,stateDetail,closed,closedAt,merged,mergedAt,mergeCommit,head,base,headRefName,baseRefName,mergeable,mergeStateStatus,statusCheckRollupbun scripts/cli.ts gh pr preflight <number> --repo pikasTech/unidesk 做只读 PR 观察、文件统计和收口元数据检查;bun scripts/cli.ts gh pr edit <number> --repo pikasTech/unidesk --title <title> --body-stdin --dry-run <<'EOF' ... EOF 检查低噪声 PR 标题/正文编辑计划;bun scripts/cli.ts gh pr comment create <number> --repo pikasTech/unidesk --body-stdin --dry-run <<'EOF' ... EOF 检查评论计划;bun scripts/cli.ts gh pr merge <number> --repo pikasTech/unidesk --dry-run 检查 guarded merge plan,真实 merge 只能在任务边界明确允许且 preflight ready 后执行。Code Queue runner 可用 bun scripts/code-queue-pr-preflight-example.ts --repo pikasTech/unidesk --base master --head <head> --comment-pr <number> 一次性跑只读 auth status 与 PR 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;只有现场同步调试才显式加 --waitrun 手动创建每 commit 检查和 Code Queue 只读性能门禁;publish-backend-corepublish-user-service 从 pushed Git commit 构建并发布 127.0.0.1:5000/unidesk/<service>:<commit> commit-pinned artifacts,输出 artifactSummary(含 serviceIdsourceCommitsourceRepodockerfileimageReftagdigestdigestRef),但不部署生产;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 listschedule getschedule runs --limit Nschedule runs <scheduleId> --limit N 是只读观察入口;schedule runschedule retry-runschedule deleteschedule upsert-pgdata-backup 会触发运行或写入配置,生产恢复时必须有明确授权。schedule runs --limit N 是全局历史视图,返回 scope=globalscheduleId=nullschedule 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 超时也必须返回 newRunIdobserveCommandschedule retry-run <failedRunId> 只接受 failed run,从原 run 反查 scheduleId 后重触发同一 schedule,并输出 originalRunIdscheduleIdnewRunIdobserveCommand。当 backend-core 目标容器缺失或只观察到 verify-only 容器时,schedule/microservice 命令必须以非零退出并返回 failureKind=target-stack-not-runningrunnerDisposition=infra-blockedreadOnlyCommandsauthorizationRequiredForRecovery,不得把 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 session 控制入口。UniDesk CLI 是 render-only client:客户端保留 k8s 风格命令解析、human 表格、生命周期摘要、下一步命令、分页、-o json|yaml 稳定客户端 schema 和错误展示;AgentRun 服务端只提供稳定 RESTful API、鉴权和业务事实,不承载 UniDesk CLI 渲染。日常查看用 get tasks --queue commanderdescribe task/<taskId>events run/<runId>logs session/<sessionId>result run/<runId> --command <commandId>;日常写入用 create task --aipod Artificer --prompt-stdinapply -f -dispatch task/<taskId>send session/<sessionId>ack/cancel task|session/<id>。用户级 CLI 取消 turnsteer 路径;send session/<sessionId> 是唯一 session follow-up 写入口,AgentRun 服务端按 durable session/run/command 状态自动决定内部 steer 或新 turn,dry-run 必须真实返回这个 decision 且不写状态。兼容 group queue|runs|commands|runner|sessions|aipod-specs 也走同一 direct HTTP transport--raw 只披露直连 AgentRun REST envelope。

  • agentrun 资源原语的默认 transport 是直连 AgentRun REST API,配置来源是 UniDesk 自有 YAML config/agentrun.yaml。鉴权可以复用 HWLAB_API_KEY 的环境变量/固定文件发现风格,但不得依赖 HWLAB runtime、HWLAB backend-core、HWLAB frontend 代理或 SSH official CLI;多一层转发会增加故障面,不能作为正式路径。agentrun control-plane ...git-mirror ... 仍属于 G14 source/runtime 运维控制路径,可以继续使用 UniDesk SSH capture bridge;这些控制面路径不得反向成为 queue/session 资源原语的默认 transport。

  • agentrun control-plane expose --dry-run|--confirmconfig/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 vhostG14 frpc Deployment/ConfigMap 必须由 AgentRun deploy/deploy.json + GitOps render 管理,不能在 UniDesk 侧手写 Kubernetes manifest。

  • codex submit/enqueuecodex steercodex resumecodex queue createcodex queue mergecodex move、旧 Web 提交表单、旧队列管理和旧 workdir 管理是冻结的 legacy Code Queue 写入口。CLI 必须返回 ok=falsefrozen=truedegradedReason=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 视图,显式分出 schedulerPreflightactiveRunnerPrCapability,并附带 commandsdisclosure,方便先看 scheduler auth 缺口、再看当前 runner/dev container 的 gh auth statusgh 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=falserunnerDisposition=infra-blockeddegradedReason=auth-broker-neededtokenCoverage.missing 同时列出 GH_TOKENGITHUB_TOKEN,并输出 authBroker.source="broker/auth-broker-needed"capability.source="missing-token"。该 auth-missing 的 scope 是 scheduler-runner-env,不能简化成“当前 active runner/dev container 不能创建 PR”;默认视图必须带 scopeBoundaryactiveRunnerPrCapability。GitHub DNS/API 连接失败应归类为 failureKind=github-transientdegradedReason=github-dns-api-transient,并带 retryable=truecommanderAction=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-coreunidesk-databasebaidu-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--tracecodex 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 overviewterminal unread 详情必须通过 codex unreadcodex tasks --unread --view supervisor--view full--full 或 per-task codex read <taskId> 获取。默认 supervisor 保持旧低噪声分区视图,只返回 activeRunningrunningcompletedUnreadrecentCompletedqueuedactivitycommanderConcurrencyexecutionDiagnostics 的紧凑行;activeRunning.count 是 running+judging 的状态计数,exact=true 时来自 queue summary countsrunning.returnedactiveRunning.rowPage.returned 只是本次返回的紧凑行数。commanderConcurrency.activeRunnerCount 是并发策略应使用的 active/running 计数,等于 activity.effectiveActiveTaskCount15 并发策略按 15 - activeRunnerCount 计算剩余窗口。commanderConcurrency.splitBrainDisposition=live-count-as-active 表示 split-brain 有 fresh heartbeat 证据,应继续监督并计入 active;interventionRequired=true 才提示介入。确定性分类只在有强基础设施故障信号时输出 infrastructure-blocker;普通 runner/CLI/治理上下文归入 infra-governanceworkflowunknown,避免把历史任务误报为基础设施阻塞。supervisor prompt/body 只给短预览和原始字符数,running/completedUnread/queued 默认只返回一个有界小页并通过 section commands.next 继续分页,recentCompleted 默认限量且不重复 completedUnread 未读终态,不嵌入完整 Trace、final response 或全量 overview。--limit 在 commander/supervisor 中主要是扫描/分页预算,不是返回几十条肥行的开关;CLI 安全上限是 100,输出会在 filters.requestedLimitfilters.effectiveLimitfilters.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 -> succeededcancelled -> canceledretry-wait|retrying -> retry_waitpending -> 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 fulllist 中展开。默认输出仍保留一次性的 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;响应会返回 nextAfterSeqpreviousBeforeSeqhasMorehasBefore 和下一页/上一页命令,默认 --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 行提示 commandOmittedLinesbodyOmittedLinesrawSeqs 时,用该命令按 seq 补取信息。默认是低噪声 raw-output 摘要:即使传入很大的 --limit,非 --full-text 也会限制返回行数和单条文本预览,并在 disclosure.limitCappedrequestedLimiteffectiveLimitcommands.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.skillsdevReady.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/promptHashdelivery.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 createqueue mergemove 等旧队列写入口冻结并返回 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 list [--limit N] [--include-command]job status <jobId|latest> [--tail-bytes N] 查询 .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 和 PipelineRunhwlab_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|flushagentrun_v01_git_mirror_sync|flush 的 progress 必须暴露 sync/flush 状态、Job 名、pendingFlush 与 fetch/push/total/SSH timing,并给出对应 repo 的 mirror status 命令。

  • debug healthdebug ssh-pool <providerId>debug dispatchdebug 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 开发、Playwright wrapper、trans <route> playwright、HWLAB web-probe run|script、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> 查询进度和尾部输出。

异步 job 的返回值只表示控制动作已经排入后台执行,不表示目标运行面对象已经创建或收敛。所有带 statusCommand 的返回都必须先用 job status <jobId> 查看 progress.stageprogress.stageStatus、关键对象名和 nextCommand;只有 progress 已进入对应创建/完成阶段后,才进入更重的运行面 status。对于 hwlab g14 control-plane trigger-current --lane v02 --confirmprogress.pipelineRun 在 refresh 或 mirror pre-sync 阶段可能只是预期 PipelineRun 名称;在 progress.stage=create-pipelinerunprogress.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 和 githubInSyncnode-scoped flush 的 progress 若出现 partialSuccess=push-succeeded-fetch-failed,先看是否同时有 partialSuccessRecovered=truepostPushRecovery,未恢复时再按 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 rebuildserver startserver stop 一样必须通过返回的 job id 确认结果;不要把连续 server rebuild 命令理解成“前一个重建已完成”,因为两个命令只是在快速创建异步 job。重建 frontend 只保留为维护/非标准路径;标准 frontend 发布必须先运行 ci publish-user-service --service frontend --commit <full-sha>,再运行 deploy apply --env dev --service frontenddeploy apply --env prod --service frontend,并验证 /health.deploy.commit。重建 dev 入口薄代理使用 bun scripts/cli.ts server rebuild dev-frontend-proxy,随后验证 server statusurls.devFrontendhttp://127.0.0.1:18083/health;重建 Todo Note 后端使用 bun scripts/cli.ts server rebuild todo-note,随后用 microservice health todo-notemicroservice proxy todo-note /api/instances 验证;重建 Code Queue Manager 使用 bun scripts/cli.ts server rebuild code-queue-mgr,随后用 microservice health code-queue-mgrmicroservice health code-queuecodex tasks --view commander --limit 5 和冻结的 codex submit 返回 legacy-code-queue-frozen 验证主 server 控制面路径;重建 Project Manager 后端使用 bun scripts/cli.ts server rebuild project-manager,随后用 microservice health project-managermicroservice proxy project-manager /api/projects 验证;重建 Baidu Netdisk 后端使用 bun scripts/cli.ts server rebuild baidu-netdisk,随后用 microservice health baidu-netdiskmicroservice proxy baidu-netdisk /api/transfers 验证,但该命令只保留为维护/非标准路径;重建 OA Event Flow 后端使用 bun scripts/cli.ts server rebuild oa-event-flow,随后用 microservice health oa-event-flowmicroservice proxy oa-event-flow /api/diagnostics 验证。D601 Code Queue 执行面和 Decision Center 后端由 D601 k3s/k8s 控制面代管;persistent dev backend-core、frontend 和 Decision Center 都走 artifact consumer,当前 Code Queue 仍不得通过维护通道直连 D601 做部署。不得把 docker rm 手工兜底当成正式交付步骤。

新部署入口优先使用 deploy applydeploy apply --env dev --service backend-core 是 D601 k3s artifact consumer,消费 ci publish-backend-core 产出的成品镜像;deploy apply --env dev|prod --service frontenddeploy apply --env dev|prod --service baidu-netdiskdeploy apply --env dev|prod --service decision-center 是 artifact-consumer 样板;旧的 codex deploy 已禁用;后续 Code Queue 等 D601 服务部署应另行收敛到同一类受控 CD 路径,部署后用 live commit 校验证明不是旧服务。

Output Contract

每条命令的最外层 JSON 包含 okcommanddataerror。失败时 CLI 设置非零退出码,但仍然输出 JSON 错误对象;错误对象应包含 namemessage 和可用的 stack

诊断命令默认采用渐进披露:server logsjob list/statuscodex task/trace/outputmicroservice health code-queuemicroservice proxy 都必须有默认条数、字节数或文本预览上限;用户显式传 --limit--tail-bytes--full-text--raw--full 才扩大单次输出。CLI stdout 遇到下游 pipe 关闭的 EPIPE 必须安静退出,不得打印 Bun stack trace。

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

Todo Note 写操作 CLI 范式(2026-06-01 #190 固化)Todo Note microservice 写不走 REST 集合(如 /api/instances/:id/todos),所有 task 写都走 action 队列 POST /api/instances/:id/actions + body {action: {type, ...}}。常见范式:

# 标记完成 / 取消完成
bun scripts/cli.ts microservice proxy todo-note \
  /api/instances/<id>/actions --method POST \
  --body-json '{"action":{"type":"toggleTodoCompleted","todoId":"todo_xxx"}}'

# 新增 todo
bun scripts/cli.ts microservice proxy todo-note \
  /api/instances/<id>/actions --method POST \
  --body-json '{"action":{"type":"addTodo","title":"..."}}'

# 改名 / 改 reminder / 删除 / 移动:换 type 即可,见 docs/reference/microservices.md
# 撤销 / 重做
bun scripts/cli.ts microservice proxy todo-note /api/instances/<id>/undo --method POST
bun scripts/cli.ts microservice proxy todo-note /api/instances/<id>/redo --method POST

看到 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.com/Lyon1998/todo_note 的 catch-all handler 当前把任何未注册路径都回 404 {"ok":false,"error":"Todo Note is running in backend-only mode"},与 TODO_NOTE_BACKEND_ONLY=1 的真实语义(只关 Vite 前端)混淆。backend-core 的 /api/microservices/todo-note/proxy/... 同源代理看到这个特征时会把响应 body 改写成结构化诊断;CLI 侧保留相同改写作为本地/旧 runtime 兜底:

{
  "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: truerewriteReason 和原始 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。命令样例:

# 命中:POST /api/instances(创建清单)
bun scripts/cli.ts microservice proxy todo-note /api/instances --method POST --check-path

# 命中:POST /api/instances/<id>/actionsaction 队列写)
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.tsTODO_NOTE_WRITABLE_ENDPOINTS / matchTodoNoteEndpoint / rewriteTodoNoteMisleadingRouteNotFound / runTodoNoteCheckPath,以及 scripts/src/e2e.tsmicroservice: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' ... EOFheredoc quoted 防 shell 展开),再 bun scripts/cli.ts microservice proxy todo-note .../actions --method POST --body-file /tmp/x.json。已交互验证 200 OK 全套 write actionsaddTodo / 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 APIissue/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-cachex-unidesk-proxy-modex-unidesk-upstream-proxy-mode 分布和 min/p50/p90/p95/maxprovider-gateway 长连接数据面验收应看到 proxyModeCounts.provider-ws-http-tunneladapter 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-readyprovider-gateway-upgrade-requiredprovider-data-pool-exhaustedprovider-data-pool-not-ready 分类;它是 trans/tran 出现 tcp-pool transient hint 后的首选低噪声探针。debug dispatch 会通过 backend-core 容器内置 helper 访问 backend-core /api/dispatchcore 再通过 WebSocket 将 docker.psprovider.upgradehost.sshmicroservice.httpecho 任务下发给 provider gateway,因此它可以验证核心调度闭环,同时不需要公开 core REST API,也不要求 frontend 容器携带调试 broker。provider.upgrade 默认使用 mode: "plan" 预检;需要验证一键升级时必须显式加 --mode schedule,并通过 --wait-msdebug task 确认任务进入 succeeded、result 中包含 updater 容器信息和 policy: "always-enabled"host.ssh 默认使用 mode: "probe" 做短超时维护桥自检;需要执行明确命令时使用 --ssh-command 进入 mode: "exec",并配合 --wait-msdebug task 查看 stdout、stderr、exitCode 与 probeLine。microservice.http 只用于开发调试 provider-gateway 私有 HTTP 代理,正式用户入口应使用 microservice CLI 或 frontend 的用户服务页面。

SSH Command

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

trans --helptrans <providerId> --help 是本地 JSON 帮助命令,必须快速返回;不能把 --help 解析成 Provider ID,不能打开交互 shell,也不能等待 provider 会话。

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

#!/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 --branchtrans D601:k3s kubectl get pods -n hwlab-devtrans D601:k3s:hwlab-dev:hwlab-cloud-web exec --cwd /tmp -- pwdtran 是历史兼容 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 单进程命令必须走 argvexec 或已知直接子命令。scriptshell operation 已移除并会失败;不得用 --shell bash 或旧名绕过显式 shell 选择。shbash 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 --branchtrans G14:/root/hwlab-v02 sh -- 'git fetch origin v0.2 && git pull --ff-only origin v0.2'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.difftrans 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 SHtran G14 sh -- 'cd /home/ubuntu/workspace/unidesk-dev && ...'trans G14 script -- '...'trans G14 shell '...'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/hwlabG14:/root/hwlab-v02)时,route 必须显式带 workspaceCLI 的 pwd 输出、后续 apply-patch 的相对路径和 sh/bash 的 cwd 全部跟随该 workspace;切换 workspace 必须切换 route,不允许在同一次 trans 链里再 cd
  • 本规则覆盖所有 host workspace 形态,包括 G14:/root/hwlabG14:/root/hwlab-v02G14:/root/agentrun-v01D601:/home/ubuntu/workspace/unidesk-devD601:/home/ubuntu/workspace/hwlab-devprovider-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_SECONDSUNIDESK_TRAN_RUNTIME_TIMEOUT_MSUNIDESK_SSH_RUNTIME_TIMEOUT_MS 只能把超时调小,不能调大超过 60 秒。到点后 wrapper、backend-core broker 或 frontend websocket 路径会主动断开并在 stderr 输出 UNIDESK_TRAN_TIMEOUT_HINTUNIDESK_SSH_RUNTIME_TIMEOUT,提示改用短查询加轮询。长时间 CI/CD、Tekton/Argo 观察、trace/result、日志 tail、构建下载和硬件任务都必须按 submit-and-poll/短查询语义拆成多次 trans 调用;不得让单个 trans 挂着等待最终完成。本规则的跟踪 issue 是 pikasTech/unidesk#187

长任务的标准形态是:用一次短 trans <route> shtrans <route> bash 启动目标侧 job、后台进程、PipelineRun 或受控命令,并把 job id、日志路径、状态文件或 Kubernetes 对象名写到目标侧;后续用多次短 trans 查询 statuslogs --tailkubectl 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 webagent inspect --trace-id <traceId> 取证。关闭 context-loss、AgentRun 复用或多轮会话类 issue 时,证据至少应记录 conversationIdsessionIdthreadIdtraceIdrunIdcommandId 和关键 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、transientEnvrunIdcommandId。当前 HWLAB v0.2 资源装配需求以 UniDesk OA 的 Runtime装配HWLAB接入 为权威: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 的 shelltrans 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、镜像构建、Rust/Go 编译、Code Queue runner 实测仍必须在 D601、CI runner 或目标运行面执行,backend-core 主 server 上线受控编译例外按 docs/reference/dev-environment.md 单独处理。若 trans/tran/SSH 文件传输遇到 provider-gateway 单次 stdin、argv 或 stdout 限制,先在 CLI 客户端做分块、SHA-256 校验、失败可观测输出和最小真实闭环;只有 client 侧不能解决且有证据时,才改 provider-gateway。文件传输默认按 1MiB raw chunk 读写,避免 100MiB 大文件被 45KiB 小块和 base64 全量暂存拖慢;upload/download 成功 JSON 中的 verified=trueverification.automatic=trueverification.verified=trueverification.match.{bytes,sha256}=true 就是端到端完整性证明,调用方不需要再额外手写 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 dispatchtrans/tran/ssh 流式透传还必须要求 provider 声明 host.ssh.tcp-pool。旧 provider 不支持该能力时必须快速失败并输出 provider-gateway-upgrade-required,提示升级 provider-gateway;不得回落到旧 WebSocket 数据路径。provider 已升级但没有可用 data channel 时,错误应区分 provider-data-pool-exhaustedprovider-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_identificationConnection closed by remote host、provider session timeout 或 exit code 255CLI 会在原始 stderr 后追加一行 UNIDESK_SSH_HINT { ... }。该 JSON 不回显原始远端命令,只包含 code=ssh-like-command-frictiontriggertrytriagetry 固定指向显式 sh stdin heredoc 形态,避免把一次 ssh-like 解析/握手摩擦误读成 D601 SSH 整体不可用。ssh/trans/tran 在失败路径识别到 tcp-pool 数据面问题时会追加 UNIDESK_SSH_TCP_POOL_HINT { ... }failureKind 固定分为 provider-data-channel-closedprovider-data-channel-missingprovider-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 包含 elapsedMselapsedSecondstransportinvocationKindexitCode,提示优先排查 provider/session 延迟、远端命令自身耗时、helper bootstrap 或工具层回归。阈值可用 UNIDESK_SSH_SLOW_WARNING_MS=<ms> 临时调节,提示同样不回显原始远端命令。

非交互 ssh/trans/tran 远端命令的流式 stdout 默认有本地输出上限,避免远端日志、PowerShell JSON 或错误对象一次性输出过大导致上下文被淹没;交互登录 shell 不套该上限。超过上限时,CLI 只继续读取远端流并把完整内容写入 /tmp/unidesk-cli-output/*.stdout.bin,本地 stderr 追加 UNIDESK_SSH_STDOUT_TRUNCATED { ... },其中包含 thresholdBytesobservedBytesAtTruncationdumpPathdumpError;stdout 本身只保留上限内的开头内容。默认上限是 256KiB,可用 UNIDESK_SSH_STDOUT_STREAM_MAX_BYTES=<bytes>UNIDESK_TRAN_STDOUT_STREAM_MAX_BYTES=<bytes> 临时调整,最小 4KiB,最大 16MiB。该机制只做渐进披露和完整 dump,不替代远端命令失败判断;看到该 hint 时应优先改成 tail、分页或更窄的结构化查询。

trans <providerId> 透传只在当前 operation 需要 helper 时才注入 /tmp/unidesk-ssh-tools,普通 argvsh/bashkubectllogs 和默认 apply-patch 等路径不得传输无关工具源码。apply-patch-v1 只注入 apply_patchglob 只注入 globskills/skill discover 只注入 skill-discoverapply_patch 接受标准 *** Begin Patch / *** End Patch patch 格式,便于通过 SSH 透传编辑远端仓库文件;远端存在 perl 时必须走快速精确匹配路径,避免大文件 hunk 被 sh 模式匹配拖成几十秒,缺少 perl 时才退回 sh-only 实现。globskill-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

如果只是远端打文本补丁,不需要再手写 ssh D601 'apply_patch' < patch.diff 这种命令拼接;正式默认入口是 trans D601:/absolute/workspace apply-patch < patch.difftrans D601:k3s:<namespace>:<workload>[:<container>] apply-patch --cwd /workspace < patch.difftrans D601:win/c/test apply-patch < patch.diff。旧 helper 只有 apply-patch-v1 一个入口,附加参数会原样透传给远端 apply_patch,例如 trans D601 apply-patch-v1 --helptrans D601 apply-patch-v1 --allow-loose < reviewed.patch。标准单命令用法如下,不需要先创建本地 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

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。

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 示例:

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,避免字符串转义问题。典型用法:

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

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

这个入口的目标是分布式调试的“0 shell-command-string”路径:本地 shell 只负责 heredoc/stdinUniDesk 只负责 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.yamlpod 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,包含 noderootscountsskillsroots 会显示每个候选 skill 根目录是否存在、扫描到多少 skill 以及错误;skills 会给出 scopenamedescriptionpathskillMd 和可转换时的 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 挂载层。

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

Windows 工具链透传的 wrapper、路径转换、是否修改 skill、是否额外安装依赖等长期规则见 docs/reference/windows-passthrough.mdtrans 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。典型用法:

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 展开。典型用法:

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 维护桥,后续 pwdgitshbashapply-patch 和旧 apply-patch-v1 fallback 等操作仍按同一套 operation parser 执行。<provider>:host:/absolute/workspace 是等价长写法;workspace 必须是绝对路径,远端是否存在由维护桥实际 cd 失败或成功证明。

当前稳定 plane 包括 wink3swin plane 的 operation 是 Windows 操作,不是 POSIX shell 别名:<provider>:win ps 在 WSL provider 上启动 Windows PowerShellstdin heredoc 会被写入临时 .ps1 后执行;<provider>:win cmd 启动 Windows host 的 cmd.exestdin 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"win32 不是合法 plane,调用者必须改用 win

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

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] 是 Windows 用户 skill 发现入口,默认只读取当前 Windows 用户的 %USERPROFILE%\.agents\skills,输出 JSON 中包含 rootscounts 和每个 skill 的 namepathskillFiledescription。需要同时检查 %USERPROFILE%\.codex\skills 时显式加 --scope all;不要为了列 skill 手写 cmd dir 或宽泛扫描整个用户目录。

D601:k3sG14: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-apipod/<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 -- pwdkubectllogsshbashapply-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 ...。定位和操作必须保持分离,kubectllogsshbashapply-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 shbash 执行带 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] shbash 把本地 stdin 作为 pod 内 shell 脚本执行;<provider>:k3s:<namespace>:<workload>[:container] apply-patch --cwd /workspace 是 pod 内文本 patch 默认入口;旧 helper 仅通过 <provider>:k3s:<namespace>:<workload> apply-patch-v1 显式调用。典型用法:

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 语法时优先改用 shbash operation,把脚本走 stdin,而不是把 kubectl exec ... -- sh -c ... 放进远端命令字符串。pod 内文本热修默认使用 workspace route 加 apply-patch,不要求目标容器自带 python3node 或仓库里的工具脚本;旧 apply-patch-v1 operation 仍使用同一个 sh helper,只作为显式 legacy fallback,不用于二进制改写。

trans <providerId> argv <command> [args...] 是通用 argv 安全拼接入口;exec 是同义入口。它是非交互远端单进程命令的默认成功路径,不需要 shell 管道时直接传命令和参数,例如 trans D601 argv true。需要管道、重定向、变量展开或多条命令时,优先改用 trans <providerId> sh <<'SH'apply-patchfindglob 和旧 apply-patch-v1 fallback 有专用入口;gitrggrepsednlstatdulscatheadtailwcpwd 可以直接作为 trans 子命令使用,CLI 会对每个 argv token 做 shell quoting。旧的自由 ssh-like 远端命令入口只保留为近似原生 ssh 的人工兼容路径。

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

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 healthdebug dispatchdebug taskartifact-registry status|healthci publish-user-service --dry-runmicroservice list/status/health/diagnostics/tunnel-self-test/proxydecision upload/list/show/healthdecision requirement list/upsertdecision diary import/list/history/months/show/edit/upsertcodex task <taskId>codex taskscodex unreadcodex queuescodex output <taskId>codex judge <taskId> --attempt Nssh <PROVIDER_ID> <remote-command>microservice status/health/diagnostics 经 frontend 远程传输时也复用本地 CLI 的默认 compact summarymicroservice 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 bridgestdout/stderr 按字节流直通到调用端,不经过 /api/dispatch/api/tasks 或 task JSON compactfrontend 运行时必须通过 PROVIDER_TOKEN/UNIDESK_PROVIDER_TOKENPROVIDER_TOKEN_FILE/UNIDESK_PROVIDER_TOKEN_FILE 读取 provider token,并且不能把 token 下发给 runner。因此 D601 Code Queue runner 内的 tran G14 ... 应与主 server 本机 trans G14 ... / tran G14 ... 在输出完整性上保持同一语义。非交互单进程命令优先 trans D601 argv trueapply-patchsh/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.sshhostSshConfigured=truehostSshKeyPresent=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 15000bun 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”作为计算节点自测的前置条件。