---
name: unidesk-trans
description: UniDesk SSH 透传与 apply-patch 语法 — `trans <route> <operation>` 分布式执行入口，包含 route 语法、workspace/k3s/Windows 路由、apply-patch envelope 格式、sh/bash/py/upload/download operation 和 60s 短连接约束。用户提到 trans、tran、ssh 透传、远端执行、apply-patch、apply_patch、远端 patch、k3s route、workspace route 时使用。
---

# UniDesk Trans（SSH 透传 + apply-patch）

UniDesk 分布式 SSH 透传入口，统一通过 `trans <route> <operation>` 在远端 host/k3s/Windows 上执行命令或文本 patch。

**固定入口**: `trans <route> ...`（wrapper 位于 `/root/.local/bin/trans`，委托 repo 内 ssh-only 启动入口 `bun scripts/ssh-cli.ts ssh "$@"`，避免被无关 CLI 子命令模块解析失败拖垮）

---

## Route 语法

```
trans <providerId>[/absolute/workspace] <operation> [args...]
trans <providerId>:<plane>[:<namespace>:<resource>[:<container>]] <operation> [args...]
```

### Host workspace route

```bash
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'
...
SH
```

**规则**: workspace 路径写在 route 第一个 token，不写进 `cd` 串。反面示例：~~`trans G14 sh -- 'cd /root/hwlab && git status'`~~

### k3s route

```bash
# 控制面
trans G14:k3s kubectl get pods -n hwlab-dev
trans D601:k3s kubectl get pods -A

# 指定 namespace + workload
trans G14:k3s:hwlab-dev:hwlab-cloud-web:app exec --cwd /app -- cat /app/version.txt
trans G14:k3s:hwlab-dev:pod:hwlab-cloud-web-abc:app apply-patch --cwd /workspace <<'PATCH'
...
PATCH
```

CLI 自动注入 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml`。k3s route 中 `:` 是分布式路由分隔符，`/` 只表示容器内文件系统 cwd；容器选择必须写 `:<container>` 或 operation 参数 `--container <container>`，不要写成 `pod/<pod>/<container>`。

### Windows route

```bash
trans D601:win ps <<'PS'
Get-ChildItem C:\test
PS

trans D601:win/c/test cmd cd
trans D601:win/c/test pwd
trans D601:win/c/test ls --limit 50
trans D601:win/c/test cat README.md
trans D601:win/c/test head -n 40 README.md
trans D601:win/c/test tail -n 40 README.md
trans D601:win/c/test stat README.md
trans D601:win/c/test wc README.md
trans D601:win/c/test rg -i needle .
trans D601:win/c/test git status --short --branch
trans D601:win/c/test git diff --check
trans D601:win/c/test git commit -m 'fix: update docs'
```

Windows route 里的 `win` 只表示 route plane，后面 operation 直接写 `ps`、`cmd`、`git` 或 fs helper；不要写成 `trans D601:win/... win ps`。Windows operation 必须显式区分：`ps` 走 PowerShell，`cmd` 走 cmd.exe。`git` 是 Windows cmd convenience wrapper，会通过 Windows cmd 在 route cwd 下执行，支持 `git status`、`git diff` 和非交互 `git commit -m ...` 等常规 argv 形态；会打开编辑器或需要复杂 shell 审阅的命令请用 `ps` 或 `cmd` 包装。`pwd|ls|cat|head|tail|stat|wc|rg` 是 Windows 文件系统只读 helper，带 UTF-8/binary 检查和输出上限，不表示 Windows route 有 POSIX `sh`/`bash`。其中 `rg` 是受限 UTF-8 正则搜索子集，支持 `-i/--ignore-case`、`-F/--fixed-strings`、`-n`、`-m/--max-count`、`--max-files`、`--max-bytes`。

扩展 Windows helper 时保持 operation-scoped PowerShell payload。不要把多 operation 的大 switch 一次性塞进 single `EncodedCommand`；超过 Windows/WSL argv 限制时，常见表现是 `/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe: Invalid argument`，stderr 不会指出真实原因。需要更长逻辑时优先拆短 helper 或切到临时脚本/受控 stdin 路径。

### GitHub issue/PR route

```bash
trans gh:/pikasTech/HWLAB/issue ls --state all --limit 20 --search 'YAML-first 测试账号 API_KEY 准备 PJ2026-0105' --full
trans gh:/pikasTech/HWLAB/issue/1236 cat
trans gh:/pikasTech/HWLAB/issue/1236 rg 'API_KEY|YAML-first'
trans gh:/pikasTech/HWLAB/issue/1236 apply-patch <<'PATCH'
*** Begin Patch
*** Update File: body.md
@@
-old text
+new text
*** End Patch
PATCH
```

GitHub issue/PR 正文读写也走 `trans gh:/owner/repo/...`。常见读取优先用 `issue ls --search/--state`、`cat`、`rg`，不要为了看正文先回到 `bun scripts/cli.ts gh issue view --json body --full`；普通小补丁可直接 `apply-patch`，`--dry-run` 只作为高风险正文预览。

---

## Operation

### sh / bash（显式 shell heredoc）

```bash
# POSIX /bin/sh heredoc
trans G14:/root/hwlab sh <<'SH'
echo "step 1"
git status --short --branch
echo "step 2"
SH

# Bash heredoc：只有用到 pipefail、数组、[[ ... ]]、${var:0:8} 等 Bash 语法时使用
trans G14:/root/hwlab bash <<'BASH'
set -euo pipefail
short="${GITHUB_SHA:0:8}"
printf '%s\n' "$short"
BASH

# one-liner
trans G14:/root/hwlab sh -- 'git fetch origin G14 && git pull --ff-only origin G14'

# 单进程 direct argv 不放在 sh/bash 下，直接用已知子命令或 argv
trans D601:/path sed -n '1,20p' AGENTS.md
trans D601:/path argv sed -n '1,20p' AGENTS.md
```

`script` 和 `shell` operation 已移除并会失败；必须在 operation 位置明确写 `sh` 或 `bash`，让调用者和 Agent 都知道脚本语法边界。Windows PowerShell 必须用 `ps`。

### argv（单命令）

```bash
trans G14:/root/hwlab git status --short --branch
trans D601 hostname
```

### apply-patch（远端文本 patch）


- **P0: 所有远端文本/源码修改必须优先使用 `apply-patch`，禁止用 `py`（python3 写文件）或 `sed` heredoc 拼接大段文本替代。** 只有当 apply-patch 本身不可用或需处理非文本/批量机械生成文件时，才使用其他受控方式；使用前必须在注释中说明原因，修改后立即用 `git diff` 或文件尾部检查确认没有截断或污染。

```bash
trans G14:/root/hwlab apply-patch <<'PATCH'
*** Begin Patch
*** Update File: AGENTS.md
@@
 ## Heading
 context line
-old line
+new line
 more context
*** End Patch
PATCH

# 从文件读
trans G14:/root/hwlab apply-patch < patch.diff
```

v2 引擎（默认）：本地 TypeScript 解析 hunk，远端只读写文件。v1 legacy 入口：`apply-patch-v1`。

Host/WSL 与 Windows route 的 `apply-patch` 优先使用 route fs adapter 的 bulk update path。单文件文本 update 应看到 `remoteOperationCounts` 类似 `{"fs.readFiles":1,"fs.applyReplacementsBulk":1}`，而不是旧慢路径 `stat/read-b64-block/write-b64-argv`。如果 D601 这类 provider 出现瞬态通道抖动，先保留 `apply-patch` 路径并重试/查 `debug ssh-pool <provider>`，不要退回 PowerShell/Python/sed 临时写文件。

### py（远端 Python 脚本）

```bash
trans D601 py -- arg1 arg2 < script.py
```

自动写到远端临时 `.py` 文件，`python3 -u` 执行后清理。

### upload / download（整文件传输）

```bash
trans G14:/root/hwlab upload ./local-file.txt /root/remote-file.txt
trans G14:/root/hwlab download /root/remote-file.txt ./local-file.txt
```

自动校验 SHA-256，结果中 `verified=true` 即完整性证明。

### kubectl / logs（k3s 诊断）

```bash
trans G14:k3s kubectl get pods -n hwlab-dev
trans G14:k3s logs deploy/hwlab-cloud-api -n hwlab-dev --tail 50
trans G14:k3s:hwlab-dev:hwlab-cloud-web-abc logs --tail 100
```

### skills（远端 skill 发现）

```bash
trans G14 skills [--scope all|wsl|windows] [--limit N]
```

### tcp-pool 状态与并发 smoke

查看 Provider 是否使用 SSH TCP data pool：

```bash
bun scripts/cli.ts debug health
```

在输出或 frontend 原始 JSON 里看这些 labels：`providerGatewaySshDataTransport=tcp-pool`、`providerGatewaySshDataPoolReady`、`providerGatewaySshDataPoolClaimed`、`providerGatewaySshDataPoolDesired`、`providerGatewaySshDataPoolLastError`。

单个 provider 的低噪声池状态：

```bash
bun scripts/cli.ts debug ssh-pool D601
```

如果 `trans`/`tran` stderr 出现 `UNIDESK_SSH_TCP_POOL_HINT`，优先按其中的 `failureKind` 处理：`provider-data-channel-closed` 表示会话中途 data channel 断开，`provider-data-channel-missing` 表示 core/provider 对 channel 状态不一致，`provider-data-pool-exhausted` 表示没有空闲 channel。对幂等受控操作先查 `debug ssh-pool <provider>`，再重试原受控 CLI；不要把这类 hint 单独定性为远端 runtime 配置失败。

快速验证 D601 维护桥：

```bash
trans D601 argv true
trans D601 argv hostname
```

并发 smoke 用短命令并给每路加本地 timeout：

```bash
tmp=$(mktemp -d /tmp/trans-d601-pool-10.XXXXXX)
for i in $(seq 1 10); do
  timeout 30s trans D601 sh -- 'printf start:'"$i"':%s\\n "$(date +%s%3N)"; sleep 2; printf end:'"$i"':%s\\n "$(date +%s%3N)"' >"$tmp/$i.out" 2>"$tmp/$i.err" &
done
wait
for i in $(seq 1 10); do echo "[$i]"; cat "$tmp/$i.out"; cat "$tmp/$i.err" >&2; done
```

期望是每一路 rc=0、stderr 为空、stdout 同时包含 start/end；结束后 pool labels 回到 `claimed=0`。

---

## apply-patch 语法（Envelope 格式）

**不是 unified diff**，是 Codex 专用 envelope。

```
*** Begin Patch
*** Update File: <relative-path>
@@
 context line
-old line
+new line
 more context
*** End Patch
```

### 关键规则

| 规则 | 正确 | 错误 |
|------|------|------|
| 路径必须相对 | `AGENTS.md` | `/root/unidesk/AGENTS.md` |
| hunk 分隔符 | `@@` | `@@ -N,M +K,L @@` |
| 空行 | ` \n`（空格+换行） | 裸 `\n` |
| 首行/尾行 | `*** Begin Patch` / `*** End Patch` | 外层不能有空行 |

### 操作类型

```bash
*** Update File: path/to/file.ext    # 修改现有文件
*** Add File: path/to/new.ext        # 新增文件（可覆盖已有）
*** Delete File: path/to/old.ext     # 删除文件
*** Move File: old/path -> new/path  # 移动/重命名
```

### 上下文定位

默认 3 行上文 + 3 行下文。同一 hunk 在文件中重复时用 `@@` 跳到 class/function：

```
*** Update File: src/app.ts
@@ class MyComponent
 old context
-old code
+new code
 more context
```

### 常见失败

| 症状 | 原因 | 处理 |
|------|------|------|
| `failed to find expected lines` | 上下文不匹配（文件已变） | 重读目标块，缩小 hunk |
| 空 stdout + stderr 报错 | 首行/路径格式错误 | 检查相对路径、envelope |
| partialChanges | 前序 hunk 成功，当前失败 | 基于当前文件状态补小 patch |

成功 stdout：`Success. Updated the following files:` + 文件列表。失败 stdout 为空，stderr 写原因。

### 远端 patch 正确姿势

第一个 route token 直接定位到目标 pod/container，容器内 cwd 用 operation 参数 `--cwd /path`，不要从 host 生成 diff 再改路径上传：

```bash
# ✅ 正确
trans G14:k3s:hwlab-dev:pod:hwlab-cloud-web-abc:app apply-patch --cwd /web <<'PATCH'
*** Begin Patch
*** Update File: app.mjs
@@
-old
+new
*** End Patch
PATCH

# ❌ 错误：host 生成 diff → 本地 sed 改路径 → 管道到 pod
```

---

## 60s 硬超时与短连接

`trans` 有 60 秒硬超时（不可调大）。长任务必须拆成 submit-and-poll：

```bash
# ✅ 异步启动 + 短轮询
trans G14:/root/hwlab sh -- 'hwlab-cli case run start d601-f103-v2-compile'
trans G14:/root/hwlab sh -- 'hwlab-cli case run status <runId>'

# ❌ 长时间挂着等
trans G14:/root/hwlab sh -- 'long_running_command && wait'
```

### HINT 信号

| stderr 输出 | 含义 |
|-------------|------|
| `UNIDESK_SSH_HINT` | SSH 握手/超时摩擦，提示改用 `sh`/`bash` stdin heredoc |
| `UNIDESK_TRAN_TIMEOUT_HINT` | 60s 硬超时触发，提示改用短查询+轮询 |
| `UNIDESK_SSH_TIMING` | 慢命令 warning（>10s），用于性能回归监控 |
| `UNIDESK_APPLY_PATCH_TIMING` | apply-patch 耗时摘要 |

---

## 关键约定

### heredoc 优先

多行远端脚本优先用 heredoc，不拼接 shell 字符串：

```bash
# ✅ 推荐
trans G14:/root/hwlab sh <<'SH'
cmd1
cmd2
SH

# ❌ 避免
trans G14 sh -- 'cmd1 && cmd2 && cmd3'
```

### 本地 shell 运算符陷阱

`&&` / `;` / `|` 在 `trans` 后面会被本地 shell 截获。需要远端执行多条命令时用 `sh` 或 `bash` 包裹：

```bash
# ❌ 第二个 sed 在 master server 本地执行
trans G14:/root/hwlab sed -n '1,20p' a && sed -n '1,20p' b

# ✅ 两个 sed 都在远端
trans G14:/root/hwlab sh -- 'sed -n "1,20p" a && sed -n "1,20p" b'
```

### Windows quoting

Windows PowerShell heredoc 用单引号 `<<'PS'`：

```bash
trans D601:win ps <<'PS'
Write-Output "hello"
PS
```
