fix: require explicit trans shell operations

This commit is contained in:
Codex
2026-06-15 04:01:04 +00:00
parent b2c2819fe2
commit b8fb3c41a8
18 changed files with 241 additions and 273 deletions
+31 -41
View File
@@ -43,14 +43,14 @@ G14/D601 v03 的 bootstrap admin password 是 HWLAB runtime Secret 生命周期
- `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-note``code-queue-mgr``project-manager``baidu-netdisk``oa-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_SERVER``PROVIDER_ID``provider-<ID>.yml` 固定 Docker socket、`pid: "host"``restart: always`、只读 `/workspace` 和 SSH 维护私钥挂载;`--up` 会立即执行生成的 `docker compose up -d --build``provider triage <providerId> [--observed-error text] [--observed-scope scope] [--microservice id ...] [--full|--raw]` 是只读多信号健康裁决入口,会把单路径 `provider is not online`、SSH 超时、registry 失败和 service proxy 失败归类成 `runner-local-observation-gap``service-degraded``provider-degraded``global-blocker`。默认输出只返回裁决、scope、失败/降级/未知信号和有界 evidence 摘要,完整 evidence 必须显式加 `--full``--raw`;推荐交叉验证命令仍包含 `debug health``debug dispatch <providerId> host.ssh --wait-ms 15000``trans <providerId> argv true``artifact-registry health --provider-id <providerId>``microservice health k3sctl-adapter``microservice health code-queue``codex tasks --view supervisor --limit 20`
- `platform-db postgres plan|status|export-secrets|apply --config config/platform-db/postgres-pk01.yaml` 管理 YAML 声明的 PK01 host-native PostgreSQL。`plan``status` 只读采集远端 host、PostgreSQL、TLS、DNS alias 和 Secret 形态;`export-secrets --confirm` 只按 YAML 物化本地 Secret source/export 文件,不触碰远端 PostgreSQL`apply --confirm` 默认创建本地异步 job`apply --confirm --wait` 用远端 root-owned job 收敛 systemd PostgreSQL、TLS、`pg_hba`、role/database、Secret export 和备份 timer。输出不得打印密码或完整 `DATABASE_URL`。跨节点消费者使用 YAML 中的 `connectionHost` 直连 PK01 公网 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,例如 `D601``G14`,也可以扩展为纯定位路径 `provider:plane[:namespace:resource[:container]]`,例如 `D601:win``D601:win/c/test``G14:k3s``D601:k3s``G14:k3s:<namespace>:<workload>`。WSL provider 的 Windows plane 固定使用 `win`,不得使用 `win32`Windows operation 必须显式区分:`ps` 执行 Windows PowerShell heredoc 或一行 PowerShell 命令,`cmd` 执行 cmd.exe/batch`skills` 发现 Windows skill 目录。需要 Windows cwd 时用 `trans D601:win/c/test ps``trans D601:win/c/test cmd cd`CLI 自动设置 UTF-8/Python 编码默认值;`cmd` 额外设置 `chcp 65001`。非交互远端命令优先使用 `trans <providerId> argv ...`;需要 POSIX shell 脚本、管道、变量或循环时优先使用 quoted heredoc 单步传输,例如 `trans G14 script <<'SCRIPT'``trans G14:k3s script <<'SCRIPT'``trans G14:k3s:<namespace>:<workload> script <<'SCRIPT'`,把脚本走 stdin。`script` 只表示 host/k3s POSIX shell,不表示 Windows PowerShellWindows PowerShell 必须写 `trans <provider>:win ps <<'PS'``script -- '<单个字符串>'` 是无需 stdin 的远端 POSIX shell one-liner,例如 `trans G14:/root/hwlab script -- 'cd /root/hwlab && git status --short --branch'``script -- <多个 argv>` 才是 direct argv,适合 `trans D601:/path script -- sed -n '1,20p' file` 这类带短横线的单进程命令。顶层 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,提示 stdin script/argv 重试和 provider triage 交叉验证。
- `trans <route> [operation args...]` / `tran <route> [operation args...]` 通过 backend-core 内网 WebSocket broker 和 provider-gateway 的 Host SSH / WSL SSH 维护桥连接目标节点;`route` 基础形态是 provider id,例如 `D601``G14`,也可以扩展为纯定位路径 `provider:plane[:namespace:resource[:container]]`,例如 `D601:win``D601:win/c/test``G14:k3s``D601:k3s``G14:k3s:<namespace>:<workload>`。WSL provider 的 Windows plane 固定使用 `win`,不得使用 `win32`Windows operation 必须显式区分:`ps` 执行 Windows PowerShell heredoc 或一行 PowerShell 命令,`cmd` 执行 cmd.exe/batch`skills` 发现 Windows skill 目录。需要 Windows cwd 时用 `trans D601:win/c/test ps``trans D601:win/c/test cmd cd`CLI 自动设置 UTF-8/Python 编码默认值;`cmd` 额外设置 `chcp 65001`。非交互远端命令优先使用 `trans <providerId> argv ...`;需要 POSIX shell 脚本、管道、变量或循环时必须在 operation 位置显式写 `sh``bash`,例如 `trans G14 sh <<'SH'``trans G14:k3s sh <<'SH'``trans G14:k3s:<namespace>:<workload> sh <<'SH'``trans D601:/workspace bash <<'BASH'``sh` 明确表示目标 `/bin/sh``bash` 明确表示目标 Bash`script``shell` 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-patch``trans gh:/owner/repo/pr/<number> apply-patch`,而不是人工优先整篇 `gh issue update --mode replace` 或底层 `gh issue patch``gh:/` 路由把 issue/PR body 暴露为一楼虚拟文件 `body.md`route 未显式写 `/1` 时默认一楼正文,`apply_patch``patch-apply` 只作为兼容别名。典型补丁写法是 `*** Update File: body.md`;普通小补丁在已用 `trans gh:/... cat|rg|ls` 确认上下文后可以直接 apply`--dry-run` 只作为高风险大段修改、关闭前验收文案或并发敏感正文的可选预览。写回仍通过 UniDesk `gh issue/pr update` guard 和 REST API,不使用原生 `gh`、手写 REST 或整篇 shell 拼接正文。单条 issue comment 的局部修补当前仍使用 `bun scripts/cli.ts gh issue comment patch <commentId> --body-patch-stdin`,直到评论楼层 route 成为稳定入口。
- `apply-patch` v2 每次结束都会在 stderr 追加一行 `UNIDESK_APPLY_PATCH_TIMING {json}`,字段包含 `durationMs``patchBytes``fileCount``hunkCount``changedCount``remoteOperationCount``remoteOperationCounts``remoteElapsedMs``remoteFailureCount``providerId``route``transport`(可得时)。普通 POSIX host/k3s 和 Windows workspace 远端的多文件 `Update File` patch 会优先合并成 bulk read/write,避免每个文件单独 stat/read/write 的 SSH 往返;Add/Delete/Move 等复杂 patch 保持原有逐步语义。timing 摘要只用于定位慢在 patch 解析、远端 stat/read/write 或 bulk read/write、provider session 还是传输层,不能替代 Codex 标准 stdout/stderr 成功失败文本,也不是门禁或自动判断。
- `trans <providerId> py [script-args...] < script.py` 把本地 stdin 落到远端临时 `.py` 文件后再以 `python3 -u` 执行并自动清理,避免再手写 `'python3 -'`、heredoc 或多层引号;`script-args` 会按 argv 安全透传给远端脚本。
- `trans <providerId> skills [--scope all|wsl|windows] [--limit N]` 发现目标节点上的 WSL/Linux skill 根目录;当 provider 是 WSL 时同一次调用还会扫描 Windows 用户目录下的 `.agents/skills``.codex/skills`
- `trans <providerId>:k3s[:namespace:workload[:container]] <operation> ...` 是原生 k3s 结构化 route 入口,route 只定位控制面或 workload`kubectl``logs``exec``script``apply-patch`、旧 `apply-patch-v1` fallback 和普通容器命令作为 operation 放在 route 之后;CLI 固定注入 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml` 并把 kubectl、workload exec、logs 和 pod workspace 读写参数组装成 argv,避免在 Host SSH、bash、kubectl exec 和容器 shell 之间反复手写多层引号;D601 与 G14 都有 provider-specific guard,分别校验 `d601` 和 G14 k3s 节点身份。
- Code Queue runner 镜像必须在 PATH 上提供 `/usr/local/bin/tran`。runner 内的 `tran` 检测到 `CODE_QUEUE_*``KUBERNETES_SERVICE_HOST` 后,默认执行 `bun /root/unidesk/scripts/cli.ts --main-server-ip <public-frontend> ssh ...`,其中 `<public-frontend>` 优先来自 `UNIDESK_MAIN_SERVER_IP` / `UNIDESK_MAIN_SERVER_HOST` / `CODE_QUEUE_DEV_CONTAINER_MASTER_HOST`。runner remote frontend HTTP 客户端默认使用 `curl` 后端,降低 Bun 在部分 runner 内读取非 SSH HTTP response body 时触发 native crash 的风险;显式 `UNIDESK_REMOTE_HTTP_CLIENT=fetch` 可用于诊断。runner 内跨 D601/G14 的分布式访问应优先使用结构化 route/operation,例如 `tran D601 argv ...``tran G14 argv ...``tran D601:k3s kubectl ...``tran D601:k3s:<namespace>:<workload> argv ...``tran G14:/absolute/workspace apply-patch ...``tran <route> upload|download ...``apply-patch``upload``download``script``py` 和旧 `apply-patch-v1` fallback 经 frontend `/ws/ssh` 通道执行,stdout/stderr 也必须完整直通,不得退回 `/api/dispatch` task JSON。非 UniDesk admin runner 可通过 `UNIDESK_SSH_CLIENT_TOKEN` 使用 scoped `/ws/ssh` client tokenfrontend 侧用 `UNIDESK_SSH_CLIENT_ROUTE_ALLOWLIST` 约束允许 route;该 token 只授予 ssh passthrough,不下发 provider token、主 server SSH key 或完整 frontend 登录态。
- `trans <providerId>:k3s[:namespace:workload[:container]] <operation> ...` 是原生 k3s 结构化 route 入口,route 只定位控制面或 workload`kubectl``logs``exec``sh``bash``apply-patch`、旧 `apply-patch-v1` fallback 和普通容器命令作为 operation 放在 route 之后;CLI 固定注入 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml` 并把 kubectl、workload exec、logs 和 pod workspace 读写参数组装成 argv,避免在 Host SSH、bash、kubectl exec 和容器 shell 之间反复手写多层引号;D601 与 G14 都有 provider-specific guard,分别校验 `d601` 和 G14 k3s 节点身份。
- Code Queue runner 镜像必须在 PATH 上提供 `/usr/local/bin/tran`。runner 内的 `tran` 检测到 `CODE_QUEUE_*``KUBERNETES_SERVICE_HOST` 后,默认执行 `bun /root/unidesk/scripts/cli.ts --main-server-ip <public-frontend> ssh ...`,其中 `<public-frontend>` 优先来自 `UNIDESK_MAIN_SERVER_IP` / `UNIDESK_MAIN_SERVER_HOST` / `CODE_QUEUE_DEV_CONTAINER_MASTER_HOST`。runner remote frontend HTTP 客户端默认使用 `curl` 后端,降低 Bun 在部分 runner 内读取非 SSH HTTP response body 时触发 native crash 的风险;显式 `UNIDESK_REMOTE_HTTP_CLIENT=fetch` 可用于诊断。runner 内跨 D601/G14 的分布式访问应优先使用结构化 route/operation,例如 `tran D601 argv ...``tran G14 argv ...``tran D601:k3s kubectl ...``tran D601:k3s:<namespace>:<workload> argv ...``tran G14:/absolute/workspace apply-patch ...``tran <route> upload|download ...``apply-patch``upload``download``sh``bash``py` 和旧 `apply-patch-v1` fallback 经 frontend `/ws/ssh` 通道执行,stdout/stderr 也必须完整直通,不得退回 `/api/dispatch` task JSON。非 UniDesk admin runner 可通过 `UNIDESK_SSH_CLIENT_TOKEN` 使用 scoped `/ws/ssh` client 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);`health``status``diagnostics` 默认返回 compact summary、body 字节数和 `--full|--raw` 展开命令,只有小 body 或无法抽取 summary 时才带有界 body preview,避免 Code Queue/k3s 诊断一次性输出爆炸;`tunnel-self-test``proxy` 会走真实 backend-core -> provider-gateway 或 k3sctl-adapter -> 节点服务链路。`microservice health code-queue` 使用 commander-safe 专用摘要,必须保留 ok/status、service id、running count、queue count、heartbeat freshness/risk、split-brain/live/degraded 解释和 raw drill-down 命令;需要完整健康 JSON 时显式加 `--raw``--full`,等价深挖路径是 `microservice proxy code-queue /health --raw --full``proxy` 支持受控 JSON 请求体并对超大响应 body 默认输出有界预览,规则见 `docs/reference/microservices.md`
- `decision upload/list/show/health` 通过 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-by``show``requirement update` 可使用 `id``docNo``decision requirement list/create/upsert/update/show` 在同一 records 模型上管理 `goal|decision|blocker|debt|experiment` 需求记录,`docNo` 唯一,未传 `--doc-no` 但提供 `--doc-type/--doc-priority/--year` 时由服务分配下一个序号。它们不得直连 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 PostgreSQL`decision diary list/history` 默认只返回摘要,需要完整 Markdown 时显式加 `--include-body``decision diary show <YYYY-MM-DD|id> [--source-file path]` 查看单日正文,`--source-file` 用于同一天存在多个导入来源时精确选择;`decision diary edit|upsert <YYYY-MM-DD|id> --body-file <path> [--title text] [--source-file path] [--tag tag]` 通过 `PUT /api/diary/entries/:idOrDate` 创建当天或历史条目并编辑既有条目。
@@ -261,35 +261,35 @@ exec /root/unidesk/scripts/trans "$@"
主 server 上的人工/Codex 分布式敏捷操作必须直接写 `trans ...`,不要在 Codex 工具调用里退回完整 `bun scripts/cli.ts ssh ...` 前缀。例如 `trans D601:/home/ubuntu/workspace/hwlab-dev git status --short --branch``trans D601:k3s kubectl get pods -n hwlab-dev``trans D601:k3s:hwlab-dev:hwlab-cloud-web exec --cwd /tmp -- pwd``tran` 是历史兼容 wrapper 和 runner 固化入口;新写长期参考、AGENTS 索引和 CLI help 时优先写 `trans ...`
`trans` 同样遵守 route/operation 解析器;route 后面的第一个 token 不是原生 ssh 命令字符串。不要写 `trans G14:/root/hwlab sh -lc '...'`,因为 `sh` 会被解析为 stdin script helper 的别名,`-lc` 会变成不受支持的 script 选项。带变量展开、管道、重定向或多条命令的远端逻辑,默认使用 `trans G14:/root/hwlab script <<'SCRIPT'`;默认 `script` 走目标节点 `/bin/sh`,并继承 provider-gateway/G14 已长期化的 proxy 环境。需要临时单步执行一行远端 shell 逻辑、且不想先创建脚本文件或 heredoc 时,优先使用 `trans G14:/root/hwlab script -- 'sed -n "1,20p" a && sed -n "1,20p" b'`,CLI 会把单个字符串放进目标节点的 `sh -c`,第二个 `sed`、管道和重定向都会留在远端;等价 `shell '<command>'` 仍保留为显式 shell operation`script``shell` helper 会在用户 shell 文本前注入一个极小的 POSIX 兼容 `printf` wrapper,使 `printf "--- section ---\n"` 这类高频排障分隔标题在 dash/sh 与 bash 下行为一致;direct argv 形态不注入该 wrapper。`script --` 后跟多个 token 时保持 direct argv,例如 `trans G14:/root/hwlab script -- sed -n '1,20p' AGENTS.md`。只有脚本确实使用 `pipefail`、数组、`[[ ... ]]` 等 bash 专有语义时才加 `--shell bash`,不能把 `--shell bash` 当作 proxy 修复手段。单进程命令才直接写成 argv,例如 `trans G14:/root/hwlab git status --short --branch`。遇到分布式开发摩擦时,优先补强 `trans`/`tran` 的 route/operation、stdin helper 或目标节点环境,并把稳定解法写回长期参考文档,不要退回多层 shell 字符串拼接。
`trans` 同样遵守 route/operation 解析器;route 后面的第一个 token 不是原生 ssh 命令字符串。带变量展开、管道、重定向或多条命令的远端逻辑,默认使用 `trans G14:/root/hwlab sh <<'SH'``sh` 走目标节点 `/bin/sh`,并继承 provider-gateway/G14 已长期化的 proxy 环境。需要 Bash 专有语法,例如 `set -o pipefail`、数组、`[[ ... ]]``${var:0:8}` 子串展开时,必须把 operation 写成 `bash`,例如 `trans D601:/home/ubuntu/workspace/hwlab-v03 bash <<'BASH'`。需要临时单步执行一行远端 shell 逻辑、且不想先创建脚本文件或 heredoc 时,使用 `trans G14:/root/hwlab sh -- 'sed -n "1,20p" a && sed -n "1,20p" b'``bash -- '<bash command>'`CLI 会把单个字符串放进目标节点对应 shell `-c`,第二个 `sed`、管道和重定向都会留在远端;`sh --``bash --` 只接受一个 shell command 字符串,多 argv 单进程命令必须走 `argv``exec` 或已知直接子命令。`script``shell` operation 已移除并会失败;不得用 `--shell bash` 或旧名绕过显式 shell 选择。`sh``bash` helper 会在用户 shell 文本前注入一个极小的 POSIX 兼容 `printf` wrapper,使 `printf "--- section ---\n"` 这类高频排障分隔标题在 dash/sh 与 bash 下行为一致;direct argv 形态不注入该 wrapper。单进程命令才直接写成 argv,例如 `trans G14:/root/hwlab git status --short --branch`。遇到分布式开发摩擦时,优先补强 `trans`/`tran` 的 route/operation、stdin helper 或目标节点环境,并把稳定解法写回长期参考文档,不要退回多层 shell 字符串拼接。
### Standard Workspace-Prefixed Passthrough
- 长期参考、AGENTS 索引、CLI help、Codex 任务脚本、CI/CD 排障和人工远端操作必须统一把已知的远端 workspace 写在 route 的第一个 token,而不是塞进 `cd` 串。`route` 段只表达分布式定位,operation 段才执行命令;workspace 路径是定位信息,不是命令。
- 标准形态是 `trans <provider>:/absolute/workspace <operation> [args...]`:例如 `trans G14:/root/hwlab git status --short --branch``trans G14:/root/hwlab-v02 script -- 'git fetch origin v0.2 && git pull --ff-only origin v0.2'``trans D601:/home/ubuntu/workspace/unidesk-dev script <<'SCRIPT'``trans G14:/root/hwlab apply-patch < patch.diff``trans G14:/root/hwlab glob --root . --pattern 'web/hwlab-cloud-web/*.ts' --contains session-tabs`
- 反面形态必须删除或迁移:`trans G14 script -- 'cd /root/hwlab && git status --short --branch'``trans G14 script <<'SCRIPT' cd /root/hwlab-v02 git fetch origin v0.2 SCRIPT``tran G14 script -- 'cd /home/ubuntu/workspace/unidesk-dev && ...'``bun scripts/cli.ts ssh G14 -- 'cd /root/hwlab && ...'`。这些写法把已知 workspace 写进 command 字符串,破坏 route/operation 分离,引入本地 shell 二次解析、远端 cwd 漂移和并行 worktree 切换摩擦。
- 标准形态是 `trans <provider>:/absolute/workspace <operation> [args...]`:例如 `trans G14:/root/hwlab git status --short --branch``trans 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.diff``trans G14:/root/hwlab glob --root . --pattern 'web/hwlab-cloud-web/*.ts' --contains session-tabs`
- 反面形态必须删除或迁移:`trans G14 sh -- 'cd /root/hwlab && git status --short --branch'``trans G14 sh <<'SH' cd /root/hwlab-v02 git fetch origin v0.2 SH``tran G14 sh -- 'cd /home/ubuntu/workspace/unidesk-dev && ...'``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/hwlab``G14:/root/hwlab-v02`)时,route 必须显式带 workspaceCLI 的 `pwd` 输出、后续 `apply-patch` 的相对路径和 `script` 的 cwd 全部跟随该 workspace;切换 workspace 必须切换 route,不允许在同一次 `trans` 链里再 `cd`
- 当远端存在多个并行 workspace(例如 `G14:/root/hwlab``G14:/root/hwlab-v02`)时,route 必须显式带 workspaceCLI 的 `pwd` 输出、后续 `apply-patch` 的相对路径和 `sh`/`bash` 的 cwd 全部跟随该 workspace;切换 workspace 必须切换 route,不允许在同一次 `trans` 链里再 `cd`
- 本规则覆盖所有 host workspace 形态,包括 `G14:/root/hwlab``G14:/root/hwlab-v02``G14:/root/agentrun-v01``D601:/home/ubuntu/workspace/unidesk-dev``D601:/home/ubuntu/workspace/hwlab-dev`provider-gateway 侧已经把它们注册为 host workspace route。
-`k3s` route 的分工不变:定位控制面继续写 `trans G14:k3s`、定位 workload/container 继续写 `trans G14:k3s:<namespace>:<workload>[:<container>]`pod/container 内 cwd 用 operation 参数 `--cwd /path`,或在已经明确选出 container 后才使用 `/path` route 后缀表达文件系统位置。host workspace 路径里的 `cd` 才需要被替换,控制面或 pod 内的多层 shell 不在本规则的清理范围。
非交互 `ssh`/`trans`/`tran` 不是登录 shell,不能依赖 `.bashrc``.profile` 或交互 alias。
CLI 会在 Host route、workspace route、k3s 控制面脚本和 pod route 的 shell/script helper
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 script -- 'bun --version'` 应该直接可用,
`trans G14:/root/hwlab-v02 sh -- 'bun --version'` 应该直接可用,
不需要在任务里硬写绝对路径。direct argv 不经过 shell 初始化;如果某个 direct argv 工具找不到,
优先改用 `script -- '<command>'` 或补强 CLI 的 argv PATH 处理,
优先改用 `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 script -- 'sed -n "1,20p" AGENTS.md && sed -n "1,20p" docs/reference/g14.md'`,或者用 `trans G14:/root/hwlab script <<'SCRIPT'` 把多行脚本送到远端
本地 shell 运算符不是 `trans` 可以拦截的内容。`trans G14:/root/hwlab sed -n '1,20p' AGENTS.md && sed -n '1,20p' docs/reference/g14.md` 会先由 master server 的本地 shell 拆成两个命令,只有第一个 `sed` 进入 G14,第二个 `sed` 会在 master server 当前目录执行。需要把两个命令都放到目标节点时,必须写成 `trans G14:/root/hwlab sh -- 'sed -n "1,20p" AGENTS.md && sed -n "1,20p" docs/reference/g14.md'`,或者用 `trans G14:/root/hwlab sh <<'SH'` 把多行脚本送到远端;需要 Bash 专有语法时把 operation 改成 `bash`
`trans`/`tran` 不做本地 provider/plane 串行锁;本地目录锁不是 G14 原生 k3s/Tekton/GitOps 的业务协调机制,stale lock 会阻塞所有后续短查询。以后不要在 wrapper 里恢复本地锁。业务并发、发布互斥和 rollout 协调必须交给 k8s/Tekton/Argo/Lease 等原生运行面机制;若 provider session allocator 需要限流,应在服务端实现带 TTL 的队列或 lease,而不是在客户端加目录锁。
非交互 `trans`/`tran`/`ssh` 有最外层运行时硬超时,默认和最大值都是 60 秒;`UNIDESK_TRAN_RUNTIME_TIMEOUT_SECONDS``UNIDESK_TRAN_RUNTIME_TIMEOUT_MS``UNIDESK_SSH_RUNTIME_TIMEOUT_MS` 只能把超时调小,不能调大超过 60 秒。到点后 wrapper、backend-core broker 或 frontend websocket 路径会主动断开并在 stderr 输出 `UNIDESK_TRAN_TIMEOUT_HINT``UNIDESK_SSH_RUNTIME_TIMEOUT`,提示改用短查询加轮询。长时间 CI/CD、Tekton/Argo 观察、trace/result、日志 tail、构建下载和硬件任务都必须按 submit-and-poll/短查询语义拆成多次 `trans` 调用;不得让单个 `trans` 挂着等待最终完成。本规则的跟踪 issue 是 [pikasTech/unidesk#187](https://github.com/pikasTech/unidesk/issues/187)。
长任务的标准形态是:用一次短 `trans <route> script` 启动目标侧 job、后台进程、PipelineRun 或受控命令,并把 job id、日志路径、状态文件或 Kubernetes 对象名写到目标侧;后续用多次短 `trans` 查询 `status``logs --tail``kubectl get/describe`、trace result 或工具自带 job-status。不要为了观察 Docker build、镜像 push、Keil 下载、串口抓取或 Code Agent turn,把 `trans` 一直挂到结束;超过 60 秒的断开只说明调用方式需要改成轮询,不应立即归因成 provider session、CI/CD 或硬件失败。
长任务的标准形态是:用一次短 `trans <route> sh``trans <route> bash` 启动目标侧 job、后台进程、PipelineRun 或受控命令,并把 job id、日志路径、状态文件或 Kubernetes 对象名写到目标侧;后续用多次短 `trans` 查询 `status``logs --tail``kubectl get/describe`、trace result 或工具自带 job-status。不要为了观察 Docker build、镜像 push、Keil 下载、串口抓取或 Code Agent turn,把 `trans` 一直挂到结束;超过 60 秒的断开只说明调用方式需要改成轮询,不应立即归因成 provider session、CI/CD 或硬件失败。
HWLAB `hwlab-cli client agent` 端到端验证经 UniDesk `trans`/`tran`/`ssh` 进入 G14 时,也按短连接 submit-and-poll 执行:在目标 workspace 和锁定 runtime env 下先 `agent send` 提交 turn,避免在可能超过 60 秒的路径上使用 `--wait` 长挂;随后多次短查询 `agent result <traceId>``agent trace <traceId> --render web``agent inspect --trace-id <traceId>` 取证。关闭 context-loss、AgentRun 复用或多轮会话类 issue 时,证据至少应记录 `conversationId``sessionId``threadId``traceId``runId``commandId` 和关键 event label。需要验证“第二轮继承第一轮上下文”时,显式传入同一 conversation/session/thread 标识,不能依赖旧 Cloud Web workspace 历史或人工印象;`--no-workspace` 这类绕过恢复的实验只可作为定位证据,不能替代默认入口验收。
@@ -297,7 +297,7 @@ HWLAB Code Agent provider profile 的 `config.toml`、完整 Codex `auth.json`
HWLAB Cloud Web Workbench 或 Code Agent 装配类 issue 的 CLI 验证必须贴近 Web 路径:优先使用会调用同一 Cloud API/Web dispatcher 的正式 `hwlab-cli client agent` 或等价 UniDesk 高层 CLI,再从 trace/inspect/result 中确认 runner job、AgentRun runtime assembly、`transientEnv``runId``commandId`。当前 HWLAB v0.2 资源装配需求以 UniDesk OA 的 [Runtime装配](../../project-management/PJ2026-01/specs/PJ2026-010202-runtime-assembly.md) 和 [HWLAB接入](../../project-management/PJ2026-01/specs/PJ2026-010205-hwlab-dispatch.md) 为权威:`ResourceBundleRef.kind="gitbundle"`,通过 `bundles[]` 装配 `tools/``.agents/skills`;不要在本 CLI 文档重复维护旧字段清单。直接调用 AgentRun manager、手写 `dispatchHwlabAgentRun()` 或临时 runner job 只可作为基础设施 canary;它不能替代 Web Workbench 原入口验收,也不能作为关闭 Web issue 的唯一证据。若缺少这种同路径 CLI,先补 CLI 可见性和 submit-and-poll 入口,再继续修复或关闭 issue。
`trans D518` 应表现为登录 D518 WSL 的 shell`trans D518 hostname` 应像 `ssh D518 hostname` 一样只输出远端命令结果并返回远端 exit code。Provider ID 前的目标选择由 UniDesk 节点清单决定,`-p``-i``-l``-o` 等传统 ssh 传输参数由 provider-gateway 部署配置统一管理,CLI 会兼容性消费这些参数但不会覆盖节点侧维护桥配置。指挥官、CI 预检和其他非交互流程不要依赖 ssh-like 自由拼接;单进程标准写法是 `trans D601 argv true`,多行 shell 逻辑标准写法是 quoted heredoc 单步调用 `trans D601 script <<'SCRIPT'`
`trans D518` 应表现为登录 D518 WSL 的 shell`trans D518 hostname` 应像 `ssh D518 hostname` 一样只输出远端命令结果并返回远端 exit code。Provider ID 前的目标选择由 UniDesk 节点清单决定,`-p``-i``-l``-o` 等传统 ssh 传输参数由 provider-gateway 部署配置统一管理,CLI 会兼容性消费这些参数但不会覆盖节点侧维护桥配置。指挥官、CI 预检和其他非交互流程不要依赖 ssh-like 自由拼接;单进程标准写法是 `trans D601 argv true`,多行 shell 逻辑标准写法是 quoted heredoc 单步调用 `trans D601 sh <<'SH'`
UniDesk CLI/trans/tran 客户端改进本身是 master server 高频控制入口维护,可以直接在 `/root/unidesk` 轻量开发、提交并推送 `origin/master`;不要为这类客户端小改强制迁移到 D601 worktree。该例外不改变 master server 禁重型验证规则:仓库级 check、Playwright/browser smoke、镜像构建、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=true``verification.automatic=true``verification.verified=true``verification.match.{bytes,sha256}=true` 就是端到端完整性证明,调用方不需要再额外手写 `sha256sum` 比对。
@@ -307,11 +307,11 @@ core 只允许声明了 `host.ssh` capability 的 provider 使用 `host.ssh` dis
本地 broker 默认等待 provider SSH 会话打开 60000ms,以便在目标节点同时有较多 microservice.http 任务时仍能建立维护会话;需要诊断慢连接时可用 `UNIDESK_SSH_OPEN_TIMEOUT_MS=<ms>` 临时调大,但最小有效值固定为 15000ms,避免把真实离线误判为长时间阻塞。注意 open timeout 只控制“会话打开”阶段,不能绕过 60 秒最外层运行时硬超时。
ssh-like 远端命令如果出现 `kex_exchange_identification``Connection closed by remote host`、provider session timeout 或 exit code 255CLI 会在原始 stderr 后追加一行 `UNIDESK_SSH_HINT { ... }`。该 JSON 不回显原始远端命令,只包含 `code=ssh-like-command-friction``trigger``try``triage``try` 固定指向 stdin script 形态,避免把一次 ssh-like 解析/握手摩擦误读成 D601 SSH 整体不可用。`ssh`/`trans`/`tran` 在失败路径识别到 tcp-pool 数据面问题时会追加 `UNIDESK_SSH_TCP_POOL_HINT { ... }``failureKind` 固定分为 `provider-data-channel-closed``provider-data-channel-missing``provider-data-pool-exhausted`;这类 hint 表示 transport/data-pool transient,幂等受控操作应先运行 `bun scripts/cli.ts debug ssh-pool <providerId>` 查看 labels,再重试原受控 CLI,不能单独定性为远端 runtime 配置失败。backend-core/provider 控制面返回结构化 `ssh.error` 时 broker 还会输出 `UNIDESK_SSH_ERROR { ... }`,供 `job status` 从旧日志或异步 job 日志中恢复 failureKind。`ssh`/`trans`/`tran` 运行时硬超时会输出 `UNIDESK_SSH_RUNTIME_TIMEOUT { ... }` 或 wrapper 层 `UNIDESK_TRAN_TIMEOUT_HINT { ... }`;这不是远端业务失败,而是调用方需要改成短查询/轮询。`ssh`/`trans`/`tran` 只有在运行耗时超过默认 10000ms 时才会在 stderr 追加一行 `UNIDESK_SSH_TIMING { ... }`,且 `level=warning`;正常短调用不输出 timing 噪声。慢成功命令也必须保留该 warning,因为它是 provider session、远端命令成本、helper bootstrap 和 `trans`/`tran`/远端 patch 性能回归的重要监控信号。warning 包含 `elapsedMs``elapsedSeconds``transport``invocationKind``exitCode`,提示优先排查 provider/session 延迟、远端命令自身耗时、helper bootstrap 或工具层回归。阈值可用 `UNIDESK_SSH_SLOW_WARNING_MS=<ms>` 临时调节,提示同样不回显原始远端命令。
ssh-like 远端命令如果出现 `kex_exchange_identification``Connection closed by remote host`、provider session timeout 或 exit code 255CLI 会在原始 stderr 后追加一行 `UNIDESK_SSH_HINT { ... }`。该 JSON 不回显原始远端命令,只包含 `code=ssh-like-command-friction``trigger``try``triage``try` 固定指向显式 `sh` stdin heredoc 形态,避免把一次 ssh-like 解析/握手摩擦误读成 D601 SSH 整体不可用。`ssh`/`trans`/`tran` 在失败路径识别到 tcp-pool 数据面问题时会追加 `UNIDESK_SSH_TCP_POOL_HINT { ... }``failureKind` 固定分为 `provider-data-channel-closed``provider-data-channel-missing``provider-data-pool-exhausted`;这类 hint 表示 transport/data-pool transient,幂等受控操作应先运行 `bun scripts/cli.ts debug ssh-pool <providerId>` 查看 labels,再重试原受控 CLI,不能单独定性为远端 runtime 配置失败。backend-core/provider 控制面返回结构化 `ssh.error` 时 broker 还会输出 `UNIDESK_SSH_ERROR { ... }`,供 `job status` 从旧日志或异步 job 日志中恢复 failureKind。`ssh`/`trans`/`tran` 运行时硬超时会输出 `UNIDESK_SSH_RUNTIME_TIMEOUT { ... }` 或 wrapper 层 `UNIDESK_TRAN_TIMEOUT_HINT { ... }`;这不是远端业务失败,而是调用方需要改成短查询/轮询。`ssh`/`trans`/`tran` 只有在运行耗时超过默认 10000ms 时才会在 stderr 追加一行 `UNIDESK_SSH_TIMING { ... }`,且 `level=warning`;正常短调用不输出 timing 噪声。慢成功命令也必须保留该 warning,因为它是 provider session、远端命令成本、helper bootstrap 和 `trans`/`tran`/远端 patch 性能回归的重要监控信号。warning 包含 `elapsedMs``elapsedSeconds``transport``invocationKind``exitCode`,提示优先排查 provider/session 延迟、远端命令自身耗时、helper bootstrap 或工具层回归。阈值可用 `UNIDESK_SSH_SLOW_WARNING_MS=<ms>` 临时调节,提示同样不回显原始远端命令。
非交互 `ssh`/`trans`/`tran` 远端命令的流式 stdout 默认有本地输出上限,避免远端日志、PowerShell JSON 或错误对象一次性输出过大导致上下文被淹没;交互登录 shell 不套该上限。超过上限时,CLI 只继续读取远端流并把完整内容写入 `/tmp/unidesk-cli-output/*.stdout.bin`,本地 stderr 追加 `UNIDESK_SSH_STDOUT_TRUNCATED { ... }`,其中包含 `thresholdBytes``observedBytesAtTruncation``dumpPath``dumpError`;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`,普通 `argv``script``kubectl``logs` 和默认 `apply-patch` 等路径不得传输无关工具源码。`apply-patch-v1` 只注入 `apply_patch``glob` 只注入 `glob``skills`/`skill discover` 只注入 `skill-discover``apply_patch` 接受标准 `*** Begin Patch` / `*** End Patch` patch 格式,便于通过 SSH 透传编辑远端仓库文件;远端存在 `perl` 时必须走快速精确匹配路径,避免大文件 hunk 被 sh 模式匹配拖成几十秒,缺少 `perl` 时才退回 sh-only 实现。`glob``skill-discover` 需要远端 `python3`。注入工具只写 `/tmp/unidesk-ssh-tools`,不修改目标仓库。
`trans <providerId>` 透传只在当前 operation 需要 helper 时才注入 `/tmp/unidesk-ssh-tools`,普通 `argv``sh`/`bash``kubectl``logs` 和默认 `apply-patch` 等路径不得传输无关工具源码。`apply-patch-v1` 只注入 `apply_patch``glob` 只注入 `glob``skills`/`skill discover` 只注入 `skill-discover``apply_patch` 接受标准 `*** Begin Patch` / `*** End Patch` patch 格式,便于通过 SSH 透传编辑远端仓库文件;远端存在 `perl` 时必须走快速精确匹配路径,避免大文件 hunk 被 sh 模式匹配拖成几十秒,缺少 `perl` 时才退回 sh-only 实现。`glob``skill-discover` 需要远端 `python3`。注入工具只写 `/tmp/unidesk-ssh-tools`,不修改目标仓库。
远端文本 patch 默认使用 `apply-patch` 的 v2 引擎:它不把 hunk 解析交给远端 shell/perl helper,而是在本地按行序列匹配,支持长中文/Unicode 行、纯新增 hunk、低上下文插入和 `@@` 上下文定位,再把完整新内容写回远端。v2 的文件操作提交顺序按 Codex 标准 `apply_patch` 语义执行:空 patch 会失败;删除不存在的文件会失败;`Add File` 可覆盖已有文件;`Move to` 可覆盖目标文件;当大 patch 后续 hunk 不匹配时,已成功提交的前序文件操作会保留,并在错误详情中记录 `partialChanges`,调用方应基于当前文件内容继续补一个更小的 patch,而不是期待全量事务回滚。若 stderr 报 `failed to find expected lines` 且显示 partial context match,尤其是大块/函数替换,调用方必须先重读目标文件当前块,再用更少稳定上下文、`@@ <unique anchor>` 或多个小 hunk 重试;该失败不构成改用 `download`/`upload`、远端脚本整文件替换或 `apply-patch-v1` 的理由。`apply_patch` 旧 helper 默认拒绝低上下文 update hunk:空搜索/纯插入无锚点、只在插入点前有上下文而没有插入点后上下文、或同一 hunk search 在目标文件中匹配多个位置时,都会结构化失败并提示补充上下文。成功应用时每个 hunk 会在 stderr 输出 `apply_patch: hunk N matched path:line`,用于复核实际落点;只有人工确认确实需要旧 helper 行为或 `--allow-loose` 时,才显式调用 `apply-patch-v1 --allow-loose`
@@ -364,29 +364,19 @@ 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 命令字符串传入。正式入口
`trans D601 script`,脚本正文从 stdin 进入;CLI 会把本地 stdin 直接送到远端
`sh -s --``--shell bash` 可切换为 bash`--` 后的内容会作为脚本参数传入。
`script`/`shell` helper 会在用户脚本文本前注入用户级工具 PATH 和兼容前缀,
`bun``tsx` 等用户级工具在非交互 shell 中可见,也让 `printf "--- section ---\n"`
这类分隔标题不再因目标 `/bin/sh` 方言失败;已有 `printf '%s\n' value``printf -- ...`
和 bash 的 `printf -v` 仍按原语义工作。临时单步执行优先用 quoted heredoc
只有命令很短、明确希望一行内完成时才用 `script -- '<command && command>'`
它会把单个字符串按远端 shell one-liner 执行且不等待 stdin
复用脚本时才用 `< script.sh` 文件重定向。`script -- <多个 argv>` 仍是 direct argv
不经过远端 shell,适合 `script -- sed -n '1,20p' file`。典型用法:
如果远端逻辑需要 shell 特性,不要再把整段脚本作为原生 ssh-like 命令字符串传入。正式入口必须在 operation 位置显式声明 shell 方言:`trans D601 sh` 表示目标 `/bin/sh``trans D601 bash` 表示目标 Bash。脚本正文从 stdin 进入;operation 后的普通参数会作为脚本参数传入。`sh`/`bash` helper 会在用户脚本文本前注入用户级工具 PATH 和兼容前缀,让 `bun``tsx` 等用户级工具在非交互 shell 中可见,也让 `printf "--- section ---\n"` 这类分隔标题不再因目标 `/bin/sh` 方言失败;已有 `printf '%s\n' value``printf -- ...` 和 bash 的 `printf -v` 仍按原语义工作。临时单步执行优先用 quoted heredoc;只有命令很短、明确希望一行内完成时才用 `sh -- '<command && command>'``bash -- '<bash command>'`,它会把单个字符串按所选远端 shell one-liner 执行且不等待 stdin`sh --` / `bash --` 后出现多个 argv token 会失败,单进程命令必须改用 `argv` 或直接子命令;复用脚本时才用 `< script.sh` 文件重定向。`script``shell` operation 已移除并会失败,不能用 `--shell bash` 或旧名绕过显式 shell 选择。典型用法:
```bash
cat <<'SCRIPT' | trans D601 script --shell bash -- alpha
cat <<'BASH' | trans D601 bash alpha
set -euo pipefail
printf 'arg=%s\n' "$1"
hostname
SCRIPT
BASH
```
这个入口的目标是分布式调试的“0 shell-command-string”路径:本地 shell 只负责 heredoc/stdinUniDesk 只负责 provider 路由,远端 shell 只解释脚本正文。脚本正文里仍然要遵守 shell 语言自身的规则,但不再穿过本地 shell、远端 shell、kubectl exec 和容器 shell 的多重字符串转义。
`trans <providerId> shell '<command>'` 是一行远端 shell 逻辑的逃生阀,不取代 `script`。它的输入必须作为一个 quoted argv 到达 CLI,适合 `sed ... && sed ...``kubectl get ... | head` 或一次性环境探测;它仍然只穿过一次目标 shell,不能解决本地 shell 已经拆开的外层 `&&``|``>`。k3s 控制面同样支持 `trans G14:k3s shell 'kubectl get nodes && kubectl get pods -A'`,并默认注入 `/etc/rancher/k3s/k3s.yaml`pod route 需要 cwd 时使用 `exec --cwd /path -- sh -c '<command>'`,例如 `trans D601:k3s:hwlab-dev:hwlab-cloud-api exec --cwd /app -- sh -c 'pwd && ls'`
一行远端 shell 逻辑同样必须用显式方言:POSIX 写 `trans <providerId> sh -- '<command>'`Bash 专有语法写 `trans <providerId> bash -- '<command>'`。它的输入必须作为一个 quoted argv 到达 CLI,适合 `sed ... && sed ...``kubectl get ... | head` 或一次性环境探测;它仍然只穿过一次目标 shell,不能解决本地 shell 已经拆开的外层 `&&``|``>`。k3s 控制面同样支持 `trans G14:k3s sh -- 'kubectl get nodes && kubectl get pods -A'`,并默认注入 `/etc/rancher/k3s/k3s.yaml`pod route 需要 cwd 时使用 workload route 的 `sh`/`bash` operation 或 `exec --cwd /path -- sh -c '<command>'`,例如 `trans D601:k3s:hwlab-dev:hwlab-cloud-api sh --cwd /app -- 'pwd && ls'`
`trans <providerId> skills` 是远端 skill 发现入口,也可写作 `trans <providerId> skill discover`。输出固定为 JSON,包含 `node``roots``counts``skills``roots` 会显示每个候选 skill 根目录是否存在、扫描到多少 skill 以及错误;`skills` 会给出 `scope``name``description``path``skillMd` 和可转换时的 `windowsPath`。默认扫描远端用户的 `~/.agents/skills``~/.codex/skills`、可访问的 `/root/.agents/skills``/root/.codex/skills`;如果目标是 WSL,还会扫描 `/mnt/c/Users/*/.agents/skills``/mnt/c/Users/*/.codex/skills`,从而一次性看清 WSL 和 Windows 两套 skill。常用参数是 `--scope wsl``--scope windows``--limit N``--max-depth N``--root <path>``--windows-root <path>`;不要用宽泛的 Linux `find /mnt/*` 扫 Windows 盘,优先用这个结构化入口避免卡在 Windows 挂载层。
@@ -409,11 +399,11 @@ trans D601 find /home/ubuntu --max-depth 4 --type d --icontains pika --limit 50
trans D601 glob --root /home/ubuntu/pikapython --pattern '**/*-test.cpp' --limit 20 --sort
```
`ssh` 的 route 语法是 `{provider}:{plane}[:{scope...}] {operation} [operation-args...]`。第一个 argv token 只负责定位分布式目标,不表达操作;第一个 token 后面的所有 token 才进入 operation 解析器。Host workspace route 使用 `<provider>:/absolute/workspace`,例如 `D601:/home/ubuntu/workspace/hwlab-dev`,CLI 会把该路径作为远端 cwd 传给 Host SSH 维护桥,后续 `pwd``git``script``apply-patch` 和旧 `apply-patch-v1` fallback 等操作仍按同一套 operation parser 执行。`<provider>:host:/absolute/workspace` 是等价长写法;workspace 必须是绝对路径,远端是否存在由维护桥实际 `cd` 失败或成功证明。
`ssh` 的 route 语法是 `{provider}:{plane}[:{scope...}] {operation} [operation-args...]`。第一个 argv token 只负责定位分布式目标,不表达操作;第一个 token 后面的所有 token 才进入 operation 解析器。Host workspace route 使用 `<provider>:/absolute/workspace`,例如 `D601:/home/ubuntu/workspace/hwlab-dev`,CLI 会把该路径作为远端 cwd 传给 Host SSH 维护桥,后续 `pwd``git``sh``bash``apply-patch` 和旧 `apply-patch-v1` fallback 等操作仍按同一套 operation parser 执行。`<provider>:host:/absolute/workspace` 是等价长写法;workspace 必须是绝对路径,远端是否存在由维护桥实际 `cd` 失败或成功证明。
当前稳定 plane 包括 `win``k3s``win` plane 的 operation 是 Windows 操作,不是 POSIX shell 别名:`<provider>:win ps` 在 WSL provider 上启动 Windows PowerShellstdin heredoc 会被写入临时 `.ps1` 后执行;`<provider>:win cmd` 启动 Windows host 的 `cmd.exe`stdin heredoc 会被写入临时 `.cmd` 后执行;`<provider>:win skills` 发现 Windows skill 目录。需要 Windows 当前目录时使用 slash 路由 `<provider>:win/<drive>/<path>`,例如 `D601:win/c/test ps` 会先在 PowerShell 内 `Set-Location -LiteralPath 'C:\test'``D601:win/c/test cmd cd` 会先在 cmd 内执行 `cd /d "C:\test"``win32` 不是合法 plane,调用者必须改用 `win`
`<provider>:win ps` 是 Windows PowerShell 专用入口,适合管道、变量、`Get-ChildItem``Start-Process``Test-Path` 和 Windows 路径脚本;不要用 host/k3s 的 `script` operation 表示 PowerShell。`ps``cmd` 都注入 UTF-8/Python 编码默认值;`cmd` 额外执行 `chcp 65001>nul`。典型用法:
`<provider>:win ps` 是 Windows PowerShell 专用入口,适合管道、变量、`Get-ChildItem``Start-Process``Test-Path` 和 Windows 路径脚本;不要用 host/k3s 的 `sh`/`bash` operation 表示 PowerShell。`ps``cmd` 都注入 UTF-8/Python 编码默认值;`cmd` 额外执行 `chcp 65001>nul`。典型用法:
```bash
trans D601:win ps <<'PS'
@@ -424,11 +414,11 @@ PS
`<provider>:win skills [--scope agents|codex|all] [--limit N]` 是 Windows 用户 skill 发现入口,默认只读取当前 Windows 用户的 `%USERPROFILE%\.agents\skills`,输出 JSON 中包含 `roots``counts` 和每个 skill 的 `name``path``skillFile``description`。需要同时检查 `%USERPROFILE%\.codex\skills` 时显式加 `--scope all`;不要为了列 skill 手写 `cmd dir` 或宽泛扫描整个用户目录。
`D601:k3s``G14:k3s` 定位到对应 provider 的原生 k3s 控制面;`<provider>:k3s:<namespace>:<workload>[:container]` 定位到 namespace 下的一个默认 deployment workload;若目标是具体 Pod,标准 workload 段写成 `pod:<podid>`,例如 `D601:k3s:hwlab-v03:pod:hwlab-cloud-api-abc:hwlab-cloud-api``pod/<podid>` 不是合法 route 写法,因为 `:` 是分布式路由分隔符,`/` 只表示目标容器里的文件系统 cwd;如果调用者写成 `pod/<podid>/<container>`,CLI 必须在连接运行面前报错并提示改用 `pod:<podid>:<container>``--container <container>`。若目标是 Deployment,也可以显式写 `deployment:<name>` 或简写 `<name>`;容器选择写 `:<container>` 或 operation 参数 `--container <container>`。pod 内 cwd 推荐用 operation 参数 `--cwd /path`,例如 `D601:k3s:hwlab-dev:hwlab-cloud-api:hwlab-cloud-api exec --cwd /app -- pwd``kubectl``logs``script``apply-patch`、旧 `apply-patch-v1` fallback、`exec` 和普通容器命令都是 route 后面的 operation,这样路由子模块和操作子模块可以独立扩展。
`D601:k3s``G14:k3s` 定位到对应 provider 的原生 k3s 控制面;`<provider>:k3s:<namespace>:<workload>[:container]` 定位到 namespace 下的一个默认 deployment workload;若目标是具体 Pod,标准 workload 段写成 `pod:<podid>`,例如 `D601:k3s:hwlab-v03:pod:hwlab-cloud-api-abc:hwlab-cloud-api``pod/<podid>` 不是合法 route 写法,因为 `:` 是分布式路由分隔符,`/` 只表示目标容器里的文件系统 cwd;如果调用者写成 `pod/<podid>/<container>`,CLI 必须在连接运行面前报错并提示改用 `pod:<podid>:<container>``--container <container>`。若目标是 Deployment,也可以显式写 `deployment:<name>` 或简写 `<name>`;容器选择写 `:<container>` 或 operation 参数 `--container <container>`。pod 内 cwd 推荐用 operation 参数 `--cwd /path`,例如 `D601:k3s:hwlab-dev:hwlab-cloud-api:hwlab-cloud-api exec --cwd /app -- pwd``kubectl``logs``sh``bash``apply-patch`、旧 `apply-patch-v1` fallback、`exec` 和普通容器命令都是 route 后面的 operation,这样路由子模块和操作子模块可以独立扩展。
`k3s` 必须出现在 route 的 plane 段里,禁止使用 `trans G14 k3s ...``trans D601 k3s ...` 这类 post-provider shorthand;正确形态是 `trans G14:k3s kubectl ...``trans D601:k3s kubectl ...`。定位和操作必须保持分离,`kubectl``logs``script``apply-patch`、旧 `apply-patch-v1` fallback、`exec` 等 operation 名也不得放进任何 colon route 段,包括 namespace、workload 或 container 段;新增分布式目标时按 `{provider}:{plane}:{scope}` 扩展 route,而不是在 operation args 中新增另一套定位语法。
`k3s` 必须出现在 route 的 plane 段里,禁止使用 `trans G14 k3s ...``trans D601 k3s ...` 这类 post-provider shorthand;正确形态是 `trans G14:k3s kubectl ...``trans D601:k3s kubectl ...`。定位和操作必须保持分离,`kubectl``logs``sh``bash``apply-patch`、旧 `apply-patch-v1` fallback、`exec` 等 operation 名也不得放进任何 colon route 段,包括 namespace、workload 或 container 段;新增分布式目标时按 `{provider}:{plane}:{scope}` 扩展 route,而不是在 operation args 中新增另一套定位语法。
该入口解决运行面调试中最常见的多层 shell 引号问题。它不要求升级 provider-gateway,也不新增业务 API,只复用现有 Host SSH 维护桥;CLI 在本地把 Kubernetes 目标、namespace、container、log 限制、容器命令、stdin script、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 script` 执行带 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] script` 把本地 stdin 作为 pod 内 shell 脚本执行;`<provider>:k3s:<namespace>:<workload>[:container] apply-patch --cwd /workspace` 是 pod 内文本 patch 默认入口;旧 helper 仅通过 `<provider>:k3s:<namespace>:<workload> apply-patch-v1` 显式调用。典型用法:
该入口解决运行面调试中最常见的多层 shell 引号问题。它不要求升级 provider-gateway,也不新增业务 API,只复用现有 Host SSH 维护桥;CLI 在本地把 Kubernetes 目标、namespace、container、log 限制、容器命令、`sh`/`bash` stdin、pod cwd `apply-patch` 读写和旧 `apply-patch-v1` fallback 组装成 kubectl argv,并固定远端 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml``<provider>:k3s` 无后续参数时执行 native k3s guard`<provider>:k3s kubectl ...` 接收原始 kubectl argv`<provider>:k3s sh``bash` 执行带 native kubeconfig 的 host stdin 脚本;`<provider>:k3s:<namespace>:<workload>[:container] logs` 读取有界日志;`<provider>:k3s:<namespace>:<workload>[:container] exec ...``<provider>:k3s:<namespace>:<workload>[:container] <command> ...` 进入目标 workload/container`<provider>:k3s:<namespace>:<workload>[:container] sh``bash` 把本地 stdin 作为 pod 内 shell 脚本执行;`<provider>:k3s:<namespace>:<workload>[:container] apply-patch --cwd /workspace` 是 pod 内文本 patch 默认入口;旧 helper 仅通过 `<provider>:k3s:<namespace>:<workload> apply-patch-v1` 显式调用。典型用法:
```bash
trans D601:k3s
@@ -442,14 +432,14 @@ 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 script
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 script -- 'curl -fsS http://user-billing/health'
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 script
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
@@ -461,17 +451,17 @@ trans D601:k3s:hwlab-dev:hwlab-cloud-api:hwlab-cloud-api apply-patch --cwd /app
PATCH
```
`logs` operation 默认是有界读取;`--follow`/`-f` 会被拒绝,防止 CLI 长时间占用维护桥。目标 route 后面直接跟普通命令时,CLI 会把 argv 放到 `kubectl exec --` 后;显式 `exec` operation 可用于让命令边界更清晰。`exec --stdin -- <command> ...` 是 workload route 的通用 stdin 流入口,适合把 tar、patch 以外的任意字节流直接送进容器命令;operation 选项必须放在 `--` 前,容器命令从 `--` 后开始。需要 shell 语法时优先改用 `script` operation,把脚本走 stdin,而不是把 `kubectl exec ... -- sh -c ...` 放进远端命令字符串。pod 内文本热修默认使用 workspace route 加 `apply-patch`,不要求目标容器自带 `python3``node` 或仓库里的工具脚本;旧 `apply-patch-v1` operation 仍使用同一个 sh helper,只作为显式 legacy fallback,不用于二进制改写。
`logs` operation 默认是有界读取;`--follow`/`-f` 会被拒绝,防止 CLI 长时间占用维护桥。目标 route 后面直接跟普通命令时,CLI 会把 argv 放到 `kubectl exec --` 后;显式 `exec` operation 可用于让命令边界更清晰。`exec --stdin -- <command> ...` 是 workload route 的通用 stdin 流入口,适合把 tar、patch 以外的任意字节流直接送进容器命令;operation 选项必须放在 `--` 前,容器命令从 `--` 后开始。需要 shell 语法时优先改用 `sh``bash` operation,把脚本走 stdin,而不是把 `kubectl exec ... -- sh -c ...` 放进远端命令字符串。pod 内文本热修默认使用 workspace route 加 `apply-patch`,不要求目标容器自带 `python3``node` 或仓库里的工具脚本;旧 `apply-patch-v1` operation 仍使用同一个 sh helper,只作为显式 legacy fallback,不用于二进制改写。
`trans <providerId> argv <command> [args...]` 是通用 argv 安全拼接入口;`exec` 是同义入口。它是非交互远端单进程命令的默认成功路径,不需要 shell 管道时直接传命令和参数,例如 `trans D601 argv true`。需要管道、重定向、变量展开或多条命令时,优先改用 `trans <providerId> script <<'SCRIPT'``apply-patch``find``glob` 和旧 `apply-patch-v1` fallback 有专用入口;`git``rg``grep``sed``nl``stat``du``ls``cat``head``tail``wc``pwd` 可以直接作为 `trans` 子命令使用,CLI 会对每个 argv token 做 shell quoting。旧的自由 ssh-like 远端命令入口只保留为近似原生 ssh 的人工兼容路径。
`trans <providerId> argv <command> [args...]` 是通用 argv 安全拼接入口;`exec` 是同义入口。它是非交互远端单进程命令的默认成功路径,不需要 shell 管道时直接传命令和参数,例如 `trans D601 argv true`。需要管道、重定向、变量展开或多条命令时,优先改用 `trans <providerId> sh <<'SH'``apply-patch``find``glob` 和旧 `apply-patch-v1` fallback 有专用入口;`git``rg``grep``sed``nl``stat``du``ls``cat``head``tail``wc``pwd` 可以直接作为 `trans` 子命令使用,CLI 会对每个 argv token 做 shell quoting。旧的自由 ssh-like 远端命令入口只保留为近似原生 ssh 的人工兼容路径。
通过 `trans <providerId>` 执行多行脚本时,优先使用结构化 helper,例如 `trans G14 py < script.py``trans G14 script <<'SCRIPT'``trans G14:k3s script <<'SCRIPT'`。不要在远端命令字符串里再嵌套 heredoc、复杂引号或 `ssh 'python3 - <<EOF ...'` 形态;多层 shell 解析容易把 stdin 绑定到错误进程,结果会打开远端交互解释器并留下悬挂的 broker/SSH 会话。长脚本需要复用时,优先提交到 repo 或通过 stdin 传输到目标节点执行。
通过 `trans <providerId>` 执行多行脚本时,优先使用结构化 helper,例如 `trans G14 py < script.py``trans G14 sh <<'SH'``trans G14:k3s sh <<'SH'`。不要在远端命令字符串里再嵌套 heredoc、复杂引号或 `ssh 'python3 - <<EOF ...'` 形态;多层 shell 解析容易把 stdin 绑定到错误进程,结果会打开远端交互解释器并留下悬挂的 broker/SSH 会话。长脚本需要复用时,优先提交到 repo 或通过 stdin 传输到目标节点执行。
## Remote Main Server Passthrough
`--main-server-ip` 是一个全局前缀,必须放在需要透传的命令同一次调用中,例如 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug health`。默认传输是公网 frontend:本地 CLI 读取本仓库 `config.json` 中的 frontend 登录账号密码,登录 `http://<ip>:<frontendPort>/` 获取 HttpOnly session cookie,然后通过 frontend 的 `/api/*` 同源代理访问 backend-core 内网 API;因此计算节点只需要能访问公网 frontend,不需要主 server SSH key,也不需要打开 backend-core REST API 或 PostgreSQL 端口。
默认 frontend 传输支持 `debug health``debug dispatch``debug task``artifact-registry status|health``ci publish-user-service --dry-run``microservice list/status/health/diagnostics/tunnel-self-test/proxy``decision upload/list/show/health``decision requirement list/upsert``decision diary import/list/history/months/show/edit/upsert``codex task <taskId>``codex tasks``codex unread``codex queues``codex output <taskId>``codex judge <taskId> --attempt N``ssh <PROVIDER_ID> <remote-command>``microservice status/health/diagnostics` 经 frontend 远程传输时也复用本地 CLI 的默认 compact summary`microservice health code-queue` 只有显式 `--raw``--full` 才返回完整健康 body。运行中纠偏已切到 AgentRun `send session/<sessionId>`;旧 `codex steer` 属于冻结写入口,不应通过 frontend 远程传输或旧 proxy 绕过。其中 `ssh` 的 remote frontend 传输使用 authenticated frontend `/ws/ssh` WebSocket 代理接入 backend-core SSH bridgestdout/stderr 按字节流直通到调用端,不经过 `/api/dispatch``/api/tasks` 或 task JSON compactfrontend 运行时必须通过 `PROVIDER_TOKEN`/`UNIDESK_PROVIDER_TOKEN``PROVIDER_TOKEN_FILE`/`UNIDESK_PROVIDER_TOKEN_FILE` 读取 provider token,并且不能把 token 下发给 runner。因此 D601 Code Queue runner 内的 `tran G14 ...` 应与主 server 本机 `trans G14 ...` / `tran G14 ...` 在输出完整性上保持同一语义。非交互单进程命令优先 `trans D601 argv true``apply-patch`stdin script`py` 和旧 `apply-patch-v1` fallback 也走同一条 `/ws/ssh` 流式通道。交互式登录 shell 仍应在主 server 本机 CLI 使用,或显式切换到旧 SSH 传输后在主 server 上执行。当 backend-core、database、provider-dispatch 或 provider-host-ssh 缺失时,这些 read-only 预检必须返回结构化 `runnerDisposition=infra-blocked` 和缺失通道列表,而不是裸 `No such container`。若确实需要旧行为,可使用 `--main-server-key <key>``--main-server-transport ssh`,这时 CLI 会通过 SSH 登录主 server 的 `--main-server-root` 目录执行同一个 `bun scripts/cli.ts <command>`
默认 frontend 传输支持 `debug health``debug dispatch``debug task``artifact-registry status|health``ci publish-user-service --dry-run``microservice list/status/health/diagnostics/tunnel-self-test/proxy``decision upload/list/show/health``decision requirement list/upsert``decision diary import/list/history/months/show/edit/upsert``codex task <taskId>``codex tasks``codex unread``codex queues``codex output <taskId>``codex judge <taskId> --attempt N``ssh <PROVIDER_ID> <remote-command>``microservice status/health/diagnostics` 经 frontend 远程传输时也复用本地 CLI 的默认 compact summary`microservice health code-queue` 只有显式 `--raw``--full` 才返回完整健康 body。运行中纠偏已切到 AgentRun `send session/<sessionId>`;旧 `codex steer` 属于冻结写入口,不应通过 frontend 远程传输或旧 proxy 绕过。其中 `ssh` 的 remote frontend 传输使用 authenticated frontend `/ws/ssh` WebSocket 代理接入 backend-core SSH bridgestdout/stderr 按字节流直通到调用端,不经过 `/api/dispatch``/api/tasks` 或 task JSON compactfrontend 运行时必须通过 `PROVIDER_TOKEN`/`UNIDESK_PROVIDER_TOKEN``PROVIDER_TOKEN_FILE`/`UNIDESK_PROVIDER_TOKEN_FILE` 读取 provider token,并且不能把 token 下发给 runner。因此 D601 Code Queue runner 内的 `tran G14 ...` 应与主 server 本机 `trans G14 ...` / `tran G14 ...` 在输出完整性上保持同一语义。非交互单进程命令优先 `trans D601 argv true``apply-patch``sh`/`bash` stdin`py` 和旧 `apply-patch-v1` fallback 也走同一条 `/ws/ssh` 流式通道。交互式登录 shell 仍应在主 server 本机 CLI 使用,或显式切换到旧 SSH 传输后在主 server 上执行。当 backend-core、database、provider-dispatch 或 provider-host-ssh 缺失时,这些 read-only 预检必须返回结构化 `runnerDisposition=infra-blocked` 和缺失通道列表,而不是裸 `No such container`。若确实需要旧行为,可使用 `--main-server-key <key>``--main-server-transport ssh`,这时 CLI 会通过 SSH 登录主 server 的 `--main-server-root` 目录执行同一个 `bun scripts/cli.ts <command>`
计算节点可以用该入口测试自身的远程升级闭环,而不需要在计算节点公开 core REST API 或 database。标准顺序是:先运行 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug health` 确认主 server 看到当前 Provider 在线,且该 Provider labels 中 `unideskCapabilities` 包含 `host.ssh``hostSshConfigured=true``hostSshKeyPresent=true`;再运行 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug dispatch <PROVIDER_ID> provider.upgrade --mode schedule --wait-ms 15000` 触发真实 `provider.upgrade`;随后再次运行 `debug health` 确认节点重新上线;最后运行 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug dispatch <PROVIDER_ID> host.ssh --wait-ms 15000``bun scripts/cli.ts --main-server-ip 74.48.78.17 ssh <PROVIDER_ID> hostname` 验证 SSH 透传能力。provider-gateway 新部署或升级后没有完成这组 remote CLI 自测,不能视为交付完成。