dsh-workbuddy2api-hub 0.0.0-stage → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,161 @@
1
+ # Changelog
2
+
3
+ 本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 与语义化版本。
4
+
5
+ ## [1.0.10] - 2026-10-24
6
+
7
+ 发版一条命令同时落到 npm 与 GitHub Release,npm 包里只留运行时代码。
8
+
9
+ - `npm run release <x.y.z>` 现在会自己发 npm:先查登录态与版本号是否已被占用,再 `npm publish`,
10
+ 最后才提交、打标签、推送(npm 失败就停,不会留「GitHub 有标签、npm 没版本」的半成品)。
11
+ `--no-publish` 只发 GitHub,`--dry-run` 只跑到测试。
12
+ - npm 包从 15 个文件瘦到 8 个(约 60 kB):只含 `lib/`、`client/`、`cordis.patch.yml` 与
13
+ README / CHANGELOG / LICENSE。`scripts/`、`tests/`、`docs/`、`.github/` 只在仓库里。
14
+ - **修掉一个会改坏用户 profile 的坑**:`package.json` 里原来有个 `"install": "node scripts/install-local.mjs"`
15
+ ——`install` 是 npm 的生命周期钩子,任何人 `npm i dsh-workbuddy2api-hub` 都会自动执行它,
16
+ 把「装包的那个人」的 profile 依赖改指向包自己所在的目录。已改名 `npm run link` / `npm run link:dry` /
17
+ `npm run unlink`,生命周期钩子不再存在。
18
+ - README 里 `docs/MAINTAINER.md` 的链接改用 GitHub 绝对地址(npm 包页里相对链接点不开)。
19
+
20
+ ## [1.0.9] - 2026-10-24
21
+
22
+ 模型选择器里能直接看到每个模型的倍率了。
23
+
24
+ - 写进 `llm-pi-ai` 的模型名改成「展示名 + 倍率」:付费模型形如 `GLM-5.1 ×0.79`,
25
+ 网关标 `x0.00`(或字面量 `free`)的免费模型形如 `Hy3 Free`;`id` 不变,路由与计费不受影响。
26
+ - 没声明倍率的模型不加后缀,不谎报免费。
27
+ - 设置页模型表的「倍率」列同样显示 `Free`,原先免费模型显示的是 `—`。
28
+
29
+ ## [1.0.8] - 2026-10-24
30
+
31
+ 插件在列表里显示「异常」「包不可用」的那个坑:`scripts/install-local.mjs` 把自己**所在**的
32
+ 目录写进 DSH profile 的 `package.json`,从临时目录(如 `tmp/verify/...`)的运行副本执行时,
33
+ profile 就被指到了一个随时会被清掉的路径——清掉之后插件立刻加载失败。
34
+
35
+ - `scripts/install-local.mjs` 拒绝从 `node_modules/` 或 `tmp/` 下的副本执行,并提示必须从仓库根目录运行。
36
+ - README 排错段补了这一症状的定位与修复:查 profile 依赖指向 + `node_modules` 链接,重跑安装脚本后重启。
37
+
38
+ ## [1.0.7] - 2026-10-24
39
+
40
+ 首个发布到 npm 的版本:`npm i dsh-workbuddy2api-hub`,不用 clone 也不用构建。
41
+
42
+ - `package.json` 补发布配置:`files` 白名单(`lib`、`client`、`scripts`、`docs` 与三份文档,
43
+ 测试与临时目录不进包,整包 15 个文件 / 75 kB)、`publishConfig` 指到公共 registry、
44
+ `prepublishOnly` 在发布前强制跑 `check-secrets` 与全部测试——凭据或坏代码进不了 npm。
45
+ - 维护者向内容搬到 `docs/MAINTAINER.md`(调试出口、主题令牌、假 hub 的鉴权语义、
46
+ 刷新与退避规则、发版流程、市场收录模板),README 只留使用者需要的部分并加了指向链接。
47
+ - 本机路径、端口、备份与凭据位置写进仓库外的 `NOTES.local.md`,并加进 `.gitignore`。
48
+ - 发版自动化:`npm run release <version>` 一条命令完成改版本、自检、测试、提交、打标签、
49
+ 推送;标签一推由 GitHub Actions 用 `GITHUB_TOKEN` 建 Release,正文取自本文件对应小节。
50
+
51
+ ## [1.0.6] - 2026-10-24
52
+
53
+ 悬停框里「今日」和「本周」的写法统一,README 改成给外部读者看的版本。
54
+
55
+ - 悬停框(`title`)原本把今日拆成三行、本周挤成一行,同一份数据在同一个框里长得
56
+ 不一样,读起来像两份东西。现在两行同构:
57
+ `今日 tokens 72.3M · 积分 61.41 · API 等价 ¥10.39` /
58
+ `本周 tokens 260.7M · 积分 465.43 · API 等价 ¥31.17`,只有开头的窗口名不同。
59
+ - 收起态与展开态共用同一个 `title`,不再有两套文案。
60
+ - README 清理:去掉维护者视角的内容(本机路径示例、`cordis_inspect_query` 这类
61
+ 内部工具名、插件市场 PR 的收录步骤),补上侧边栏徽标长什么样、`npm run check`
62
+ 命令;「面板密码不落盘」的说法改为如实描述(它确实存在状态文件里)。
63
+ - 测试 +1(悬停框两行同构、收起态同一套文案),共 87 条。
64
+
65
+ ## [1.0.5] - 2026-10-24
66
+
67
+ 徽标加一行「本周」,两行数据左标签贴左、三个数字贴右。
68
+
69
+ - 展开态现在是三行:`● WorkBuddy … 3729.25` / `今日 49.9M · 45.57 · ¥7.21` /
70
+ `本周 248.1M · 455.45 · ¥29.30`。窗口名贴左(`minWidth: 44px`,中英文都不抖),
71
+ 三个数字用 `marginLeft: auto` 顶到最右,两行上下对齐,一眼能比出今日与本周的差距。
72
+ - 宿主每次刷新固定多拉一次 `range=week`,存在 `usageWeek` 槽位;`usage`(主窗口,默认
73
+ `today`)不动,所以把 `usageRange` 配成 `month`/`all` 也不会把本周数据顶掉。
74
+ - 快照新增 `usageWeek`;`GET /api/usage?range=week` 走同一个槽位。老宿主没有
75
+ `usageWeek` 时前端**不画第三行**,绝不拿今日的数冒充本周。
76
+ - **口径说明**:hub 的「本周」是**日历周**,从本周一 00:00 起(`wb_proxy.py:747
77
+ range_window()`:`_local_midnight(days_back=tm_wday)`),不是「近 7 天」;源码注释
78
+ 明确说滚动别名 `7d`/`30d` 故意不提供。真要近七天可以用 `range=custom&since=<epoch>`
79
+ 自己算窗口。
80
+ - 测试 +2(徽标两行的左右对齐结构、老宿主不画第三行)+ 宿主/e2e 的 `usageWeek` 断言,
81
+ 共 86 条。
82
+
83
+ ## [1.0.4] - 2026-10-24
84
+
85
+ 徽标第二行不再堆标签,改成「窗口 + 三个数字」。
86
+
87
+ - 展开态第二行:`今日 49.9M · 45.57 · ¥7.21`——窗口名只在最前面标一次,后面三个数
88
+ 靠 `·` 分隔,不再写三份「今日 tokens / 今日积分 / API 等价」。11px 的侧边栏宽度本来就
89
+ 放不下三份标签,挤在一起只会换行、更难读。
90
+ - 三个数字各自是什么,仍然写在 `title` 里(悬停可读:余额、tokens、积分、API 等价、错误或地址)。
91
+ - 删掉 `HubFooter` 里的 `item(label, value)` 小助手(三份标签都去掉后没人用了)。
92
+ - 测试 +1:直接渲染 `__HubFooter({ wide: true })` 断言第二行正好 6 个子节点
93
+ (窗口名 + 三个数字 + 两个分隔点),共 85 条。
94
+
95
+ ## [1.0.3] - 2026-10-24
96
+
97
+ 侧边栏徽标改成五项,并修掉一个「参数名传错」的旧 bug。
98
+
99
+ - 徽标(展开态)现在显示:`WorkBuddy` · `积分余额` · `今日 tokens` · `今日积分` · `API 等价`;
100
+ 收起态(约 48px)只留状态点 + 积分余额 + 今日积分,完整四项放进 `title` 悬停可读。
101
+ - **修 bug**:hub 的 `/usage` 只认 `range` / `since` / `until`(`wb_proxy.py:784 range_query()`),
102
+ 传 `hours=` 会被静默忽略、退化成**全量历史**——所以以前标着「近 24 小时」的数字其实是累计总额。
103
+ 现在按 `range=today` 请求,与看板「今日」口径一致。
104
+ - 新增 `normalizeUsageRange(value)` / `usageQuery(range)` / `USAGE_RANGES`:`today`(默认)/
105
+ `week` / `month` / `all`,非法值退回 `today`;`all` 不带参数(hub 侧不过滤)。
106
+ - 快照字段 `usageHours` 换成 `usageRange`;插件接口 `GET /api/usage?range=today|week|month|all`。
107
+ - 设置页用量行新增「积分」徽标,标签由「近 24 小时」改为「今日」。
108
+ - 新增 `footerSummary(snapshot)` 纯函数(导出 `__footerSummary` 便于测试):积分两位小数、
109
+ tokens 走 K/M/B、金额 `¥0.00`;余额 0 视为有效值而不是缺失。
110
+ - 测试 +4(`normalizeUsageRange`/`usageQuery`、`footerSummary` 正常态与缺失态、双语标签),共 84 条。
111
+
112
+ ## [1.0.2] - 2026-10-24
113
+
114
+ 模型列表改成按名称排序。
115
+
116
+ - 新增 `sortModels(models)` / `compareModelsByName(left, right)`:按模型的显示名排序,
117
+ 忽略大小写、数字按数值比较(`GPT-9` 在 `GPT-10` 前面),同名按 id 兜底,保证顺序稳定。
118
+ - `buildRouteModels` 与设置页表格共用同一个比较器,所以写进 `llm-pi-ai` 的 `models`
119
+ 顺序和设置页看到的一致;原先的「按倍率从便宜到贵」排序已移除,倍率只作为展示字段。
120
+ - 没有 `name` 的条目用 id 当名字参与排序,不会因为缺字段被打到末尾。
121
+ - 设置页表格在客户端也排了一次序(),宿主还没热更新时也不会按 hub 的原始顺序乱放。
122
+ - 因为顺序变了,下一次刷新会把 `providers.workbuddy2api-hub` 重写一次(内容相同也算变更)。
123
+
124
+ ## [1.0.1] - 2026-10-24
125
+
126
+ 修复浅色主题下设置页「字看不清」。
127
+
128
+ - 配色改用 DSH 真正注册的主题令牌 `--dsw-alias-*`(原先是 `--dsh-*`,这个名字在
129
+ 0.2.1-rc.2 里不存在,`var()` 静默走兜底,而兜底是给深色主题写的浅灰字)。
130
+ 用户在浅色主题下看到的就是「浅灰字 + 白底」。
131
+ - 输入框 / 次级按钮 / 信息条底色改成 `--dsw-alias-bg-layer-2`,不再写死
132
+ `rgba(0,0,0,.18)`、`rgba(255,255,255,.06)` 这类只对深色主题成立的半透明。
133
+ - 思考档位选中的高亮色改成 `color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent)`,
134
+ 深浅两套主题都不会出现「浅底浅字」。
135
+ - 11px 的辅助说明与侧栏额度数字提高对比度(次要文字改用 `label-secondary`)。
136
+ - 测试新增 2 条:palette 的每个值必须是 `--dsw-alias-*` 令牌;样式里不许再出现写死的深色底。
137
+
138
+ ## [1.0.0] - 2026-10-24
139
+
140
+ 首个版本。把本地 workbuddy2api-hub 接进 DSH 桌面端。
141
+
142
+ ### 新增
143
+
144
+ - 设置页分区 `workbuddy2api-hub`:服务地址、面板密码、默认页签、轮询间隔、API Key 的可视化配置;测试连接、立即同步、打开看板、清空同步。
145
+ - 侧边栏徽标:credit 余额 + 连接状态点,点击直接打开带 `pwd`/`tab` 的看板深链。
146
+ - 模型同步到 `llm-pi-ai` 的 `providers.workbuddy2api-hub`:`contextWindow` / `maxTokens` / 图片输入 / 思考档位 / 倍率排序;内容没变不写盘,`SettingsConflictError` 自动重试。
147
+ - 模型下架宽限期(默认 24 小时)与复活;`newModelPolicy` 决定新模型默认是否勾选。
148
+ - 余额、用量(请求数 / 失败数 / credit / 缓存命中)、账号状态聚合。
149
+ - 六类告警:连不上、密码错、登录限流、缺 API Key、额度偏低、账号需重登/过期;可「知道了」抑制 24 小时。
150
+ - 失败分类(`classifyFailure`):连不上 / 超时 / 鉴权失败 / 限流 / HTTP 错误 / 非 JSON,全部折成中文提示,写进 `lastError`。
151
+ - `scripts/mock-hub.mjs`:复刻真实 hub 鉴权语义的假服务(含 60 秒 5 次失败的 429)。
152
+ - `scripts/smoke-live.mjs`:对真实 hub 的只读联调(不读明文 Key、不写 DSH 配置)。
153
+ - `scripts/install-local.mjs`:把仓库挂进 profile,带备份、`--dry-run`、`--uninstall`。
154
+
155
+ ### 设计决定
156
+
157
+ - 路由键默认 `workbuddy2api-hub`,不复用 `wb`:装上插件不该改写用户已有的 provider 路由。
158
+ - `pwd` 只用来换 `X-Panel-Token`。面板 Token 不能当 Bearer 用(实测 `/v1/chat/completions` 带面板 Token 仍 401),所以真实调用必须落到 API Key 上。
159
+ - 缺 API Key 时不写模型路由:写一条注定 401 的 provider 比什么都不写更糟。
160
+ - `baseUrl` / `pwd` / `tab` 用显式字段指纹判定:YAML 改了才覆盖,没改就保留设置页里的改动。
161
+ - 状态文件放在 profile 目录(`workbuddy2api-hub.json`),`stateDir` 可覆盖;API Key 只进凭据库与内存。
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-workbuddy2api-hub contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,214 @@
1
- # Temporary Holding Version
1
+ # dsh-workbuddy2api-hub
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 把本地跑的 [workbuddy2api-hub](https://github.com/ardeyouxipianyi/workbuddy2api-hub) 接进 DSH 桌面端。
4
+
5
+ 装上之后:hub 上的模型会出现在 DSH 的模型列表里(带上下文窗口、图片输入、思考档位),侧边栏底部常驻一个徽标显示积分余额和今日/本周用量,设置页里多一块面板管连接。
6
+
7
+ ```
8
+ 本地 workbuddy2api-hub (:8788) ← X-Panel-Token ─┐
9
+ └─ /v1(OpenAI 兼容) ← Bearer Key ────┤
10
+ ├─→ 本插件(DSH 宿主侧)
11
+ DSH 设置页 / 侧边栏 ← /workbuddy2api-hub/api/* ──┘ └─→ llm-pi-ai providers.workbuddy2api-hub
12
+ ```
13
+
14
+ ## 功能
15
+
16
+ - **连接面板**:服务地址、面板密码、默认页签、轮询间隔;「测试连接」「立即同步」「打开看板」「清空同步」。
17
+ - **模型同步**:把 `/v1/models` 写进 `llm-pi-ai` 的 `providers.workbuddy2api-hub`,每个模型带上 `contextWindow` / `maxTokens` / 图片输入 / 思考档位;按模型名称排序(不区分大小写、数字按数值),设置页表格与写进 DSH 的顺序一致。模型名后面直接带网关的倍率(`GLM-5.1 ×0.79`),免费模型标 `Free`——倍率写不进名字,选择器里就看不见。
18
+ - **增量与容错**:模型下架先进宽限期(默认 24 小时,可一键立即移除),回来能复活;内容没变就不写配置,避免每次轮询都触发一次配置更新;配置冲突自动重取 revision 重试。
19
+ - **余额与用量**:`/v1/balance-summary` 的 credit 余额,`/usage?range=today` 的请求数 / 失败数 / tokens / credit / API 等价花费 / 缓存命中。
20
+ - **侧边栏徽标**:展开态三行——`● WorkBuddy … 3715.39` / `今日 72.3M · 61.41 · ¥10.39` / `本周 260.7M · 465.43 · ¥31.17`;窗口名贴左、三个数字贴右,依次是 tokens / 积分消耗 / API 等价花费。悬停能看完整数字和连接地址,点一下直接打开 hub 看板。
21
+ - **告警**:连不上、密码错、登录被限流、缺 API Key、额度低于阈值、账号需要重登——都能「知道了」消掉 24 小时。
22
+ - **不崩**:hub 没开、密码错、超时、返回 HTML、返回半截 JSON,插件都只把它变成一段中文提示;`/state` 永远返回 200,前端永远有东西可渲染。
23
+
24
+ ## 为什么不是「填个地址就行」
25
+
26
+ 读 hub 的源码并实测之后,有三件事必须先说清楚,否则接进去就是一堆 401:
27
+
28
+ | 参数 | 真实作用 | 不要误解成 |
29
+ | --- | --- | --- |
30
+ | `pwd` | 面板密码(默认 `admin`)。`POST /panel/login` 换一个 `X-Panel-Token`,之后所有管理接口带这个头 | 它不是 API Key:`Authorization: Bearer <面板 Token>` 一律 **401** |
31
+ | `tab` | 纯前端页签深链(`dashboard.html` 读 `?tab=`,白名单 `gateway/accounts/tasks/analytics/agents/settings/logs`) | 不是 API 参数,服务端不认 |
32
+ | `?pwd=admin` | 同上,只是面板自己的便利参数,服务端不处理 | 不代表鉴权已经完成 |
33
+
34
+ 所以插件分两条腿走路:
35
+
36
+ 1. **管理面**用 `pwd` 换面板 Token,读 `/health`、`/panel/status`、`/v1/models`、`/v1/balance-summary`、`/usage`、`/accounts`、`/settings`;
37
+ 2. **对话面**必须有一个真正的 API Key(DSH 调 `/v1/chat/completions` 时走 `Authorization: Bearer`)。Key 的取法三级:配置里写了 `apiKey` → 写进 DSH 凭据库;凭据库里已有同名的 → 直接用;都没有 → 用面板 Token 读 `/settings` + `/settings/reveal?id=<keyId>` 取第一个启用的 Key。
38
+
39
+ 拿不到 Key 时插件**不会**硬写一条注定 401 的路由,而是把「缺少 hub API Key」挂到告警里,等你填。
40
+
41
+ ## 安装
42
+
43
+ 前置:
44
+
45
+ - Node.js ≥ 20(`node -v` 看一眼)
46
+ - 本地 `workbuddy2api-hub` 已经跑起来,浏览器能打开 `http://127.0.0.1:8788`
47
+ - DSH 桌面端能正常打开
48
+
49
+ **不需要 `npm install`**:本包没有运行时依赖(`@deepseek-ai/*` 全是 `peerDependencies`,由 DSH 自己提供),也没有打包步骤——`client/client.js` 就是可以直接加载的 `window.__ModuleLoader__` bundle。
50
+
51
+ 最快的一条路是从 npm 装(装进 profile,不用 clone):
52
+
53
+ ```bash
54
+ cd ~/.dsh/profiles/desktop
55
+ npm i dsh-workbuddy2api-hub
56
+ ```
57
+
58
+ 然后重启 DSH 桌面端。想用仓库里的安装脚本(会同时登记 `dsh.profile.bundles`,更稳)就走下面三步:
59
+
60
+ ```bash
61
+ # 1. 克隆到任意目录
62
+ git clone https://github.com/HimA6652/dsh-workbuddy2api-hub.git
63
+ cd dsh-workbuddy2api-hub
64
+
65
+ # 2. 先确认 hub 通不通(只读,不改任何东西)
66
+ node scripts/smoke-live.mjs
67
+
68
+ # 3. 挂进桌面端 profile(默认 ~/.dsh/profiles/desktop)
69
+ node scripts/install-local.mjs
70
+
71
+ # 4. 重启 DSH 桌面端
72
+ ```
73
+
74
+ 重启后:**设置 → workbuddy2api-hub** → 确认地址/密码 → 「测试连接」→「立即同步」→ 模型出现在 **设置 → 模型** 里,provider 名 `workbuddy2api-hub`。
75
+
76
+ `install-local.mjs` 只做三件事,都可逆:在 profile 的 `package.json` 里加一条 `file:` 依赖、往 `dsh.profile.bundles` 追加一个名字、在 `node_modules/` 下建一个指向本仓库的链接(Windows 用 junction,不需要管理员权限)。改之前会备份 `package.json`;`--dry-run` 只看不做,`--uninstall` 原样退回。
77
+
78
+ 仓库里没有任何凭据:`pwd` 与 API Key 都在**你自己机器**上填,不进代码、不进 git。
79
+
80
+ ### 其他安装方式
81
+
82
+ 装好了 DSH CLI 的机器上,也可以直接让它从 GitHub 拉(本包声明了 `dsh.bundle`,安装时不需要构建):
83
+
84
+ ```bash
85
+ dsh plugin --profile desktop add github:HimA6652/dsh-workbuddy2api-hub
86
+ ```
87
+
88
+ 自己维护索引源的话,把仓库地址加进 **设置 → 插件 → Discover → Index sources** 也可以。
89
+
90
+ ## 配置
91
+
92
+ 改 profile 的 `cordis.patch.yml`(或本仓库的 `cordis.patch.yml` 作为默认值)。**只改配置就能换地址/密码,不用改代码**:
93
+
94
+ ```yaml
95
+ - id: workbuddy-hub
96
+ name: dsh-workbuddy2api-hub
97
+ config:
98
+ baseUrl: http://127.0.0.1:8788 # 换机器就改成 http://192.168.1.10:8788
99
+ pwd: admin # 面板密码
100
+ tab: gateway # 打开看板时落在哪个页签
101
+ ```
102
+
103
+ | 配置 | 默认 | 说明 |
104
+ | --- | --- | --- |
105
+ | `baseUrl` | `http://127.0.0.1:8788` | 服务地址。从浏览器地址栏整条粘进来也行(`?pwd=…&tab=…` 会被剥掉),缺协议自动补 `http://` |
106
+ | `pwd` | `admin` | 面板密码。只用于换 Token,不会被当成 API Key |
107
+ | `tab` | `gateway` | 深链页签,白名单外的值退回 `gateway` |
108
+ | `apiKey` | 空 | 可选。写了就存进 DSH 凭据库(引用名见 `apiKeyEnv`),不落状态文件 |
109
+ | `apiKeyEnv` | `WORKBUDDY2API_HUB_API_KEY` | DSH 凭据库里的引用名 |
110
+ | `providerEntry` | `llm-pi-ai` | 写到哪个 settings 的 ns 下 |
111
+ | `routeKey` | `workbuddy2api-hub` | 写进 `providers.<routeKey>`。**故意不叫 `wb`**,免得覆盖你已有的路由 |
112
+ | `intervalSeconds` | `120` | 轮询间隔,下限 30、上限 3600;连续失败会指数退避到 30 分钟 |
113
+ | `sync` | `true` | 关掉就只看数据、不写模型 |
114
+ | `autoApiKey` | `true` | 缺 Key 时是否允许从面板 `/settings/reveal` 自动取 |
115
+ | `newModelPolicy` | `select` | hub 上新出的模型默认勾选(`select`)还是先不写(`ignore`) |
116
+ | `retireHours` | `24` | 模型下架后的宽限期 |
117
+ | `thresholds.lowCredits` | `100` | 余额低于它就告警;`0` 关掉 |
118
+ | `thresholds.unreachablePolls` | `5` | 连续失败几次才报「连不上」 |
119
+ | `stateDir` | 空 | 状态文件目录。默认跟 profile 同级(`workbuddy2api-hub.json`) |
120
+
121
+ `baseUrl` / `pwd` / `tab` 三个字段按「显式字段指纹」判定:YAML 里改了值就覆盖状态,没改就保留你在设置页里最后改的值——所以「改配置即生效」和「UI 改动不被重启抹掉」不会打架。
122
+
123
+ ## 错误处理
124
+
125
+ 所有失败都折成一句话写进 `lastError`,同时决定要不要出告警:
126
+
127
+ | 情况 | 面板上看到的 | 还会做什么 |
128
+ | --- | --- | --- |
129
+ | 服务没开 / 端口不通 | 连不上 hub(fetch failed):确认本地服务已启动(默认 http://127.0.0.1:8788) | 冷启动 60 秒内每 15 秒重试,之后指数退避 |
130
+ | 8 秒没响应 | 连不上 hub(请求超时) | 同上 |
131
+ | 密码错 | 面板密码(pwd)不对 | 出 `auth` 告警,不反复猛撞 |
132
+ | 60 秒内错 5 次 | 面板登录被限流,N 秒后再试 | 轮询间隔抬到 hub 建议的等待时间以上 |
133
+ | 404 | 服务版本可能与本插件不匹配(HTTP 404) | — |
134
+ | 5xx | hub 内部错误(HTTP 500) | — |
135
+ | 返回 HTML | 返回了非 JSON 内容 | — |
136
+ | 缺 API Key | 还没有可用的 hub API Key,暂不写入模型 | 出 `api-key` 告警,不写注定 401 的路由 |
137
+
138
+ `/state` 无论如何都是 200 + 一份完整快照,前端不会因为一次失败白屏。
139
+
140
+ ## 插件接口
141
+
142
+ 宿主侧注册一个前缀路由 `/workbuddy2api-hub/api`:
143
+
144
+ | 方法 | 路径 | 说明 |
145
+ | --- | --- | --- |
146
+ | GET | `/state` | 全量快照(带 `ETag`,前端用 `If-None-Match` 拿 304) |
147
+ | GET | `/usage?range=today` | 只刷用量(`range` 取 `today` / `week` / `month` / `all`) |
148
+ | GET | `/accounts` | 只刷账号 |
149
+ | GET | `/dashboard-url` | 看板深链(含 `pwd`),**只给本机** |
150
+ | POST | `/config` | 改地址 / 密码 / 页签 / 间隔 / API Key |
151
+ | POST | `/selection` `/bulk` `/enable-new` | 勾选模型、全选/全不选、新模型默认策略 |
152
+ | POST | `/refresh` `/test` `/policy` `/dismiss` `/retire` `/clear` | 同步、探测、策略、消警、立即移除、清空同步 |
153
+
154
+ 写接口有三道闸:只接受本机来源(`127.0.0.1` / `::1` / `::ffff:127.0.0.1`)、`sec-fetch-site` 必须是 `same-origin` 或 `none` 且 `Origin` 与 `Host` 一致、`content-type` 必须是 JSON。响应不带任何 CORS 头——这样同机网页用 `no-cors` 的简单请求也打不进写接口。
155
+
156
+ ## 安全与隐私
157
+
158
+ - **API Key** 只进 DSH 凭据库和内存,**绝不**写状态文件,也**绝不**出现在 `/state` 里(连掩码都不给)。
159
+ - **面板密码**会存进 profile 的状态文件 `workbuddy2api-hub.json`(明文,重启后要靠它继续登录)。它只是 hub 的面板密码,不等于 API Key;如果你的 hub 用了别的重要密码,建议给面板单独设一个。
160
+ - `/dashboard-url` 会返回带 `pwd` 的深链,所以它只对本机开放。
161
+ - 插件对 hub 只做 GET 和 `/panel/login`,不碰任何写入接口。
162
+
163
+ ## 排错
164
+
165
+ **设置页没有这一块**:插件没加载。看 DSH 启动日志里有没有 `workbuddy-hub`;确认装完之后重启过;确认 `~/.dsh/profiles/<profile>/node_modules/dsh-workbuddy2api-hub` 这个链接存在。
166
+
167
+ **插件列表里显示「异常」「包不可用」**:那个链接指着的地方没了。最常见的原因是 profile 的依赖被写成了一个临时目录(例如 `.../tmp/...`),临时目录一清就断。看一眼:
168
+
169
+ ```bash
170
+ node -e "const p=require(process.env.HOME+'/.dsh/profiles/desktop/package.json');console.log(p.dependencies['dsh-workbuddy2api-hub'])"
171
+ ls -l ~/.dsh/profiles/desktop/node_modules/dsh-workbuddy2api-hub
172
+ ```
173
+
174
+ 依赖应当指向仓库或已发布包的目录;指到 `tmp/` 之类的路径就重跑一次 `node scripts/install-local.mjs`(**必须从仓库根目录跑**,脚本会拒绝从 `node_modules/` 或 `tmp/` 下的副本执行),然后重启 DSH。
175
+
176
+ **面板显示「连不上 hub」**:先在浏览器打开 `http://127.0.0.1:8788`。打不开就是服务没起——本插件只负责连,不负责启动。
177
+
178
+ **「还没有可用的 hub API Key」**:hub 的 `/settings` 里没有启用的 Key,或者你关了 `autoApiKey`。去 hub 的「设置 → API Key」建一个,或在插件设置页填进去。
179
+
180
+ **模型没出现在「设置 → 模型」**:看 `lastSyncError`;确认 `sync: true`;确认 provider 名是 `workbuddy2api-hub`(没有把你原来的 `wb` 覆盖掉)。
181
+
182
+ **想彻底退回去**:`node scripts/install-local.mjs --uninstall`,重启 DSH。状态文件想一起删就删 `~/.dsh/profiles/<profile>/workbuddy2api-hub.json`。
183
+
184
+ ## 开发
185
+
186
+ 下面这些命令要 clone 仓库才能用——npm 包里只有运行时代码(`lib/`、`client/`、`cordis.patch.yml`),`scripts/`、`tests/`、`docs/` 只在仓库里。
187
+
188
+ ```bash
189
+ git clone https://github.com/HimA6652/dsh-workbuddy2api-hub.git
190
+ cd dsh-workbuddy2api-hub
191
+ npm test # 88 个测试,跑在假宿主 + 假 hub 上,不需要起 DSH
192
+ node scripts/mock-hub.mjs --port 8789 # 起一个假 hub,用来手工点界面
193
+ node scripts/smoke-live.mjs --json # 对真实 hub 做只读联调
194
+ npm run check # 确认没有把凭据/本机路径写进仓库
195
+ ```
196
+
197
+ 目录:
198
+
199
+ - `lib/hub.js`:纯函数层(地址归一化、模型档案、用量汇总、退避、告警),无网络、无 cordis,测试覆盖最厚。
200
+ - `lib/index.js`:宿主插件(`name` / `apply`);`HubSession` 管登录与 Token,`HubRuntime` 管刷新与写配置。
201
+ - `client/client.js`:已构建的 ModuleLoader bundle(设置页分区 + 侧边栏徽标),测试用 `node:vm` 加载。
202
+ - `scripts/mock-hub.mjs`:复刻真实 hub 的鉴权语义(面板 Token 能读管理接口、Bearer 只认 API Key、60 秒 5 次失败返 429)。
203
+
204
+ 改 UI 时注意:颜色一律用 DSH 注册的主题令牌 `--dsw-alias-*`(`label-primary`、`label-secondary`、`bg-layer-1/2`、`border-l1/l2`、`brand-primary`、`state-*`),不要写死色值——否则深色主题能看、浅色主题就成了「浅灰字压白底」。在哪能看到当前有哪些令牌:DSH 里打开开发者工具,看 `:root` 上的 CSS 变量。`tests/client.test.mjs` 里有两条测试盯着这件事。
205
+
206
+ 改代码需要的细节(调试出口、主题令牌清单、假 hub 复刻的鉴权语义、刷新退避规则、发版流程、市场收录模板)都在 [docs/MAINTAINER.md](https://github.com/HimA6652/dsh-workbuddy2api-hub/blob/main/docs/MAINTAINER.md) —— README 这里只留使用者需要知道的部分。那份文档只在仓库里,不随 npm 包发出去。
207
+
208
+ ### 与上游的关系
209
+
210
+ 目录结构和「与 DSH 对接的方式」参照 [dsh-workbuddy2api-panel](https://github.com/jerry9692/dsh-workbuddy2api-panel):宿主侧只碰 cordis 注入的服务,不 import 任何 `@deepseek-ai/*` 运行时包(各版本导出名会变);前端是一个可被直接加载的 `window.__ModuleLoader__` bundle,没有打包步骤。
211
+
212
+ ## 许可
213
+
214
+ MIT。图标、模型清单、额度数据都来自你本地的 workbuddy2api-hub,本项目只是读它。