Ianzhyh/workbuddy-to-dsh

dsh-plugin

把本机的本地 OpenAI 兼容桥注册成 dsh 原生模型 provider:复用这台机器桌面端已登录的模型,管理桥与其本地控制台进程,并附带 5 个工具、/workbuddy 命令与 9 个标签页的设置面板。需同机已安装并登录该桌面端;桥只监听 127.0.0.1。

模型与账号接入ai-codinganthropic-compatibleclaude-code

dsh-plugin-workbuddy

把本机 WorkBuddy 的模型(桌面端已登录,或在插件里完成一次浏览器授权), 做成 DeepSeek Harness 的一等公民。

一键即用(三步,零配置)

  1. 安装插件(dsh 市场 / dsh plugin add / tgz)。
  2. 设置 → WorkBuddy → 「账号」→「开始登录」——授权页会自动在浏览器打开。
  3. 授权完成,回 dsh 模型选择器选一个 WorkBuddy 模型即可对话。

不用填 API Key、Base URL、令牌、端口或环境变量;桥与控制台由插件自动管理。 没装桌面端也能用;已经登录桌面端则自动复用,第 2 步都不用做。 国内 / 国际版会根据现有账号或桌面端域名自动预选;登录、切号或重启桥后, dsh 的模型选择器会自动刷新,不需要再重启一次。

聊天页增强(不用打开设置页)

  • 模型名带积分倍率:选择器和聊天顶部显示 DeepSeek-V4.1-Flash · ×0.11;

免费模型标「免费」,倍率来自桥目录,不是人民币单价。

  • 模型清单与官方对齐:默认只把 WorkBuddy 官方模型选择器列出的模型放进

dsh(与官方 GUI 一致);网关有、官方未上架的模型在面板里标「官方未上架」, 默认不进 dsh 选择器,可先体检再在「显示官方目录外的模型」里勾选。 思考档位优先取上游目录的 reasoning.supportedEfforts(官方 GUI 的低/高/极致 = low/high/max),上游没给时才用本地实测表;上下文按官方默认预算声明, 需要 600K / 1M 时设 WORKBUDDY_CONTEXT_WINDOW。

  • 顶部积分胶囊:显示 积分 N;悬停看套餐余量 / 今日已用 / 最近一次调用;

套餐余量 ≤30% 变黄、≤10% 变红;点击强制刷新。读取失败时保留上次余额并标红; 已有对话但未登录 / 凭据异常时,这里直接变成登录入口(不用回设置页)。

  • 空会话直接登录:未登录时 hero 区出现「连接 WorkBuddy」,点击后浏览器授权,

成功后选择器自动刷新;等待授权可取消,超时会自动收尾。

  • 每轮积分:最新一轮回复末尾显示「本轮 x.xxx 积分 / 免费」。

宿主通过标准 prop useChat 给出本轮 tokenUsage / turnTimings 时,会拿 tokens 与本地请求账本核对,得到实际扣费;旧宿主或核对不上时才退回 「最近一次已完成的模型请求」估算(可见文案标 ≈,悬停注明)。只有最后一个回合显示, 新回合开始后旧标签会自动消失。

这些分别注册在 conversation.session.header.utilities、conversation.hero.options、 conversation.chat.turnTail;旧版 dsh 缺少某个槽位时会跳过,不影响设置页。

分工是「插件当引擎,控制台当界面 —— 且界面就长在 dsh 里」:

· 角色 · 负责什么 插件(dsh 内) · 引擎 + 界面 · 原生模型路由、桥与控制台的启停、工具、命令,以及 设置 → WorkBuddy 里的 9 个标签页:概览 / 账号 / 用量 / 请求 / 签到 / 诊断 / 模型 / 对话测试 / 日志 —— 控制台的全部功能 控制台(本仓库原有网页) · 同一界面的网页版 · 功能与设置页完全等价(见下文的同步设计),想在大屏浏览器里用就开它

dsh 的模型选择器  ──►  provider: workbuddy   ──►  插件内置适配器
                                                    │  (dsh 词汇 ↔ OpenAI 词汇)
                                                    ▼
                                        bridge/workbuddy-bridge.mjs(独立进程,127.0.0.1:8790)
                                                    │  注入鉴权头 / 现取现解凭据
                                                    ▼
                                              WorkBuddy 上游

dsh 设置 → WorkBuddy(9 个标签页)═══ 同一份状态 ═══ dashboard/server.mjs(控制台网页)

能力一览

装进 dsh 后,这些能力都在同一个插件里(明细见下方「它做了什么」):

  • 零配置接入 —— 不需要 API Key:有桌面端就复用登录态;没有桌面端就点「插件登录」
  • 插件内登录 —— 设置页点「开始登录」→ 浏览器授权;不安装、不切换桌面端也能用;

凭据 DPAPI 加密落盘(可关),不读桌面端登录文件

  • 模型直接进选择器 —— 原生 provider: workbuddy 路由,不写任何配置文件;

模型名直接带 ×0.11 积分倍率 /「免费」标记

  • 模型管理 —— 启用 / 禁用、体检(可用性 · 消耗倍率 · 实测成本)、详情、CSV 导出
  • 聊天页闭环 —— 未登录时空会话里直接登录;顶部积分胶囊(含今日/最近一次/套餐余量,低余额变色);每轮回复末尾显示本轮积分
  • 账号切换、积分与用量(趋势图 + 排行 + CSV)、请求明细(失败标红 + 错误码一键复制)
  • 环境诊断(含客户端安装布局体检)、多轮对话测试、每日自动签到
  • 中英双语 —— 9 个标签页界面全部双语

两边如何同步、互不冲突(设计核心)

dsh 设置页与控制台网页是两个前端、一个后端,所以天然一致:

数据 · 谁写 · 为什么 模型目录 / 用量 / 最近请求 / 签到状态 / 桥日志 · 桥(两边都只读桥的接口) · 单一事实来源,读操作无冲突 账号切换 / 自动签到开关 / 模型体检结论 · 只由控制台写(设置页通过 /workbuddy/console-api/* 白名单透传) · 控制台的 lib/state.mjs 带进程内缓存,插件若另写这个文件,控制台的缓存就过期了 —— 让唯一持有缓存的进程写,两边立刻一致 桥 / 控制台进程的启停 · 插件 · 生命周期归引擎管;插件不会去停用户自己双击 启动.cmd 起的进程

因此:在控制台网页里切账号,设置页 30 秒内(下一次轮询)同步;在设置页体检模型, 控制台的「可用模型」面板看到的是同一份结论。控制台进程没跑时,读功能照常 (读桥),写功能给出「启动控制台」的一键提示;宿主端旧构建(未重启 dsh)时, 明确提示「重启一次 dsh」而不是空白。

透传接口是白名单(consoleApi.mjs),不是任意路径代理;写操作同样要求 x-workbuddy-panel: 1 头。控制台的代码与文件一个字未改。

它做了什么

能力 · 说明 原生模型路由 · ctx.llm.registerAdapter(['workbuddy'], …) —— 模型直接出现在 dsh 模型选择器里,不写 settings.yaml,也不依赖 llm-pi-ai 动态模型目录 · 模型列表每次向桥要(带 1 分钟缓存),上游加/减模型不必改配置、不必重启 桥的生命周期 · 启动时复用已在跑的桥,没跑就按配置拉起;桥仍是独立进程,控制台、start-bridge.cmd、其它 OpenAI 客户端照旧可用 控制台的生命周期 · 同样复用/拉起 dashboard/server.mjs,让它常驻;dsh 里一个链接就进完整控制台(不会自动弹浏览器窗口) 5 个工具 · workbuddy_status / workbuddy_models / workbuddy_usage / workbuddy_checkin / workbuddy_bridge(后者 action=console 可确保控制台在跑) 斜杠命令 · /workbuddy status\ · models\ · usage\ · checkin\ · console\ · websearch\ · start\ · stop\ · restart\ · cleanup dsh 里的设置页 · 设置 → WorkBuddy,9 个标签页 = 控制台的全部功能:概览(含网页搜索状态 / 一键接入、待办提醒与诊断报告)/ 账号(切换)/ 用量(趋势图 + 积分排行 + CSV)/ 请求(筛选 + CSV)/ 签到(领取 + 自动开关)/ 诊断 / 模型(体检 + 详情)/ 对话测试(多轮流式)/ 日志(过滤 + 清空) 旧路由迁移 · 首次加载自动清掉 llm-pi-ai.providers.workbuddy 手写路由(先备份),否则两条同名路由会撞名

安装

插件就在本仓库的 dsh-plugin/ 里,安装到某个 dsh profile:

# 方式零:在 dsh 设置 → 插件 → 添加插件,填 GitHub 地址(推荐给最终用户)
github:Ianzhyh/workbuddy-to-dsh

# 方式一:用 dsh 自带的插件管理(等价命令行)
dsh plugin --profile desktop add github:Ianzhyh/workbuddy-to-dsh

# 方式二:本机开发 —— 设置 → 插件 → 添加插件,填本仓库 dsh-plugin 目录的绝对路径
npm 名 dsh-plugin-workbuddy 已被他人占用(不是本项目),不要填;npm 分发使用
根包 workbuddy-to-dsh(已准备发布,发布后可直接填这个裸包名)。

装完 重启一次 DeepSeek Harness。原因:插件模块会被 ESM 缓存,客户端半个 插件的引导行也只在应用启动时组装一次 —— 热更新看不到新面板。

本机(Windows + DSH Desktop)已装好并验证通过,见文末「验证记录」。

给别人用 / 分发

插件是自带一切的独立包:npm run vendor 会把桥、控制台与共享库复制进 dsh-plugin/vendor/(18 个文件、约 1.3 MB),于是对方不需要仓库,只要有:

  • Windows + Node 18+
  • dsh 桌面版
  • 二选一:
  • WorkBuddy 桌面端已登录(复用它的登录态,凭据不落盘);或
  • 不装桌面端:在插件里用「插件登录(不依赖桌面端)」完成一次浏览器授权

(需要一个 WorkBuddy / CodeBuddy 账号;凭据由插件保管,DPAPI 加密落盘)

拷 dsh-plugin/ 文件夹(或 npm run pack:plugin 出的 tgz)过去 → 对方跑一次 node /scripts/preflight.mjs 自检 → 用 dsh 的插件安装指向它 → 重启 dsh。

完整的路线(拷文件夹 / tarball / 发 npm)、验收清单、端口与目录说明、九条常见 故障排查,见 docs/INSTALL.md;

npm run vendor             # 生成/更新插件自带的 vendor/(分发前必做)
npm run vendor:check       # 校验 vendor/ 与仓库是否同步(CI / 发版前)
npm run preflight          # 环境自检:Node、脚本、登录文件、端口、模型、安装情况
npm run pack:plugin        # vendor + npm pack → dsh-plugin-workbuddy-<版本>.tgz
npm run verify:standalone  # 把插件拷到没有仓库的临时目录,真起一遍桥与控制台
npm run release:check      # = vendor:check + 单测 + 独立分发演练(发版前一键)
仓库在旁边时插件优先用仓库(本机改 bridge/dashboard 立刻生效),
vendor/ 只在找不到仓库时兜底 —— 这条顺序有单测守着。
vendor/ 只含运行必需的 18 个文件(约 1.3 MB);日志、用量账本、.state.json、
*.bak、.env 一律不打包(脚本还会主动清理遗留的这类文件)。

依赖

  • Node.js 18+
  • 桥与控制台脚本:仓库里的 bridge/workbuddy-bridge.mjs、dashboard/server.mjs,

或插件自带的 vendor/ 副本(插件通过 projectRoot 找它们)

  • WorkBuddy 桌面端已安装并登录,或者使用插件内登录(见下)

插件只连本机回环地址,不新增任何对外监听、不上报任何数据。

插件登录(不依赖桌面端)

「设置 → WorkBuddy → 账号」里有一张插件登录卡片(控制台的「账号」区块也有同一张)。 流程:点「开始登录」→ 在浏览器里完成 WorkBuddy / CodeBuddy 授权 → 回到面板等待自动完成 (也可用 /workbuddy login 两步式命令)。密码不经过插件,插件只接收令牌。

凭据来源优先级(auto,默认):

  1. CODEBUDDY_API_KEY(显式环境变量覆盖,与旧行为一致)
  2. 桌面端登录文件(能读、能解密、有 token)
  3. 插件登录凭据(桌面端本地不可用时的回退;access 过期会自动刷新)
  4. 都没有 → 明确报错并给出两种登录入口
上游 401 不会触发中途换号:账户可预测性优先。登录成功后,UI 会明确把来源切到
插件并提示(可一键切回)。不设置 WORKBUDDY_CREDENTIAL_SOURCE 时 UI 可自由切换;
auto 是软默认(不锁定);只有显式写 desktop|plugin|api-key 才会把来源锁定
(面板里的切换会被拒绝)。

存储:默认 %USERPROFILE%.workbuddy-bridge\credentials:

文件 · 说明 store.key · 32 字节随机密钥,由 Windows DPAPI(当前用户) 保护 .cred · AES-256-GCM 信封(AAD 绑定 uid),刷新轮换后原子回写 active.json / source.json · 当前账号 / 来源选择,非机密

  • 换机器 / 换 Windows 用户 → 解不开;复制目录到别处不可用。
  • DPAPI 不可用(组策略禁用 PowerShell 等)→ 自动退回仅内存,绝不静默写明文;

面板/诊断会明确显示「凭据存储:仅内存」。

  • 同用户的恶意进程仍能调用 DPAPI / 读进程内存 —— 这是无 TPM/Hello 方案的共同上限。
  • WORKBUDDY_CREDENTIAL_STORE=memory 可主动选择不落盘(桥重启后需要重新登录)。
  • 「退出登录」只删除插件自己保存的那份凭据,不会注销上游账号。
  • 同账号识别与互通:桌面端 JWT 的 sub 与插件凭据的 uid 是同一套账号标识。

两边是同一账号时,账号页合并成一行:桌面账号 + 「双凭据」+「用插件凭据」, 两条凭据可互换;某一条鉴权失败(401/403)会自动用另一条重试,钱包不变。两边是 不同账号时,一次请求只能用一个账号;桌面端没有的插件账号会标「插件」并进同一个 账号列表,插件登录卡片只负责登录与来源选择。WORKBUDDY_CREDENTIAL_FAILOVER=any 可让不同账号也自动接管(会切换账号/钱包,默认关闭)。

  • 插件来源的模型请求使用 WorkBuddy 身份头(UA / X-IDE-* / Origin),与桌面来源的

CodeBuddy 扩展头分开;上游若收紧,可设 WORKBUDDY_PLUGIN_IDENTITY=vscode 退回旧头。

插件目录里不包含任何凭据;分发插件不会把账号带给别人。

配置

配置写在 profile 的 cordis.patch.yml 里,按 id 覆盖插件条目:

- id: workbuddy
  config:
    projectRoot: E:\workbuddy-to-dsh   # 可选:桥脚本所在仓库;默认自动探测
    bridgePort: 8790
    localToken: wb-local-bridge
    autoStart: true
    consoleAutoStart: true             # 控制台(数据界面)也由插件复用/拉起
    consolePort: 8792                  # 默认跟 .env 的 DASHBOARD_PORT 对齐
    displayName: WorkBuddy
    loginRegion: cn                    # 插件登录默认区域:cn / global
    modelAllow: []                     # 只放行这些模型 id(空 = 全部)
    modelDeny: []
    migrateLegacy: true                # 首次加载清理 llm-pi-ai 里的旧 workbuddy 路由
    tools: true
    commands: true
    routes: true

完整默认值见 lib/index.js 的 DEFAULTS。

projectRoot 的探测顺序:配置 → WORKBUDDY_ROOT 环境变量 → 插件目录的上一级 (插件放在仓库里时)→ node_modules 上溯三级 → ~/workbuddy-to-dsh → E:\workbuddy-to-dsh。

`.env` 也会被尊重:桥进程只认环境变量,而端口 / 登录文件可能配置在仓库的 .env 里(config.mjs 的"统一配置真源")。插件会读它并补齐默认值,优先级为