dsh-model-usage 0.0.0-stage → 0.8.0
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 +33 -0
- package/LICENSE +21 -0
- package/README.md +228 -2
- package/cordis.patch.yml +11 -0
- package/icon.svg +7 -0
- package/lib/client.js +1410 -0
- package/lib/index.js +1083 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +70 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
First release prepared for npm (`dsh plugin --profile <profile> add dsh-model-usage`).
|
|
6
|
+
|
|
7
|
+
- Host half: only `webServer` is a hard dependency. `connection` (browser trust fence),
|
|
8
|
+
`credentials` (key lookup), `llm` / `settings` / `sessions` / `sessionProjections` /
|
|
9
|
+
`sessionController` / `agentDefaultModel` / `deepseekAccount` are read through `ctx.get()` per use,
|
|
10
|
+
so the plugin mounts in more compositions and picks up a service that activates later.
|
|
11
|
+
- Browser half: `locale` is read through `ctx.get()` too; without it the panel falls back to the
|
|
12
|
+
Chinese source copy instead of not rendering.
|
|
13
|
+
- Publish metadata and docs: `engines.dsh` / `engines.node`, repository, homepage, bugs, keywords,
|
|
14
|
+
a bilingual README, and `scripts/check.mjs` wired to `prepublishOnly`.
|
|
15
|
+
- `private` removed so the package can be published.
|
|
16
|
+
|
|
17
|
+
## 0.7.0
|
|
18
|
+
|
|
19
|
+
- The browser half no longer imports any Harness Client package: the button and the four dialogs are
|
|
20
|
+
this plugin's own controls, styled only with the theme tokens the running build lists.
|
|
21
|
+
- All interface copy moved into the Client locale service (namespace `dsh-model-usage`, zh + en);
|
|
22
|
+
the panel follows the interface language live.
|
|
23
|
+
- The stylesheet renders as part of the cell (no orphan `<style>` in `document.head`).
|
|
24
|
+
- Host routes apply the composition's browser trust fence and answer 401/403 themselves; the browser
|
|
25
|
+
half addresses them with document-relative URLs.
|
|
26
|
+
- Display metadata: `locale/zh.json`, `locale/en.json`, `icon.svg`, plus `dsh.manifestVersion: 1`
|
|
27
|
+
and `engines.dsh`.
|
|
28
|
+
- `modelSelection` is read through its wire view (`{ lastUsed, next }`).
|
|
29
|
+
|
|
30
|
+
## 0.6.0
|
|
31
|
+
|
|
32
|
+
- Usage for the current conversation's model, manual target override, background auto-refresh,
|
|
33
|
+
read-only provider directory.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 liuchaoxu
|
|
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,229 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-model-usage(用量)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## English
|
|
4
|
+
|
|
5
|
+
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin. It adds a **用量 / Usage**
|
|
6
|
+
entry to the right end of the session header (`conversation.session.header.utilities`) showing the
|
|
7
|
+
provider-account usage behind the model the current conversation runs on — read with that provider's
|
|
8
|
+
own credential reference, never with another provider's key.
|
|
9
|
+
|
|
10
|
+
- **Follows the conversation**: the model comes from the session's `modelSelection` projection, the
|
|
11
|
+
key from that provider's own credential reference, the numbers from that provider's usage API.
|
|
12
|
+
- **Manual target**: pick any routable provider model in the panel without changing what the
|
|
13
|
+
conversation runs on.
|
|
14
|
+
- **Warm in the background**: refreshes on an interval while the panel is closed.
|
|
15
|
+
- **Read-only directory**: lists the deployment's provider routes, their usage API kind, credential
|
|
16
|
+
reference name, and whether that reference is configured — never a value.
|
|
17
|
+
|
|
18
|
+
Adapters: Command Code, DeepSeek (official balance and signed-in account wallet), OpenCode Go,
|
|
19
|
+
OpenRouter, Moonshot / Kimi, SiliconFlow, and the cc-switch New API convention for other
|
|
20
|
+
OpenAI-compatible routes. Everything else reports "usage query not supported" instead of guessing.
|
|
21
|
+
|
|
22
|
+
### Install
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
# npm (this package is published as a Harness bundle)
|
|
26
|
+
dsh plugin --profile <profile> add dsh-model-usage
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or, from a harness agent session, ask the plugin manager to install the bundle by name
|
|
30
|
+
(`install_bundle` with target `dsh-model-usage`). Either path installs the package into the profile,
|
|
31
|
+
mounts its `cordis.patch.yml` row, and enables the bundle (installation enables a new bundle by
|
|
32
|
+
default). With the profile's HMR enabled the change applies immediately; otherwise restart the host,
|
|
33
|
+
and hard-refresh the page for the browser half (it is served by `dsh-client-modules`).
|
|
34
|
+
|
|
35
|
+
Requirements: Harness `>=0.2.1-rc.2` (declared as `engines.dsh`) and its Web surface. No build step,
|
|
36
|
+
no runtime dependencies: the host half is Node builtins only, the browser half requires nothing but
|
|
37
|
+
the frozen `react` module. Nothing is uploaded anywhere; the host process calls the provider API with
|
|
38
|
+
the key it already holds and returns only normalized numbers plus the credential *reference name*.
|
|
39
|
+
|
|
40
|
+
License: MIT. This is an independent community plugin, not affiliated with or endorsed by DeepSeek.
|
|
41
|
+
|
|
42
|
+
## 中文
|
|
43
|
+
|
|
44
|
+
在会话页面头部最右侧的 utilities 区(`conversation.session.header.utilities`)加一个「用量」入口;
|
|
45
|
+
点开弹窗即可查看**当前对话所用模型**对应供应商账户的用量,也可以在面板里**手动切换**到别的
|
|
46
|
+
供应商模型查询。
|
|
47
|
+
|
|
48
|
+
插件做四件事:
|
|
49
|
+
|
|
50
|
+
- **跟随对话查询**:模型取自会话的 `modelSelection` 投影(与模型选择器同一份事实),
|
|
51
|
+
密钥取自该供应商自己的凭据引用,用量来自该供应商的用量接口。
|
|
52
|
+
- **支持手动切换查询对象**:可查任意可路由的供应商模型,且不改变当前对话使用的模型。
|
|
53
|
+
- **后台自动刷新**:按间隔在后台保持数字新鲜,弹窗关着也照常刷新。
|
|
54
|
+
- **只读说明目录**:列出本部署声明的供应商路由、各自的用量接口类型、密钥引用名与是否已配置(永不返回值)。
|
|
55
|
+
|
|
56
|
+
## 原理
|
|
57
|
+
|
|
58
|
+
- **node 半**(`lib/index.js`):通过 `ctx.webServer.register()` 注册 loopback Web 路由:
|
|
59
|
+
- `POST /model-usage/balance`:按给定(或当前对话)的模型查询用量;
|
|
60
|
+
- `GET /model-usage/providers`:只读列出本部署声明的供应商路由与密钥是否就绪;
|
|
61
|
+
- `GET /model-usage/models`:可路由模型目录 + 每个供应商对应的用量接口类型(手动切换用)。
|
|
62
|
+
三条路由都会先向 `connection` 服务要一次浏览器信任裁决(Host/Origin 栅栏),被拒即 401/403;
|
|
63
|
+
密钥只在本机 host 进程内使用,浏览器只拿到归一化数据 + 凭据**引用名**(永不返回值)。
|
|
64
|
+
- **浏览器半**(`lib/client.js`):注册 `conversation.session.header.utilities` slot,
|
|
65
|
+
从会话的 `modelSelection` 投影读出当前模型(线格式 `{ lastUsed, next }`,`next` 已经含了
|
|
66
|
+
尚未使用的这次选择),随请求发给 host;在后台按间隔刷新用量(弹窗关闭也生效),
|
|
67
|
+
点开弹窗展示状态与用量。控件(按钮 / 弹窗)是本插件自写的,样式与文案分别来自主题 token
|
|
68
|
+
与 Client locale 服务。
|
|
69
|
+
|
|
70
|
+
### 模型与密钥是怎么确定的
|
|
71
|
+
|
|
72
|
+
1. 浏览器读会话投影 `modelSelection` 的 `next ?? lastUsed`(与模型选择器同一份事实),
|
|
73
|
+
POST `{ provider, model, reasoningEffort, sessionId }` 给 host。
|
|
74
|
+
payload 里没有 provider/model 时,host 依次回退到「本进程的会话投影」→「部署默认模型」
|
|
75
|
+
(`agentDefaultModel.currentSelection()`)。
|
|
76
|
+
2. host 用 `llm.listConfigurableProviders()` 找到该 provider 的配置地址
|
|
77
|
+
(`settingsNs` + `settingsPath`),再用 `settings.describe()` 读实时配置,得到
|
|
78
|
+
`apiKeyEnv`(凭据引用)、`baseURL`、`api`、自定义 headers。
|
|
79
|
+
3. 用 `ctx.credentials.resolve(apiKeyEnv)` 取到**当前对话正在用的那把 key**:
|
|
80
|
+
该引用没配置时回退到同名环境变量;Command Code 再回退 `~/.commandcode/auth.json`。
|
|
81
|
+
解析是逐次调用进行的,在 设置 → 模型 里新填的 key 下一次查询即可用,不需要重启。
|
|
82
|
+
4. 按 provider / baseURL 选择对应的用量接口(见下表)。
|
|
83
|
+
|
|
84
|
+
provider 没声明 `apiKeyEnv` 时按约定推导引用名 `${PROVIDER}_API_KEY`
|
|
85
|
+
(如 `commandcode` → `COMMANDCODE_API_KEY`,与 设置 → 模型 里存 key 的名字一致);
|
|
86
|
+
`deepseek-official` 固定用 `DEEPSEEK_API_KEY`。
|
|
87
|
+
|
|
88
|
+
### 手动切换查询对象
|
|
89
|
+
|
|
90
|
+
面板顶部有一行「查询对象」,显示这次查询用的是谁:
|
|
91
|
+
|
|
92
|
+
- 默认 `自动 · 供应商 / 模型`,跟随当前对话的模型选择(对话里换模型,插件跟着换)。
|
|
93
|
+
- 点它打开「选择模型」:可选 `自动(跟随当前对话)`,或**任意可路由的供应商模型**
|
|
94
|
+
(来自 `sessionController.modelCatalog()`,每条路由标注它对应的用量接口类型;不支持的会写明
|
|
95
|
+
`不支持用量查询`)。
|
|
96
|
+
- 选中后只改变**插件查询的对象**,不会切换当前对话使用的模型;密钥也随之变成那个供应商自己的
|
|
97
|
+
凭据引用。选择存在浏览器 localStorage(`dsh-model-usage:model`),弹窗里「改回自动」可恢复。
|
|
98
|
+
- 注意:用量是**账户级**的,同一把 key 下的模型共享同一份额度,所以切换模型实际是在切换
|
|
99
|
+
「用哪个供应商的 key 去查哪份额度」;卡片下方「模型 / 密钥」两行会如实显示这次用的是谁。
|
|
100
|
+
|
|
101
|
+
### 用量接口
|
|
102
|
+
|
|
103
|
+
| provider / baseURL | 用量来源 |
|
|
104
|
+
| --- | --- |
|
|
105
|
+
| `commandcode`(或 baseURL 落在 `*.commandcode.ai`) | Command Code 私有 API:`GET /alpha/whoami?limits=1`、`/alpha/billing/credits`、`/alpha/billing/subscriptions`、`/alpha/usage/summary?since=`,即官方 CLI `/usage` 的同一组端点;显示套餐、5 小时 / 7 天窗口用量条、信用余额、请求数 |
|
|
106
|
+
| `deepseek-official`、`deepseek`(或 baseURL 落在 `*.deepseek.com`) | `GET https://api.deepseek.com/user/balance`,按币种显示余额 |
|
|
107
|
+
| `deepseek-account` | `ctx.deepseekAccount.getBalance()`:读已登录 DeepSeek 账户的钱包余额(不涉及 API Key) |
|
|
108
|
+
| `opencode-go`(或 baseURL 落在 `opencode.ai/zen/go`) | `GET {origin}/zen/go/v1/usage`(OpenCode Go / Go Plus 订阅额度:5 小时 / 周 / 月,按模型各自的月额度计)。**该端点未公开文档化**,字段按常见写法归一化,识别不了的会原样显示在「原始返回」里 |
|
|
109
|
+
| `openrouter`(或 baseURL 落在 `*.openrouter.ai`) | `GET /api/v1/key`(已用 / 额度 / 剩余);key 没有独立额度时再查 `GET /api/v1/credits` 补充账户总额度与已用 |
|
|
110
|
+
| `moonshotai`、`moonshotai-cn`、`kimi-coding`(或 baseURL 落在 `*.moonshot.cn` / `*.moonshot.ai`) | `GET /v1/users/me/balance`(可用余额 / 现金余额 / 代金券) |
|
|
111
|
+
| `siliconflow`(或 baseURL 落在 `*.siliconflow.cn` / `*.siliconflow.com`) | `GET /v1/user/info`(总余额 / 充值余额 / 赠送余额) |
|
|
112
|
+
| 其它已配置 `baseURL` 的 OpenAI 兼容路由 | 尽力而为:按 cc-switch 的 New API 约定查 `GET {origin}/api/user/self`(`Authorization: Bearer <key>`、`User-Agent: cc-switch/1.0`),按 `quota / 500000` 归一化为 USD |
|
|
113
|
+
|
|
114
|
+
**OpenCode Zen(按量付费余额)没有用量接口**:`/zen/v1/usage`、`/me`、`/credits` 全是 404,官方只能在 console 网页看,
|
|
115
|
+
所以 `opencode`(baseURL `https://opencode.ai/zen`)在面板里会显示「不支持用量查询」——同一个域名下的 `/zen/go` 才走 Go 适配器。
|
|
116
|
+
|
|
117
|
+
既没有 `baseURL`、也不是已知供应商的路由会明确报错(“无法查询用量”),不会去猜接口。
|
|
118
|
+
|
|
119
|
+
新增一个适配器大约 20 行:在 `kindOf()` 里按 host / provider 认领,写一个 `queryXxx()` 归一到 `{ rows }` 或 `{ windows, models }`,
|
|
120
|
+
客户端会自动用通用卡片渲染(`rows` 出标签值行,`windows` 出用量条,`raw` 收在「原始返回」按钮里)。
|
|
121
|
+
|
|
122
|
+
### 刷新与状态
|
|
123
|
+
|
|
124
|
+
刷新是后台行为,不是点击行为:这个 cell 随会话视图挂载,所以它在**挂载时、切换模型时**各查询一次,
|
|
125
|
+
之后只要「自动刷新」是开着的就按间隔在后台自己刷新 —— 弹窗关着也照样刷新,打开时直接就是最近一次的结果。
|
|
126
|
+
|
|
127
|
+
- **状态行**(弹窗顶部)显示本次刷新的新鲜度:`刷新时间:刚刚` / `刷新时间:12 分钟前`,
|
|
128
|
+
查询进行中显示 `刷新中… · 当前显示 3 分钟前数据`,从未查询过显示 `尚未刷新`;
|
|
129
|
+
数据超过刷新间隔时会在状态行补一句提示。
|
|
130
|
+
- **自动刷新开关**:状态行右侧的 `自动刷新:开/关` chip,点一下即切换(设置弹窗里也有「开启/关闭」)。
|
|
131
|
+
关闭后不再有后台定时刷新,打开弹窗且数据过期时才查询。
|
|
132
|
+
- **刷新间隔**:`刷新设置` 里可选 1 / 5 / 15 / 30 / 60 分钟,也可以直接填 1–1440 之间的分钟数;
|
|
133
|
+
默认开启自动刷新、间隔 5 分钟。策略存在浏览器 localStorage(`dsh-model-usage:refresh`)。
|
|
134
|
+
- **上次刷新超过间隔时**:打开弹窗不会清空内容 —— 先显示上次查询到的用量,并标记 `刷新中…`,
|
|
135
|
+
用量接口返回后再替换内容,状态变为 `刷新时间:刚刚`。
|
|
136
|
+
- 数据在间隔内时打开弹窗**不会**发请求(直接用缓存),要强制刷新就点卡片里的「刷新」。
|
|
137
|
+
- 刷新失败(例如接口 5xx / 网络不通)时保留上次数据,并在卡片下方追加 `上次刷新失败:…`;
|
|
138
|
+
从未成功过才显示整屏错误 + 「重试」。标题按钮在后台刷新时带一个呼吸小圆点,
|
|
139
|
+
鼠标悬停显示刷新策略。
|
|
140
|
+
- host 侧每次用量接口调用有 30 秒超时,浏览器侧另有一道 45 秒的外层兜底,
|
|
141
|
+
避免一次卡住的请求把后续自动刷新一直挡在门外。
|
|
142
|
+
|
|
143
|
+
### 弹窗内容
|
|
144
|
+
|
|
145
|
+
- 顶部状态行 + 自动刷新 chip + `刷新设置`。
|
|
146
|
+
- 卡片:按上面的接口类型渲染(窗口用量条 / 余额 / 钱包)。
|
|
147
|
+
- 卡片下方「模型 · 密钥 · 用量页」:本次查询用的 provider/model(含推理档位)与**凭据引用名 + 来源**
|
|
148
|
+
(例如 `COMMANDCODE_API_KEY · 凭据 COMMANDCODE_API_KEY(store)`),确认用的是当前对话那把 key。
|
|
149
|
+
- 底部「说明」:列出本部署声明的供应商路由 —— 用量接口类型、密钥引用名、是否已配置、接口地址。
|
|
150
|
+
默认只列出**有用量接口或已配置密钥**的路由(有些部署自带的目录有数十个路由),
|
|
151
|
+
其余收在「显示其余 N 个未配置路由」按钮后面;每个弹窗都自带上限高度 + 内部滚动
|
|
152
|
+
(Modal 原语把高度留给调用方,不设上限时内容会顶出屏幕)。
|
|
153
|
+
|
|
154
|
+
### 与当前 Harness 的适配
|
|
155
|
+
|
|
156
|
+
- manifest:`dsh.bundle.patch`、`dsh.client`(`platform: web`)、`dsh.manifestVersion: 1`,
|
|
157
|
+
以及 `engines.dsh: ">=0.2.1-rc.2"`(本插件逐项核对过的版本,只挡更旧的宿主)。
|
|
158
|
+
- 展示元数据:`locale/zh.json` + `locale/en.json`(`meta.title` / `meta.description`)与
|
|
159
|
+
`icon.svg` 都已从 `exports` / `files` 导出,插件列表与 bundle 详情直接读取。
|
|
160
|
+
- 浏览器半只 require `react`(loader 的冻结模块表),不 require 任何 Harness Client 包;
|
|
161
|
+
数据面走本插件自己的 `webServer` 路由 + 同源 `fetch`(官方浏览器插件同款做法)。
|
|
162
|
+
- host 半只用 Node 原生模块(`node:fs` / `node:os`);只有 `webServer` 是硬依赖,
|
|
163
|
+
`connection`(信任栅栏)、`credentials`(取键)、`llm` / `settings` / `sessions` /
|
|
164
|
+
`sessionProjections` / `sessionController` / `agentDefaultModel` / `deepseekAccount`
|
|
165
|
+
都在每次使用时通过 `ctx.get()` 读取 —— 少挂服务时插件照常挂载并在面板里说明缺什么,
|
|
166
|
+
后激活的服务下一次查询就能用上。
|
|
167
|
+
- 浏览器半只有 `slots` 是硬依赖,`locale` 同样按需读取:没有 locale 服务时面板降级显示中文原文,
|
|
168
|
+
而不是整格消失。
|
|
169
|
+
|
|
170
|
+
## 安装
|
|
171
|
+
|
|
172
|
+
包已发布为 npm bundle,安装入口是"把 bundle 装进 profile":
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
# CLI(推荐)
|
|
176
|
+
dsh plugin --profile <profile> add dsh-model-usage
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
或者在 harness 的 agent 会话里让插件管理器装:`install_bundle`,target 传 `dsh-model-usage`
|
|
180
|
+
(本机开发时传本目录的绝对路径)。两条路都会把包装进 profile、把 `dsh.bundle.patch` 指向的
|
|
181
|
+
row(id `model-usage`)挂进 patch 层并激活——**不要**手写 profile 的 `cordis.patch.yml`,
|
|
182
|
+
也不要往 `$DSH_HOME/profiles/<profile>/node_modules` 手工复制。
|
|
183
|
+
|
|
184
|
+
安装后:
|
|
185
|
+
|
|
186
|
+
- host 半改动/升级包后需要重启宿主(`dsh web` 或桌面版);
|
|
187
|
+
- 浏览器半(`lib/client.js`)改动后硬刷新页面即可(开发时 `pnpm run dev:web` 会推送重建)。
|
|
188
|
+
|
|
189
|
+
## 发布(维护者)
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
npm run verify # check + smoke;prepublishOnly 会自动跑同一组检查
|
|
193
|
+
npm publish # 公开包,无需 --access
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
`scripts/check.mjs` 会在发布前拦住会导致"装完不可用"的问题:缺 `dsh.bundle.patch`、
|
|
197
|
+
`private: true`、exports/files 漏掉 locale 或图标、`lib/client.js` 的 loader id 与包名不一致、
|
|
198
|
+
require 了非基线模块、往 `document.head`/`document.body` 写东西、字典缺键或中英不对称、
|
|
199
|
+
host 半 import 了 node_modules 依赖、路由没用 `ctx.effect` 注册等。
|
|
200
|
+
`scripts/smoke.mjs` 则在纯 Node 里把 host 半挂到桩 ctx 上跑一遍:三条路由的 kind/path、
|
|
201
|
+
无会话服务时的错误信封、以及信任栅栏的 403。两个脚本都不随包发布。
|
|
202
|
+
|
|
203
|
+
版本约定:面向用户的可见行为变化 → minor;修 bug → patch。`engines.dsh` 只挡比"已核对版本"更旧的宿主。
|
|
204
|
+
|
|
205
|
+
账号侧前置条件:如果 npm 账号开了 2FA,用普通 `.npmrc` 里的令牌发布会返回
|
|
206
|
+
`E403 ... Two-factor authentication or granular access token with bypass 2fa enabled is required`。
|
|
207
|
+
两条解法:`npm publish --otp=<验证码>`(TOTP 账号),或在 npm 网页上建一个
|
|
208
|
+
**Granular Access Token**(Permissions = Read and write,Packages = All packages,
|
|
209
|
+
勾选 allow bypass 2FA),再 `npm config set //registry.npmjs.org/:_authToken <token>`。
|
|
210
|
+
令牌只写进用户级 `~/.npmrc`,不要进仓库。
|
|
211
|
+
|
|
212
|
+
## 说明
|
|
213
|
+
|
|
214
|
+
- 浏览器半**只从 loader 的模块表取 `react`**,不 require 任何 Harness Client 包:
|
|
215
|
+
面板里的按钮与弹窗是本插件自己的控件,只用当前主题列出的 `--dsw-alias-*` token 上色
|
|
216
|
+
(唯一例外是弹窗遮罩,主题没有对应的 scrim token)。
|
|
217
|
+
- 浏览器半的文案全部走 Client locale 服务(`ctx.locale`,命名空间 `dsh-model-usage`,
|
|
218
|
+
中英双语),跟随界面语言切换;host 返回的**接口诊断信息**(供应商报错原文)按原样显示。
|
|
219
|
+
- 样式表随 cell 渲染(`<style>` 是 cell 输出的一部分),slot 条目卸载时一起消失,
|
|
220
|
+
不往 `document.head` 之外留东西。
|
|
221
|
+
- 三条 host 路由在应答前都会先问 composition 的 connection 服务要一次浏览器信任裁决
|
|
222
|
+
(本机 Host/Origin 栅栏),与官方浏览器插件同款;被拒时直接回 401/403。
|
|
223
|
+
- 浏览器半用**文档相对路径**(`model-usage/...`)访问这三条路由,因此 GUI 挂在子目录下也能用。
|
|
224
|
+
- 用量只能查到**供应商账户级**的数据(余额 / 套餐窗口 / 请求数);同一把 key 下的模型共享这些额度。
|
|
225
|
+
- Command Code 模式的数字与官方 CLI 的 `/usage` 一致(同一组私有端点)。
|
|
226
|
+
- 密钥只在本机 host 进程内使用,不写入日志、不返回给浏览器。
|
|
227
|
+
- 本插件以 [MIT 许可](LICENSE)发布;DeepSeek Harness 本身同为 MIT,二者许可一致、可双向复用代码。
|
|
228
|
+
本项目是独立社区插件,与深度求索公司无隶属或背书关系。
|
|
229
|
+
- 浏览器半是**手写的闭包工厂 bundle**,改动后硬刷新浏览器生效;host 半改动需重启 `dsh web`。
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# dsh-model-usage bundle patch: mounts the package's node half as a host entry.
|
|
2
|
+
# The node half hosts the loopback-only /model-usage Web routes that query the
|
|
3
|
+
# usage of the model the current conversation runs on (with that provider's own
|
|
4
|
+
# credential reference); the browser half (discovered by client-modules from
|
|
5
|
+
# this row's dsh.client declaration) renders the 用量 button and panel.
|
|
6
|
+
# No Config schema is declared, so an empty config keeps the row easy to extend
|
|
7
|
+
# from a user patch layer later.
|
|
8
|
+
- insert:
|
|
9
|
+
- id: model-usage
|
|
10
|
+
name: 'dsh-model-usage'
|
|
11
|
+
config: {}
|
package/icon.svg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" role="img" aria-label="Usage">
|
|
2
|
+
<rect x="1" y="1" width="30" height="30" rx="8" fill="#1f6feb"/>
|
|
3
|
+
<path d="M7.5 21.5a8.5 8.5 0 0 1 17 0" fill="none" stroke="#ffffff" stroke-width="2.4" stroke-linecap="round"/>
|
|
4
|
+
<path d="M16 21.5 21.4 16.4" fill="none" stroke="#ffffff" stroke-width="2.4" stroke-linecap="round"/>
|
|
5
|
+
<circle cx="16" cy="21.5" r="2" fill="#ffffff"/>
|
|
6
|
+
<path d="M9.5 26h13" fill="none" stroke="#ffffff" stroke-width="2.2" stroke-linecap="round" opacity="0.7"/>
|
|
7
|
+
</svg>
|