基于 SSH 的远程开发:把注册机器上的目录选为会话工作区后,文件、shell、bash 与搜索工具即改在远程主机上执行——agent 用与本地相同的工具在那里工作,不新增任何面向模型的工具。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:CJYLZS/dsh-remote-development
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
English | 中文
摘要
本插件为 DeepSeek Harness 提供轻量化远程开发:注册一台 SSH 机器,把远程目录选为会话工作区之后,agent 即可用与本地完全相同的工具(文件工具、shell、搜索)在该远程工作区上工作。插件不新增任何面向模型的工具,也不引入第三方 UI 插件:它把文件系统、子进程、bash 三个 provider 替换为路由版本,将本地工具调用翻译为经 SSH 的远程执行;同时在 Web GUI 中贡献一个设置分区和一个工作区目录选择对话框。
核心特性
- 同构工具集。 远程工作区不增加任何工具调用:agent 的工具集与本地工作区完全一致,由插件在底层把调用翻译为远程执行。
- 远程零依赖。 远程机器不需要任何额外的服务端,一条 SSH 连接即可使用。
- Web GUI 集成。 连接管理覆盖密码 / 私钥 / SSH agent、跳板机、主机密钥 TOFU 与连接测试;支持为不同远程工作区设置自定义颜色标记。
目录
安装
推荐直接从 GitHub 安装——lib/ 构建产物已入库,一条命令即可,无需构建:
dsh plugin add --profile web github:CJYLZS/dsh-remote-development
开发模式则链接本地检出:
cd dsh-remote-development
pnpm install # 自包含 workspace;store 位于 .pnpm-store/
pnpm run build # 产出 lib/index.js(宿主半)与 lib/client.js(浏览器半)
dsh plugin add --profile web link:/absolute/path/to/dsh-remote-development
link: 安装把 profile 指向检出目录,之后每次 pnpm run build 重启 harness 即生效,无需重新 add。
安装后重启 harness。
使用
只需三步:
- 添加机器。 在 Web GUI 的 dsh-remote-development 设置分区填入 host、port、用户名,选择密码 / 私钥 / SSH agent 认证(可选跳板机),点击测试连接。
- 选择远程目录。 在工作区目录流(hero 的「选择目录」对话框或侧边栏工作区选择器)打开远程页签,浏览机器目录,把某个远程目录设为会话工作区。
- 照常工作。 到此为止。文件工具、shell、bash、搜索仍以同样的调用方式执行,只是落在远程机器上;模型的工作目录就是远程路径,不需要任何额外说明,也不会多出任何新工具。所选目录之外的路径保持本地行为,既有会话不受影响。
其底层机制:设置远程工作区会在 $DSH_HOME/remote-workspaces/<host>-<user>-<port>/<basename> 下创建一个锚点——一个真实本地目录,元数据记录远程坐标。不存在「当前机器」或默认目标,锚点独自决定其会话工具的执行位置。若该机器随后被删除,工作区上的操作会以明确的「机器已失配(no longer configured)」错误失败,而不是悄悄换到别的机器执行——重新添加机器即可恢复,或删除该工作区目录。
理解设计
三个路由 provider 替换同一服务的基座行,所有本地工具继续可用,只有传输层改变:
RoutingFileSystem(替换沙箱文件系统)——路径解析到远程根的读写、编辑、列目录经 SFTP 完成;其余调用经super()委托本地基座。RoutingSubprocessRuntime(替换本地子进程运行时)——以锚点为 cwd 的 spawn 在远程主机上经 SSH exec 通道执行;搜索工具使用的打包 ripgrep 会被改写为远程rg二进制。路由只看工作目录,所有宿主平台行为一致。RoutingBashExecutor/RoutingPwshExecutor(替换沙箱 bash/pwsh 执行器)——工作目录在锚点下的命令经远程bash -c执行;后台进程通过进程组 kill 协议拿到真实远程 PID。宿主平台决定挂载哪个执行器——只有本地回退与平台相关(POSIX 用本地 bash,Windows 用本地 pwsh);远程方言始终由远程主机的 POSIX shell 决定。- 按 agent 的工具可见性。 patch 同时挂载两套 shell 工具栈,并按会话安装作用域限制,隐藏该会话工作区不应使用的方言:远程会话只见
bash工具(不见pwsh),Windows 本机会话只见pwsh(不见插件补入的bash)。POSIX 本机会话两个世界都用bash,与基础组合一致。 - 每机器一条共享 SFTP 会话。 SFTP 协议在单一子系统通道上多路复用所有请求,全部文件操作共享一条会话,而不是每次调用开一条(并泄漏)通道——服务器对单连接的会话数有上限,耗尽后所有打开请求都以通道失败告终。
- 远程工作区在文件树中有标记。 client 会为远程工作区重新着色文件夹图标:host 将每个锚点与其机器的标记颜色(
Machine字段,可在设置中编辑)联接,client 把这份清单转成文件树data-files-*钩子上的属性选择器并以样式表注入。每台机器一个颜色;留空则回退到主题强调色。侧边栏的工作区行没有数据钩子,其规则经行内aria-label(:has())命中,匹配锚点工作区采用目录基名得到的标题。 - 远程工作区显示远程路径。 shell 展示工作区目录的位置——文件树的根头部与工作区列表的 hover 卡片——显示的是会话工作目录,而远程工作区的会话工作目录是插件的本地锚点目录。client 维护一张别名表(锚点目录 → 远程路径,与标记颜色共用同一份
/status联接),经 mutation observer 把这些展示文本改写为远程路径,只修改既有文本节点的值,React 的协调器因此保留它拥有的每个元素。底层的data-files-*坐标保持本地:文件树仍按它们导航。
模型看不到锚点句柄。 harness 的系统提示会报告会话工作目录;远程会话下插件按 agent 覆盖该变量为远程路径,模型可见的 cwd 即命令真正运行的目录。作为兜底,命令文本中的锚点目录写法(绝对路径、~、$HOME、${HOME})会在执行前改写为远程路径——仅限同机锚点,stdin 保持原样。本地会话不受影响。
远程变更策略与本地沙箱一致:read-only 模式拒绝远程写入;workspace-write 仅允许写远程工作区根与远程 /tmp。远程写入按文件串行化、原子发布(临时文件 + rename),并对过期版本与歧义编辑返回与本地文件系统相同的错误码。
主机密钥采用 TOFU(默认 accept-new):首次见到的密钥被记录,变更的密钥以中间人原因拒绝;每台机器可选 verify/off 模式。
配置
机器在设置分区中管理;插件自身通过 cordis.yml 接受配置默认值(均可选):
| 字段 | 默认值 | 含义 |
|---|---|---|
commandTimeoutMs |
20000 | 单命令超时;SIGTERM 宽限后关闭通道。 |
connectTimeoutMs |
15000 | SSH 连接建立超时。 |
maxOutputChars |
200000 | 超出后命令输出保留头尾。 |
maxFileBytes |
52428800 | SFTP 单次读写的最大文件体积。 |
hostKeyMode |
accept-new |
accept-new、verify 或 off。 |
remoteRipgrep |
rg |
打包 ripgrep 改写到的远程二进制。 |
anchorRoot |
$DSH_HOME/remote-workspaces |
锚点目录的根目录。 |
auditLog |
关闭 | 远程执行的追加式 JSONL 审计。 |
已知限制与延期工作
- Windows 远程机延期支持。 远程机器必须运行 POSIX shell;
uname探测会以明确错误拒绝 Windows 目标。适配预留到后续阶段。 - Windows 本机支持远程 shell 路由。 Windows 宿主挂载基于 pwsh 的路由执行器:本地工作目录保持沙箱 pwsh 执行器,锚点工作目录跨到远程主机的 bash。模型在远程会话看到
bash工具,本地会话看到pwsh工具。 - 不支持持久终端会话。 终端工具会返回明确的"not supported by dsh-remote-development"错误,而不是让 agent 自行尝试;远程命令请使用 bash 工具。持久 shell 工具仍仅限本地:指向远程工作区的持久工具会以同样错误拒绝。
- 远程会话不支持
@文件引用。 远程会话中输入@会给出单条明确的"暂不支持"候选,而不是静默失败;引用源接口已预留到后续阶段。 - 没有镜像或同步层。 锚点目录只保存元数据,不保存文件副本;每次读写都经 SSH,受
maxFileBytes限制。 - 文件树标记依赖 in-box 的
data-files-*钩子。 着色目标是文件树的数据属性,它们不是声明过的公开契约;dsh 若重命名这些属性,着色会静默消失(纯展示层,不影响其他功能)。工作区行的标记还依赖工作区标题匹配:重命名工作区、或 dsh 更改侧边栏aria-label文案,会让行标记失效(文件树标记不受影响)。 - 路径别名依赖展示结构。 远程路径改写针对树根头部的 span 形状与 hover 卡片的 portal 形状,两者都未声明;dsh 若更改任一形状,本地锚点路径会静默恢复显示(纯展示层——导航、寻址与复制操作不受影响,仍使用真实的本地目录)。
- SSH 走纯 JS 而非原生加密。 打包的
ssh2不会加载可选原生加速件,大文件 SFTP 传输的吞吐低于原生构建版本。 - 搜索依赖远程 ripgrep。 远程机器上必须存在
rg二进制(可用remoteRipgrep配置);否则搜索工具在远程路径上失败。 - 不发布 npm。 从 GitHub 或本地检出安装,见安装。
- 内建目录选择流是被覆盖而非替换。 两个目录流注册以不同优先级共存(本插件使用 -1,最低者优先渲染);卸载本插件后槽位交还给内建选择器。
- 「本机」页签跟随宿主组合的 picker 能力。 宿主在启动时解析一次目录选择器后端:WSL 缺少 zenity/kdialog、经 SSH 启动、绑定非回环地址或无显示会话的 Linux 都会组合出
browse后端(只有list/createDirectory原语,没有 OS 选择器)。插件的「本机」页签据此分流——native打开 OS 选择器,browse改用宿主的网页目录浏览器;在此之前的版本「本机」页签硬编码pick,在这类启动下会以directory-picker/unavailable失败。 - 删除机器后其工作区被有意搁置。 锚点在机器删除后仍然存在,所有工具面对它都会以同样的「机器已失配」错误拒绝(fs、bash、subprocess,提示词的
cwd变量回退为本地句柄),而不是换一台机器或在本机执行。
开发说明
插件目录是自包含的 pnpm workspace(packages: [- .]、storeDir: .pnpm-store),阻断 pnpm 向上探测 harness 仓库的 workspace。dsh 框架包声明为 peerDependencies(^0.1.2-rc.1,由宿主 profile 提供),并在 devDependencies 中精确锁同版本用于本地类型与构建;依赖图内不存在相对 link: 依赖,因此该目录可在任意位置独立构建。
命令:pnpm run build(tsdown,双半)、pnpm run typecheck、pnpm run test(node:test 经 tsx;无需 SSH 服务器——连接池接受注入的 client 工厂,SFTP 表面使用假件)。
ssh2 位于 devDependencies,因为它是构建输入而非运行时依赖:pnpm run build 会把它打进 lib/index.js。任何源码改动都要连同重新构建的 lib/ 一起提交,否则 GitHub 安装拿到的是旧代码。
第三方代码
lib/index.js 内含 ssh2(MIT)、asn1(MIT)、safer-buffer(MIT)、tweetnacl(Unlicense)、bcrypt-pbkdf(BSD-3-Clause)的打包副本,许可证全文见 THIRD-PARTY-NOTICES.md。
打包把安全更新的责任移到了本仓库:ssh2 的安全公告不再经用户自己的 pnpm update 到达他们。修补方式是 pnpm update ssh2 && pnpm run build,然后把结果提交到这里。
链接
同类插件
zhu1090093659/dsh-web-ui#packages/dsh-ssh★ 7488
SSH 远程运维面板:Web 终端、SFTP 传输、本地端口转发与一条命令并发集群执行,Agent 与面板共用同一份主机配置。
zhu1090093659/dsh-web#packages/dsh-remote-web-ui★ 7488
手机/PC 远程操控 dsh web 工作区:扫码配对、令牌门控通道、SSE 实时同步,提供移动端与完整桌面 GUI 两种远程形态。
ZSeven-W/dsh-ios★ 288
在对话里直接操作 iOS 模拟器或 USB 连接的 iPhone:22 个 Agent 工具用于启动、构建、按无障碍标识或 OCR 文本驱动 UI、列表行操作与 SwiftUI 预览热重载,并附带可点击拖拽的流式侧边栏面板。
saya-ch/dsh-mobile★ 260
通过 Android App 或手机浏览器访问 DeepSeek Harness,支持安全局域网连接、远程访问、持久设备配对和可自定义移动界面。
liguobao/deepseek-harness-remote★ 183
DeepSeek Harness 多端远程访问:从手机、平板、浏览器或另一台电脑继续进行中的会话,端到端加密通道(Noise IK + 自适应 Relay/WebRTC 传输),设备授权管理;远程端仅开放 ApiProxy 能力,支持 dsh-file-viewer 只读文件预览,不提供 Shell、远程桌面或写入权限。
wenbin-wb/dsh-bridge★ 158
DeepSeek Harness 远程与移动端接入插件:提供局域网扫码直连、Cloudflare 与自建公网隧道,以及微信、QQ、飞书、Telegram 机器人交互,内置安全认证与访问控制。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。