Files
pikasTech-unidesk/docs/reference/cli.md
T
2026-05-20 12:52:58 +00:00

43 KiB
Raw Blame History

UniDesk CLI Reference

UniDesk 的统一 CLI 入口是根目录 scripts/cli.ts,运行方式固定为 bun scripts/cli.ts <command>。CLI 默认输出 JSON,所有成功和失败路径都必须向 stdout 写出结构化对象,避免无输出造成状态不可观测。

CLI 可以从 master 快速演进,但必须兼容 deploy.json 固定的 CI/CD server 和生产运行面。CLI/server 能力协商、unsupported-version 失败语义和 release-line 边界由 docs/reference/release-governance.mdGitHub issue #6 约束。

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 传输。
  • config show 读取并校验根目录 config.json,不从环境变量、默认值或隐藏文件静默补配置。
  • check 默认只执行轻量配置校验、Bun 版本检查和 Bun Transpiler 语法解析(覆盖 CLI 入口、主要 scripts/ 模块和核心组件入口,不做类型推导);关键文件存在性、scripts/ TypeScript 类型检查、src/components/ TypeScript 类型检查、Docker Compose config 和日志轮转策略扫描默认不启用,分别通过 --files--scripts-typecheck--components--compose--logs 开启,或用 --full 一次性开启。--rust 只允许在 D601 CI/dev execution 中配合 UNIDESK_D601_RUST_CHECK=1 使用,长期规则见 docs/reference/dev-environment.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 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 迭代不得用 server rebuild backend-core 在 master server 编译,规则见 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 ...] 是只读多信号健康裁决入口,会把单路径 provider is not online、SSH 超时、registry 失败和 service proxy 失败归类成 runner-local-observation-gapservice-degradedprovider-degradedglobal-blocker,且默认提供 debug healthdebug dispatch <providerId> host.ssh --wait-ms 15000ssh <providerId> argv trueartifact-registry health --provider-id <providerId>microservice health k3sctl-adaptermicroservice health code-queuecodex tasks --view supervisor --limit 20 作为推荐交叉验证命令。
  • ssh <providerId> [ssh-like args...] 通过 backend-core 内网 WebSocket broker 和 provider-gateway 的 Host SSH / WSL SSH 维护桥连接目标节点;无后续参数时进入远端登录 shell,有后续参数时按 ssh 远端命令体验执行并返回远端 exit code。
  • ssh <providerId> apply-patch [tool args...] < patch.diff 直接调用远端注入的 apply_patch 工具,并把本地 stdin 中的标准 *** Begin Patch / *** End Patch patch 流透传给目标节点。
  • ssh <providerId> py [script-args...] < script.py 把本地 stdin 落到远端临时 .py 文件后再以 python3 -u 执行并自动清理,避免再手写 'python3 -'、heredoc 或多层引号;script-args 会按 argv 安全透传给远端脚本。
  • ssh <providerId> skills [--scope all|wsl|windows] [--limit N] 发现目标节点上的 WSL/Linux skill 根目录;当 provider 是 WSL 时同一次调用还会扫描 Windows 用户目录下的 .agents/skills.codex/skills
  • microservice list/status/health/diagnostics/tunnel-self-test/proxy 通过 backend-core 内网 API 管理挂载在计算节点 Docker 或 k3s 控制面中的用户服务(底层命令名仍为 microservice);healthdiagnosticstunnel-self-testproxy 会走真实 backend-core -> provider-gateway 或 k3sctl-adapter -> 节点服务链路,proxy 支持受控 JSON 请求体并对超大响应 body 默认输出有界预览,规则见 docs/reference/microservices.md
  • decision upload/list/show/health 通过 backend-core 用户服务代理访问 D601 k3s Decision Center,用于上传会议记录/决议 Markdown、列出权威记录、查看详情和健康检查;decision requirement list/upsert 在同一 records 模型上管理 goal|decision|blocker|debt|experiment 需求记录。它们不得直连 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/months/show 分别用于按月/日期查询、列出月份和查看单日正文;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 单一路径校验或更新已支持目标;deploy plan --env dev|prod 只从 origin/master:deploy.json#environments.<env> 读取 manifest 并输出 dry-run 环境计划,不使用本地 dirty worktree;当前 deploy apply --env dev 支持 D601 backend-core target-side rollout,以及 frontend/baidu-netdisk/decision-center 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 时额外执行 kubectl apply --dry-run=client --validate=false -f <manifest>,仍不 apply 资源。
  • 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
  • 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-failednetwork-proxy-failedpermission-deniedrepo-not-foundrepo-forbiddenissue-not-foundpr-not-foundscope-insufficientvalidation-failedinvalid-responseunsupported-command,不得打印 token;失败对象必须包含 runnerDisposition=infra-blocked|business-failedrunner 应优先用该字段分流。
  • gh issue list [--state open|closed|all] [--limit N] [--repo owner/name] [--json number,title,state,url,updatedAt,createdAt,author,labels] 通过 GitHub REST 列出 issue,默认 state=openlimit=30,输出稳定 JSON 且不依赖系统 gh binary。--limit 会映射到 GitHub per_page 并限制返回数量,避免一次拉爆上下文;未知 state 或未知 --json 字段必须结构化失败并带 runnerDisposition=business-failed。GitHub issues API 可能混入 PRCLI 会从 .data.issues 中过滤 pull request。
  • gh issue view <number> [--repo owner/name] [--json body,title,state,comments] 通过 GitHub REST 读取 issue title/body/state/url 和 comments,默认输出 JSON;兼容旧脚本的 --json body--json body,title,state,comments 字段选择,且正文仍稳定暴露在 .data.issue.body,避免调用方因为 JSON 路径变化把空值当成正文。字段白名单是 body,title,state,comments,number,url,author,createdAt,updatedAt,未知字段必须结构化失败并带 runnerDisposition=business-failedgh issue create --title <title> --body-file <file> [--dry-run]gh issue update <number> --mode replace|append --body-file <file> [--title ...] [--dry-run]gh issue comment create <number> --body-file <file> [--dry-run]gh issue comment delete <commentId> [--dry-run]gh issue close|reopen <number> [--dry-run] 都走 REST,不依赖 gh binary。gh issue delete <number> 是结构化 unsupported-command,因为 GitHub REST 不支持 issue 硬删除;生命周期删除语义请使用 close
  • gh issue update <number> --mode replace|append --body-file <file> 是正文更新主入口,edit 保留为兼容别名。replace 用文件正文替换现有 bodyappend 先读取当前 body,再按 UTF-8 文件字节追加,保留真实换行、反引号和 Markdown 表格。更新默认拒绝字面量 null、空白正文和过短正文;只有真实需要写短正文时才允许显式加 --allow-short-body,返回 JSON 会报告该风险。#20 总看板和 #24 指挥简报是长期 body-only issue--body-profile auto 会按 issue number 自动启用结构 guard#20 必须包含 ## 看板(OPEN#24 必须包含 ## 常驻观察与长期建议;也可显式使用 --body-profile code-queue-board|commander-brief--dry-run 不 PATCH GitHub,输出新正文长度、SHA、关键标题检查结果、字面量 \n、反引号、Markdown 表格和 shell 污染信号;若环境里有 GH_TOKENGITHUB_TOKEN,dry-run 还会只读抓取旧正文长度、SHA 和 updatedAt 作为更新前对照。正式写入可带 --expect-updated-at <updated_at>--expect-body-sha <sha256>,CLI 会先读当前 issue,匹配后才 PATCH,防止旧缓存覆盖新正文。
  • gh issue edit 24 --body-file <file> --notify-claudeqq-brief-diff [--dry-run] 是指挥简报 #24 的通知入口。正式执行会先读取 GitHub 上 #24 旧正文并通过 #24 body profile guard,再从 --body-file 读取新正文;随后先 PATCH issue 主体,再把本次新增的 ## 更新 YYYY-MM-DD HH:MM 北京时间 段落发送给 ClaudeQQClaudeQQ 失败不会回滚 issue 正文,失败只体现在返回 JSON 的 claudeqq.ok=false 和结构化 degradedReason。带通知 flag 的 --dry-run 不 PATCH、不发送;它按新正文做发送预览,并在输出中标明非 dry-run 才会读取旧正文做可靠 diff。默认 ClaudeQQ 目标是私聊 645275593,默认 base URL 是 UniDesk 受控入口 http://backend-core:8080/api/microservices/claudeqq/proxy,可用 UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_ENABLEDUNIDESK_COMMANDER_BRIEF_CLAUDEQQ_BASE_URLUNIDESK_COMMANDER_BRIEF_CLAUDEQQ_TARGET_TYPEUNIDESK_COMMANDER_BRIEF_CLAUDEQQ_USER_IDUNIDESK_COMMANDER_BRIEF_CLAUDEQQ_GROUP_IDUNIDESK_COMMANDER_BRIEF_CLAUDEQQ_TIMEOUT_MS 覆盖。
  • gh issue scan-escape [--repo owner/name] [--limit N] 只读扫描 issue 主体和 comments 中的字面量 \n、可疑 \t、shell newline escape 和 ANSI escape 字符串,输出 issue/comment id、url、kind、snippet,不自动修复。gh pr list|view [--json ...] 提供 REST 列表和详情,PR 字段白名单是 body,title,state,number,url,author,head,base,draft,createdAt,updatedAtgh pr create --title <title> --body-file <file>|--body <text> --base <branch> --head <branch> [--draft] [--dry-run]gh pr update <number> --mode replace|append --body-file <file>|--body <text> [--title ...] [--dry-run]gh pr comment create <number> --body-file <file>|--body <text> [--dry-run]gh pr comment delete <commentId> [--dry-run]gh pr close|reopen <number> [--dry-run] 是 PR CRUD/生命周期入口。pr create --dry-run 只输出 planned operation,不访问 GitHub;非 dry-run 创建前会校验 repo、base、head 和 compare ahead 状态,成功时返回 PR number/url。pr update --mode append 会先读取当前 PR body 再追加正文。gh pr delete <number>gh pr merge 本阶段不开放,始终结构化返回 unsupported-commandPR 生命周期删除语义请使用 close
  • ci install|status|run|publish-backend-core|publish-user-service|run-dev-e2e|logs 管理 D601 原生 k3s 上的 Tekton CI。run 手动创建每 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
  • codex deploy <commitId> 是旧 Code Queue 兼容部署入口,已禁用以防止维护通道直连 D601 部署 Code Queue;当前 dev 自动化只做 ci run-dev-e2e smoke,不提供 Code Queue CD,详细规则见 docs/reference/codex-deploy.md
  • codex submit [prompt] [--prompt-file path|--prompt-stdin] [--queue queueId] [--provider-id id] [--cwd path] [--model model] [--reasoning-effort effort] [--execution-mode mode] [--max-attempts N] [--reference-task-id id] [--dry-run] 通过 backend-core 私有代理向稳定 code-queue 用户服务路径提交任务;prompt 必须且只能来自位置参数、文件或 stdin 之一,--dry-run 只返回结构化请求且不实际入队。提交确认和 dry-run 必须返回完整 prompt、字符数和 truncated=false,不能套用任务详情的预览截断策略,否则长任务 prompt 无法被人工验收。真实提交会经过本机本地串行化保护和短节流,避免同一指挥端并发 submit 把低内存主机或 code-queue-mgr 控制面打抖;返回值会附带 submitConcurrencyGuard 说明本次提交的锁与等待信息。backend-core 默认把提交、队列 CRUD、已读状态、历史摘要和轻量 Trace 读取分流到主 server code-queue-mgr,由它写入主 PostgreSQLD601 scheduler 只轮询并执行已入库任务。
  • codex task <taskId> 通过 Code Queue 私有代理按任务 ID 查询结构化执行摘要;默认只返回有界 prompt/response 预览、执行 Provider、工作目录、最后 assistant message、最近工具调用摘要、attempt、judge、错误、耗时和 trace 翻页提示,适合在新队列任务中引用历史 session 且避免噪声爆炸。该摘要读取默认由主 server code-queue-mgr 从 PostgreSQL 返回,不依赖 D601 code-queue-read Service 可用。
  • codex tasks [--view supervisor|full] [--queue id] [--status succeeded|running|queued|failed|canceled|judging|retry_wait[,..]] [--unread|--unread-only] [--limit N] [--before-id id] 通过同一私有代理输出渐进式披露视图。默认 supervisor 只返回 runningcompletedUnreadrecentCompletedqueuedexecutionDiagnostics 摘要,不嵌入完整 Trace、final response 或全量 overview;每个条目都带 commands.showcommands.tracecommands.outputcommands.readcommands.full--unread--unread-only 的别名,必须只保留未读终态;--status 必须真实过滤支持的状态,未知参数或未知状态必须结构化失败,不能静默忽略。需要完整当前页任务简表时显式使用 --view full--full,仍受 --limit--before-id 分页约束。
  • codex task <taskId> --trace --tail|--from-start|--after-seq N|--before-seq N --limit N 按页拉取 Code Queue 的逻辑 trace;响应会返回 nextAfterSeqpreviousBeforeSeqhasMorehasBefore 和下一页/上一页命令,默认 --trace 取最新一页,需要完整 prompt/最后 response 时加 --full
  • codex output <taskId> --tail|--from-start|--after-seq N|--before-seq N --limit N [--full-text] 按原始 output seq 分页读取底层记录;当 trace 行提示 commandOmittedLinesbodyOmittedLinesrawSeqs 时,用该命令按 seq 补取完整信息,默认仍有单条文本预览上限,显式 --full-text 才返回该页全文。
  • codex read <taskId> 在人工审阅后标记单个终态任务已读;列表、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 <taskId> [prompt|--prompt-file path|--prompt-stdin] [--dry-run] 通过 Code Queue 私有代理向正在运行的 task 注入纠偏提示,正式替代底层 microservice proxy code-queue /api/tasks/<taskId>/steer 调用。prompt 必须且只能来自位置参数、文件或 stdin 之一;--dry-run 只输出将要发送的结构化请求和 prompt 字符数,不触碰运行中 session。真实执行仍走 /api/microservices/code-queue/proxy/api/tasks/<taskId>/steer,只能作用于 D601 scheduler 上存在 active steerable turn 的 running task;若任务不在 running/active-turn 状态,返回上游 409 和有界 task 摘要,不得静默成功。
  • 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] 列表、queue create <queueId> 创建、queue merge <sourceQueueId> --into <targetQueueId> 合并、move <taskId> --queue <queueId> 迁移;这些队列管理入口默认由主 server code-queue-mgr 直管 PostgreSQL,仍通过稳定 code-queue 用户服务代理路径访问。codex queues 默认只返回 active/nonempty/unread/runnable queue 摘要、全局 counts 和 execution diagnostics;完整队列数组必须显式 --full--all。同一个 queue 内部串行执行,不同 queue 之间并行执行。迁移只允许尚未被 scheduler claim 的 queued/retry_wait 任务,必须满足 startedAt=nullcurrentAttempt=0 且没有 active thread/turn;已进入 running/judging 或已有 claim 标记的任务返回 409,不得被 move/merge 回写成 queued。合并会移动可迁移任务归属并自动删除源 queue 记录,只保留合并后的目标 queue;若 source 或 target queue 存在 active/claimed 任务,合并整体返回 409。合并后的目标 queue 按任务原 queueEnteredAt/createdAt 时间顺序串行,成功迁移 queued/retry_wait 任务后由 D601 scheduler 轮询推进。
  • 所有 codex 查询和管理命令必须走与 WebUI 相同的 backend-core 私有代理路径 /api/microservices/code-queue/proxy/...;CLI 不得为了提交、移动、中断、取消或队列管理直接调用 D601 内部 Service、数据库、pod curl 或 k3sctl scheduler 子服务。若该路径失败,应先修复 CLI/backend/provider tunnel 链路,而不是绕过控制面。
  • job list [--limit N] [--include-command]job status <jobId|latest> [--tail-bytes N] 查询 .state/jobs/ 文件系统状态,是异步命令的可观测入口。job list 默认只返回最新 50 条摘要;job status 默认只返回 stdout/stderr 末尾 12000 字节,并带 tailPolicy 与完整日志路径。
  • debug healthdebug dispatchdebug task 走真实内部 core、WebSocket、数据库、provider、系统指标、Docker 状态和 Host SSH 维护桥流程,只用于开发调试,不写入 TEST.md 的正式验收步骤。
  • 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 跑最小必要集合。

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> 查询进度和尾部输出。

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 submit --dry-run 验证主 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 走 target-side dev rolloutpersistent dev frontend 和 Decision Center 走 artifact consumer,当前 Code Queue 仍不得通过维护通道直连 D601 做部署。不得把 docker rm 手工兜底当成正式交付步骤。

新部署入口优先使用 deploy applydeploy apply --env dev --service backend-core 是 D601 target-side dev 路径;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 proxy 都必须有默认条数、字节数或文本预览上限;用户显式传 --limit--tail-bytes--full-text--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。

GitHub issue/PR 写操作必须优先使用 bun scripts/cli.ts gh issue|pr ... --body-file <file>。不要把 Markdown 正文拼进 shell 参数、gh issue comment --bodygh api -f body=...;这些路径容易把真实换行污染成字面量 \ngh issue 写命令第一阶段不接受 stdin 正文;需要从生成内容写入 issue 时,先落到临时 Markdown 文件或已审阅的工作文件,再把该文件路径传给 --body-file。PR 安全写入口同样优先 --body-file--body 只适合短单行内容;update --mode append 用 REST 读取旧正文后追加文件字节,不引入 shell 拼接正文路径。gh pr merge 暂不开放,不存在 --confirm 可绕过的真实 merge 路径。CLI 会按 UTF-8 原样读取文件内容并用 JSON body 调用 REST API。

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 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

ssh <providerId> [ssh-like args...] 是面向人的终端透传入口,不包装 JSON 输出。CLI 会在宿主机启动 docker exec -i unidesk-backend-core backend-core --ssh-broker ...broker 只连接 backend-core 的 Docker 内网 /ws/sshcore 再把 stdin/stdout/stderr 流量通过目标 provider 的既有 WebSocket 转发到 provider-gatewayprovider-gateway 最终执行维护用 SSH 连接宿主或 WSL sshd。TTY 策略固定为交互登录 shell 使用 ssh -tt,带远端命令的会话使用 ssh -T;脚本 stdin、apply-patchpy 这类命令模式不得被伪终端回显或注入控制字符。该入口不新增 core 公网端口,不暴露 database,也不改变 frontend/dev frontend/provider ingress 之外的公网边界。

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

bun scripts/cli.ts ssh D518 应表现为登录 D518 WSL 的 shellbun scripts/cli.ts ssh D518 hostname 应像 ssh D518 hostname 一样只输出远端命令结果并返回远端 exit code。Provider ID 前的目标选择由 UniDesk 节点清单决定,-p-i-l-o 等传统 ssh 传输参数由 provider-gateway 部署配置统一管理,CLI 会兼容性消费这些参数但不会覆盖节点侧维护桥配置。

core 只允许声明了 host.ssh capability 的 provider 使用 ssh 透传或 host.ssh dispatch;旧 provider 不支持该能力时必须快速失败并输出错误,不能把未知命令误判成 echo 成功。

本地 broker 默认等待 provider SSH 会话打开 60000ms,以便在目标节点同时有较多 microservice.http 任务时仍能建立维护会话;需要诊断慢连接时可用 UNIDESK_SSH_OPEN_TIMEOUT_MS=<ms> 临时调大,但最小有效值固定为 15000ms,避免把真实离线误判为长时间阻塞。

ssh <providerId> 会在远端会话启动时注入 /tmp/unidesk-ssh-tools/apply_patch/tmp/unidesk-ssh-tools/glob/tmp/unidesk-ssh-tools/skill-discover,并把该目录加入远端 PATHapply_patch 接受标准 *** Begin Patch / *** End Patch patch 格式,便于通过 SSH 透传编辑远端仓库文件;glob 在远端用 Python 执行路径匹配,避免依赖 shell glob 展开;skill-discover 用于列出远端 Linux/WSL 与 Windows skill。目标节点需要具备 python3base64。注入工具只写 /tmp/unidesk-ssh-tools,不修改目标仓库,交互式 shell 和远端命令都可以直接调用这些工具。

如果只是远端打小补丁,不需要再手写 ssh D601 'apply_patch' < patch.diff 这种命令拼接;正式入口是 bun scripts/cli.ts ssh D601 apply-patch < patch.diffapply-patchpatch 等价,附加参数会原样透传给远端 apply_patch,例如 bun scripts/cli.ts ssh D601 apply-patch --help。标准单命令用法如下,不需要先创建本地 patch 临时文件:

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

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

printf 'import sys\nprint(sys.argv)\n' | bun scripts/cli.ts ssh D601 py foo '--bar=baz'

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

ssh <providerId> skills 是远端 skill 发现入口,也可写作 ssh <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 挂载层。

bun scripts/cli.ts ssh D601 skills --limit 80
bun scripts/cli.ts ssh D601 skills --scope windows --limit 40

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

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

bun scripts/cli.ts ssh D601 find /home/ubuntu --max-depth 4 --type d --icontains pika --limit 50 --sort

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

bun scripts/cli.ts ssh D601 glob --root /home/ubuntu/pikapython --pattern '**/*-test.cpp' --limit 20 --sort

ssh <providerId> argv <command> [args...] 是通用 argv 安全拼接入口;exec 是同义入口。它适合不需要 shell 管道的常用命令。findglobapply-patch 有专用入口;rggrepsednlstatdulscatheadtailwcpwd 可以直接作为 ssh 子命令使用,CLI 会对每个 argv token 做 shell quoting。需要管道、重定向、变量展开或多条命令时仍使用旧的自由远端命令入口,并把整段远端 shell 脚本作为一个本地参数传入。

通过 ssh <providerId> 执行多行脚本时,优先使用结构化 helper,例如 bun scripts/cli.ts ssh D601 py < script.pyprintf ... | (bun scripts/cli.ts ssh D601 'bash -s') 这种单层 stdin 传输。不要在远端命令字符串里再嵌套 heredoc、复杂引号或 ssh 'python3 - <<EOF ...' 形态;多层 shell 解析容易把 stdin 绑定到错误进程,结果会打开远端交互解释器并留下悬挂的 broker/SSH 会话。长脚本需要复用时,优先通过 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 taskmicroservice list/status/health/diagnostics/tunnel-self-test/proxydecision upload/list/show/healthdecision requirement list/upsertdecision diary import/list/months/show/edit/upsertcodex task <taskId>codex taskscodex output <taskId>codex judge <taskId> --attempt Nssh <PROVIDER_ID> <remote-command>。运行中纠偏 codex steer 属于 active run write control,应在主 server 本机 CLI 或显式 SSH 传输上执行,避免公网 frontend 透传限制 stdin/body 审计语义。其中 ssh 的 remote frontend 传输使用 host.ssh dispatch 执行有界远端命令,适合 ssh D601 hostnamessh D601 skills 这类自测;交互式登录 shell 仍应在主 server 本机 CLI 使用,或显式切换到旧 SSH 传输后在主 server 上执行。frontend 远程透传不会流式转发本地 stdin,因此 ssh py < script.pyssh apply-patch < patch.diff 这类 stdin-backed helper 必须在主 server 本机运行,或显式切换到 --main-server-transport ssh。若确实需要旧行为,可使用 --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”作为计算节点自测的前置条件。