把 WorkBuddy 账号接入模型选择器,免密钥双链路
31.4/100
综合分
4
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/4 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:npm 同名包「dsh-llm-workbuddy」归属 zdk119746/dsh-llm-workbuddy,装到的可能不是本插件。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add zz991/dsh-workbuddy该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:需留意
是什么
dsh 原生插件 · model
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 42 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
⚠︎ 实装验证未通过(dependency_conflict · 2026/10/30) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意npm 同名包「dsh-llm-workbuddy」归属 zdk119746/dsh-llm-workbuddy,装到的可能不是本插件
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-llm-workbuddy @ 0.1.25
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/12 01:47:57
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 102 处,展示前 54 条)
- 写入本地文件lib/index.js:475
mkdirSync(dirname(file), { recursive: true }); - 写入本地文件lib/index.js:485
appendFileSync(file, `${line}\n`); - 读取本地文件lib/index.js:487
const size = existsSync(file) ? readFileSync(file, "utf8").split("\n").filter(Boolean).length : 0; - 读取本地文件lib/index.js:487
const size = existsSync(file) ? readFileSync(file, "utf8").split("\n").filter(Boolean).length : 0; - 读取本地文件lib/index.js:489
const lines = readFileSync(file, "utf8").split("\n").filter(Boolean).slice(-USAGE_MAX_LINES); - 读取本地文件lib/index.js:513
if (!existsSync(file)) { - 读取本地文件lib/index.js:516
const lines = readFileSync(file, "utf8").split("\n").filter(Boolean); - 发起网络请求lib/index.js:742
const response = await fetch(`${connection.baseURL}/models`, { signal: controller.signal }); - 发起网络请求lib/index.js:849
const iterator = this.request(options, watchdog.signal, connection, () => watchdog.pulse())[Symbol.asyncIterator](); - 发起网络请求lib/index.js:895
response = await fetch(`${connection.baseURL}/chat/completions`, { - 读取本地文件lib/index.js:1074
return JSON.parse(readFileSync(checkinStatePath(), "utf-8")); - 写入本地文件lib/index.js:1084
mkdirSync(dirname(file), { recursive: true }); - 写入本地文件lib/index.js:1085
writeFileSync(file, `${JSON.stringify(state, null, 2)}\n`); - 发起网络请求lib/index.js:1114
const response = await fetch(`${baseURL.replace(/ $/, "")}${path}`, { - 发起网络请求lib/index.js:1497
const response = await fetch(`${baseURL.replace(/ v1 ?$/, "")}/health`, { - 发起网络请求lib/index.js:1525
const response = await fetch(endpoint, { - 执行外部命令固定命令lib/index.js:1690
const child = spawn("python3", args, { env: { ...process.env, PYTHONUNBUFFERED: "1" } }); - 发起网络请求lib/client.js:197
return fetch("/api/workbuddy/status") - 发起网络请求lib/client.js:214
fetch("/api/workbuddy/login" + (force ? "?force=1" : ""), { method: "POST" }) - 发起网络请求lib/client.js:253
fetch("/api/workbuddy/diagnose", { method: "POST" }) - 写入剪贴板lib/client.js:288
navigator.clipboard.writeText(d.restartCommand).then(function () { - 发起网络请求lib/client.js:307
fetch("/api/workbuddy/usage") - 发起网络请求lib/client.js:385
fetch("/api/workbuddy/checkin", { method: "POST" }) - 发起网络请求lib/client.js:408
fetch("/api/workbuddy/refresh-models", { method: "POST" }) - 读取本地文件install/setup.mjs:188
if (existsSync(candidate)) return candidate; - 写入本地文件install/setup.mjs:214
mkdirSync(dirname(to), { recursive: true }); - 写入本地文件install/setup.mjs:215
copyFileSync(from, to); - 写入本地文件install/setup.mjs:225
mkdirSync(to, { recursive: true }); - 读取本地文件install/setup.mjs:226
for (const entry of readdirSync(from, { withFileTypes: true })) { - 写入本地文件install/setup.mjs:230
else if (entry.isFile()) copyFileSync(src, dst); - 读取本地文件install/setup.mjs:244
if (!existsSync(file) || backedUp.has(file) || DRY_RUN) return null; - 写入本地文件install/setup.mjs:246
copyFileSync(file, target); - 读取本地文件install/setup.mjs:328
if (!existsSync(DSH_HOME)) { - 读取本地文件install/setup.mjs:333
if (!existsSync(PROFILE_DIR)) { - 读取本地文件install/setup.mjs:385
const settings = yaml && existsSync(SETTINGS_FILE) - 删除本地文件递归install/setup.mjs:450
if (isOwnInstall(target, pkg.name)) rmSync(target, { recursive: true, force: true }); - 写入本地文件install/setup.mjs:451
mkdirSync(target, { recursive: true }); - 删除本地文件install/setup.mjs:691
if (IS_WIN) rmdirSync(linkPath); - 删除本地文件install/setup.mjs:692
else unlinkSync(linkPath); - 删除本地文件递归install/setup.mjs:719
rmSync(target, { recursive: true, force: true }); - 发起网络请求install/setup.mjs:823
const response = await fetch(`http://127.0.0.1:${GLOBAL_PORT}/v1/models`, { signal: controller.signal }); - 发起网络请求install/setup.mjs:1015
const response = await fetch(url); - 执行外部命令来自配置/变量install/setup.mjs:1079
const child = spawn(env.python, [script, "--session-file", sessionFile], { - 执行外部命令来自配置/变量install/setup.mjs:1151
spawnSync(loginBin, args, { encoding: "utf8", cwd: goDir, timeout: 60_000 }); - 读取本地文件packages/wb-gateway-manager/index.js:68
if (!existsSync(settingsFile)) return null; - 读取本地文件packages/wb-gateway-manager/index.js:72
text = readFileSync(settingsFile, "utf8"); - 读取本地文件packages/wb-gateway-manager/index.js:119
if (existsSync(candidate)) return candidate; - 读取本地文件packages/wb-gateway-manager/index.js:135
if (existsSync(candidate)) return candidate; - 读取本地文件packages/wb-gateway-manager/index.js:148
if (candidate && existsSync(candidate)) return candidate; - 写入本地文件packages/wb-gateway-manager/index.js:275
mkdirSync(logDir, { recursive: true }); - 执行外部命令来自配置/变量packages/wb-gateway-manager/index.js:282
const child = spawn(spec.command, spec.args, { - 执行外部命令固定命令packages/wb-gateway-manager/index.js:328
const out = execFileSync("netstat", ["-ano", "-p", "tcp"], { encoding: "utf8", timeout: 10_000 }); - 执行外部命令固定命令packages/wb-gateway-manager/index.js:337
const out = execFileSync("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], { encoding: "utf8", timeout: 10_000 }); - 执行外部命令固定命令packages/wb-gateway-manager/index.js:355
if (IS_WIN) execFileSync("taskkill", ["/F", "/PID", String(pid)], { stdio: "ignore", timeout: 10_000 });
扫描于 2026/10/31(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-llm@deepseek-ai/dsh-settings@deepseek-ai/dsh-timeout@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 接入账号到模型选择器
- 国内国际双链路
- 一键安装
把 WorkBuddy / CodeBuddy 账号接入 DeepSeek Harness:国内版(8787) + 国际版(8788) 双链路,一键安装
README
由 DeepSeek 最新模型翻译生成dsh-workbuddy
把 WorkBuddy / CodeBuddy 账号接进 DeepSeek Harness 的模型选择器 —— 国内版(codebuddy.cn)和国际版(workbuddy.ai)两条链路,装一条或两条都装。
不用 API Key,不用改 DSH 源码,一条命令装完,右下角有状态胶囊,模型选择器里直接多出两个分组。
git clone https://github.com/zz991/dsh-workbuddy
cd dsh-workbuddy
install\install.cmd # Windows
bash install/install.sh # macOS / Linux
Windows 上别直接跑 pwsh -File install/install.ps1:系统默认的 Restricted 执行策略会在安装器打印任何提示之前就把它拦下。install.cmd 不受该策略约束,它会自己带上 -ExecutionPolicy Bypass 调起安装器。
展开完整文档(README 剩余 1 节)
dsh-workbuddy
把 WorkBuddy / CodeBuddy 账号接进 DeepSeek Harness 的模型选择器 —— 国内版(codebuddy.cn)和国际版(workbuddy.ai)两条链路,装一条或两条都装。
不用 API Key,不用改 DSH 源码,一条命令装完,右下角有状态胶囊,模型选择器里直接多出两个分组。
git clone https://github.com/zz991/dsh-workbuddy
cd dsh-workbuddy
install\install.cmd # Windows
bash install/install.sh # macOS / Linux
Windows 上别直接跑 pwsh -File install/install.ps1:系统默认的 Restricted 执行策略会在安装器打印任何提示之前就把它拦下。install.cmd 不受该策略约束,它会自己带上 -ExecutionPolicy Bypass 调起安装器。
English documentation: README.en.md
装完你会得到什么
| | 国内版 | 国际版 |
| 账号来源 | WorkBuddy / CodeBuddy 国内站(腾讯账号) | WorkBuddy 国际站 |
| 本地网关 | workbuddy2api(Python)· 127.0.0.1:8787 | wb2api(Go)· 127.0.0.1:8788 |
| DSH 里挂在 | workbuddy provider(本插件的 LLM 适配器) | llm-pi-ai 的 globalwb provider(DSH 内置能力) |
| 模型选择器分组 | WorkBuddy | WorkBuddy-Global |
| 登录态文件 | <网关根>/session.json | <网关根>/upstream-go/auths/workbuddy-<uid>.json |
| 登录方式 | 插件内置 login_workbuddy.py 设备流 | login_bin 的 url / poll 设备流 |
三条实用能力:
- 模型即插即用:网关通了就实时拉 /v1/models,平台新上架的模型刷新即出现,不用等插件发版。支持推理的模型(DeepSeek-V4、GLM、Kimi、MiniMax、Hy3…)带 Low / Medium / High 推理等级下拉。
- 右下角状态胶囊:常驻显示登录与代理状态,未登录时点一下就在新标签页开授权页,登完自动变绿 —— 全程不用回终端。
- 诊断与用量:胶囊的 ⚙️ 菜单里有 🔍 诊断(真实发一次模型请求,戳穿「胶囊绿了但模型全 500」)、📊 用量(今日 / 累计 token 与积分消耗)、🔄 刷新模型、🔑 重新登录。
架构
┌──────────────────────── DSH Web GUI(127.0.0.1:3080)────────────────────────┐ │ │ │ 模型选择器 右下角状态胶囊 │ │ ├─ WorkBuddy 分组 ────────┐ ├─ 登录 / 重新登录 │ │ └─ WorkBuddy-Global 分组 ─┼─┐ ├─ 🔍 诊断 / 📊 用量 │ │ │ │ └─ 🔄 刷新模型 │ └─────────────────────────────┼─┼──────────────────────────────────────────────┘ │ │ ┌─────────────────────┘ └──────────────────────┐ ▼ ▼ dsh-llm-workbuddy 插件 llm-pi-ai(DSH 内置) provider: workbuddy provider: globalwb /api/workbuddy/* 路由 settings.yaml 里配的 OpenAI 兼容端点 │ │ ▼ ▼ 127.0.0.1:8787 ◀──────────────────────────▶ 127.0.0.1:8788 国内版 Python 网关 国际版 Go 网关 hawklithm/workbuddy2api Sliverkiss/workbuddy2api ▲ ▲ └────────── wb-gateway-manager 插件 ───────────┘ 每次 DSH 后端启动后探测端口、按需拉起
wb-gateway-manager 是那个"省事"的部件:DSH 改设置会重启后端,重启会连带杀掉它进程树里的网关子进程。这个插件在每次后端启动后重新探测两个端口,没在监听就拉起来 —— 所以只要 DSH 活着,模型路由就是通的,你不需要开一堆终端窗口守着网关。
安装器做了什么
install/setup.mjs(install.ps1 / install.sh 只是它的外壳)按顺序跑六步,全部幂等,重复执行不会重复写、不会覆盖你自己改过的设置值:
1. 环境体检 —— Node ≥ 18、DSH_HOME、profile 是否存在,顺带报出 python / uv / go / dsh CLI 的位置。
2. 装插件 —— 两个包复制进 <DSH_HOME>/plugins/,再在 profile 的 node_modules 里建 junction 指过去。
3. 挂载 profile —— 幂等追加 <profile>/cordis.patch.yml 的 insert 行(保留文件原有注释,不整段重写)。
4. 写设置 —— 用 DSH 自带的 js-yaml 合并 settings.yaml:只补缺失的键,已存在就原样保留;写之前自动备份成 settings.yaml.bak.<时间戳>。
5. 准备网关 —— 找到就用;国内版缺失时给出 uv tool install 指引,国际版缺失时可从 Release 下载。
6. 引导授权 —— 国内版跑 login_workbuddy.py,国际版跑 login_bin,把授权链接打给你,登录态自动落盘。
网关根目录不用你填:安装器会从 settings.yaml 里 llm-workbuddy.sessionFile 反推,找不到才回落到 $DSH_HOME/workbuddy。已经装过网关的机器会被无损接管,不会另起一个空目录。
常用参数:
node install/setup.mjs --realm=both # cn / global / both,不给就交互询问
node install/setup.mjs --realm=cn --yes # 国内版,全默认不交互
node install/setup.mjs --plugins-only # 只装插件,不碰网关和登录
node install/setup.mjs --dry-run # 只打印将要做的事,一个字节都不写
node install/setup.mjs --force-settings # 用安装器的值覆盖已存在的设置项
node install/setup.mjs --dsh-home=D:\my-dsh # 指定 DSH 家目录
node install/setup.mjs --uninstall # 卸载:撤掉挂载、链接、插件目录与设置项
装完重启 DSH 后端(关掉 dsh web / 桌面版再打开),插件与网关会自己挂上。
前置条件
- DeepSeek Harness,且至少跑过一次(DSH_HOME 与 profile 要存在)。
- Node.js ≥ 18 —— 只给安装器用,插件本身零依赖、无构建步骤。
- 网关(第三方项目,本仓库不打包它们的源码):
- 国内版:uv tool install -U workbuddy2api(需 ≥ 2.0.4;2.0.3 及更早缺登录所需请求头,登录最后一步会 401)
- 国际版:从 Release 下 wb2api.exe,或按 docs/GLOBAL.md 自行 go build
- 国内版登录需要系统里有 python3(纯标准库,Python 3.7+ 即可)。
日常使用
登录、重登、诊断、刷新模型都在 Web GUI 右下角的胶囊里点,不用命令行。要手动跑也行:
国内版登录(会话写入 <网关根>/session.json)
python3 <DSH_HOME>/plugins/dsh-llm-workbuddy/login_workbuddy.py --session-file <网关根>/session.json
国际版登录
cd <网关根>/upstream-go && ./login.sh --realm=global
看两个网关的监听状态
curl http://127.0.0.1:3080/api/wb-gateway/status
关于「🎁 签到」:入口只在网关真的实现了 /v1/checkin-status 与 /v1/checkin 时出现。国内版网关(workbuddy2api Python)至今没有这两个端点,插件探测到 404 后自动隐藏入口并停止每日重试,不会留一堆失败记录。国际版网关自带排程签到,走它自己的 schedule 配置。
配置参考
设置写在 $DSH_HOME/settings.yaml(安装器会自动合并,这里是给你手改的参考):
llm-workbuddy: # 国内版:本插件的适配器 baseURL: http://127.0.0.1:8787/v1 # 网关端点 sessionFile: <网关根>/session.json # 会话文件(胶囊据此判断登录态) discovery: true # 实时拉 /v1/models(30s 缓存)
llm-pi-ai: # 国际版:DSH 内置的 OpenAI 兼容适配器 providers: globalwb: displayName: WorkBuddy-Global apiKeyEnv: WB_GLOBAL_API_KEY # 网关不校验时可留空 api: openai-completions baseURL: http://127.0.0.1:8788/v1 models:
- { id: global:glm-5.3, name: GLM-5.3 (Global) }
- { id: global:gpt-5.6-terra, name: GPT-5.6 Terra (Global) }
网关侧的端口、账号池、冷却策略在 <网关根>/upstream-go/config.json(国际版)和网关命令行参数(国内版)里,见 docs/GLOBAL.md。
排错速查
| 现象 | 处理 |
| 右下角没有胶囊 | DSH 后端没重启 → 重启;或 curl http://127.0.0.1:3080/plugins/dsh-llm-workbuddy/client.js 应返回 200 |
| 胶囊红 + 代理未运行 | 网关没起 → curl http://127.0.0.1:3080/api/wb-gateway/status 看是哪个,再按提示补装 |
| 胶囊绿但模型全 500 | 典型的「网关活着但指向旧路径」假象 → 点胶囊 🔍 诊断,看「模型出字」一行 |
| 点登录返回 alreadyLoggedIn 但 token 已失效 | 本地判定是启发式 → 用 ⚙️ → 🔑 重新登录 强制重跑设备流 |
| 模型选择器里没有新模型 | 网关的模型清单来自本机 WorkBuddy 应用 → 更新应用后点 🔄 刷新模型 |
| 启动报 EPERM ... cordis.yml | DSH_HOME 所在卷受保护 → 换 DSH_HOME 或修权限 |
完整清单见 docs/TROUBLESHOOTING.md。
目录结构
dsh-workbuddy/
├─ package.json 根包 = dsh-llm-workbuddy 插件本体 ├─ lib/index.js LLM 适配器 + /api/workbuddy/* 路由 ├─ lib/client.js 零依赖浏览器小部件(状态胶囊) ├─ login_workbuddy.py 国内版设备流登录脚本 ├─ cordis.patch.yml 本包的 Cordis bundle 挂载声明 ├─ packages/ │ └─ wb-gateway-manager/ 双网关守护插件(路径自动探测) ├─ install/ 一键安装器(ps1 / sh 外壳 + setup.mjs 内核) ├─ scripts/ 辅助工具(清理重复包裹、构建国际版网关) ├─ test/plugin-smoke.mjs 加载冒烟测试:两个包各跑一次真实 apply() └─ docs/ CN.md · GLOBAL.md · FAQ.md · TROUBLESHOOTING.md
自检
node test/plugin-smoke.mjs # 需要本机装过 DSH(peer 依赖取自它的 node_modules)
它把仓库里两个包的入口分别复制到临时目录、把各自的 node_modules/@deepseek-ai 指向你的 DSH 运行时,然后真实加载插件、对着 mock 的 Cordis 上下文调一次 apply(),断言注册了什么(共 37 项)—— 覆盖 headless(没有 webServer)与无 entry config 两条路径;网关守护插件还会真的调一次 /api/wb-gateway/status 的 handler,校验响应 JSON 与 405 分支。
node --check 查不出「新版 harness 删掉了某个具名导出」这类问题,因为那是加载期的 SyntaxError,会把整个插件拖下水。这个测试能。
许可与声明
MIT(见 LICENSE)。
本仓库只做 DSH 侧的适配与安装编排,不打包也不修改第三方网关的源码:
- 国内版网关 hawklithm/workbuddy2api(Python)
- 国际版网关 Sliverkiss/workbuddy2api(Go,MIT)
Release 里附带的 wb2api / login_bin 二进制由上游源码构建,遵循上游 MIT 许可。
这是非官方工具,与腾讯 / CodeBuddy / WorkBuddy 官方无关。请只在自己的账号、自己的机器上使用。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
zz991/dsh-workbuddy
把 WorkBuddy 账号接入模型选择器,免密钥双链路
相关插件 · 模型接入
API 中继安全审计toby-bridges/api-relay-audit
面向 AI API 中转与 LLM 代理的本地安全审计。
★ 897已汉化DSH
69.4
免费搜索插件DDDMUC/dsh-free-search
DeepSeek Harness 免费搜索插件 —— 无需 API key,零成本,多引擎可切换。 一个给…
★ 761已汉化DSH
68.7
免费联网搜索liustack/modsearch
在官方 App 里模型能联网,切到 API 就不能了。ModSearch 把联网补回来:网页搜索、X…
★ 863已汉化DSH
68.5
OpenCode 免费模型FishBottle7/opencode2dsh
在 DSHDeepSeek Harness里原生使用 OpenCode Zen 的免费匿名模型。
★ 379已汉化DSH
67.8
AI 模型网关tingly-dev/tingly-box
Tingly Box Web UI 演示
★ 373已汉化DSH
67.4
WorkBuddy 账号池XDTrees/dsh-xdpool
把你能白嫖的模型额度接进 DSH 同一个池:WorkBuddy 多账号自动容错、十三家扫码登录、76…
★ 359已汉化DSH
67.1