Skip to content
dsh.fish
Bundle

dsh-bsk-ws-bridge

DSH plugin: expose the local bsk daemon WebSocket to remote browser extensions via a web-server upgrade route

Source
kaixinguo360
License
MIT
Updated
Updated 2 days ago

Readme

# dsh-bsk-ws-bridge

[DSH](https://github.com/deepseek-ai/deepseek-harness) 插件:把本机 bsk daemon 的回环 WebSocket 暴露为 DSH web server 上的一个 WebSocket 端点(默认 `/__bsk__`),供配套的修改版 browser-skill 扩展接入——Agent 由此经 DSH 页面远程操控客户端浏览器。

bsk daemon 只监听本机回环(`ws://127.0.0.1:52800`),原本浏览器必须与它同机;经本插件暴露到 DSH web server 后,浏览器只要打得开 DSH 网页就能连上,Agent 跑在远端服务器也能使用这台浏览器。

本插件只提供数据链路,不为 Agent 提供浏览器操作能力;还需安装 `dsh-plugin-browserskill` 插件与配套修改版的 browser-skill 扩展(见「配套组件」)。

## 核心功能

- **WebSocket 端点**:在 DSH web server 上注册 `/__bsk__`(路径可配置),将入站连接转发到本机 bsk daemon(默认 `ws://127.0.0.1:52800`)。
- **透明转发**:对 WebSocket 帧原样转发、不解析不改写,握手与会话语义全部交给真正的 daemon 处理;仅转发文本帧(bsk-protocol 为 JSON 行),关闭码双向透传。
- **Origin 伪装**:daemon 只接受 `chrome-extension://` 来源的握手,本插件连接 daemon 时按配置伪造该前缀的 Origin;upstream 只走本机回环。
- **健康检查端点**:`GET /__bsk__/health` 返回 JSON 探活信息。
- **会话保持**:客户端断开时保持 daemon 连接,客户端重连时通过 `instance_id` 恢复会话,避免网络抖动导致会话丢失。

## 配套组件

端到端的远程操控需要以下组件配合,本插件只承担其中的数据链路:

- **[`bsk`](https://github.com/Tencent/BrowserSkill)**(CLI/daemon):安装在 DSH 所在机器,其 daemon 是这条链路的另一端;
- **[`dsh-plugin-browserskill`](https://github.com/Tencent/BrowserSkill/tree/main/packages/dsh-plugin-browserskill)**:BrowserSkill 官方的 dsh 插件,把 bsk 能力以 `browser_*` 工具的形式提供给 Agent——没有它,Agent 发起不了任何浏览器操作;
- **修改版 browser-skill 扩展**:与本插件配套的修改版 browser-skill 扩展,fork 自 [Tencent/BrowserSkill](https://github.com/Tencent/BrowserSkill),装在客户端浏览器里,打开任意 DSH 页面即自动接入本端点,真正执行页面操作。

## 安装

遵循标准 dsh 插件流程:

```bash
# 1. 加入 web profile(本地路径安装;发布到 npm 后可直接写包名)
dsh plugin --profile web add file:<本仓库路径>
# 2. 启动该 profile,端点随之注册
dsh --profile web
# 3. 验证
curl http://127.0.0.1:3080/__bsk__/health
```

## 配置

配置来源优先级:**内置默认值 < `cordis.patch.yml` 的 config 块 < DSH 界面保存的配置文件**
(默认 `~/.dsh/bsk-bridge-config.json`,可用环境变量 `BSK_BRIDGE_CONFIG` 覆盖路径)。

### 方式一:DSH 设置界面(推荐)

配置以**设置卡片**形式出现在 DSH 的「设置」页(仿照 modsearch 插件的模式:
host 侧注册 `bsk-ws-bridge` settings 命名空间 + loopback 配置路由,浏览器侧
`dsh/client.js` 经 `settings.plugin.item` slot 注册卡片):

- **设置卡片**:DSH 设置页 → 插件区 → 「bsk 桥接(dsh-bsk-ws-bridge)」,展开即改即存;
- **配置 API**:`GET/PUT /__bsk__/config`(JSON;PUT 校验后立即热生效,无需重启 DSH);
- 以上均受 `dsh-web-startup-auth` 会话保护(未登录返回 401)。

即使 `enabled=false`(桥接停用、不再接受扩展 WebSocket),配置 API 与设置卡片仍可用,
方便随时重新启用。修改 `path` 会即时迁移 upgrade 路由,但配套扩展默认连接
`/__bsk__`,改路径需扩展侧同步(卡片上有提示)。

> 热更新与会话保持:修改路径或运行时参数(空闲超时/缓冲上限/命令兜底)时,
> daemon 连接与会话**原样保留**(bridge 代理心跳维持浏览器存活,无需重建会话)。
> 只有修改「上游地址 / Origin / 握手超时」这类**拨号参数**才会重建到 daemon 的
> 连接,此时当前会话会断开(不可避免,需重新创建会话)。

### 方式二:行内 config(cordis.patch.yml)

| 键 | 默认值 | 说明 |
| --- | --- | --- |
| `enabled` | `true` | `false` 时桥接停用(配置界面仍可访问) |
| `path` | `/__bsk__` | DSH 上的 WebSocket 端点路径(exact match,无尾斜杠) |
| `upstream` | `ws://127.0.0.1:52800` | 本机 bsk daemon 的 WebSocket 地址 |
| `origin` | `chrome-extension://aab…` | 连接 daemon 时伪造的 Origin 头 |
| `upstreamIdleTimeout` | `300000` | 无客户端时 upstream 保持时间(毫秒),默认 5 分钟 |
| `bufferMaxSize` | `1000` | 断联期间缓冲消息最大数量 |
| `handshakeTimeout` | `8000` | 握手超时(毫秒) |
| `heartbeatIntervalMs` | `20000` | 扩展心跳间隔(毫秒;桥接代理保活固定 15s) |
| `commandTimeout` | `25000` | 命令兜底超时(毫秒;转发给扩展无响应时合成超时错误给 daemon) |

> ⚠️ 同一台机器上若同时运行多个 DSH 实例且都安装了本插件,它们的桥接会各自拨号
> `ws://127.0.0.1:52800`(同一个 daemon)。daemon 的浏览器注册规则是「最新握手者胜」,
> 两个实例争抢同一浏览器注册会导致会话创建路由错乱 —— 此时应在其中一个实例的
> 界面上把 `enabled` 关掉,或把它的 `upstream` 指向别的 daemon。

## 会话保持机制

### 工作原理

1. **首次连接**:客户端发送握手帧(`system.handshake`),其中包含 `instance_id`
2. **会话绑定**:Bridge 将 `instance_id` 与 daemon 连接绑定
3. **客户端断开**:Bridge 保持 daemon 连接,进入"等待重连"状态
4. **客户端重连**:新客户端发送相同 `instance_id` 的握手,Bridge 恢复原有连接

### 健康检查

```bash
curl http://127.0.0.1:3080/__bsk__/health
```

响应示例:
```json
{
  "ok": true,
  "bridge": "dsh-bsk-ws-bridge",
  "path": "/__bsk__",
  "upstream": "ws://127.0.0.1:52800",
  "activeUpstreams": 1,
  "waitingUpstreams": 0,
  "sessionRetention": "300s"
}
```

Install

dsh plugin --profile web add github:kaixinguo360/dsh-bsk-ws-bridge

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source