@sligqoer/dsh-usage-stats 0.1.2 → 0.2.1

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +135 -1
  2. package/NOTICE +39 -0
  3. package/README.en.md +187 -0
  4. package/README.md +93 -224
  5. package/lib/bridge.js +33 -0
  6. package/lib/client.js +2587 -1159
  7. package/lib/index.js +420 -150
  8. package/lib/lm-fingerprint-engine.js +166 -0
  9. package/lib/lm-fingerprint-source.js +134 -0
  10. package/lib/lm-fingerprint-worker.js +31 -0
  11. package/lib/model-detection-history.js +86 -0
  12. package/lib/model-detection.js +255 -0
  13. package/lib/provider-quotas.js +26 -5
  14. package/lib/quota-controls.js +112 -30
  15. package/lib/supplemental-usage.js +77 -0
  16. package/lib/usage-preferences.js +51 -0
  17. package/locale/en.json +6 -0
  18. package/locale/ja.json +6 -0
  19. package/locale/zh.json +6 -0
  20. package/package.json +28 -18
  21. package/screenshots/controls.png +0 -0
  22. package/screenshots/detection.png +0 -0
  23. package/screenshots/quotas.png +0 -0
  24. package/screenshots/usage.png +0 -0
  25. package/third_party/brand-icons/CHANNEL-ICONS-LICENSE +21 -0
  26. package/third_party/brand-icons/LICENSE +59 -0
  27. package/third_party/brand-icons/NOTICE.txt +5 -0
  28. package/third_party/brand-icons/REACT-ICONS-LICENSE +104 -0
  29. package/third_party/brand-icons/channel-icons/LICENSE +21 -0
  30. package/third_party/brand-icons/channel-icons/UPSTREAM.json +6 -0
  31. package/third_party/brand-icons/lobe-icons/LICENSE +21 -0
  32. package/third_party/brand-icons/lobe-icons/UPSTREAM.json +16 -0
  33. package/third_party/brand-icons/react-icons/LICENSE +13 -0
  34. package/third_party/brand-icons/react-icons/UPSTREAM.json +6 -0
  35. package/third_party/lm-fingerprint/LICENSE +21 -0
  36. package/third_party/lm-fingerprint/UPSTREAM.json +32 -0
  37. package/third_party/lm-fingerprint/core/challenge-browser.mjs +210 -0
  38. package/third_party/lm-fingerprint/core/detector-codec.mjs +20 -0
  39. package/third_party/lm-fingerprint/core/fingerprint-core.mjs +121 -0
  40. package/third_party/lm-fingerprint/core/positional.mjs +64 -0
  41. package/third_party/lm-fingerprint/core/shared-detector.mjs +132 -0
  42. package/third_party/lm-fingerprint/data/shared_detector.bin +0 -0
  43. package/third_party/lm-fingerprint/data/unified_bank.json +826820 -0
  44. package/README.zh-CN.md +0 -318
package/README.md CHANGED
@@ -1,318 +1,187 @@
1
1
  <p align="center">
2
- <img src="screenshots/icon.svg" alt="dsh-usage-stats" width="80" height="80">
2
+ <img src="screenshots/icon.svg" alt="DSH 用量统计" width="80" height="80">
3
3
  </p>
4
4
 
5
5
  <h1 align="center">dsh-usage-stats</h1>
6
6
 
7
7
  <p align="center">
8
- <strong>See your token usage, balances, and quotas inside DSH.</strong><br>
9
- A local usage dashboard for <a href="https://github.com/deepseek-ai/deepseek-harness">DeepSeek Harness Desktop</a>.
8
+ <strong>在 DSH 里,看清 Token 用量、账户余额与供应商配额。</strong><br>
9
+ 为 <a href="https://github.com/deepseek-ai/deepseek-harness">DeepSeek Harness 桌面端</a>打造的本地用量面板。
10
10
  </p>
11
11
 
12
12
  <p align="center">
13
- <a href="#installation"><img src="https://img.shields.io/badge/DSH-Desktop-2563eb?style=flat-square" alt="DSH Desktop"></a>
14
- <a href="https://github.com/Jockjrop/dsh-usage-stats/releases/latest"><img src="https://img.shields.io/github/v/release/Jockjrop/dsh-usage-stats?style=flat-square&amp;color=64748b" alt="Latest release"></a>
15
- <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-22c55e?style=flat-square" alt="Apache 2.0 license"></a>
13
+ <a href="#安装"><img src="https://img.shields.io/badge/DSH-Desktop-2563eb?style=flat-square" alt="DSH 桌面端"></a>
14
+ <a href="https://github.com/Jockjrop/dsh-usage-stats/releases/latest"><img src="https://img.shields.io/badge/release-v0.2.1-64748b?style=flat-square" alt="插件版本 0.2.1"></a>
15
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-22c55e?style=flat-square" alt="Apache 2.0 许可"></a>
16
16
  </p>
17
17
 
18
18
  <p align="center">
19
- English · <a href="README.zh-CN.md">简体中文</a><br>
20
- <a href="https://github.com/Jockjrop/dsh-usage-stats/releases/latest">Download</a> ·
21
- <a href="#features">Features</a> ·
22
- <a href="#installation">Installation</a> ·
23
- <a href="#usage">Usage</a> ·
24
- <a href="#faq">FAQ</a> ·
25
- <a href="CHANGELOG.md">Changelog</a> ·
26
- <a href="https://github.com/Jockjrop/dsh-usage-stats/issues">Feedback</a>
19
+ <a href="README.en.md">English</a><br>
20
+ <a href="https://github.com/Jockjrop/dsh-usage-stats/releases/latest">下载</a> ·
21
+ <a href="#功能">功能</a> ·
22
+ <a href="#安装">安装</a> ·
23
+ <a href="#使用">使用</a> ·
24
+ <a href="#常见问题">常见问题</a> ·
25
+ <a href="CHANGELOG.md">更新日志</a> ·
26
+ <a href="https://github.com/Jockjrop/dsh-usage-stats/issues">反馈问题</a>
27
27
  </p>
28
28
 
29
29
  <p align="center">
30
- <a href="screenshots/usage.png"><img src="screenshots/usage.png" alt="Usage dashboard with totals, hourly tokens and a calendar heatmap" width="800"></a>
30
+ <a href="screenshots/usage.png"><img src="screenshots/usage.png" alt="用量面板:概览指标、今日图表与使用量热力图" width="800"></a>
31
31
  </p>
32
32
 
33
- <p align="center"><sub>Today's usage, lifetime totals, and the patterns behind them.</sub></p>
33
+ <p align="center"><sub>查看今日与累计 Token、小时趋势和使用量热力图。</sub></p>
34
34
 
35
35
  <table align="center">
36
36
  <thead>
37
- <tr><th align="center">Quotas · 配额</th><th align="center">Controls · 控制</th></tr>
37
+ <tr><th align="center">配额</th><th align="center">控制</th></tr>
38
38
  </thead>
39
39
  <tbody>
40
40
  <tr>
41
- <td align="center"><a href="screenshots/quotas.png"><img src="screenshots/quotas.png" alt="Provider balances and WorkBuddy credits" width="400"></a></td>
42
- <td align="center"><a href="screenshots/controls.png"><img src="screenshots/controls.png" alt="Refresh settings and custom quota queries" width="400"></a></td>
41
+ <td align="center"><a href="screenshots/quotas.png"><img src="screenshots/quotas.png" alt="供应商余额与账号积分" width="400"></a></td>
42
+ <td align="center"><a href="screenshots/controls.png"><img src="screenshots/controls.png" alt="模型功能、展示偏好与查询来源" width="400"></a></td>
43
43
  </tr>
44
44
  <tr>
45
- <td align="center">Check provider balances and WorkBuddy credits in one place.</td>
46
- <td align="center">Set automatic refresh intervals and custom quota queries.</td>
45
+ <td align="center">集中查看供应商余额、账号积分和周期额度。</td>
46
+ <td align="center">设置模型功能、展示偏好和自定义配额查询。</td>
47
47
  </tr>
48
48
  </tbody>
49
49
  </table>
50
50
 
51
- ## Features
52
-
53
- | Tab | What you can do |
54
- | --- | --- |
55
- | **Usage · 用量** | View today's and lifetime tokens, active days, hourly calls, a daily/weekly heatmap, and model breakdowns. |
56
- | **Quotas · 配额** | Check configured account balances, subscription windows, and optional WorkBuddy / WorkBuddy AI credits. |
57
- | **Controls · 控制** | Choose a refresh interval, configure custom quota queries, and enable model details or the advanced model selector. |
58
-
59
- - **Follow your usage:** filter historical charts by 7 / 30 / 365 days or all history, and compare providers and models.
60
- - **Keep quotas together:** use built-in readers or map a custom provider's JSON response.
61
- - **Refresh on your terms:** fetch manually or enable scheduled queries. Automatic quota refresh is off by default.
62
- - **Choose models faster:** opt into a model/reasoning panel with an effort slider; disabling it restores the official selector.
63
- - **Fit the desktop:** light/dark themes, responsive charts, pinned tabs, and a keyboard-operable provider picker.
64
- - **Follow your language:** Chinese, English, and Japanese UI text updates with DSH's selected language. User-defined names and quota labels stay as configured.
65
-
66
- ## Installation
51
+ <p align="center">
52
+ <a href="screenshots/detection.png"><img src="screenshots/detection.png" alt="模型检测:候选排名、库内置信度与采样状态" width="800"></a>
53
+ </p>
67
54
 
68
- **Recommended: install the [npm package `@sligqoer/dsh-usage-stats`](https://www.npmjs.com/package/@sligqoer/dsh-usage-stats) through DSH Desktop.** It includes prebuilt modules, needs no Git checkout or local build, and supports the plugin page's Check updates button when installed by package name.
55
+ <p align="center"><sub>查看 LM Fingerprint 候选排名、采样状态和已发生用量。</sub></p>
69
56
 
70
- ### 1. Open the plugin installer
57
+ ## 功能
71
58
 
72
- In DSH Desktop's main sidebar, open **插件 → 添加插件** (Plugins → Add plugin).
59
+ | 页面 | 你可以做什么 |
60
+ | --- | --- |
61
+ | **用量** | 查看今日与累计 Token、使用天数、小时调用次数、每日/每周热力图、趋势、模型明细与输出速度。 |
62
+ | **配额** | 集中查看供应商余额、账号积分与周期配额,支持手动或定时刷新及自定义查询。 |
63
+ | **检测** | 独立选择供应商和模型,确认预算后运行 LM Fingerprint 检测,查看候选排名、采样状态与历史记录。 |
64
+ | **控制** | 调整展示偏好、配额查询设置、高级模型选择器与逐模型推理强度。 |
73
65
 
74
- ### 2. Enter the full npm package name
66
+ - **看清使用趋势**:按日/周浏览热力图,切换 7/30 天趋势,按供应商与模型查看用量。
67
+ - **比较输出速度**:按 TPS 排序,显示平均首 Token 耗时(TTFT);缺少有效时间记录的样本不参与速度排名。
68
+ - **按需刷新配额**:通过 DSH 凭据服务查询已配置供应商,账号配额需要对应的账号插件或宿主服务。自动查询默认关闭。
69
+ - **独立运行检测**:默认采样 3 次,也可选择 1 次初筛;先确认预算,再手动开始,支持取消、超时和用量预算控制。
70
+ - **调整模型设置**:分别控制高级模型选择器与模型推理强度,保留已有的模型属性、参数映射和个人设置。
71
+ - **跟随应用语言**:支持中文、英语和日语,随 DSH 所选语言切换;用户自定义名称与配额标签保持原样。
75
72
 
76
- ```text
77
- @sligqoer/dsh-usage-stats
78
- ```
73
+ 检测通过随机数样本与参考库对照。排名和库内置信度表示与已知候选的接近程度,不能证明模型身份或能力。读取模型目录、预算和历史结果不会启动推理。
79
74
 
80
- Paste it into **包名或地址** (Package name or address) and click **安装** (Install). Keep the full `@sligqoer/` scope.
75
+ ## 安装
81
76
 
82
- ### 3. Enable and open
77
+ 当前插件版本为 **0.2.1**,适配 **DSH Desktop `0.2.1-alpha.2` 和 `0.2.1-rc.2`**。版本不匹配时,宿主插件管理器会拒绝安装或启用。
83
78
 
84
- Click **立即启用** (Enable now), then open **Settings → 用量统计**. Restart DSH if its plugin manager asks you to.
79
+ **推荐通过 DSH Desktop 安装 [npm 包 `@sligqoer/dsh-usage-stats`](https://www.npmjs.com/package/@sligqoer/dsh-usage-stats)。** 已包含预构建模块,无需克隆仓库或在本机构建;通过包名安装后可使用插件页的「检查更新」。
85
80
 
86
- Usage statistics load from your local DSH sessions. Open **配额** and click a refresh button to query an account.
81
+ ### 1. 打开插件安装入口
87
82
 
88
- <details>
89
- <summary>Install a specific version or a downloaded archive</summary>
83
+ 在 DSH Desktop 主界面侧栏进入 **插件 → 添加插件**。
90
84
 
91
- To install version `0.1.2`, enter this in the same installer:
85
+ ### 2. 填入完整 npm 包名
92
86
 
93
87
  ```text
94
- @sligqoer/dsh-usage-stats@0.1.2
88
+ @sligqoer/dsh-usage-stats
95
89
  ```
96
90
 
97
- You can also manually install a [Release archive](https://github.com/Jockjrop/dsh-usage-stats/releases/latest). Enter the URL below, or download the `.tgz` and `SHA256SUMS`, verify the hash, and enter the archive's local absolute path. Do not extract it before installing.
91
+ 将包名粘贴到 **包名或地址**,点击 **安装**,保留完整的 `@sligqoer/` 前缀。
98
92
 
99
- ```text
100
- https://github.com/Jockjrop/dsh-usage-stats/releases/latest/download/dsh-usage-stats.tgz
101
- ```
93
+ ### 3. 启用并打开面板
102
94
 
103
- ```powershell
104
- Get-FileHash ./sligqoer-dsh-usage-stats-0.1.2.tgz -Algorithm SHA256
105
- ```
106
-
107
- </details>
95
+ 点击 **立即启用**,进入 **设置 → 用量统计**。插件管理器提示需要重启时,完全退出并重新打开 DSH Desktop。
108
96
 
109
97
  <details>
110
- <summary>Install from source / manually link a checkout</summary>
98
+ <summary>安装指定版本或已下载的压缩包</summary>
111
99
 
112
- For development, install Git, Node.js and pnpm, then build the checkout. This path is verified on Windows with Node.js 24:
100
+ 安装本次版本时,在同一入口填入:
113
101
 
114
- ```sh
115
- git clone https://github.com/Jockjrop/dsh-usage-stats.git
116
- cd dsh-usage-stats
117
- npm ci
118
- npm run build
102
+ ```text
103
+ @sligqoer/dsh-usage-stats@0.2.1
119
104
  ```
120
105
 
121
- Keep the clone in a permanent location; DSH will link to it.
122
-
123
- In **插件 → 添加插件**, enter the clone's absolute path, install it, and click **立即启用**. To link it manually instead, fully exit DSH Desktop and back up its profile's `package.json`, then run this in **PowerShell from the cloned directory**:
106
+ 也可从 [GitHub 发布页](https://github.com/Jockjrop/dsh-usage-stats/releases/latest)下载 `.tgz` 安装包和 `SHA256SUMS`,校验后填入压缩包的本地绝对路径,无需解压。
124
107
 
125
108
  ```powershell
126
- $pluginDir = (Get-Location).Path.Replace('\', '/')
127
- $dshDataDir = if ($env:DSH_HOME) { $env:DSH_HOME } else { Join-Path $env:USERPROFILE '.dsh' }
128
- $profileDir = Join-Path $dshDataDir 'profiles/desktop'
129
- pnpm --dir $profileDir add "link:$pluginDir"
130
- ```
131
-
132
- Open `$profileDir/package.json` and append `"@sligqoer/dsh-usage-stats"` to its existing `dsh.profile.bundles` array. Keep the other bundle entries.
133
-
134
- DSH Desktop manages its own profile; `dsh plugin --profile desktop` is unavailable. After a manual link, start the app and open **Settings → 用量统计**.
135
-
136
- </details>
137
-
138
- <details>
139
- <summary>Updating or uninstalling</summary>
140
-
141
- **Migrating an older installation:** uninstall the old `dsh-usage-stats` package from the Plugins page, then install and enable `@sligqoer/dsh-usage-stats` by name. This package-name migration is needed only once; the plugin keeps its existing data directory, quota routes, and settings identifiers.
142
-
143
- **npm installation:** use Check updates on the plugin page and restart if prompted. The current update checker only handles direct npm package-name installations. GitHub URLs, archive URLs, local paths, and `link:` installations need manual updates; “Already up to date” for these sources does not confirm that no newer release exists.
144
-
145
- **Release installation:** uninstall the package from the Plugins page, install the Release URL above again, and enable it. To uninstall permanently, use the same page's uninstall action.
146
-
147
- **Source installation:** fully exit DSH Desktop, run these commands in the clone, and restart:
148
-
149
- ```sh
150
- git pull --ff-only
151
- npm ci
152
- npm run build
109
+ Get-FileHash ./sligqoer-dsh-usage-stats-0.2.1.tgz -Algorithm SHA256
153
110
  ```
154
111
 
155
- **Manual link removal:** exit DSH Desktop, remove only the `@sligqoer/dsh-usage-stats` dependency and bundle entry from its profile, run `pnpm install` there, and restart.
156
-
157
- </details>
158
-
159
- ## Usage
160
-
161
- **用量** shows how much you use and when. Hover a chart or heatmap cell for its breakdown. The overview cards retain their today/lifetime meanings when you change a historical filter.
162
-
163
- **配额** shows data returned by connected platforms. Configured balances may show **未查询** until their first query; available cards depend on credentials and account permissions.
164
-
165
- **控制** lets you change display and refresh settings:
166
-
167
- | Setting | Default |
168
- | --- | --- |
169
- | Automatic quota refresh | Off |
170
- | Refresh interval | 1 hour; also supports 10 minutes, 5 hours, or daily |
171
- | Model details | On |
172
- | Advanced model selector | Off |
173
-
174
- Enabling automatic queries asks you to acknowledge possible query costs. The schedule continues while the settings page is closed. Opening the quota page normally reads cached results.
175
-
176
- <details>
177
- <summary><strong>Supported providers and credentials</strong></summary>
178
-
179
- Built-in readers cover Claude, DeepSeek, StepFun, Codex, GitHub Copilot, OpenRouter, Moonshot China/global, Kimi Coding, MiniMax China/global, Z.AI, GLM Coding, Alibaba Cloud Token Plan China, xAI, and OpenCode Go.
180
-
181
- The corresponding provider must be configured in DSH. Supported OAuth readers use existing unexpired grants; this plugin does not refresh or modify logins.
182
-
183
- | Optional reader | Host credential references |
184
- | --- | --- |
185
- | OpenRouter account credits | `OPENROUTER_MANAGEMENT_API_KEY` |
186
- | xAI prepaid balance | `XAI_MANAGEMENT_API_KEY`, `XAI_TEAM_ID` |
187
- | Alibaba Cloud Token Plan China | `ALIBABA_CLOUD_ACCESS_KEY_ID`, `ALIBABA_CLOUD_ACCESS_KEY_SECRET`; optional `ALIBABA_CLOUD_SECURITY_TOKEN` |
188
-
189
- OpenCode Go uses only its own configured DSH credential. Zen has no built-in wallet balance reader, but supports custom queries. Alibaba Cloud's international Token Plan is not queried.
190
-
191
- WorkBuddy and WorkBuddy AI require the optional `dsh-workbuddy-connect` adapter. Their quotas are cached and refreshed separately.
112
+ 发布附件包含版本安装包 `sligqoer-dsh-usage-stats-0.2.1.tgz`、通用安装包 `dsh-usage-stats.tgz` 和校验文件 `SHA256SUMS`;两个安装包内容一致。
192
113
 
193
114
  </details>
194
115
 
195
116
  <details>
196
- <summary><strong>Set up a custom quota query</strong></summary>
197
-
198
- 1. Open **控制 → 配额查询** and select an existing provider.
199
- 2. Enter the query URL and response mapping.
200
- 3. Click **测试** and check the parsed result.
201
- 4. Confirm the query to show it in **配额**.
202
-
203
- For an endpoint returning `{ "data": { "balance": 12.34 } }`:
204
-
205
- ```json
206
- {
207
- "url": "https://api.example.com/balance",
208
- "method": "GET",
209
- "auth": "provider",
210
- "headers": { "accept": "application/json" },
211
- "response": {
212
- "metrics": [
213
- {
214
- "label": "Account balance",
215
- "kind": "amount",
216
- "remaining": "data.balance",
217
- "currency": "USD"
218
- }
219
- ]
220
- }
221
- }
222
- ```
223
-
224
- Replace the example URL with the provider's working endpoint. `auth: "provider"` uses its configured DSH credential; authenticated URLs must share the configured or official quota origin.
117
+ <summary>更新与迁移</summary>
225
118
 
226
- Templates support GET/POST, JSON bodies, amount/window metrics, and paths such as `data.items[0].balance`. Window metrics accept percentage fields or `total` with `remaining`/`used`; `response.rows` selects an array. Use `auth: "none"` for unauthenticated endpoints.
119
+ 通过 npm 包名安装的用户可在插件页使用「检查更新」。通过 GitHub 地址、压缩包或本地路径安装的用户,需要下载新版重新安装。
227
120
 
228
- Editing invalidates the test; successful tests expire after 15 minutes. A confirmed query overrides the built-in reader for that provider. Removing it restores the built-in reader.
121
+ 使用旧包名 `dsh-usage-stats` 的用户,先卸载旧包,再安装 `@sligqoer/dsh-usage-stats`。更新保留本地配置与用量数据;升级记录见 [CHANGELOG.md](CHANGELOG.md)。
229
122
 
230
123
  </details>
231
124
 
232
- ## Privacy
125
+ ## 使用
233
126
 
234
- Usage aggregation runs locally. The plugin saves counts, model identifiers and usage timestamps, without conversation text. Credentials are resolved on the host and are not returned to the renderer.
127
+ 1. 在「用量」查看概览、趋势、热力图和输出速度;在「控制」调整模型明细与速度的显示。
128
+ 2. 在「配额」点击供应商或账号卡片的刷新按钮。自动查询默认关闭,可在「控制」确认提示后开启。
129
+ 3. 在「检测」选择供应商与模型、设置采样次数和输出上限,确认预算后手动开始。读取目录或历史结果不会启动检测。
130
+ 4. 在「控制」分别开启或关闭高级模型选择器、模型推理强度和模型检测,编辑自定义配额查询。
235
131
 
236
- Quota tests and refreshes contact the selected platform. There is no analytics or telemetry endpoint.
237
-
238
- <details>
239
- <summary>Storage and request safeguards</summary>
132
+ ## 数据与兼容
240
133
 
241
- Both files live under `<DSH_HOME>/storages/`, or the current user's `.dsh/storages/` when `DSH_HOME` is unset:
134
+ 本地数据位于 `DSH_HOME/storages`:
242
135
 
243
- | File | Contents |
136
+ | 文件或目录 | 内容 |
244
137
  | --- | --- |
245
- | `usage-stats-corpus.json` | Per-session usage contributions |
246
- | `usage-stats-controls.json` | Controls, custom templates and quota snapshots |
138
+ | `usage-stats-corpus.json` | 会话用量汇总。 |
139
+ | `usage-stats-display.json` | 用量展示偏好。 |
140
+ | `usage-stats-quota-controls.json` | 查询和模型设置、供应商配额缓存。 |
141
+ | `usage-stats-detections.json` | 检测结果与逐次样本用量。 |
142
+ | `usage-stats-lm-fingerprint/` | 通过校验的指纹引擎与参考库更新。 |
143
+ | `usage-stats-supplemental.json` | 按任务和样本 ID 去重的检测用量,重启后保留。 |
247
144
 
248
- These are private local files, excluded from Git along with credentials, environment files, databases, logs, backups and previews.
145
+ 普通对话从 DSH 会话日志计数,检测用量按任务和样本 ID 去重后计入统计。请求诊断日志不参与 Token 汇总。更新会保留已保存的配置与历史用量。
249
146
 
250
- The API checks loopback addresses, Host, Origin and cross-site requests, sends `Cache-Control: no-store`, and hides unexpected host exception details. Another process under your account can access local data.
147
+ 从 0.2.0 升级后,模型检测使用 LM Fingerprint,不再提供旧版行为参考、KBF 导入/导出和能力基线测试;已发生的检测用量继续保留。发布安装包不包含个人会话、账号凭据、配额缓存或检测历史。
251
148
 
252
- Custom queries reject authentication headers and common credential fields in templates, require the appropriate origin for provider authentication, and do not follow redirects. They have an 8-second timeout and a 1 MB response limit. WorkBuddy adapters retain quota display fields only.
149
+ ## 常见问题
253
150
 
254
- </details>
255
-
256
- ## FAQ
151
+ **支持 DSH Web 吗?**
257
152
 
258
- **Does it work in DSH Web?**
153
+ 当前版本仅支持 DSH Desktop 的 desktop profile。
259
154
 
260
- This version loads only in the desktop profile and Electron main window.
155
+ **为什么配额卡片不显示或无法获取?**
261
156
 
262
- **Why is a quota card missing or unavailable?**
157
+ 先确认供应商已配置、凭据可用、账号插件已启用且账户支持对应配额接口。普通模型 API Key 可能没有账单查询权限。
263
158
 
264
- Check that the provider is configured, its credential is usable, and the account supports the quota API. A model API key may not have billing permissions.
159
+ **Token 总数就是账单金额吗?**
265
160
 
266
- **Are displayed token totals a bill?**
161
+ 不是。Token 统计来自本地会话和已上报的检测用量,账户余额与周期额度来自供应商接口。
267
162
 
268
- No. Usage totals sum input, output, cache-read and cache-write tokens. Account balances come from platform APIs.
163
+ **检测排名能证明真实模型身份吗?**
269
164
 
270
- **Will it change DSH's files?**
165
+ 不能。候选排名表示与参考库的接近程度;请求模型不在参考库时,候选仅供比较。
271
166
 
272
- It registers an external bundle. The optional model selector takes over a UI slot while enabled; disabling it restores the official selector without changing DSH source files.
167
+ ## 接口
273
168
 
274
- ## Contributing
169
+ 宿主服务 `dshUsageStats` 使用 `protocolVersion: 1`,提供 `readStats`、`readControls`、`updateControls`、`readProviderQuotas` 和 `readSupplementalUsage`。
275
170
 
276
- Bug reports and pull requests are welcome. For a bug, include your DSH version, plugin version, steps to reproduce, and a screenshot with private account details removed.
171
+ HTTP 接口使用 `/api/dsh-usage-stats/*`,提供统计、控制、配额查询与检测功能,仅接受本机与可信来源请求,并禁用缓存。
277
172
 
278
- <details>
279
- <summary><strong>Development and local API</strong></summary>
173
+ ## 开发
280
174
 
281
- Edit module sources in `src/`. `npm run build` synchronizes modules to `lib/` and root compatibility copies and injects the renderer package identity and header version from `package.json`; package exports load `lib/`.
175
+ 使用 Node.js 24,并安装 `package-lock.json` 锁定的依赖:
282
176
 
283
177
  ```sh
178
+ npm ci
284
179
  npm run build
285
180
  npm test
286
- node scripts/render-heatmap-check.mjs
287
- node scripts/check-heat-tip-placement.mjs
288
- npm run preview:heatmap
289
- npm pack --dry-run
181
+ npm run check:release
290
182
  npm run release
291
183
  ```
292
184
 
293
- Tests use synthetic data and temporary DSH homes; no live credentials or paid calls are required. Set `DSH_THEME_CLIENT` to validate an installed theme client instead of the checked-in alias contract. The synthetic preview writes an ignored `preview-heatmap.html`.
294
-
295
- `npm run release` builds the package, writes `sligqoer-dsh-usage-stats-<version>.tgz`, the `dsh-usage-stats.tgz` alias and `SHA256SUMS` to the ignored `release/` directory, then verifies installation in a temporary profile. Release notes include the matching version entry from [CHANGELOG.md](CHANGELOG.md).
296
-
297
- A matching `v<package.json version>` tag triggers GitHub Actions to run the tests, publish the verified archive as a public npm package through trusted publishing, and attach the same files to a GitHub Release. Trust is bound to the `release.yml` workflow in `Jockjrop/dsh-usage-stats`; no npm token is stored in the repository. `npm run publish:release` publishes the prebuilt archive and skips an existing version only when its integrity matches; different contents fail the release.
298
-
299
- Routes use the `/api/dsh-usage-stats/` prefix:
300
-
301
- | Route | Method | Purpose |
302
- | --- | --- | --- |
303
- | `stats` | GET | Usage; `days`, `tz`, `model`, optional `fresh=1` |
304
- | `provider-quotas` | GET | Cached quotas; `fresh=1` refreshes |
305
- | `workbuddy`, `workbuddy-ai` | GET | Adapter caches; support `fresh=1` |
306
- | `controls` | GET / POST | Read/update controls; writes require JSON |
307
- | `quota-providers` | GET | Configured providers and credential-free templates |
308
- | `quota-test` | POST | Test a template and return an expiring confirmation ID |
309
-
310
- The corpus refreshes every 30 seconds. Requests wait up to 1500 ms and may return `stale: true`/`partial: true`. SQLite fingerprints require `node:sqlite`; otherwise sessions are reread. Timezone changes re-bucket stored events, with possible approximation for old hourly-only history at fractional-hour boundaries.
311
-
312
- The `platform: "web"` declaration is DSH Desktop's renderer transport; both halves still require the desktop profile and the renderer's native bridge.
313
-
314
- </details>
315
-
316
- ## License
185
+ 修改 `src/` 后运行 `npm run build` 生成 `lib/`。`npm run check:release` 检查版本、构建一致性、第三方完整性与工作区隐私文件;`npm run release` 构建安装包并在独立临时项目中验证安装与加载,输出位于 `release/`。
317
186
 
318
- [Apache-2.0](LICENSE).
187
+ GitHub 发布流程要求标签与包版本一致(本版为 `v0.2.1`),通过检查后使用同一份安装包发布 npm 与 GitHub Release。npm 可信发布对应的工作流文件为 `.github/workflows/release.yml`。第三方资源、来源版本和许可记录于 `third_party/` 与 [NOTICE](NOTICE),本项目使用 [Apache-2.0 许可证](LICENSE)。
package/lib/bridge.js ADDED
@@ -0,0 +1,33 @@
1
+ /** Versioned host-service lookup and registration. */
2
+ export const PROTOCOL_VERSION = 1
3
+ export const HUB_SERVICE = 'dshModelsHub'
4
+ export const USAGE_SERVICE = 'dshUsageStats'
5
+ export const HUB_UPDATED = 'dsh-models-hub/updated'
6
+
7
+ export function getBridge(ctx, name) {
8
+ try {
9
+ const service = ctx.get(name)
10
+ return service?.protocolVersion === PROTOCOL_VERSION ? service : null
11
+ } catch { return null }
12
+ }
13
+
14
+ export function publishBridge(ctx, name, methods) {
15
+ if (getBridge(ctx, name)) throw new Error(`The ${name} service is already registered.`)
16
+ const service = Object.freeze({ protocolVersion: PROTOCOL_VERSION, ...methods })
17
+ if (typeof ctx.provide === 'function') ctx.provide(name, service)
18
+ return service
19
+ }
20
+
21
+ export class IntegrationError extends Error {
22
+ constructor(message = '账号配额暂不可用,请稍后重试。') {
23
+ super(message)
24
+ this.code = 'PLUGIN_UNAVAILABLE'
25
+ this.httpStatus = 503
26
+ }
27
+ }
28
+
29
+ export function requireBridge(ctx, name = HUB_SERVICE) {
30
+ const service = getBridge(ctx, name)
31
+ if (!service) throw new IntegrationError(name === HUB_SERVICE ? undefined : '用量统计暂不可用,请稍后重试。')
32
+ return service
33
+ }