fix: harden Windows trans helpers

Resolve #1691 by preserving argv boundaries, adding bounded native rg and wc/skill query support, surfacing WSL-to-Windows hints, and splitting the oversized SSH module and embedded remote scripts.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Codex
2026-07-10 13:13:03 +02:00
parent 2d4c1a5ffa
commit 3a17d3b9fd
22 changed files with 2712 additions and 2249 deletions
+5 -3
View File
@@ -413,7 +413,7 @@ trans D601 glob --root /home/ubuntu/pikapython --pattern '**/*-test.cpp' --limit
`ssh` 的 route 语法是 `{provider}:{plane}[:{scope...}] {operation} [operation-args...]`。第一个 argv token 只负责定位分布式目标,不表达操作;第一个 token 后面的所有 token 才进入 operation 解析器。Host workspace route 使用 `<provider>:/absolute/workspace`,例如 `D601:/home/ubuntu/workspace/hwlab-dev`,CLI 会把该路径作为远端 cwd 传给 Host SSH 维护桥,后续 `pwd`、`git`、`sh`、`bash`、`apply-patch` 和旧 `apply-patch-v1` fallback 等操作仍按同一套 operation parser 执行。`<provider>:host:/absolute/workspace` 是等价长写法;workspace 必须是绝对路径,远端是否存在由维护桥实际 `cd` 失败或成功证明。显式 host workspace 进入失败必须返回 `UNIDESK_SSH_CWD_FAILED` 和非零退出,不得静默落回默认目录;完整 provider-gateway 语义见 `docs/reference/provider-gateway.md`。
当前稳定 plane 包括 `win` 和 `k3s`。`win` plane 的 operation 是 Windows 操作,不是 POSIX shell 别名:`<provider>:win ps` 在 WSL provider 上启动 Windows 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"`。`D601:win/c/test git ...` 是 cmd convenience wrapper,覆盖 `status`、`diff`、非交互 `commit -m ...` 等常规 argv 形态;会打开编辑器或需要 shell 审阅的 git 命令仍用 `ps` 或 `cmd` 包装。`win32` 不是合法 plane,调用者必须改用 `win`。
当前稳定 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"`。`cmd`、`git` 和 host direct argv 会逐 token 保留调用端已经形成的参数边界,包括空格与中文;会打开编辑器或需要 shell 审阅的命令仍用 `ps` 或 `cmd` heredoc 包装。`win32` 不是合法 plane,调用者必须改用 `win`。
Windows workspace 中依赖 Windows PATH、解释器、SDK 或编译工具链的操作必须优先在 `win` plane 执行,而不是先进入同一 provider 的 WSL `/mnt/<drive>` host workspace。WSL/host plane 与 Windows plane 是两套命令环境:前者出现 `python: command not found` 只证明 WSL PATH 中没有该命令,禁止据此判断 Windows 未安装 Python。Windows Python 的最小探测入口是 `trans G14-WSL:win/d/Work/CONSTAR_workspace cmd python --version`;需要 PowerShell 变量、管道或多步逻辑时改用同一路由的 `ps`。
@@ -426,7 +426,9 @@ Get-ChildItem -LiteralPath 'F:\Work' -Directory -Filter '*HWLAB*' | Select-Objec
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` 或宽泛扫描整个用户目录
`<provider>:win skills [--scope agents|codex|all] [--limit N] [--name <精确名称>|--filter <文本>]` 是 Windows 用户 skill 发现入口,默认只读取当前 Windows 用户的 `%USERPROFILE%\.agents\skills`,输出 JSON 中包含 `roots`、`counts`、`query` 和每个 skill 的 `name`、`path`、`skillFile`、`description`。查单个 skill 时优先 `--name`,模糊查找时使用 `--filter`,避免全量结果触发 stdout dump需要同时检查 `%USERPROFILE%\.codex\skills` 时显式加 `--scope all`。
`<provider>:win/<drive>/<path> rg` 是有界 Windows 文件搜索入口,调用 Windows PATH 中的原生 `rg.exe`,支持 `--files`、`-g|--glob`、`--max-count`、`--max-files` 和 `--timeout-ms`。每次搜索都在 stderr 输出 `UNIDESK_WINDOWS_RG_SUMMARY`,稳定披露 `matched`、`fileCount`、`elapsedMs`、`timeout` 和截断状态;默认预算由 `config/unidesk-cli.yaml#trans.windowsFs.rg` 唯一控制。超时返回 124,无匹配返回 1,缺少 `rg.exe` 返回 127 和可执行替代提示,均不会以空输出伪装成功。Windows `wc` 同时支持 `-l|--lines`、`-w|--words`、`-m|--chars` 与 `-c|--bytes`。
`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,这样路由子模块和操作子模块可以独立扩展。
@@ -467,7 +469,7 @@ PATCH
`logs` operation 默认是有界读取;`--follow`/`-f` 会被拒绝,防止 CLI 长时间占用维护桥。目标 route 后面直接跟普通命令时,CLI 会把 argv 放到 `kubectl exec --` 后;显式 `exec` operation 可用于让命令边界更清晰。`exec --stdin -- <command> ...` 是 workload route 的通用 stdin 流入口,适合把 tar、patch 以外的任意字节流直接送进容器命令;operation 选项必须放在 `--` 前,容器命令从 `--` 后开始。需要 shell 语法时优先改用 `sh` 或 `bash` operation,把脚本走 stdin,而不是把 `kubectl exec ... -- sh -c ...` 放进远端命令字符串。pod 内文本热修默认使用 workspace route 加 `apply-patch`,不要求目标容器自带 `python3`、`node` 或仓库里的工具脚本;旧 `apply-patch-v1` operation 仍使用同一个 sh helper,只作为显式 legacy fallback,不用于二进制改写。
`trans <providerId> argv <command> [args...]` 是通用 argv 安全拼接入口;`exec` 是同义入口。它是非交互远端单进程命令的默认成功路径,不需要 shell 管道时直接传命令和参数,例如 `trans D601 argv true`。需要管道、重定向、变量展开或多条命令时,优先改用 `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> argv <command> [args...]` 是通用 argv 安全拼接入口;`exec` 是同义入口。它是非交互远端单进程命令的默认成功路径,不需要 shell 管道时直接传命令和参数,例如 `trans D601 argv true`。直接写未列入专用 helper 的单进程命令时也会逐 token shell quote,不再把已形成的多词参数重新按空格拆分。需要管道、重定向、变量展开或多条命令时,优先改用 `trans <providerId> sh <<'SH'`。`apply-patch`、`find`、`glob` 和旧 `apply-patch-v1` fallback 有专用入口;`git`、`rg`、`grep`、`sed`、`nl`、`stat`、`du`、`ls`、`cat`、`head`、`tail`、`wc` 和 `pwd` 可以直接作为 `trans` 子命令使用,CLI 会对每个 argv token 做 shell quoting。`/mnt/<drive>` workspace 上的命令若以 127 和 `command not found` 失败,stderr 会给出同 provider 对应 `:win/<drive>/... cmd` 的 `UNIDESK_SSH_HINT`,用于核对 Windows PATH;原退出码保持不变
通过 `trans <providerId>` 执行多行脚本时,优先使用结构化 helper,例如 `trans G14 py < script.py`、`trans G14 sh <<'SH'` 或 `trans G14:k3s sh <<'SH'`。不要在远端命令字符串里再嵌套 heredoc、复杂引号或 `ssh 'python3 - <<EOF ...'` 形态;多层 shell 解析容易把 stdin 绑定到错误进程,结果会打开远端交互解释器并留下悬挂的 broker/SSH 会话。长脚本需要复用时,优先提交到 repo 或通过 stdin 传输到目标节点执行。