dsh-multi-provider-usage 0.0.0-stage → 0.7.2
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/LICENSE +21 -0
- package/README.md +427 -2
- package/README.zh.md +377 -0
- package/cordis.patch.yml +15 -0
- package/docs/widget.png +0 -0
- package/lib/auto-update.js +570 -0
- package/lib/client.js +2226 -0
- package/lib/index.js +1290 -0
- package/lib/opencode-console.js +556 -0
- package/lib/opencode-session.js +139 -0
- package/lib/providers.js +919 -0
- package/lib/util.js +27 -0
- package/package.json +64 -4
package/README.zh.md
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# dsh-multi-provider-usage
|
|
2
|
+
|
|
3
|
+
[DSH](https://github.com/deepseek-ai/deepseek-harness)(DeepSeek Harness)插件:
|
|
4
|
+
在同一个侧边栏组件里查看 **OpenCode GO**、**Command Code** 和 **GLM Code Plan**
|
|
5
|
+
三个服务商的套餐用量。它以
|
|
6
|
+
[`@astervolans/dsh-opencode-go-usage`](https://github.com/Astervolans/dsh-opencode-go-usage)
|
|
7
|
+
为蓝本——同样的双端包结构、同源代理、侧边栏插槽和 Plugins 面板设置页——从单一
|
|
8
|
+
服务商扩展到三个。
|
|
9
|
+
|
|
10
|
+
> npm 上 `dsh-provider-usage` 已被另一个插件占用,所以包名使用
|
|
11
|
+
> `dsh-multi-provider-usage`。HTTP 路由(`/provider-usage/*`)和聊天命令
|
|
12
|
+
> (`/provider-usage`)仍保持简短。
|
|
13
|
+
|
|
14
|
+
## 功能
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
- **一个组件,一列显示三个服务商。** 所有启用的服务商纵向排列;每家标题带健康
|
|
20
|
+
状态点、主窗口百分比和充值余额。点击某一家标题即可折叠/展开该家的套餐窗口、
|
|
21
|
+
额度条和时间条;折叠状态本地保存,可长期只展开需要看的几家。
|
|
22
|
+
- **OpenCode GO** — 5 小时窗口、周窗口、月窗口(API 中 5 小时字段名为 `rolling`)。优先读取
|
|
23
|
+
`dsh-opencode-go` 插件当前账号的 `opencodeGoUsage` 宿主服务,失败时回退到官方
|
|
24
|
+
`GET /v1/usage`。
|
|
25
|
+
- **Command Code** — 月度额度池、5 小时窗口、周窗口,数据来自官方
|
|
26
|
+
`/alpha/billing/*` 与 `/alpha/usage/summary`。
|
|
27
|
+
- **GLM Code Plan** — 5 小时 Token 窗口、周 Token 窗口、月度 MCP 工具额度,数据
|
|
28
|
+
来自 Z.ai / BigModel 的 `/api/monitor/usage/quota/limit`。
|
|
29
|
+
- **订阅外充值余额** — OpenCode GO 显示 OpenCode Zen 预付费余额,Command Code 显示
|
|
30
|
+
购买额度 + 免费额度的 “Extra Credits” 余额;两者都显示在账号/套餐旁,并出现在
|
|
31
|
+
`/provider-usage` 文本中。OpenCode 控制台令牌依次从 `OPENCODE_CONSOLE_TOKEN`、
|
|
32
|
+
OpenCode CLI 的 auth.json 或本机 `opencode.db` 自动发现,令牌不会离开宿主进程。
|
|
33
|
+
没找到控制台令牌时,余额位置显示可点击的「配置余额」,点击直接打开本插件设置页;
|
|
34
|
+
设置页内为分步引导:可复制的登录命令、控制台网页链接与「重新检测」按钮。
|
|
35
|
+
Command Code 的悬停提示会拆成「购买 + 免费」;credits 响应没有这两个池时显示
|
|
36
|
+
灰色「无充值额度」。
|
|
37
|
+
- **自动更新** — 宿主启动后以及按配置的间隔检查 GitHub Release。本地
|
|
38
|
+
`link:`/`file:` 目录检出在「main 分支、工作区干净、可严格 fast-forward」时直接
|
|
39
|
+
`git pull`;npm / 市场 / tarball 安装的副本则下载该 Release 的 tarball,先写临时
|
|
40
|
+
文件再 `rename` 覆盖 `lib/`、`package.json`、`cordis.patch.yml` 等打包文件——不会
|
|
41
|
+
就地改写 pnpm store 的硬链接。两种方式完成后,运行中的宿主仍持有旧模块,所以
|
|
42
|
+
组件/设置页显示“已更新到 vX,重启 DSH 生效”;插件不会自行重启 DSH。
|
|
43
|
+
- **余额变化动画** — 组件按正常轮询周期刷新;某个服务商的余额相比上一次轮询
|
|
44
|
+
发生变化时,数字会从旧值滚动到新值,同时一个红色/绿色差值(例如 `-0.1`)
|
|
45
|
+
向上飘走并淡出。没有弹窗,也不依赖对话轮次事件;动画最多可能晚一个轮询周期。
|
|
46
|
+
- **余额低额预警** — 余额 ≤ 5 时余额徽章转黄、≤ 1 转红(货币单位通用),侧边栏
|
|
47
|
+
和设置页的「实时用量」一致生效,不用点开卡片也能一眼看到余额告急。
|
|
48
|
+
- **失败可一键重试** — 读取失败时,组件里的错误文字本身可点击(也支持键盘
|
|
49
|
+
Enter/空格),立即强制重新读取。
|
|
50
|
+
- **同源代理** — 浏览器只访问 `/provider-usage/usage` 和
|
|
51
|
+
`/provider-usage/settings`,API Key 始终留在宿主进程。
|
|
52
|
+
- **故障隔离** — 一个服务商失败不会影响另外两个;只要还有服务商成功,路由就返回
|
|
53
|
+
`200`,全部失败才返回 `502`。部分接口失败时数字照常显示,但健康点变黄,悬停
|
|
54
|
+
列出失败的那几个接口。
|
|
55
|
+
- **设置快捷入口** — 组件标题栏的「设置」按钮直接打开侧边栏「插件」中的本插件
|
|
56
|
+
页面,并定位到下面的配置页。
|
|
57
|
+
- **插件设置页** — 侧边栏「插件」→ 本插件卡片:启用/禁用服务商、编辑凭据引用和
|
|
58
|
+
接口地址、选择 GLM 区域,并查看无网络请求的检测状态。保存后立即生效。每个服务商
|
|
59
|
+
卡片内嵌「实时用量」:显示各额度窗口的百分比、剩余重置时间与订阅外充值余额(与
|
|
60
|
+
侧边栏组件同一份数据);页面打开期间每 30 秒自动跟随刷新,并显示「更新于 HH:MM」
|
|
61
|
+
时间戳;「刷新用量」按钮强制读取;保存设置(例如换了 apiKeyEnv 凭据引用)后会以
|
|
62
|
+
`refresh=1` 立即重新读取,马上反映新凭据的用量与余额。
|
|
63
|
+
GLM 卡片底部还有一条**推广链接**(Z.ai「邀请好友得积分」),可点击打开或一键复制;
|
|
64
|
+
链接是写死的常量,不经过设置接口,也不会被保存的表单覆盖。
|
|
65
|
+
- **`/provider-usage` 聊天命令** — 在对话中打印所有启用服务商的用量文本。
|
|
66
|
+
- **时间条** — 额度条下方,灰色是窗口已流逝时间,蓝色是剩余时间,几何尺寸与参考
|
|
67
|
+
组件一致。
|
|
68
|
+
- **`x-opencode-session` 修复** — 运行时为 OpenCode GO 聊天请求注入真实的会话 id,
|
|
69
|
+
不修改 DSH 安装文件。
|
|
70
|
+
- **中英文 UI** — 通过 DSH locale 服务。
|
|
71
|
+
|
|
72
|
+
## 安装
|
|
73
|
+
|
|
74
|
+
从 npm 安装:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
dsh plugin --profile desktop add dsh-multi-provider-usage
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
开发时也可以直接从本地 checkout 安装:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
dsh plugin --profile desktop add /path/to/dsh-provider-usage
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
或安装到 web profile:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
dsh plugin --profile web add /path/to/dsh-provider-usage
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
包内声明了 `dsh.bundle.patch`,CLI 会自动把它合并进 profile 的 bundle 层。
|
|
93
|
+
客户端 bundle 属于 profile 的 client-modules 启动图,因此**安装后重启一次 DSH**;
|
|
94
|
+
运行中的宿主不会为新链接的包重建 `window.__DSH_BOOT__` 清单。
|
|
95
|
+
|
|
96
|
+
使用本地 `link:` 依赖时 pnpm 会提示 `@deepseek-ai/schemastery` /
|
|
97
|
+
`@deepseek-ai/dsh` 的 peer 依赖警告。这是预期现象:开发时 checkout 从自己的
|
|
98
|
+
`node_modules` 解析 schemastery;正式 npm 安装时 peer 由 DSH 运行时提供。
|
|
99
|
+
|
|
100
|
+
## 凭据
|
|
101
|
+
|
|
102
|
+
所有凭据都通过 DSH 凭据域解析(进程环境变量、`$DSH_HOME/.credentials.yaml`、
|
|
103
|
+
`.env` 层)。设置路由不会返回值,浏览器也永远拿不到。
|
|
104
|
+
|
|
105
|
+
| 服务商 | 默认引用 | 解析顺序 | 回退来源 |
|
|
106
|
+
|---|---|---|---|
|
|
107
|
+
| OpenCode GO | `OPENCODE_GO_API_KEY` | `opencodeGoApiKeyEnv` → `dsh-opencode-go` 当前账号引用(仅当该条目启用)→ `OPENCODE_GO_API_KEY` → `OPENCODE_API_KEY` | `GET {baseUrl}/v1/usage` |
|
|
108
|
+
| Command Code | `COMMANDCODE_API_KEY` | `commandCodeApiKeyEnv` → `COMMANDCODE_API_KEY` → CLI 登录文件 | `~/.commandcode/auth.json` 中的 `apiKey` |
|
|
109
|
+
| GLM Code Plan | `ZAI_API_KEY` | `glmApiKeyEnv` → `ZAI_CODING_CN_API_KEY` → `ZAI_API_KEY` → `ZHIPU_API_KEY` → `GLM_API_KEY` → `BIGMODEL_API_KEY` | — |
|
|
110
|
+
|
|
111
|
+
在「插件 → dsh-multi-provider-usage → 设置」或自动生成的「设置 → 插件 →
|
|
112
|
+
插件配置」里填写引用名(例如 `OPENCODE_GO_API_KEY`),真正的密钥保存在 DSH
|
|
113
|
+
凭据库中。
|
|
114
|
+
|
|
115
|
+
### OpenCode 控制台余额
|
|
116
|
+
|
|
117
|
+
GO 额度接口不包含账户预付费余额。余额来自
|
|
118
|
+
`GET https://opencode.ai/console/api/billing/status`,它需要 OpenCode **控制台**
|
|
119
|
+
OAuth 令牌(GO API Key 访问会返回 403)。宿主按以下顺序解析:
|
|
120
|
+
|
|
121
|
+
1. `opencodeConsoleApiKeyEnv`(默认 `OPENCODE_CONSOLE_TOKEN`),通过 DSH 凭据解析;
|
|
122
|
+
2. `~/.local/share/opencode/opencode.db` 的 `credential` 表(Node 支持
|
|
123
|
+
`node:sqlite` 时读取;当前 OpenCode 将 OAuth grant 存在这里并在运行时轮换);
|
|
124
|
+
3. `~/.local/share/opencode/auth.json`(设置了 `$XDG_DATA_HOME` 时用
|
|
125
|
+
`$XDG_DATA_HOME/opencode/auth.json`)中的 `opencode` provider——旧版本的位置。
|
|
126
|
+
|
|
127
|
+
数据库优先是刻意的:OpenCode 已把登录态迁到数据库,但经常把旧的 `auth.json`
|
|
128
|
+
留在磁盘上,里面的过期令牌会返回 401。宿主会依次尝试每个可用的 OAuth 登录(最多
|
|
129
|
+
四个),所以一份过期数据不会遮住仍然有效的登录。渠道版数据库(`opencode-beta.db`、
|
|
130
|
+
`opencode-dev.db` 等)和 `$OPENCODE_DB` 也会被发现。余额请求使用 grant 里的
|
|
131
|
+
`metadata.server`(自建控制台可用),缺省回落到公开域名;
|
|
132
|
+
`opencodeConsoleBaseUrl` 可覆盖。
|
|
133
|
+
|
|
134
|
+
OpenCode 的 **API Key** 登录(`oc_sk_…`,service-account 方式)不含控制台会话,
|
|
135
|
+
不会被发到只接受控制台令牌的 billing 接口。API Key 登录、缺少令牌或登录已过期/
|
|
136
|
+
被吊销时,余额位置显示可点击的「配置余额」而不是灰色横杠;点击打开本插件在
|
|
137
|
+
Plugins 面板中的设置页,悬停提示修复方式:运行 `opencode auth login` 并选择
|
|
138
|
+
**OpenCode Console account**,或把控制台令牌保存为 `OPENCODE_CONSOLE_TOKEN`。
|
|
139
|
+
|
|
140
|
+
余额未配置或控制台登录可修复时,插件设置页的 OpenCode GO 卡片不再给一句静态
|
|
141
|
+
提示,而是渲染分步**引导**:引言按当前状态指明修复方式(未配置 / API Key 登录 /
|
|
142
|
+
登录已过期)。第①步给出 `opencode auth login` 命令与「复制命令」按钮;第②步是
|
|
143
|
+
手动路径——从控制台网页复制令牌、保存为 `OPENCODE_CONSOLE_TOKEN` 凭据——带
|
|
144
|
+
「复制凭据名」按钮和打开 OpenCode 控制台网页的链接(由 `opencodeConsoleBaseUrl`
|
|
145
|
+
推导,以 `/console` 结尾);第③步提供「重新检测」按钮,重读登录状态并强制刷新
|
|
146
|
+
一次用量,新登录无需重启 DSH 即可显示余额(重新检测不会丢弃表单里未保存的修改)。
|
|
147
|
+
`/provider-usage` 命令对三种可修复状态都会给出同样的文字引导。
|
|
148
|
+
|
|
149
|
+
可用 `opencodeConsoleAuthFile` 覆盖 auth.json 路径(其目录也用于定位
|
|
150
|
+
`opencode.db`),`opencodeConsoleOrgId` 提供 `x-org-id`,
|
|
151
|
+
`opencodeConsoleEnabled: false` 可关闭余额读取。余额失败不会影响 GO 额度:
|
|
152
|
+
provider 仍为 `ok`,`balance` 为 `null` 并带 `meta.balanceError`(可由用户修复时
|
|
153
|
+
另带 `meta.balanceSetup`)。其它余额失败显示灰色「余额 —」,悬停给出原因。
|
|
154
|
+
|
|
155
|
+
### Command Code 余额
|
|
156
|
+
|
|
157
|
+
Command Code 的额度与余额共用同一个 API Key 和同一组 billing 接口,不会像
|
|
158
|
+
OpenCode 那样分叉:缺少 `COMMANDCODE_API_KEY` 且没有 `~/.commandcode/auth.json`
|
|
159
|
+
时整个服务商报错并显示 `no API key`,不会只丢余额。另有两个较窄的缺口,现在会
|
|
160
|
+
显式报告而不是留白:
|
|
161
|
+
|
|
162
|
+
- `/alpha/billing/credits` 失败时,由于所有窗口都来自这个请求,服务商本身也会
|
|
163
|
+
进入错误状态;错误消息现在会带上底层接口和状态码,而不是只显示
|
|
164
|
+
“no usable quota windows”,同时 `meta.balanceError` 让标题栏显示灰色
|
|
165
|
+
「余额 —」并携带原因;
|
|
166
|
+
- credits 请求成功但没有 `purchasedCredits` / `freeCredits` 时,`balance` 保持
|
|
167
|
+
`null` 并带 `meta.balanceMissing: true`,标题栏显示灰色「无充值额度」(接口
|
|
168
|
+
真的返回 0 时仍显示 `$0.00`)。
|
|
169
|
+
|
|
170
|
+
### OpenCode GO 集成与回退
|
|
171
|
+
|
|
172
|
+
`opencodeGoSource` 默认为 `opencode-go` 时,宿主依次探测:
|
|
173
|
+
|
|
174
|
+
1. 是否存在 `opencode-go` / `dsh-opencode-go` 的 loader 条目;
|
|
175
|
+
2. 条目未被禁用;
|
|
176
|
+
3. `ctx.get("opencodeGoUsage")` 提供 `read()`;
|
|
177
|
+
4. `read()` 返回合法的 `rolling` / `weekly` / `monthly`;
|
|
178
|
+
5. 从该条目的 `apiKeyEnv` + `accounts[]` 解析当前账号。
|
|
179
|
+
|
|
180
|
+
任一步失败都会改读内置接口,并在 `fallback` 中给出原因:`not-installed`、
|
|
181
|
+
`entry-disabled`、`service-unavailable`、`read-failed`、`invalid-response`。
|
|
182
|
+
组件显示「内置」徽标,悬停可看原因和消息。`opencodeGoSource: "builtin"` 会固定
|
|
183
|
+
走 HTTP 接口,完全不读取另一个插件。
|
|
184
|
+
|
|
185
|
+
## 套餐窗口
|
|
186
|
+
|
|
187
|
+
| 服务商 | 窗口 | 窗口长度 |
|
|
188
|
+
|---|---|---|
|
|
189
|
+
| OpenCode GO | `rolling`、`weekly`、`monthly` | 5 小时、7 天、约 30 天 |
|
|
190
|
+
| Command Code | `five-hour`、`weekly`、`monthly` | 5 小时、7 天、真实账单周期 |
|
|
191
|
+
| GLM Code Plan | `five-hour`、`weekly`、`mcp` | 5 小时、7 天、月度 |
|
|
192
|
+
|
|
193
|
+
百分比表示**已使用**比例,显示时限制在 `[0, 100]`。Command Code 的月用量为
|
|
194
|
+
`totalCost / (totalCost + monthlyCredits)`;购买额度和免费额度单独记录在
|
|
195
|
+
`meta.monthly`,不改变套餐条;两者之和就是可见的充值余额(`balance.extra`)。5 小时/周窗口来自
|
|
196
|
+
`windowLimits.fiveHour` / `weekly`(`used`、`cap`、`resetAt`、`exceeded`)。
|
|
197
|
+
|
|
198
|
+
GLM 账号没有 Coding Plan 时,接口会返回 HTTP 200 +
|
|
199
|
+
`{ "success": false, "msg": ... }`;适配器会显示该消息,组件把服务商标记为错误状态。
|
|
200
|
+
|
|
201
|
+
## 配置
|
|
202
|
+
|
|
203
|
+
Loader 直接读取导出的 `Config` schema;所有字段都是 `.volatile()`,设置页和自动
|
|
204
|
+
生成的表单都能热更新。
|
|
205
|
+
|
|
206
|
+
| 字段 | 默认值 | 说明 |
|
|
207
|
+
|---|---|---|
|
|
208
|
+
| `opencodeGoEnabled` | `true` | 显示 OpenCode GO |
|
|
209
|
+
| `opencodeGoSource` | `"opencode-go"` | `opencode-go` 或 `builtin` |
|
|
210
|
+
| `opencodeGoApiKeyEnv` | `"OPENCODE_GO_API_KEY"` | 凭据引用 |
|
|
211
|
+
| `opencodeGoBaseUrl` | `"https://opencode.ai/zen/go"` | 网关地址 |
|
|
212
|
+
| `opencodeConsoleEnabled` | `true` | 读取 OpenCode Zen 预付费余额 |
|
|
213
|
+
| `opencodeConsoleApiKeyEnv` | `"OPENCODE_CONSOLE_TOKEN"` | 控制台令牌引用 |
|
|
214
|
+
| `opencodeConsoleOrgId` | `""` | 可选 `x-org-id` |
|
|
215
|
+
| `opencodeConsoleAuthFile` | `""` | 可选 auth.json 路径;空则自动发现 |
|
|
216
|
+
| `opencodeConsoleDbFile` | `""` | 可选 opencode.db 路径;空则自动推导 |
|
|
217
|
+
| `opencodeConsoleBaseUrl` | `"https://opencode.ai"` | 控制台地址 |
|
|
218
|
+
| `commandCodeEnabled` | `true` | 显示 Command Code |
|
|
219
|
+
| `commandCodeApiKeyEnv` | `"COMMANDCODE_API_KEY"` | 凭据引用 |
|
|
220
|
+
| `commandCodeBaseUrl` | `"https://api.commandcode.ai"` | API 地址 |
|
|
221
|
+
| `commandCodeAuthFile` | `""` | 空 = `~/.commandcode/auth.json` |
|
|
222
|
+
| `glmEnabled` | `true` | 显示 GLM Code Plan |
|
|
223
|
+
| `glmApiKeyEnv` | `"ZAI_API_KEY"` | 凭据引用 |
|
|
224
|
+
| `glmBaseUrl` | `""` | 可选接口地址覆盖 |
|
|
225
|
+
| `glmRegion` | `"auto"` | `auto`、`zai`、`bigmodel`、`custom` |
|
|
226
|
+
| `cacheMs` | `30000` | 单个服务商的宿主缓存 TTL |
|
|
227
|
+
| `updateCheck` | `true` | npm 新版本检查(24 小时) |
|
|
228
|
+
| `autoUpdate` | `true` | 检查 GitHub Release;干净 checkout 快进,安装包用 Release tarball 原地替换 |
|
|
229
|
+
| `autoUpdateCheckHours` | `6` | 自动更新检查间隔(1–168 小时) |
|
|
230
|
+
| `injectSessionHeader` | `true` | OpenCode GO 会话头修复 |
|
|
231
|
+
| `providerOrder` | 三个 id 全集 | 组件中的显示顺序;在插件设置里拖动卡片调整 |
|
|
232
|
+
|
|
233
|
+
`glmRegion: "custom"` 必须提供 `glmBaseUrl`;`auto` 先探测
|
|
234
|
+
`https://api.z.ai`,再探测 `https://open.bigmodel.cn`。
|
|
235
|
+
|
|
236
|
+
## HTTP API
|
|
237
|
+
|
|
238
|
+
### `GET /provider-usage/usage`
|
|
239
|
+
|
|
240
|
+
`?refresh=1`(或 `?force=1`)绕过宿主缓存。
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"ok": true,
|
|
245
|
+
"enabled": ["opencode-go", "command-code", "glm"],
|
|
246
|
+
"providerOrder": ["opencode-go", "command-code", "glm"],
|
|
247
|
+
"providers": [
|
|
248
|
+
{
|
|
249
|
+
"id": "opencode-go",
|
|
250
|
+
"name": "OpenCode GO",
|
|
251
|
+
"short": "GO",
|
|
252
|
+
"status": "ok",
|
|
253
|
+
"account": { "ref": "OPENCODE_GO_API_KEY", "id": null, "name": "" },
|
|
254
|
+
"plan": null,
|
|
255
|
+
"source": "builtin",
|
|
256
|
+
"requested": "opencode-go",
|
|
257
|
+
"fallback": {
|
|
258
|
+
"from": "opencode-go",
|
|
259
|
+
"reason": "not-installed",
|
|
260
|
+
"message": "dsh-opencode-go is not installed, or its profile entry is inactive"
|
|
261
|
+
},
|
|
262
|
+
"balance": {
|
|
263
|
+
"amount": 5.01495352,
|
|
264
|
+
"currency": "USD",
|
|
265
|
+
"labelKey": "balance.zen",
|
|
266
|
+
"source": "opencode-db",
|
|
267
|
+
"details": { "billingMode": "prepaid", "mode": "pay-as-you-go" }
|
|
268
|
+
},
|
|
269
|
+
"windows": [
|
|
270
|
+
{
|
|
271
|
+
"key": "rolling",
|
|
272
|
+
"labelKey": "window.five-hour",
|
|
273
|
+
"hintKey": "window.five-hour.hint",
|
|
274
|
+
"percent": 0,
|
|
275
|
+
"status": "ok",
|
|
276
|
+
"resetsAt": "2026-11-05T13:50:46.363Z",
|
|
277
|
+
"windowMs": 18000000
|
|
278
|
+
}
|
|
279
|
+
],
|
|
280
|
+
"meta": {}
|
|
281
|
+
}
|
|
282
|
+
],
|
|
283
|
+
"update": { "current": "0.1.0", "available": false, "latest": null },
|
|
284
|
+
"sessionHeader": { "active": true, "count": 0, "diag": {} }
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
失败的服务商为 `"status": "error"`,带 `code`、`error` 和空 `windows`,其余服务商
|
|
289
|
+
照常返回。`providers: []` 表示没有启用任何服务商。`meta.balanceError` 表示被容忍
|
|
290
|
+
的余额失败(provider 仍为 `ok`);`meta.balanceSetup`(`no-credential`、`api-key`
|
|
291
|
+
或 `expired`)表示用户重新登录即可修复的余额状态;`meta.balanceMissing` 表示
|
|
292
|
+
Command Code 的 credits 响应没有购买/免费额度。`meta.errors` 列出 Command Code
|
|
293
|
+
的部分接口失败:数字照常显示,但健康点变黄,悬停可看到失败的接口。错误卡片仍
|
|
294
|
+
保留已经解析出的套餐信息。
|
|
295
|
+
|
|
296
|
+
### `GET /provider-usage/settings`
|
|
297
|
+
|
|
298
|
+
返回设置描述符(`namespace`、`revision`、`value`、`base`、`user`)以及无网络请求的
|
|
299
|
+
`detection` 检测报告:
|
|
300
|
+
|
|
301
|
+
```json
|
|
302
|
+
{
|
|
303
|
+
"ok": true,
|
|
304
|
+
"namespace": "dsh-multi-provider-usage",
|
|
305
|
+
"revision": 0,
|
|
306
|
+
"value": { "opencodeGoEnabled": true },
|
|
307
|
+
"detection": {
|
|
308
|
+
"providerOrder": ["opencode-go", "command-code", "glm"],
|
|
309
|
+
"enabled": ["opencode-go", "command-code", "glm"],
|
|
310
|
+
"providers": {
|
|
311
|
+
"opencode-go": { "configured": true, "entryFound": false, "fallback": { "...": "..." } },
|
|
312
|
+
"command-code": { "configured": true, "source": "auth-file" },
|
|
313
|
+
"glm": { "configured": true, "region": "auto" }
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
`503` 表示宿主没有 settings 服务,或条目没有 volatile 字段;设置页会给出修复提示。
|
|
320
|
+
|
|
321
|
+
### `POST /provider-usage/settings`
|
|
322
|
+
|
|
323
|
+
只接受上表中的字段,其他字段会被忽略。并发修改时 `expectedRevision` 会触发 `409`。
|
|
324
|
+
|
|
325
|
+
```json
|
|
326
|
+
{
|
|
327
|
+
"patch": { "commandCodeEnabled": false, "providerOrder": ["glm", "opencode-go", "command-code"] },
|
|
328
|
+
"expectedRevision": 0
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
跨源写入返回 `403`。usage 路由只读。
|
|
333
|
+
|
|
334
|
+
## 结构
|
|
335
|
+
|
|
336
|
+
| 端 | 文件 | 职责 |
|
|
337
|
+
|---|---|---|
|
|
338
|
+
| 宿主(Node) | `lib/index.js` | 配置 schema、路由、命令、设置/检测、缓存、会话头修复 |
|
|
339
|
+
| 宿主适配器 | `lib/providers.js` | 统一窗口结构 + 三个服务商适配器 |
|
|
340
|
+
| 控制台余额 | `lib/opencode-console.js` | OpenCode 控制台令牌发现 + billing status |
|
|
341
|
+
| 会话修复 | `lib/opencode-session.js` | `globalThis.fetch` 包装 + `llm/stream` ALS 上下文 |
|
|
342
|
+
| 浏览器 | `lib/client.js` | 手写 `window.__ModuleLoader__.load({ id, factory })` bundle:组件、设置页、i18n |
|
|
343
|
+
| bundle patch | `cordis.patch.yml` | 插入 profile 条目 |
|
|
344
|
+
|
|
345
|
+
浏览器 bundle 由 DSH 官方 client-modules 扫描通过 `dsh.client` +
|
|
346
|
+
`exports["./client"]` 组合,并注册到 `sidebar.footer.action` 和
|
|
347
|
+
`plugins.bundle.config`,与参考插件一致。
|
|
348
|
+
|
|
349
|
+
会话修复只包装一次 `globalThis.fetch`;仅当请求 URL 以当前 `llm/stream` 调用的网关
|
|
350
|
+
base 开头时才添加 `x-opencode-session`。base 来自
|
|
351
|
+
`llm-pi-ai.providers.<route>.baseURL`,缺失时回退到 `opencodeGoBaseUrl`。
|
|
352
|
+
|
|
353
|
+
## 兼容性
|
|
354
|
+
|
|
355
|
+
- DSH `0.1.7` 及以上,包括 `0.2.0` 系列;已在 `0.2.1-rc.5` 验证。
|
|
356
|
+
- `@deepseek-ai/schemastery` `^3.18.4`(volatile 字段 / 设置页)。
|
|
357
|
+
- Node.js ≥ 18(全局 `fetch`、`AbortSignal.timeout`)。
|
|
358
|
+
- `dsh-opencode-go` 可选;未安装属于正常回退。
|
|
359
|
+
- 设置 `COMMANDCODE_API_KEY` 时,Command Code CLI 登录文件可选。
|
|
360
|
+
- 宿主不提供 `plugins.bundle.config` 时只会失去设置页;侧边栏组件和
|
|
361
|
+
`/provider-usage` 命令仍可用。此时可在 profile patch 或自动生成表单中改配置。
|
|
362
|
+
|
|
363
|
+
## 开发
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
npm install
|
|
367
|
+
npm test
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
测试是封闭的:伪造 `globalThis.fetch` + stub Cordis 上下文,不访问网络、不使用真实
|
|
371
|
+
密钥。覆盖 schema、三个适配器、OpenCode GO 服务集成/回退、聚合与故障隔离、缓存与
|
|
372
|
+
强制刷新、设置冲突/白名单、客户端 bundle 契约、充值余额发现(凭据 / 本地
|
|
373
|
+
auth.json)与失败隔离、会话头注入、余额变化动画;共 98 个测试。
|
|
374
|
+
|
|
375
|
+
## 许可证
|
|
376
|
+
|
|
377
|
+
MIT。
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# dsh-multi-provider-usage — profile bundle patch.
|
|
2
|
+
#
|
|
3
|
+
# `dsh plugin --profile <name> add dsh-multi-provider-usage` installs this package
|
|
4
|
+
# and, because package.json declares `dsh.bundle.patch`, reconciles it into the
|
|
5
|
+
# profile's `dsh.profile.bundles` layer stack automatically. This file is that
|
|
6
|
+
# bundle layer: it inserts the plugin entry with schema defaults; user
|
|
7
|
+
# overrides live in the entry's config (Settings → Plugins → Plugin
|
|
8
|
+
# configuration, or the bundle's own settings page).
|
|
9
|
+
#
|
|
10
|
+
# `name` MUST be the package's resolvable module specifier: the cordis loader
|
|
11
|
+
# imports exactly this string from the profile directory, where the package
|
|
12
|
+
# exists.
|
|
13
|
+
- insert:
|
|
14
|
+
- id: dsh-multi-provider-usage
|
|
15
|
+
name: "dsh-multi-provider-usage"
|
package/docs/widget.png
ADDED
|
Binary file
|