npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zhangfengshun/dsh-remote-ssh

v2.4.19

Published

DSH web plugin: VSCode Remote-SSH-like remote development (SSH to supercomputers/servers, remote workspace, file explorer, integrated terminal), integrated with dsh-better-sidebar and DSH settings.

Readme

@zhangfengshun/dsh-remote-ssh

English | 中文

类 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 一键导入

内置「文件」页签:直接浏览远程主机文件(右侧文件树即远程目录,编辑保存直写远程)

内置「终端」页签:自动 SSH 到远程超算(图为 SLURM 作业调度环境);左侧会话即模型免填调用 remote_ssh_* 工具

安装

前置要求

| 项 | 要求 | | --- | --- | | 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/[email protected]

安装后重启 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 是随时可用的手动兜底。

示例 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,批量高效)。

模型工具

| 工具 | 用途 | | --- | --- | | remote_ssh_profiles | 列出连接配置 + 当前会话远程工作区上下文 | | remote_ssh_exec | 执行远程命令(默认 120s 命令级超时,timeoutMs 可放宽/禁用) | | remote_ssh_kill | 强制关闭池化 SSH 会话(挂起命令的兜底恢复) | | remote_ssh_ls | 列举远程目录 | | remote_ssh_cat | 读取远程文件 | | remote_ssh_write | 写入远程文件 | | remote_ssh_grep | 搜索远程文件内容 | | remote_ssh_glob | 查找远程文件 | | remote_ssh_mkdir | 创建远程目录 | | remote_ssh_delete | 删除远程文件/目录 | | remote_ssh_move | 移动/重命名 | | remote_ssh_sync | 远端同步到本地镜像 | | remote_ssh_push | 本地镜像推送回远端 |

远程工作区会话中调用工具可免填 profileId 等连接参数;全部文件/命令类工具走持久 SSH 会话池 + 结果缓存,remote_ssh_exec 单命令实测 ≈15× 提速。

@ 文件引用补全

远程工作区会话里输入 @,候选来自远端(与「文件」页签的树一致),而不是本地镜像目录:

  • 索引来源:git 仓库用 git ls-files --cached --others --exclude-standard(尊重 .gitignore、含未跟踪文件;真实超算实测 0.117s / 137 条),非 git 目录回退有界 find(maxdepth 5 + 剪枝,实测 1.57s / 3121 条);
  • 排除在远端、截断之前(2.4.8 修复):git ls-files --cached --others 的输出不是全局字典序(未跟踪文件按 readdir 顺序先输出),node_modules/ 这类目录可能占满前两万行把配额吃光——因此排除目录由远端 grep -vE 在 head 之前完成(与 -prune 同源,正则由同一份排除表生成),客户端过滤仅作双保险;索引达到上限时会打一条 warn 提示可能漏文件;
  • 查询语义与官方 provider 逐条对齐:@ 与 @src/ 走远端目录列举;@read 走索引模糊匹配(同名 > 前缀 > 名称子串 > 路径子串 > 子序列,目录加权 +25);
  • 不卡输入框:索引按工作区缓存 60 秒(写文件/执行命令后自动失效),单次补全只等 900ms——超时先用旧索引作答、重建在后台进行;连接异常时自动回退到本地行为;
  • 本地工作区不受影响:非远程会话直接委托宿主原实现,索引与排序完全没有改动。

命令超时与恢复

所有 SSH 命令默认 120 秒超时(issue #5):一条挂起的远端命令(网络卡顿、远端进程僵死、等待 stdin 的 cat)不会再永久占用会话、拖死后续命令。

  • 超时后自动恢复:池化会话超时即被丢弃并自动重建,后续命令照常执行;一次性连接超时即终止 SSH 进程;
  • 显式放宽:remote_ssh_exec 传 timeoutMs(毫秒)覆盖单次预算,0 禁用超时(长时构建/训练);环境变量 DSH_REMOTE_SSH_CMD_TIMEOUT_MS 覆盖全局默认;
  • 手动兜底:remote_ssh_kill(或 all: true)强制关闭某个/全部池化会话,挂起命令随时可清理;
  • 超时命令不做自动重试(重试一条挂起的命令只会再次挂起),由模型决定是否改用 remote_ssh_kill 或换命令重试。

兼容性

实测矩阵(2026-09-12,均为真机验证):

| 组件 | 版本 | 状态 | | --- | --- | --- | | DSH | 0.1.5-rc.1(DSH Desktop v2.0.9) | ✅ 主机服务 / settings / tools / slot / 上传下载拦截全部咬合 | | DSH | 0.2.0-rc.1(DeepSeek Harness 桌面端 nightly,2026-09-28) | ✅ 2.4.16 起适配并真机验证:peer 范围显式列出该版本线(否则 harness 会拒绝安装/激活);settings 新 API 与旧数据迁移继续有效(实测升级后首次启动即恢复全部连接与工作区);终端 patch 仍命中 terminal-controller。客户端注入清单同步移除运行时已不提供的 dsh-client-runtime;2.4.17 修好浅色主题下"工作区地球角标不可见"(颜色改为取图标自身计算色) | | DSH | 0.1.7-rc.2(DSH Desktop v2.0.15) | ✅ 2.4.15 起适配:settings 新 API(configure/describe/update,数据存于本插件 entry 的 Config,字段标 .volatile())+ 旧 settings.yaml 一次性迁移(连接/工作区 ID 与 mirrorPath 全保留,无需重建);侧边栏终端改由宿主原生 terminal-controller 管理,patch 已同时覆盖它与 better-sidebar | | DSH | 0.1.5-rc.1 / 0.1.0-rc.6 线 | ✅ 主机服务 / settings / tools / slot / 上传下载拦截全部咬合(peer 范围继续覆盖) | | DSH | 0.1.2-rc.1 稳定线 | ✅(插件 2.3.x 时代基线) | | dsh-better-sidebar | 0.15.0 – 0.18.0 | ✅ fs.tree/fs.read/fs.write + fs.search({ matches: cwd 相对 '/'-分隔路径, truncated } 契约,2.4.11 起;此前只回 entries 会让「按文件名搜索」崩掉整块页签) | | dsh-better-sidebar | 0.19.x | ⚠️ 插件侧已适配 6 端点(含 fs.rename/fs.remove);但 0.19.0/0.19.1 自身在 DSH Desktop 上主机半边无法加载,需等上游修复(见安装的警告) | | dsh-better-sidebar | 0.20 – 0.24.x(实测 0.24.1) | ✅ 2.4.18 起适配 9 端点:0.23+ 的文件树改为批量 fs.trees(一次请求列举「可见集」,≤64 条)+ 新增 fs.mkdir,0.24 的「打开方式」走 open.external。此前只注册 fs.tree → 新版的列举绕过拦截落到 better-sidebar 自己的本地实现,远程项目里看到的就成了本地镜像目录;「打开方式」也只会打开本地镜像(见故障排查) | | dsh-better-sidebar | 未安装 / 加载失败 | ✅ 2.4.18 起可正常启动(不再阻塞 web boot,见安装):设置页「远程连接」、模型工具、远程终端、@ 补全照常;⚠️ 「文件」页签的远程读写与编辑器页签不可用(/sidebar/api/fs.* 属于 better-sidebar;内核原生侧边栏走自己的 /api/*)。宿主会打一条 patch: entry "better-sidebar" not found 的 warn,属正常 | | 远程主机 sshd | 标准 OpenSSH(Linux / 超算 / Windows) | ✅ 密钥认证;密码认证需本机 sshpass(POSIX) |

插件不修改 DSH 源码、不注入 profile 依赖树,全部能力经官方 cordis.patch.yml + profile 机制挂载。

故障排查

| 现象 | 原因与解法 | | --- | --- | | 「测试连接」报 Permission denied (publickey) | ① 私钥带口令:插件以批处理模式运行(BatchMode=yes),无法交互输口令——先用 ssh-add 加载,或去掉密钥口令;② Windows host 且用户在 Administrators 组时,公钥须写入 C:\ProgramData\ssh\administrators_authorized_keys;③ 用户名的写法(user / .\user / user@domain)要与手动连接一致 | | 从 git-bash 启动 dsh web 后密钥认证失败 | 2.3.9 起已修复:Windows 下 ssh 解析固定为系统 OpenSSH 绝对路径(此前会误用 Git 自带的 MSYS2 ssh) | | 侧边栏文件页签显示「这类内容还没有可用的查看方式。」 | dsh-better-sidebar 主机半边未加载:0.18.1 / 0.19.0 / 0.19.1 在 DSH Desktop 上会因 SessionLogOffset 运行时导入失败——降到 0.18.0 或使用修复版(上游 PR #641) | | 前端整屏报 Failed to load plugins / web boot: 1 entry did not activate / @zhangfengshun/dsh-remote-ssh: pending (waiting for service: betterSidebar),Desktop 还提示「插件恢复」 | ≤ 2.4.17 已知问题(issue #18):本插件当时把 better-sidebar 的客户端服务声明为硬依赖,未安装它的用户前端会停在 pending(cordis 的 fiber 只要一个 inject 键缺失就整体不激活)。升级到 2.4.18 即可;或临时装上 dsh-better-sidebar(注意版本线要与内核匹配)并重启 | | 远程项目的侧边栏「文件」页签显示的是本地目录(不是远程目录) | 2.4.18 起已修复:dsh-better-sidebar 0.23+ 把文件树从「逐层 fs.tree」改成「一次 fs.trees 批量列举可见集」,而插件当时只注册了 fs.tree 的 exact 路由 → 列举请求绕过拦截、落到 better-sidebar 自己的宿主实现(读本地 fs)。升级插件到 2.4.18 并重启 DSH 即可;本地工作区不受影响(两条分支都实现了 fs.trees)。0.24 新增的 fs.mkdir(新建目录)同理,此前只会建在本地镜像里 | | 右键「打开方式 / 在文件管理器中显示」打开的是本地镜像目录(不是远端) | 2.4.18 起已修复:该菜单把客户端已知的绝对路径直接交给本机打开器(explorer.exe /select,<路径> / rundll32 url.dll,FileProtocolHandler <url>),远程工作区里客户端只有镜像路径。现在拦截 open.external:远程工作区改开 vscode://vscode-remote/ssh-remote+<别名><远端路径>(别名取自 ~/.ssh/config;reveal 打开的是该文件所在的远端目录),本地工作区行为不变 | | 远程工作区里「用 VS Code 打开」没反应 / 提示连不上 | 需要 ~/.ssh/config 里有与连接一致的别名(Host 同名或 HostName 相同、且端口与用户名一致)——插件据此生成 ssh-remote+<别名>,VS Code 会复用该条目的 Port/User/IdentityFile/ProxyJump。没有别名且端口不是 22 时插件回退本机行为并在 DSH 日志里打一条 warn(避免静默失败)。另外:不要在 better-sidebar 的 openWith.sshHost 里手填主机——那条分支由客户端自行打开、路径仍是本地镜像路径,交给本插件处理才对 | | 内置「终端」页签连不上 | 终端为 ssh -tt 交互式通道,仅支持密钥认证;密码认证的连接会回退为本地 shell 并打印一行提示(避免把本地 shell 误认为已连上远程),密码认证请改用「文件」页签与模型工具 | | 「测试连接」报 配置的私钥文件不存在或不可读:…(或原始信息里有 Warning: Identity file … not accessible) | 2.4.19 起会直接点名:连接里 keyPath 指向的私钥文件在本机不存在(拼错路径、换机后密钥没同步、或写了 ~ 但文件不在那儿)。改成正确路径,或清空 keyPath 改为依赖 ssh-agent / ~/.ssh/config 里的 IdentityFile;注意「测试连接」以批处理模式运行,带口令的密钥无法交互输口令(先 ssh-add) | | 远端要求扫码 / 动态口令 / 二次验证(keyboard-interactive),「测试连接」仍失败 | 「测试连接」与文件、工具能力走的是非交互公钥通道(BatchMode=yes + PreferredAuthentications=publickey),不会弹出扫码提示 —— 这是刻意设计(批量、并发、无人值守都不能等人工扫码)。交互式登录请用内置「终端」页签(ssh -tt 交互通道,可扫码/输密码/输动态口令);要让文件与工具能力可用,请在远端 ~/.ssh/authorized_keys 收录本机公钥(贴出的 Permission denied (publickey,password,keyboard-interactive) 只说明远端允许这些方式,不代表本插件能用它们) | | 终端落在远程 $HOME 而不是工作区目录 | 2.4.5 起已修复(wrapper 会 cd 到工作区 remotePath,目录不存在时回退 $HOME);若仍停在 $HOME,确认 2.4.5 已装入并重启 DSH | | 「文件」页签树根显示镜像目录 ID(如 wmirror3) | 2.4.6 起已修复:树根改为显示远程目录名(如 my-project),悬停可见完整远程路径;该标签不经过 fs.* 路由,由客户端渲染层替换 | | @ 补全只搜到镜像里那几个文件 | 2.4.7 起已修复:远程工作区会话的 @ 补全改列远端文件(索引缓存 60s + 900ms 查询预算);若仍只有镜像文件,确认 2.4.7 已装入并重启 DSH | | 大仓里 @ 搜不到真实文件(如根目录 AGENTS.md、src/**) | 2.4.8 起已修复:此前排除目录发生在截断之后,node_modules/ 这类目录会吃光索引配额;现在排除由远端 grep/-prune 在截断前完成,并会在索引达上限时打 warn 提示 | | 想加的远程目录还不存在,「添加工作区」里没法创建 | 2.4.9 起「目录选择器」底部有「📁 新建目录」(本地 / 远程 tab 均有):输入名字即可就地创建并自动进入 | | 从局域网 / 另一台设备访问时插件文件能力全部报 403 | 2.4.10 起已修复:信任判定改用宿主 ctx.webRuntime.trustedHosts(与 /api 网关同源)。把访问地址加进 DSH 信任列表即可:启动时加 --trusted-host <host[:port]>(或经配对设备访问);未配置时行为与之前一致(仅本机 loopback) | | 「文件」页签的「按文件名搜索」一输入就报 Cannot read properties of undefined (reading 'length') | 2.4.11 起已修复:fs.search 拦截此前只返回 entries,而 better-sidebar 客户端契约是 { matches, truncated };现在补上 matches(cwd 相对、/ 分隔,与上游自带实现一致)并保留 entries | | 远程工作区里「按文件名搜索」一直转圈(大工作区) | 2.4.11 起已修复:改为浅层优先(-maxdepth 3,实测冷 0.68s / 热 0.11s)且有命中就立即返回(深挖转后台预热缓存,浅层零命中才同步等深挖 -maxdepth 8),遍历前剪噪声目录、去掉会阻塞短路的 sort,并加远端墙钟预算——到点返回已收集的部分结果并标记不完整。实测某大型远程项目工作区:旧实现 5 分钟零输出 → 现在 0.96s 返回 43 条 | | 远程会话里 @文件名 没有候选,但单独输入 @ 有 | 2.4.11 起已修复:模糊查询依赖索引,而索引首选 git ls-files --cached --others(--others 要遍历整棵工作树,巨型项目上跑不完 → 索引为空)。现在三级降级(完整 git 6s → 仅索引 git 3s → 有界 find maxdepth 3 + 5s),并在索引未就绪时用有界 find 即时兜底(实测 0.65s),不再出现「全空」 | | 安装时提示 minimumReleaseAge 或「No matching version」(刚发布) | npm 供应链新鲜度策略,等 1–5 分钟后重试即可 | | 换一台电脑后,远程工作区的文件夹图标上没有本机看到的地球角标 | 该角标是客户端半边的 DOM 装饰(壳层工作区行只有固定文件夹原语,没有 per-workspace 图标 API),成立前提是:客户端半边已加载 → 宿主能返回远程工作区 → 行文本/属性与工作区标题匹配 → 壳层 DOM 结构一致 → 角标颜色在该主题下可见。2.4.17 起:颜色改为取文件夹图标自身的计算色(浅色/深色都可见,此前硬编码白色在浅色主题下不可见)、匹配做空白归一化并兼容 title/aria-label、并加了自检。排查:在开发者工具 Console 执行 window.__dshRemoteSshGlobeStats(true) —— 返回 undefined 说明客户端半边没加载(升级插件后硬刷新页面);remoteWorkspaces: 0 说明宿主没返回工作区(查插件版本与 harness 兼容性);remoteWorkspaces > 0 而 globesInDom: 0 说明标题或 DOM 没匹配上(对照输出里的 titleSamples 与侧边栏实际显示文字)。 | | remote_ssh_push / remote_ssh_sync 明明推送成功却报 returned invalid output | 2.4.13 起已修复:这两个工具共用的 output schema 把 error 标成必填、成功路径又返回未声明的 remotePath/mirrorPath,于是只有成功会报错(失败路径反而合法)。现在 schema 声明两个路径字段、error 改为可选,成功路径也带 error: "";全文件所有 output schema 的 error 一并改为可选 | | 命令卡住不返回 | 默认 120s 超时后自动丢弃会话;长时任务用 timeoutMs: 0,随时可用 remote_ssh_kill 强杀 | | 大文件读取被截断 | 单文件读取上限 4MB、下载池化路径约 6.29MB(更大自动回落一次性连接);用 remote_ssh_exec + head/tail 分段处理 |

原理

插件注册 9 个 exact 路由(/sidebar/api/fs.tree、fs.read、fs.write、fs.search,better-sidebar 0.19 新增的 fs.rename、fs.remove,0.23+ 新增的 fs.trees、fs.mkdir,以及 0.24 的 open.external),在 better-sidebar 的 prefix 路由之前拦截。会话 cwd 含 .remote-ssh.json 时走 SSH,否则走本地 fs。客户端看到的是本地镜像路径,Host 自动转换为远程路径——对客户端完全透明。

fs.trees 是 0.23+ 的批量列举端点(一次请求带上「工作区根 + 所有已展开目录」,≤64 条;旧版是逐层 fs.tree)。远程分支用 remoteListDirsBatch() 一次 SSH 往返列举全部目录(逐目录标记行 + find -printf,单层失败只影响该层),命中目录缓存(TTL 5s)的层 0 RTT。少注册这一个路由,新版客户端的整棵文件树就会静默回落到宿主的本地实现 —— 这正是 2.4.18 修的问题。

open.external 是 0.24 的「打开方式 / 在文件管理器中显示」端点,宿主侧用本机打开器执行(Windows:explorer.exe /select,<路径>、rundll32 url.dll,FileProtocolHandler <url>)。远程工作区里客户端只有镜像路径,本插件因此把路径翻译成远端路径并改开 vscode://vscode-remote/ssh-remote+<~/.ssh/config 别名><远端路径>:url 保留客户端选中的 scheme(vscode / cursor / zed),reveal 打开该文件所在的远端目录。别名按「Host 同名或 HostName 相同 + 端口一致 + 用户兼容」匹配(纯函数 remoteEditorAuthority),让 VS Code 复用该条目的端口/用户/密钥/跳板机;~ 由插件自己展开(URL 不过 shell,~/run/... 必须先换成远端 home 的绝对路径 —— 用 printf %s "$HOME" 查一次并按 profile 缓存 10 分钟),无可用别名或拿不到 home 时回退本机行为并打 warn。不要在 better-sidebar 里填 openWith.sshHost——那条分支由客户端自行打开、路径仍是镜像路径。

模型侧的文件工具(agent 的 write/edit)走的是进程内 ctx.fs(宿主 base bundle 挂的是本地 fs-sandbox),不经过任何 HTTP 路由,因此 2.4.13 及以前只落本地镜像——用户在远端机器上找不到文件,只能人工 remote_ssh_push。2.4.14 起插件包装 ctx.fs 的 writeText/editText:原写入照旧(镜像内容、沙箱围栏、写意图语义全不变),成功后把同一份内容定向推回远端对应的那个文件(不是整镜像 tar,避免用旧镜像覆盖远端其它文件),写前自动 mkdir -p 远端父目录。推送失败只记一条 warn——本地写入已成功,桥接层不会让写操作变成失败;包装不可用时(服务缺失/被替换)退回旧行为并在日志提示。

远程读取采用单往返合并读:一条池化命令同时返回 size/mtime 帧与文件内容(文本类扩展名优先 raw 直传,字节长 + U+FFFD 双校验失败自动回退 base64,结果逐字节一致);配合主机侧结果缓存与变更失效(见下节)。

Shell wrapper(~/.dsh/remote-ssh/dsh-remote-shell[.cmd])检测工作区 .remote-ssh.json,自动 ssh -tt 连接远程,使内置「终端」页签透明接入。

缓存与一致性

远程读取与目录列举结果在主机侧缓存(读 LRU 32 条 + 列举 LRU 64 条,TTL 5 秒;单条 >1MiB 不缓存、总量 32MB 字节预算,防止大文件驻留拖慢宿主):TTL 内重复打开或切回页签 0 网络往返;过期后先做一次轻量 mtime+size 复验,未变化则免重传。写、删除、移动、建目录、上传、推送(push)、成功的远端 exec 与变更类 git 子命令(add/reset/commit/checkout/revert/cherry-pick)会自动失效相关缓存,并以每 profile 缓存代(epoch)兜底「同秒同 size 写」等粒度盲区。

已知限制:

  • 集成终端(ssh -tt)与远端其它进程改动的文件依赖 TTL + 复验兜底,最多 5 秒陈旧;
  • agent 的 read 仍读本地镜像:2.4.14 起 write/edit 会同步到远端,但若文件在远端被其它人改动,agent 读到的是镜像里的旧内容(用 remote_ssh_sync 重新拉取镜像即可);
  • /sidebar/file 下载池化路径有效上限约 6.29MB,更大文件自动退回一次性连接下载(可成功,多一次重连开销);
  • 二进制内容伪装成文本扩展名时会多一次 base64 回退往返(结果正确)。

❤️ 七夕快乐

本项目是送给 zhangyi 的七夕礼物。

愿它像连接起一台台远方的超算一样,也把我们紧紧连在一起。七夕快乐 ❤️

—— 2026 年 8 月 18 日

更新日志

版本历史与每版修复细节见 CHANGELOG.md(最近:2.4.3 适配 better-sidebar 0.19 端点、2.4.2 修复设置图标闪现、2.4.0 命令级超时与 remote_ssh_kill)。

许可证

MIT


如果这个插件帮到了你,欢迎在 GitHub 上点个 ⭐ Star,或到 DSH Market 收藏——这会帮助更多需要远程超算开发的人找到它。