@zhangfengshun/dsh-remote-ssh
VSCode Remote-SSH-style development for DSH — connect to HPC and servers over SSH, read and edit remote files in the built-in Files tab, auto-SSH terminal, remote workspaces with single-roundtrip reads and result caching, and 12 session-aware remote_ssh_* model tools.
Install
dsh plugin --profile web add @zhangfengshun/dsh-remote-ssh
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
@zhangfengshun/dsh-remote-ssh
[English](./README_EN.md) | 中文
类 VSCode Remote-SSH 的 DSH 插件:通过 SSH 连接远程超算 / 服务器,在 DSH 内置「文件」「终端」页签中直接操作远程文件和终端。
目录:[功能](#功能) · [截图](#截图) · [安装](#安装) · [使用](#使用) · [代码示例](#代码示例) · [模型工具](#模型工具) · [命令超时与恢复](#命令超时与恢复) · [兼容性](#兼容性) · [故障排查](#故障排查) · [原理](#原理) · [缓存与一致性](#缓存与一致性) · [许可证](#许可证)
功能
能力 · 说明
🔌 SSH 连接 · 密钥 / 密码认证,ProxyJump 跳板机,~/.ssh/config 一键导入
📂 远程文件 · 内置「文件」页签直接 SSH 读写远程文件,无需同步
💻 远程终端 · 内置「终端」页签自动检测远程工作区,SSH 交互式终端,落在工作区对应的远程目录(与 VSCode Remote-SSH 一致)
🌐 远程工作区 · 选择远程目录创建原生工作区,一键进入远程环境
🤖 模型工具 · 13 个 remote_ssh_* 工具,会话感知免填连接参数;命令级超时 + remote_ssh_kill 兜底恢复
🗂️ @ 引用补全 · 远程工作区会话里 @ 补全列远端文件(git 仓库走 git ls-files,实测 0.1s;非 git 用有界 find;索引缓存 + 900ms 查询预算,超时降级不卡输入框)
⚡ 打开提速 · 单往返合并读 + raw 文本快路径 + 结果缓存(LRU + 5s TTL):首开 ≈1.31×,TTL 内重复打开 0 往返,过期复验 ≈5×(真实超算实测);remote_ssh_exec 连接复用 ≈15×
截图
设置 → 远程连接:连接配置(密钥 / 密码 / ProxyJump 跳板机)· 连接测试 · 从 ~/.ssh/config 一键导入
<p align="center"><img src="assets/settings-remote-connections.png" width="420" alt="设置:远程连接"></p>
内置「文件」页签:直接浏览远程主机文件(右侧文件树即远程目录,编辑保存直写远程)
<p align="center"><img src="assets/remote-files-tab.webp" width="820" alt="内置文件页签直接浏览远程文件"></p>
内置「终端」页签:自动 SSH 到远程超算(图为 SLURM 作业调度环境);左侧会话即模型免填调用 remote_ssh_* 工具
<p align="center"><img src="assets/remote-terminal.webp" width="820" alt="内置终端页签自动 SSH 远程超算"></p>
安装
前置要求
项 · 要求
DSH · ≥ 0.1.5-rc.1,含 0.2.0-rc.1(最新官方线;0.1.2 稳定线请用 v0.18.1 时代的插件版本)。插件声明的 peer 范围显式列出每条已验证版本线,因此新版 harness 的兼容性门(见[安装](#安装))不会拦住它
dsh-better-sidebar · ≥ 0.15(本插件依赖其 /sidebar/api/ 文件 API 与 0.24 的 open.external「打开方式」端点;0.23 起文件树改为批量 fs.trees 并新增 fs.mkdir,2.4.18 起已适配)。可以只装本插件:2.4.18 起未安装它时不再卡住 web boot(见下方说明),但「文件」页签的远程读写与编辑器页签也随之不可用
本机 SSH 客户端 · Windows:系统自带 OpenSSH(%SystemRoot%\System32\OpenSSH\ssh.exe);Linux/macOS:openssh-client
远程主机 · 任意标准 sshd(超算 / 服务器 / 跳板机均可)
一条命令安装(无需 token、API Key 或额外配置):
dsh plugin --profile <name> add @zhangfengshun/dsh-remote-ssh@2.4.45
安装后重启 DSH。@zhangfengshun/dsh-remote-ssh 必须在 bundles 列表中排在 dsh-better-sidebar 之后。
只装本插件、不装dsh-better-sidebar(或它加载失败)会怎样? 2.4.18 起可以正常启动:客户端只把内核服务(slots/locale)声明为硬依赖,better-sidebar 改走子 fiber 软注入 —— 装了才注册远程文件编辑器页签,没装就静默降级。此时能用:设置页「远程连接」(SSH 连接与远程工作区)、模型工具(remote_ssh_)、远程终端集成、@远程文件补全;不能用:「文件」页签的远程读写与编辑器页签 —— 那套/sidebar/api/fs.通道属于 better-sidebar(内核原生侧边栏走的是它自己的/api/*,本插件不接管)。1.0.0 之前的旧版插件在这里会永久 pending,前端直接报web boot: 1 entry did not activate/pending (waiting for service: betterSidebar)(issue #18)。另外 better-sidebar 缺席时宿主会打一条patch: entry "better-sidebar" not found的 warn ——dsh-app-boot对缺席的 patch 目标无条件告警,属正常,可忽略。
DSH 0.2.0-rc.1 起:装不上 / 插件列表里不出现? 新版 harness 会按插件自己声明的 DSH peer 版本范围判定兼容性,范围覆盖不到当前运行时版本时会拒绝安装/激活(提示Plugin … is incompatible with dsh <版本>),并在插件管理器里给你一个「接受风险」的逐版本豁免。2.4.16 起本插件的 peer 范围已显式列出所有已验证版本线(^0.1.0-rc.6 || ^0.1.5-rc.1 || ^0.1.7-rc.2 || ^0.2.0-rc.1),不需要任何豁免即可安装。若你用的是更早的插件版本,请升级而不是点"接受风险"。(判定是严格 semver:预发布运行时只被"版本线显式列出"的范围覆盖 —— 这也是为什么范围里要逐条列0.1.5-rc.1这类版本。)
卸载:
dsh plugin --profile <name> remove @zhangfengshun/dsh-remote-ssh
⚠️ dsh-better-sidebar 版本兼容性(2026-09 实测):0.18.1 / 0.19.0 / 0.19.1在 DSH Desktop v2.0.9(DSH 0.1.5-rc.1)上主机半边无法加载(它们以值方式导入SessionLogOffset,桌面版模块面只提供该类型声明)→ 侧边栏文件页签显示「这类内容还没有可用的查看方式。」。请使用 0.18.0,或使用已修复该导入的构建;本插件对 0.18(4 端点)与 0.19(6 端点,含fs.rename/fs.remove)两套契约均已适配。
使用
三步上手
1. 设置 → 远程连接 → 添加连接(主机 / 端口 / 用户 / 密钥)→ 点「测试连接」验证;已有 ~/.ssh/config 可直接一键导入
2. 添加工作区 → 选「选择远程目录…」→ 选连接 → 浏览并选择远程目录(该目录会成为原生 DSH 工作区);目录还不存在时点「📁 新建目录」就地创建(本地 / 远程 tab 均支持),创建后自动进入新目录
3. 进入该工作区会话:内置「文件」页签直接显示远程文件(编辑保存直写远程),「终端」页签自动 SSH 到该工作区的远程目录(仅密钥认证)
会话内直接对模型说(远程工作区会话中免填连接参数):
看看 /home/user/project 下有什么,然后把 train.py 的第 20 行改掉 跑一下 squeue -u $USER,把排队情况整理成表格 把这个目录的 *.log 里含 ERROR 的行抓出来
代码示例
示例 1 · 执行远程命令(remote_ssh_exec,默认 120s 超时):
{
"command": "sinfo -h -o '%P %a %D %t %N' | head -20",
"timeoutMs": 30000
}
返回 { ok, exitCode, stdout, stderr, error, truncated, isTimeout }——例如:
{ "ok": true, "exitCode": 0, "stdout": "cpu* up 12 idle 8 ...\n", "stderr": "", "error": "", "truncated": false, "isTimeout": false }
示例 2 · 文件读写(无需同步):
{ "path": "~/project/config.yaml", "content": "lr: 0.001\nepochs: 50\n" }
{ "path": "~/project/train.py" }
remote_ssh_cat 走 base64 传输(二进制安全),remote_ssh_write 为原子写入(写临时文件再 rename)。
示例 3 · 长时任务与挂起恢复(构建 / 训练显式放宽,卡住可强杀会话):
{ "command": "cd ~/project && bash run_train.sh", "timeoutMs": 0 }
{ "all": true }
timeoutMs: 0 禁用本次超时;环境变量 DSH_REMOTE_SSH_CMD_TIMEOUT_MS=600000 可改全局默认。超时后池化会话自动丢弃重建,remote_ssh_kill 是随时可用的手动兜底。
远端语义(2.4.44 起写清):timeoutMs 只是本地等待预算 —— 到点只放弃等待并丢弃会话,不会终止远端命令(远端进程可能继续运行,输出不再回传;断开连接 / 退出 DSH 同理)。需要远端硬时限请用远端自己的 timeout <秒> <命令>。按停止键取消与 remote_ssh_kill 才代表「终止」:插件会给远端 shell 所在的进程组发 SIGHUP(最多等 4s;与关终端同义,nohup / setsid 起的任务不受影响)。
示例 4 · 远程工作区内的工具调用(免填 profileId,相对路径基于工作区远程目录):
{ "path": "configs/exp1.yaml" }
示例 5 · 从 ~/.ssh/config 导入连接:设置 → 远程连接 → 「导入 SSH config」→ 勾选主机 → 自动填充 host / user / port / keyPath / ProxyJump。
示例 6 · 本地镜像同步与回推(离线批改后再一次性上传):
{ "workspaceId": "w_xxx" }
{ "workspaceId": "w_xxx" }
remote_ssh_sync 把远端拉进本地镜像目录,remote_ssh_push 把镜像改动推回远端(tar over ssh,批量高效)。
2.4.20 起同步是「有门槛的整树操作」,顺序固定为 体积哨兵 → 解包到临时目录 →(整树时)比对「只存在于镜像的文件」→ 原子替换,任何一步失败都不碰旧镜像:
参数 · 作用
paths · 只同步这些子路径(相对远端根),例如 ["src","docs"]。局部同步只覆盖对应子路径,不删除镜像里任何其它文件。
exclude · 排除规则(相对远端根,支持 ),下推为 tar --exclude=./x,例如 ["data",".log"]
force · 显式确认:跳过体积哨兵与「仅存在于镜像的文件」保护(确认要整树全量复制时才用)
maxBytes · 本次同步的体积上限,覆盖工作区设置与默认 2 GiB
timeoutMs · 本次同步的墙钟预
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::92,最后更新 2026-11-06