dsh-remote-hub:为 DSH Hub 提供多远端统一入口的插件

前言

DeepSeek Harness(DSH)使用同源策略来隔离不同页面的信任边界:Host/Origin 必须相等、Cookie 必须是 SameSite=Strict,不允许跨域请求。在本地开发或调试时,你通常会在不同端口(例如 3182、3183)启动多个 DSH Hub 实例,每个实例有独立的 origin。浏览器直接访问这些不同 origin 会触发同源限制,无法像访问单个 Hub 那样顺畅地切换。

dsh-remote-hub 是一个运行在 Hub 端的 host 插件:它为浏览器提供一个统一的 origin(即 Hub 自己的 origin),然后将所有注册的远端后端通过反向代理暴露在 /remotes/<id>/ 下。浏览器始终只与 Hub origin 通信,满足 DSH 的同源要求;远端之间的连接方式(例如 ssh -L、未来的代理通道)由插件底层处理,代理逻辑本身不关心具体传输。

插件定位与维护者

dsh-remote-hub 是一个 DSH Hub 端插件,由维护者 yhuan416 开发。它不改变 DSH 的运行时架构,只是扩展了 Hub 的能力,让一个 Hub 可以统一管理多个远端后端,并为用户提供一个无刷新的切换入口。

核心功能

1. 反向代理与同源访问

Hub 通过 dsh web 启动,浏览器访问 Hub origin。插件将每个远端(例如 n100)的 HTTP 服务反向代理到 /remotes/n100/ 下:

  • 浏览器请求路径 /remotes/n100/api/x 被转发到远端的 /api/x
  • 请求的 Host 和 Origin 被重写为远端的 authority(例如 127.0.0.1:3182),远端的 Host/Origin fence 可以将其识别为 loopback
  • 远端返回的 Cookie 会被插件缓存,后续请求自动带上该远端的 Cookie

这样,浏览器只与 Hub origin 交互,满足 DSH 的同源要求。

2. 远端链路管理与 UI

在 DSH 的「Plugins」页面(Settings → Plugins → dsh-remote-hub)中,插件提供两个部分:

  • 配置表单:从导出的 Config 生成,包含 upstreamTimeoutMs、probeIntervalMs、switcher.mode、switcher.dropdown 等字段
  • 远端链路:一个表格,列出所有已注册的远端,每行显示状态点、标签、传输方式、token 来源、延迟、最后错误。每行提供「打开 / 测试 / 删除」操作,以及一个添加远端的表单(label、ssh host、user、remote port 等)

表格还展示「远端工作区」列表:每个后端的工作区与会话由 Hub 聚合(通过 ssh 读取工作区存储和 session/list RPC;若存储不可读则按 cwd 分组)。点击会话会在 Hub 的顶部栏打开该后端,并通过消息机制打开对应的 iframe 页面。

3. 运行时存储

远端配置存储在 $DSH_HOME/remote-hosts.json(权限 0600,原子写入):

{
  "version": 1,
  "removed": ["old-id"],
  "hosts": [
    {
      "id": "...",
      "label": "...",
      "ssh": {...},
      "tokenFile": {...}
    }
  ]
}
  • 首次启动时,从 cordis.patch.yml 中的 remotes 数组导入到存储中
  • 后续启动以存储为准;新增的 seed id 会导入,除非已被标记为 tombstone(删除操作会在存储中添加 tombstone,防止 seed 重新出现)

4. 管理 API(Owner 端)

插件注册了以下 owner 端的 API 路由(通过 ctx.connection.fetch.register,框架会强制 Peer 为 owner 且浏览器信任墙生效):

  • GET /api/remote-hosts/list:返回已清理的远端列表,附带状态、健康、延迟、tunnel、token 统计信息
  • POST /api/remote-hosts/save:保存远端配置,返回 { ok, id }
  • POST /api/remote-hosts/remove:删除远端,返回 { ok }
  • POST /api/remote-hosts/probe:探测指定远端,返回状态、延迟、token 是否解析、是否有 cookie
  • GET /api/remote-hosts/workspaces:按远端返回工作区列表(workspaces[{id,title,path,sessions[]}])及孤儿工作区;远端通过 ssh 读取工作区存储,若不可读则按 cwd 分组

5. 统一入口与状态指示

插件通过 webserver/index-inject 钩子在 Hub 的索引页注入一个顶部栏:

  • 默认模式 bar:持久显示「本机」+ 所有远端标签,点击后在下方的 iframe 中显示对应后端(只挂载一次,切换时不刷新页面)
  • 颜色使用应用的主题 token(--dsw-alias-bg-base、--dsw-alias-label-primary 等),跟随浅色/深色主题
  • 每个远端标签有一个状态点,每 5 秒从 /api/remote-hosts/list 轮询一次:绿色在线、琥珀色 pending/starting、红色离线、灰色未知;悬停可查看状态/tunnel 状态/最后错误

默认情况下,顶部栏已足够,侧边栏切换下拉框被关闭。可在配置中开启 switcher.dropdown: true 来启用它。

6. 入口路径与 token 处理

插件提供多个入口路径:

  • /remotes/?token=<hub launch token>:一次性入口。插件将 token 转发给 Hub 自己的 /?token= 交换机制,设置 Hub 的 cookie,然后通过 303 重定向到干净的 /remotes/。注意:token URL 使用的 hostname 必须与设置 cookie 的 hostname 一致(例如 127.0.0.1 与 localhost 被视为不同的 cookie 主机)
  • /remotes/:备用入口页,只提供纯链接,管理入口已移至 Plugins 页面
  • /remotes/<id>/:远端的 SPA,由插件反向代理
  • /remotes/_status:JSON 诊断信息,列出每个远端的 token 是否存在、cookie 是否存在、最后错误

7. 传输方式无关性

插件将远端定义为 Hub 可访问的 HTTP 基础 URL。传输方式由运维决定:

  • 可以是手动 ssh -L 隧道
  • 可以是未来自动管理的隧道
  • 也可以是未来的 agent 通道

代理代码本身不关心传输方式,只负责转发 HTTP 请求和 WebSocket 升级。

8. WebSocket 支持

插件为每个远端注册精确的 WebSocket 路由,并建立 socket-to-socket 的管道,将 WebSocket 升级请求转发到对应的远端。

安装与启用

插件通过 cordis.patch.yml 插入到 DSH:

- insert:
    - id: remote-hub
      name: dsh-remote-hub
      config:
        remotes:
          - id: n100
            label: yhuan@192.168.4.50
            upstream: http://127.0.0.1:3182
            token: <remote dsh launch token>

在 package.json 中,插件的入口为 lib/index.js,客户端入口为 lib/client.js。插件遵循 MIT 许可证,Node.js 要求版本 >=22.19.0。

典型用法

  1. 在 Hub 所在机器上,为每个远端后端启动 DSH 实例,并确保 Hub 可以通过 HTTP 访问远端(例如通过 ssh -L 或内网地址)。
  2. 在 cordis.patch.yml 中添加 dsh-remote-hub 插件,配置远端 id、label、upstream 和 token。
  3. 重启 DSH Hub,在浏览器中访问 Hub origin,顶部栏将显示「本机」和已注册的远端。
  4. 点击远端标签,iframe 中会显示对应后端,切换时不会刷新页面。
  5. 在 Plugins 页面的「远端链路」区域添加新远端、测试连通性、查看工作区与会话。

适用场景与注意

dsh-remote-hub 适合需要在同一个浏览器窗口中访问多个 DSH Hub 后端的场景,例如本地多实例调试、跨主机的远程开发环境统一入口。插件以当前 DSH 进程的权限运行,安装前应检查源码与许可证。插件仅管理远端配置与代理逻辑,不涉及 AI 模型推理或数据存储。

总结

dsh-remote-hub 通过反向代理和统一入口,将多个 DSH Hub 后端折叠到同一个 origin 下,使浏览器始终在同源环境下工作,满足 DSH 的信任墙要求。它提供了可视化的远端管理界面、工作区聚合、状态指示与探测功能,并支持多种传输方式,适合需要在 Hub 端统一管理多个远端后端的开发者。

插件目录页 | GitHub 仓库

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜