← Back to home@Excapesx

dsh-plugins

两个 DeepSeek Harness 本地插件:会话余额徽标 + 推理等级滑块,以及手机局域网免登录访问

Stars
1
Language
JavaScript
Created
Oct 22, 2026
Updated
Oct 22, 2026
GitHub repo

Introduction

dsh-plugins

两个给 DeepSeek Harness(DSH) 用的本地插件。装上之后:

  • 会话标题栏右上角多一个余额徽标 —— ● ¥18.69,点一下立刻刷新;
  • 输入框右侧多一枚「推理等级」胶囊 —— 拖滑块调思考强度,档位跟着当前模型走;
  • 左栏底部多一个「手机访问」按钮 —— 一键让手机在同一局域网里打开 DSH,手机端不用登录。
插件你会看到做什么
dsh-balance-effort标题栏 ● ¥xx.xx · 输入框右侧 ⚡ 高 ⌄余额徽标(Host 直连 DeepSeek 余额接口,不把 Key 送到浏览器)+ 推理等级滑块
dsh-mobile-access左栏「手机访问」内嵌反向代理,手机免登录打开 DSH 界面

两个包都是纯本地插件:没有构建步骤、没有第三方依赖,只有 lib/index.js(Host 半)和 lib/client.js(浏览器半)两份源码,直接就是本机正在跑的版本。

⚠️ dsh-mobile-access 会把本机 DSH 的完整控制权开给端口上任何设备(等于本机代码执行,且不需要登录)。只在可信局域网里开,用完随手关掉 —— 详见安全说明。


安装

两个插件装法完全一样,以 dsh-balance-effort 为例(把名字换成 dsh-mobile-access 即是另一个)。

1. 放源码

# 把仓库里的插件目录整个拷到 DSH 的本地插件目录
Copy-Item -Recurse .\plugins\dsh-balance-effort "$env:USERPROFILE\.dsh\plugins\dsh-balance-effort"

目标路径是 %USERPROFILE%\.dsh\plugins\<包名>,里面应该直接就是 package.json / cordis.patch.yml / lib/。

2. 挂进 profile

DSH 按 profile 组合插件,改 %USERPROFILE%\.dsh\profiles\<profile>\package.json(<profile> 通常是 desktop 或 web)两处:

{
  "dependencies": {
    // ① 加一条 link 依赖,指向你刚放的目录(注意用正斜杠)
    "dsh-balance-effort": "link:C:/Users/你的用户名/.dsh/plugins/dsh-balance-effort"
  },
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        "@deepseek-ai/dsh-web-app",
        // ② 把包名追加进 bundles,它才会被真的加载
        "dsh-balance-effort"
      ]
    }
  }
}

3. 重启 DSH

重启后 DSH 会按 link: 依赖在 profiles/<profile>/node_modules/ 里建好链接,并把 lib/client.js 编进页面模块图。重启完直接看界面:

  • 余额徽标在会话标题栏右侧(跟 ... 同一行);
  • 推理等级胶囊在输入框右边;
  • 「手机访问」在左栏底部、设置按钮旁边。

这两个插件互不依赖,可以只装其中一个。

排查:装完没反应

  1. 包名对不上。 bundles 里的名字、dependencies 的键、package.json 的 name、cordis.patch.yml 里的 id/name,四处必须完全一致。
  2. link: 路径写错。 Windows 路径照样用正斜杠;写错的话 node_modules 里不会出现链接。
  3. 没重启。 Host 半(lib/index.js)注册路由发生在启动时,改完必须重启 DSH。
  4. 浏览器半加载失败。 lib/client.js 顶层是 window.__ModuleLoader__.load({ id, ... }),id 必须等于包名;改包名时别漏了它。
  5. 想看 Host 半的日志:插件里用的是 ctx.logger.info,正常启动会各打印一行 serving ... / ready ...。

1. dsh-balance-effort

余额 + 推理等级,一个包两个控件。

余额徽标

  • 每 60 秒自动刷新;点一下立刻强制刷新(?force=1 绕过缓存);请求失败 5 秒后自动重试一次。
  • 颜色即状态:🟢 正常 · 🟡 余额低于 ¥10 · 🔴 接口报错或 is_available: false · 脉冲 = 加载中。
  • 悬停出明细:总余额、赠金 / 充值、更新时间。
  • 没配 Key 时显示「未配置」,不会满屏报错。

Host 半在 DSH 自己的 webServer 上挂一条只读路由:

GET /dsh-balance/balance[?force=1]
→ { phase, total, granted, toppedUp, currency, isAvailable, updatedLabel, source }

流程是:ctx.credentials.resolve('DEEPSEEK_API_KEY') 拿到 Key → 服务端请求 https://api.deepseek.com/user/balance → 只把数字回给浏览器。安全口径在代码注释里写死了:只接受 GET、不接受任何入参(没法当 SSRF 跳板)、响应 no-store、永不回显 Key。5 秒内的重复请求合并成一次,单次请求 20 秒硬超时。

推理等级滑块

  • 胶囊上写着当前档位(低 / 中 / 高 …,取模型目录里的 name),点开是滑轨面板。
  • 拖动、点轨道、方向键都能改;改动立刻通过 modelDirectories.select() 写回会话,左上角按钮恢复模型默认档位。
  • 档位不是写死的,来自模型目录里 reasoning.efforts;换模型时胶囊跟着变。
  • 拿不到档位时不会静默消失,而是渲染一枚灰胶囊并写明断点原因 —— 无服务 / 无目录 / 加载中 / 无选择 / 未收录 / 无档位。这是刻意的:注册成功却看不见属于最难查的哑失败。

2. dsh-mobile-access

让手机访问只监听 127.0.0.1 的 DSH Web GUI,全程在界面里开关。

用法:左栏底部「手机访问」→ 点开 → 开启 → 面板列出本机所有局域网地址(带网卡名、可复制)→ 手机连同一个 WiFi,浏览器打开任意一条即可,不用输 token、不用配对。

为什么能免登录:DSH 的 /api 信任围栏只认环回或已 trusted 的 authority,并且用 authority 绑定的签名 cookie 认浏览器。插件做两件事:

  1. 内嵌一个 http 反向代理,监听 0.0.0.0:3081 → 转发到 127.0.0.1:<DSH 真实端口>,把每个请求的 Host / Origin 重写成环回 authority,围栏自然放行(不用改 DSH 配置,也不用 --trusted-host);
  2. 用本机凭据 client-connection/browser-session 里的密钥现场签发一张 cookie 注入每个转发请求,所以手机侧不需要任何凭据。

普通 HTTP 和 WebSocket 升级(/api/remote.mux 流式通道)都支持,否则手机上会一直转圈。

控制面(挂在 DSH 自己的 webServer 上,只有同源浏览器会调):

GET  /dsh-mobile-access/state   → { running, dshPort, proxyPort, urls: [{ ifName, address, url }], error }
POST /dsh-mobile-access/start
POST /dsh-mobile-access/stop

几个实现细节:

  • 默认不自动启动,必须你在界面上显式点开;插件被禁用/卸载、DSH 退出时监听器跟着关。
  • 代理端口默认 3081;被占用时 start 会返回 500 并把错误显示在面板上。
  • 会滤掉 169.254.x.x 这类链路本地地址(网卡没拿到 DHCP 时出现的占位地址,手机连不上)。

安全说明

  • dsh-balance-effort:浏览器半只拿得到余额数字。Key 全程留在 Host 进程里,路由无入参、只读。
  • dsh-mobile-access:开启期间,任何能访问该端口的设备都拥有对本机 DSH 的完全控制权(等价于本机代码执行),而且不需要登录。面板上这句警告是常驻的,不是装饰。
    • 只在你能信任的局域网里开(家里 / 自己的热点);
    • 别在公共 WiFi、公司网络、或者端口被映射到公网的情况下开;
    • 用完点「关闭手机访问」,不要靠关浏览器标签页。

卸载

  1. 从 profile 的 bundles 里删掉包名,从 dependencies 里删掉那条 link:;
  2. 删掉 %USERPROFILE%\.dsh\plugins\<包名>;
  3. 重启 DSH。

浏览器端注入的样式标签和监听器都跟着 effect 一起回收,不会残留。

许可

MIT —— 见 LICENSE。