dsh-ds-balance 2.3.0 → 3.0.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.
Files changed (48) hide show
  1. package/README.md +84 -177
  2. package/README_zh.md +140 -0
  3. package/lib/adapters/domain-core-store.d.ts +1 -1
  4. package/lib/adapters/domain-core-store.js +1 -1
  5. package/lib/adapters/host-account.d.ts +22 -1
  6. package/lib/adapters/host-account.js +13 -0
  7. package/lib/adapters/salt-file.d.ts +1 -1
  8. package/lib/adapters/salt-file.js +1 -1
  9. package/lib/client.js +619 -461
  10. package/lib/config.d.ts +28 -19
  11. package/lib/config.js +27 -19
  12. package/lib/domain/credential.d.ts +41 -0
  13. package/lib/domain/credential.js +52 -0
  14. package/lib/http/handlers.d.ts +34 -3
  15. package/lib/http/handlers.js +125 -32
  16. package/lib/http/routes.d.ts +6 -2
  17. package/lib/http/routes.js +3 -2
  18. package/lib/http/wire.d.ts +59 -2
  19. package/lib/http/wire.js +4 -2
  20. package/lib/index.d.ts +1 -1
  21. package/lib/index.js +35 -6
  22. package/lib/ports/account.d.ts +25 -0
  23. package/lib/ports/core-store.d.ts +1 -1
  24. package/lib/ports/core-store.js +1 -1
  25. package/lib/services/key-resolver.d.ts +33 -3
  26. package/lib/services/key-resolver.js +41 -12
  27. package/lib/services/source-readers.js +3 -3
  28. package/lib/services/source-selector.d.ts +10 -0
  29. package/lib/services/source-selector.js +14 -4
  30. package/lib/services/sources-service.d.ts +148 -0
  31. package/lib/services/sources-service.js +209 -0
  32. package/lib/types/client/api-types.d.ts +8 -0
  33. package/lib/types/client/data.d.ts +72 -0
  34. package/lib/types/client/icons/currency.d.ts +26 -0
  35. package/lib/types/client/icons.d.ts +92 -0
  36. package/lib/types/client/locales.d.ts +15 -13
  37. package/lib/types/client/model.d.ts +10 -0
  38. package/lib/types/client/settings/AccountAvatar.d.ts +27 -0
  39. package/lib/types/client/settings/BalanceSettingsCard.d.ts +8 -1
  40. package/lib/types/client/settings/fields.d.ts +70 -39
  41. package/lib/types/client/settings/source-status.d.ts +43 -0
  42. package/lib/types/client/settings/use-config-form.d.ts +1 -27
  43. package/lib/types/client/settings/use-sources.d.ts +38 -0
  44. package/lib/version.d.ts +1 -1
  45. package/lib/version.js +1 -1
  46. package/package.json +32 -32
  47. package/README_en.md +0 -237
  48. package/lib/types/client/settings/use-credential-state.d.ts +0 -36
package/README.md CHANGED
@@ -2,232 +2,139 @@
2
2
  <img src="icon.svg" alt="dsh-ds-balance" width="80" height="80">
3
3
  </p>
4
4
 
5
- <p align="center">
6
- <h1 align="center">dsh-ds-balance</h1>
7
- </p>
5
+ <h1 align="center">dsh-ds-balance</h1>
8
6
 
9
7
  <div align="center">
10
- <p><strong>把 DeepSeek 账户余额放进 DSH 的左边栏</strong></p>
11
- <p><em>DeepSeek account balance in the DSH sidebar</em></p>
8
+ <p><strong>DeepSeek account balance in the DSH sidebar</strong></p>
9
+ <p><em>把 DeepSeek 账户余额放进 DSH 的左边栏</em></p>
10
+
11
+ <p>
12
+ <a href="https://api-docs.deepseek.com/"><img src="https://img.shields.io/badge/DeepSeek%20API-Official-4D6BFE?style=flat" alt="DeepSeek official API"></a>
13
+ <a href="https://github.com/deepseek-ai/deepseek-harness"><img src="https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat&logo=deepseek&logoColor=white" alt="powered by dsh"></a>
14
+ </p>
12
15
 
13
16
  <p>
14
- <a href="https://api-docs.deepseek.com/"><img src="https://img.shields.io/badge/DeepSeek%20API-Official-4D6BFE?style=flat" alt="DeepSeek 官方接口"></a>
15
- <a href="https://github.com/deepseek-ai/deepseek-harness"><img src="https://img.shields.io/badge/DeepSeek%20Harness-Plugin-4176E6?style=flat" alt="DeepSeek Harness Plugin"></a>
17
+ <a href="https://github.com/dsh-plugin-lab/dsh-ds-balance/actions/workflows/ci.yml"><img src="https://github.com/dsh-plugin-lab/dsh-ds-balance/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
18
+ <a href="https://www.npmjs.com/package/dsh-ds-balance"><img src="https://img.shields.io/npm/v/dsh-ds-balance.svg?style=flat" alt="npm"></a>
19
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat" alt="MIT License"></a>
20
+ <a href="https://www.npmjs.com/package/dsh-ds-balance"><img src="https://img.shields.io/badge/SLSA-Build%20L2-green?logo=slsa&style=flat" alt="SLSA Build L2"></a>
16
21
  </p>
17
22
 
18
23
  <p>
19
- <a href="https://github.com/zlZayn/dsh-ds-balance/actions/workflows/ci.yml"><img src="https://github.com/zlZayn/dsh-ds-balance/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
20
- <a href="https://www.npmjs.com/package/dsh-ds-balance"><img src="https://img.shields.io/npm/v/dsh-ds-balance.svg" alt="npm"></a>
21
- <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT 许可证"></a>
24
+ Per-version changes → <a href="https://github.com/dsh-plugin-lab/dsh-ds-balance/releases">Releases</a> (one-to-one with npm versions)
22
25
  </p>
23
26
 
24
27
  <p>
25
- <strong><a href="README.md">简体中文</a></strong> · <a href="README_en.md">English</a>
28
+ <a href="README_zh.md">简体中文</a> · <strong><a href="README.md">English</a></strong>
26
29
  </p>
27
30
  </div>
28
31
 
29
32
  ---
30
33
 
31
- > [!NOTE]
32
- > **余额读自 DeepSeek 官方接口**,不是估算。凭据只经 DSH 的凭据通道解析:API Key 不会出现在设置文件里,也不会返回给界面。
34
+ A status ring is pinned to the bottom of the sidebar; clicking it shows the actual balance figures. To change settings, open the **Plugins** page in the sidebar and pick this plugin. The key and the account both follow the official Models page, and the endpoint is the official one — none of the three is set here.
33
35
 
34
- 余额要有地方看,但不该占地方。左边栏底部一个常驻的状态环,点开是三段金额与数据新鲜度;要改配置,进侧边栏**插件(Plugins)**页里本插件的详情页。
36
+ ## Data and credentials
35
37
 
36
- <p align="center">
37
- <img src="assets/sidebar-popover.png" alt="左边栏底部的「DeepSeek 余额」条目与展开的余额浮层" width="360">
38
- <br>
39
- <em>常驻<strong>左边栏底部</strong>,与「使用统计」「设置」并排;点开是余额、赠送 / 充值拆分与数据新鲜度。</em>
40
- </p>
38
+ The balance is read directly from the official DeepSeek API, not estimated from usage.
41
39
 
42
- ## 一眼看懂那个环
40
+ - The credential is resolved through DSH's credential channel; the plugin stores no key of its own: a key never lands in a settings file.
41
+ - The UI only ever sees a **head-and-tail mask** (`sk-cf08d*****3b84`, the same shape the DeepSeek platform console uses); **the full key never crosses the wire**, is never logged, and is never written to any file of this plugin.
42
+ - Only `api.deepseek.com` is contacted; no other traffic is proxied or forwarded.
43
+ - Balance snapshots are stored per credential — **changing the key starts keeping records afresh**, so old figures are never mixed in.
43
44
 
44
- 那个环是「现在是什么情况」,一眼能分出五种,各自对应你该做的事:
45
+ ## Getting started
45
46
 
46
- | 你看到 | 意思 | 你该做什么 |
47
- |---|---|---|
48
- | 彩环 + 一段弧 | 有余额,颜色就是多还是少 | **看数字** |
49
- | 灰环 + 一段缺口在转 | 正在取,还没结果 | **等** |
50
- | 灰环 + 中间一个 **+** | 没接入官方 | **去配置**(填 API Key 或登录账号) |
51
- | 灰色空环 | 连上了,账户就是没余额 | **不用管** |
52
- | 红环 + 中间一个 **叉** | 这里没有可用的数字 | **等、检查,或去查账户** |
47
+ **Prerequisites**: DSH on its current RC line (specify `@next` when installing); Node `>= 20`. The only source for the compatible range is `engines.dsh` in [package.json](package.json).
53
48
 
54
- **鼠标停上去,它会告诉你这一格现在什么意思**(收起态那 56px 轨道、展开态带名字的条目,
55
- 停上去显示的是同一句话):
49
+ 1. Install the host. Neither `latest` nor `alpha` is the line we declare, so specify the version line:
56
50
 
57
- - **数字可信时**(正常 / 偏低 / 告急)—— 直接显示**金额**;
58
- - **其余情况** —— 显示这个处境自己的话:「正在获取」「读不到余额」「服务异常」
59
- 「尚未配置凭据」「账户不可用」「数据已过期」「暂无余额」。
51
+ ```bash
52
+ npm install -g @deepseek-ai/dsh@next
53
+ ```
60
54
 
61
- **账户停用**与**数据过期**虽然手里有数字,也**不**显示那个数字:
62
- 停用的账户、过期的快照,报出来的数只会误导(「我有 ¥0」/「我有 ¥110」)。
63
- 环已经把问题画出来了(红叉 / 旧色),悬停该做的是解释问题。
55
+ 2. Install the plugin:
64
56
 
65
- 两种「看不到」分得开:**没接入**提示你去配凭据;**接入了但读不到**说「读不到余额」
66
- (不写「暂时」—— 有些原因等一下就好,有些得你去改凭据,说「暂时」会把人劝去干等)。
67
- 那个**叉**既表示「读不到」,也表示「读到了但这个账户不能用」——
68
- 两者都是「这里没有可用的数字」,都要你去查。
57
+ ```bash
58
+ dsh plugin --profile web add dsh-ds-balance
59
+ ```
69
60
 
70
- ## 界面一览
61
+ 3. Start (or restart) `dsh --profile web`; the balance entry appears at the bottom of the sidebar.
71
62
 
72
- | 界面 | 一句话 | 你会用它来 |
73
- |---|---|---|
74
- | 侧栏圆环 | 常驻左边栏底部的状态环 + 名称;**悬停(收起态与展开态一样)显示同一句话**:数字可信时显金额,否则显状态文案;**环里填了多少 = 余额离该币种预警线还有多远** | 扫一眼就知道还剩多少、离预警线多远 |
75
- | 余额浮层 | 点条目展开:总额、赠送 / 充值拆分、数据新鲜度、手动刷新(带冷却);**右上角图标直达本插件的配置**(宿主版本不支持时退回 Plugins 列表,悬浮文字同步改口径) | 核对具体数字,以及数据是几分钟前的 |
76
- | 设置卡片 | 连接 / 展示 / 阈值 / 刷新四组,**默认四组全收起**,点组头逐组展开 | 换端点、换币种、调预警线、调节奏 |
63
+ From source: `git clone`, then `pnpm install && pnpm run build`, then `dsh plugin --profile web add "$PWD"` — the same restart applies.
64
+ That `pnpm install` cannot be skipped: under a path install the repository supplies its own dependencies, and missing them makes the plugin show as "not running".
65
+
66
+ ## What it shows
77
67
 
78
- 三种界面的分工是死的:**圆环回答「大概还剩多少」,浮层回答「具体是多少」,卡片回答「怎么算」。**
68
+ Three surfaces, each with one job:
69
+
70
+ | Surface | Where | What it does |
71
+ |---|---|---|
72
+ | Status ring | Pinned to the bottom of the sidebar | See at a glance how much is left and how close you are to the warning threshold |
73
+ | Balance popover | Click to expand | See the total, the granted / topped-up split, and how many minutes old the data is |
74
+ | Settings card | This plugin's details page under Plugins | Check both ways of reading your balance, and set the currency, the warning thresholds and the refresh cadence |
79
75
 
80
76
  <p align="center">
81
- <img src="assets/settings-card.png" alt="插件页里的「DeepSeek 余额」卡片" width="360">
77
+ <img src="assets/sidebar-popover_en.png" alt="The DeepSeek Balance entry at the bottom of the sidebar, with the balance popover expanded" width="360">
82
78
  <br>
83
- <em>卡片就是这四组:默认四组全收起,点组头逐组展开;组里有填错的项时那一组会自己展开。</em>
79
+ <em>The entry is pinned to the bottom of the sidebar; clicking it opens the balance popover: the total, the granted / topped-up split, how many minutes ago the data was, and manual refresh at the bottom right.</em>
84
80
  </p>
85
81
 
86
- ## 能力
87
-
88
- - 左边栏底部常驻一个状态环加名称,点开看明细;收起与展开是同一个环,位置不变。
89
- - 余额按设定的周期自动刷新,界面读的是缓存 —— 开着界面不会反复去打上游接口。
90
- - 浮层给出总额、赠送 / 充值拆分、数据是多久之前的,以及一个带冷却的手动刷新;标题那行「鲸鱼图标 + DeepSeek 余额」本身是外链,点开是新标签页里的[官网用量页](https://platform.deepseek.com/usage)。
91
- - 多币种:显示哪个币种由账户决定;设置里选的币种账户里没有时,浮层会说明并给「改用实际币种」——**点它直接写进设置**,设置页那一格跟着变;宿主不可写时按钮置灰。
92
- - 设置卡片分四组、**默认全收起**、点组头展开;组里有填错的项时,那一组会自己展开。
93
- - 凭据默认继承官方模型页配好的那一份,不必重填;徽标只报「已配置密钥。/ 未配置密钥。」(官方卡片同款),
94
- 只读时不给编辑,并说明原因。
95
- - 颜色只表达状态(正常 / 偏低 / 告急),与金额大小无关;读法与理由见「[圆环怎么读](#圆环怎么读)」。
96
- - 插件页里以**本地化名字**出现:中文界面是「DeepSeek 余额」,英文界面是「DeepSeek Balance」——
97
- 卡片与详情页的标题、那句话说明都跟随界面语言,图标就是左边栏那个环(橙色弧环,画的是「用了七成」那一档);
98
- 详情页仍会把包名 `dsh-ds-balance` 单独写出来。
99
-
100
- ## 安装
101
-
102
- ### 前置
103
-
104
- - **DSH**:版本范围以 [package.json](package.json) 的声明为准,本插件跟的是宿主当前那条 **RC 线**(dist-tag 是 `next`)。
105
- - **Node**:`>= 20`(同一处声明)。
106
-
107
- 装宿主时**要显式点名版本线**:`@deepseek-ai/dsh` 的 `alpha` 与 `latest` 都**不是**我们声明的那条线 —— 按默认方式装会落在声明范围之外。
108
-
109
- ```bash
110
- npm install -g @deepseek-ai/dsh@next # 本插件承诺支持的线(RC 线;npm 上没有 rc 这个 tag)
111
- ```
112
-
113
- 兼容性怎么保证、哪条线该跟,见[版本兼容](#版本兼容)。
114
-
115
- ### 从 npm 安装
82
+ The ring itself is "what is going on right now", five states you can tell apart at a glance:
116
83
 
117
- ```bash
118
- dsh plugin --profile web add dsh-ds-balance
119
- ```
120
-
121
- 装完**重启 `dsh --profile web`** 生效。
122
-
123
- ### 从源码安装
124
-
125
- ```bash
126
- git clone https://github.com/zlZayn/dsh-ds-balance.git
127
- cd dsh-ds-balance
128
- npm install && npm run build
129
-
130
- dsh plugin --profile web add "$PWD"
131
- ```
132
-
133
- 与 npm 那条路一样,重启后生效。
134
-
135
- ⚠️ 上面那步 `npm install` 不能省:`link:` 装法下依赖由仓库自己提供(见 [AGENTS.md](AGENTS.md)),
136
- 漏装则插件显示「未运行」(`ERR_MODULE_NOT_FOUND`)。
84
+ | The ring | Meaning | What you do |
85
+ |---|---|---|
86
+ | Coloured ring + an arc | There is a balance; the colour says more or less | Read the number |
87
+ | Grey ring + a rotating gap | Fetching, no result yet | Wait |
88
+ | Grey ring + a **+** in the middle | Not connected to your account yet | Configure it |
89
+ | Grey, empty ring | Connected to your account, which simply has no balance | Nothing |
90
+ | Red ring + a **cross** in the middle | No usable number here | Check it |
137
91
 
138
- ### 发现与安装
92
+ ## What each thing is
139
93
 
140
- - **npm**:[`dsh-ds-balance`](https://www.npmjs.com/package/dsh-ds-balance)
141
- - **GitHub**:[`zlZayn/dsh-ds-balance`](https://github.com/zlZayn/dsh-ds-balance)
94
+ | Thing | What it means |
95
+ |---|---|
96
+ | Arc length | The balance as a share of that currency's **warning threshold**, capped at a full circle |
97
+ | Colour | State only (normal / low / critical), never the amount; the **critical threshold only sets the colour** and takes no part in drawing the ring |
98
+ | The mark in the middle | **+** means not connected yet; go configure; **cross** means no usable number here — it could not be read, or it was read but the account cannot be used |
99
+ | Hover text | The **amount** when the number is trustworthy, that state's own line otherwise; collapsed and expanded say the same sentence |
100
+ | The source bracket | To the right of the popover title: which credential this number came from — a head-and-tail mask such as `sk-cf08d*****3b84`, or the signed-in account's name |
101
+ | Data freshness | The "how long ago" in the popover, counted from the moment the data arrived |
102
+ | Manual refresh | Cooldown applies; the cooldown restarts when the refresh finishes, and the seconds on the popover are the real ones left |
103
+ | Settings groups | Connection / Display / Thresholds / Refresh |
142
104
 
143
- 仓库带有 GitHub topic [`dsh-plugin`](https://github.com/topics/dsh-plugin),插件市场据此自动发现插件。
105
+ ## Configuration
144
106
 
145
- ## 版本兼容
107
+ The card lives on the Plugins page: sidebar **Plugins** → "Installed" → click the **DeepSeek Balance** card to step into its details page.
146
108
 
147
- - **需要哪一版宿主**:以 [package.json](package.json) 的声明为准,本插件跟的是宿主当前那条 **RC 线**。
148
- 需要配置界面,就把宿主升到那一版或更高:`npm install -g @deepseek-ai/dsh@next`。
149
- - **声明是「窄」的**:下限是我们实测过的那一版,用 `>=` 而**不设上限** —— 不承诺「以后都兼容」。
150
- (它罩得住**同一 `major.minor.patch` 内**后续的预发布版本;宿主换一个补丁位再推预发布,
151
- 这条下限就罩不住了,届时要再抬一次。为什么见[兼容性](docs/PUBLISHING.md#兼容性)。)
152
- - **下限为什么抬上去**:不是换了界面位置,而是**设置接缝换过**(旧宿主上没有本插件依赖的那两样东西,
153
- 浏览器半边会整个不渲染 —— 圆环与浮层也一起消失)。插件不查宿主版本号,而是**当场探测那个能力**;
154
- 拿不到时浮层里会多一行英文提示,说明配置界面为什么不可用、该往哪儿升级。
155
- 技术细节见 [配置表单的能力探测](docs/ARCHITECTURE.md)。
156
- - **兼容性不是推断出来的**:每周由 [compat.yml](.github/workflows/compat.yml) 在 `next`(RC 线)上
157
- 换包实跑一遍现有测试,另有一步单独判声明面罩不罩得住;红了会开或更新一条固定标题的跟踪 issue。
158
- 当前结论与红了怎么办见 [兼容性](docs/PUBLISHING.md#兼容性)。
109
+ The configuration area is on the details page, right below the description, ready to edit:
159
110
 
160
- ## 配置
111
+ - **Connection** — read-only: the two ways this plugin can read your balance, what each one is using right now, where that credential comes from, and a **Test** button that really calls the provider.
112
+ - **Display** — which currency amounts use, or let it follow the account.
113
+ - **Thresholds** — two lines per currency: a warning threshold and a critical threshold. Within one currency the **critical value must stay below the warning value**; saving is blocked otherwise.
114
+ - **Refresh** — the server refresh interval, the UI poll interval and the manual refresh cooldown; the defaults suit most setups.
161
115
 
162
- 打开侧边栏 **插件(Plugins)** →「已安装(Installed)」组 → 点进 **DeepSeek 余额**(英文界面下是 **DeepSeek Balance**)的详情页 —— **配置区就在描述下面,直接可改**(那一行上没有第二个 Configure 步骤);四组**默认全收起**,点组头逐组展开:
116
+ Saving applies immediately; there is no need to restart DSH.
163
117
 
164
118
  <p align="center">
165
- <img src="assets/settings-cards-position.png" alt="Plugins 页列表里「DeepSeek 余额」的位置" width="480">
119
+ <img src="assets/settings-card_en.png" alt="DeepSeek Balance details page: the four configuration groups below the description" width="360">
166
120
  <br>
167
- <em>Plugins 页列表里的位置:「DeepSeek 余额」与其他已安装插件并排;点它的插件名进详情页,上面那张配置表单就在描述下面。</em>
121
+ <em>The configuration area on the details page. A group with an invalid entry expands itself.</em>
168
122
  </p>
169
123
 
170
- - **连接**:API 地址与凭据,两项都默认留空 —— 地址留空即用 DeepSeek 官方端点,凭据继承官方模型页那一份、只读不可改;
171
- 二级「自定义设置」里只放凭据引用名。
172
- - **展示**:金额用哪种币种,或让它自动跟随账户。
173
- - **阈值**:每个币种两档提醒线(预警 / 告急)。同一币种内**告急必须严格低于预警**,相等也会被拒绝
174
- (保存时就会拦下来);但**手改配置文件写成的非法组合不会再报错** ——
175
- 插件读到的那一刻会把这一对**回落成默认值**并在日志里记一次。
176
-
177
- > **升级提示**:设置项存在插件那一行的配置里,键名跟着宿主升级变过一次,**旧值不会自动迁移** —— 升级后请照上表重填一次。
178
- - **刷新**:服务端刷新周期、界面轮询周期与手动刷新冷却。冷却从**刷完那一刻**起算,
179
- 浮层上的秒数就是真实剩余;后端说这次没触发,界面按它给的剩余时间收尾,不假装刷过。
180
-
181
- 保存即生效,不必重启 DSH。
182
-
183
- ### 圆环怎么读
184
-
185
- - 环里填多少 = 当前余额占该币种**预警线**的比例,100% 封顶;告急线不参与画环 —— 它已经决定了颜色。
186
- - 颜色只表达状态,与金额大小无关:正常、偏低、告急各一色;账户读不到时另画一个带叉号的环。
187
- - 没配阈值的币种退回按状态定性:**正常画满环,偏低 3/4,告急 1/4**。
188
- (只有**有余额可看**的那一族画弧 —— 上面三档,加上「数据已过期」时的那份旧数字;
189
- 账户读不到、账户停用、没接入、账户没钱这些**都不画弧**,环靠颜色与中心记号说话。)
190
- - 为什么颜色不由金额算、阈值为什么只当刻度 → [数据流](docs/ARCHITECTURE.md#数据流)。
191
-
192
- ### 凭据
193
-
194
- 密钥只经 DSH 的凭据通道解析,卡片里的 `API Key` 一栏默认继承官方模型页配好的那一份,且只读不可改。
195
- 由启动环境(环境变量)提供时,字段只读,徽标写明来源。
196
-
197
- **余额有两条官方取数路,插件自己选**:模型页 / 环境变量配的 API Key 一条,**DSH 账号登录**一条
198
- (只登录、没配 Key 也能看到余额)。选择顺序是:
199
-
200
- - **当前会话在用的那条** —— 切会话、换模型都跟着换;
201
- - 读不到会话就按全局默认模型的路由;
202
- - 都判不出来时 **Key 优先、账号兜底**;
203
- - 两条都没有,才是「尚未配置凭据」。
204
-
205
- 浮层标题右边那个括号就是这份数字的来源:`(API Key)` / `(账号登录)`。**显示哪个、刷新就刷哪个、标签也写哪个** —— 三者始终同一条。
206
-
207
- **这个插件只记官方的那一个数字**,所以首选那条读不到时会自动退到另一条官方路:只要账号或 API Key 有一个能用,就照常显示(哪怕是一份稍旧的快照)。**两条路都拿不到数字,才会提示** —— 那才是真的没接入官方。左栏那个环这时长什么样,见[一眼看懂那个环](#一眼看懂那个环)。
208
-
209
- **换了 key 多久生效,跟着 DSH 的层走 —— 本插件不额外追:**
210
-
211
- - **启动环境(环境变量)给的 key:改了要重启 DSH。** 进程的环境在它启动那一刻就定死了,之后再改外面那个变量,跑着的插件看不到。
212
- - **在官方模型页 / 凭据库换的 key:不必重启**,最迟下一个服务端刷新周期生效(连续失败退避期间会更久);想立刻看到就点浮层里的手动刷新(它带冷却)。
213
- - 生效之前,界面显示的还是**旧账本**的数字 —— 账本标识按 key 派生,新旧不会混,但内存里那份要等下一次抓取成功才被换掉。
214
-
215
- 为什么这么定 → [关键决策](docs/ARCHITECTURE.md#关键决策)。
124
+ > **Upgrade notes**: the keys these settings are filed under changed once with a host upgrade, and **old values are not migrated**; after upgrading, fill the four groups in again as above. Separately, **version 3.0 removed two settings**: a hand-written `apiKey` and a custom `baseUrl` now have no effect — the credential is the one the official Models page holds, and the endpoint is the official one. Remove them from your settings file if you had set them by hand.
216
125
 
217
- ## 安全与边界
126
+ ## Version compatibility
218
127
 
219
- - **API Key 永不返回界面**:配置接口只回一个固定长度的掩码串,连末几位也不给。
220
- - 密钥不落日志、不落本插件的文件;设置文件里只有引用名,卡片可以安全截图或分享。
221
- - 余额快照存在 DSH 自己的数据目录里,按凭据派生出的标识分组 —— **换 key 自动开新账本**,旧快照不会被混用。
222
- - 那份标识还要 DSH home 目录下一个随机盐文件参与派生;**它丢了,旧快照就读不回来**(不会串到别人账上)。
223
- - 只访问 `api.deepseek.com`,不代理、不转发其他流量。
128
+ - **Which host version is required**: whatever `engines.dsh` in [package.json](package.json) declares — that range names the host **lines** this plugin covers, ceiling included; anything past the ceiling is not supported. If you need the settings UI, upgrade the host to the newest line: `npm install -g @deepseek-ai/dsh@next`.
129
+ - **The declaration enumerates lines explicitly**: only the lines listed in `engines.dsh` are promised. A new line past the ceiling becomes supported only after it has been measured in the [compat.yml](.github/workflows/compat.yml) matrix and written into the declaration; it does not follow the host automatically. **Patch releases inside a listed line (prereleases included) need no declaration change**.
130
+ - **Compatibility is measured**: weekly, [compat.yml](.github/workflows/compat.yml) runs the tests on the declared host line, plus a separate step checking the declared range still covers it; a red committed line opens a tracking issue. Verdicts and handling: [Compatibility](docs/PUBLISHING.md#兼容性).
224
131
 
225
- ## 许可
132
+ ## License
226
133
 
227
- [MIT](LICENSE)。
134
+ [MIT](LICENSE).
228
135
 
229
- ## 贡献
136
+ ## Contributing
230
137
 
231
- 外部贡献入口(报 bug 带什么、提功能前先翻什么、提 PR 前做什么)→ [CONTRIBUTING.md](CONTRIBUTING.md)。
138
+ Bugs and requests go to the repository Issues.
232
139
 
233
- 设计取向与实现约束 → [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md);发布流程与版本号判定 → [docs/PUBLISHING.md](docs/PUBLISHING.md);维护者文档地图 → [AGENTS.md](AGENTS.md)。
140
+ Maintainer's document map → [AGENTS.md](AGENTS.md).
package/README_zh.md ADDED
@@ -0,0 +1,140 @@
1
+ <p align="center">
2
+ <img src="icon.svg" alt="dsh-ds-balance" width="80" height="80">
3
+ </p>
4
+
5
+ <h1 align="center">dsh-ds-balance</h1>
6
+
7
+ <div align="center">
8
+ <p><strong>把 DeepSeek 账户余额放进 DSH 的左边栏</strong></p>
9
+ <p><em>DeepSeek account balance in the DSH sidebar</em></p>
10
+
11
+ <p>
12
+ <a href="https://api-docs.deepseek.com/"><img src="https://img.shields.io/badge/DeepSeek%20API-Official-4D6BFE?style=flat" alt="DeepSeek 官方接口"></a>
13
+ <a href="https://github.com/deepseek-ai/deepseek-harness"><img src="https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat&logo=deepseek&logoColor=white" alt="由 dsh 驱动"></a>
14
+ </p>
15
+
16
+ <p>
17
+ <a href="https://github.com/dsh-plugin-lab/dsh-ds-balance/actions/workflows/ci.yml"><img src="https://github.com/dsh-plugin-lab/dsh-ds-balance/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
18
+ <a href="https://www.npmjs.com/package/dsh-ds-balance"><img src="https://img.shields.io/npm/v/dsh-ds-balance.svg?style=flat" alt="npm"></a>
19
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat" alt="MIT 许可证"></a>
20
+ <a href="https://www.npmjs.com/package/dsh-ds-balance"><img src="https://img.shields.io/badge/SLSA-Build%20L2-green?logo=slsa&style=flat" alt="SLSA Build L2"></a>
21
+ </p>
22
+
23
+ <p>
24
+ 各版本改动 → <a href="https://github.com/dsh-plugin-lab/dsh-ds-balance/releases">Releases</a>(与 npm 版本一一对应)
25
+ </p>
26
+
27
+ <p>
28
+ <strong><a href="README_zh.md">简体中文</a></strong> · <a href="README.md">English</a>
29
+ </p>
30
+ </div>
31
+
32
+ ---
33
+
34
+ 左边栏底部常驻一个状态环,点开能看到具体的余额数字。要改配置,进侧栏的 **插件(Plugins)** 页,点开本插件。密钥与账号跟官方模型页走,端点是官方那一个 —— 这三样都不在这里配。
35
+
36
+ ## 数据与凭据
37
+
38
+ 余额直接读 DeepSeek 官方接口,不是根据用量估算的。
39
+
40
+ - 凭据由 DSH 的凭据通道解析,插件不自己保存密钥:密钥不会写进设置文件。
41
+ - 界面只看得到**首尾片段掩码**(`sk-cf08d*****3b84`,与 DeepSeek 平台控制台同形),**完整密钥永不跨线**;密钥不落日志,不落本插件的任何文件。
42
+ - 只访问 `api.deepseek.com`,不代理、不转发其他流量。
43
+ - 余额快照按凭据分开存放 —— **换 key 会重新开始记账**,旧的数字不会混进来。
44
+
45
+ ## 上手
46
+
47
+ **前置**:DSH 跟的是当前那条 RC 线(安装时写明 `@next`);Node `>= 20`。兼容范围的唯一出处是 [package.json](package.json) 的 `engines.dsh`。
48
+
49
+ 1. 装宿主。`latest` 与 `alpha` 都不是我们声明的那条线,请写明版本线:
50
+
51
+ ```bash
52
+ npm install -g @deepseek-ai/dsh@next
53
+ ```
54
+
55
+ 2. 装插件:
56
+
57
+ ```bash
58
+ dsh plugin --profile web add dsh-ds-balance
59
+ ```
60
+
61
+ 3. 启动(或重启)`dsh --profile web`,左边栏底部就会出现余额条目。
62
+
63
+ 从源码安装:`git clone` 之后 `pnpm install && pnpm run build`,再执行 `dsh plugin --profile web add "$PWD"`,同样重启生效。
64
+ 那一步 `pnpm install` 不能省 —— 按路径挂载时依赖由仓库自己提供,漏装会让插件显示「未运行」。
65
+
66
+ ## 显示什么
67
+
68
+ 三处界面,各管一件事:
69
+
70
+ | 界面 | 位置 | 做什么 |
71
+ |---|---|---|
72
+ | 状态环 | 左边栏底部,常驻 | 一眼看得出还剩多少、离预警线多远 |
73
+ | 余额浮层 | 点条目展开 | 看总额、赠送 / 充值拆分,以及数据是几分钟前的 |
74
+ | 设置卡片 | Plugins 页里本插件的详情页 | 查两条读余额的途径,换币种、调预警线、调刷新节奏 |
75
+
76
+ <p align="center">
77
+ <img src="assets/sidebar-popover.png" alt="左边栏底部的「DeepSeek 余额」条目与展开的余额浮层" width="360">
78
+ <br>
79
+ <em>条目常驻左边栏底部,点开是余额浮层:总额、赠送 / 充值拆分、数据是几分钟前的,右下角是手动刷新。</em>
80
+ </p>
81
+
82
+ 环本身就是「现在是什么情况」,一眼能分出五种:
83
+
84
+ | 环的样子 | 意思 | 你该做什么 |
85
+ |---|---|---|
86
+ | 彩环 + 一段弧 | 有余额,颜色表示多还是少 | 看数字 |
87
+ | 灰环 + 一段缺口在转 | 正在取,还没结果 | 等 |
88
+ | 灰环 + 中间一个 **+** | 还没接入账户 | 去配置 |
89
+ | 灰色空环 | 已接入账户,本身没有余额 | 不用管 |
90
+ | 红环 + 中间一个 **叉** | 这里没有可用的数字 | 去查 |
91
+
92
+ ## 每样东西是什么
93
+
94
+ | 东西 | 说明 |
95
+ |---|---|
96
+ | 弧长 | 余额占该币种**预警线**的比例,满格封顶一整圈 |
97
+ | 颜色 | 只表示状态(正常 / 偏低 / 告急),与金额大小无关;**告急线只决定颜色**,不参与画环 |
98
+ | 中心记号 | **+** 是还没接入,去配置;**叉**是这里没有可用的数字 —— 读不到,或者读到了但账户不能用 |
99
+ | 悬停提示 | 数字可信时显示**金额**,其余情况显示这个状态自己的话;收起态与展开态说的是同一句 |
100
+ | 来源括号 | 浮层标题右侧:这份数字用的是**哪一份凭据** —— 首尾片段掩码如 `sk-cf08d*****3b84`,或已登录账号的名字 |
101
+ | 数据新鲜度 | 浮层里的「多久之前」,从收到数据的时刻算起 |
102
+ | 手动刷新 | 带冷却,冷却从刷完那一刻重新计时,浮层上的秒数就是真实剩余 |
103
+ | 设置分组 | 连接 / 展示 / 阈值 / 刷新 |
104
+
105
+ ## 配置
106
+
107
+ 卡片在 Plugins 页:侧边栏 **插件(Plugins)** →「已安装」→ 点 **DeepSeek 余额** 卡片进详情页。
108
+
109
+ 配置区在详情页,描述下面,直接可改:
110
+
111
+ - **连接** —— 只读:本插件读余额的两条途径、每条此刻在用哪一份凭据、那份凭据从哪来,外加一个**真的去打提供方**的 **Test** 按钮。
112
+ - **展示** —— 金额用哪种币种,或让它跟随账户。
113
+ - **阈值** —— 每个币种两条线:预警线与告急线。同一币种内**告急值必须低于预警值**,保存时会拦下来。
114
+ - **刷新** —— 服务端刷新周期、界面轮询周期与手动刷新冷却;默认值适用于大多数情况。
115
+
116
+ 保存即生效,不必重启 DSH。
117
+
118
+ <p align="center">
119
+ <img src="assets/settings-card.png" alt="DeepSeek 余额详情页:描述下面的四组配置" width="360">
120
+ <br>
121
+ <em>详情页的配置区。组里有填错的项时,那一组会自己展开。</em>
122
+ </p>
123
+
124
+ > **升级提示**:设置项的键名跟着宿主升级改过一次,**旧值不会自动迁移**;升级之后请按上面四组重填一次。另有一条:**3.0 删掉了两个设置项** —— 手写的 `apiKey` 与自定的 `baseUrl` 从此不再起作用(凭据以官方模型页那一份为准,端点固定为官方地址);手改过设置文件的请把它们删掉。
125
+
126
+ ## 版本兼容
127
+
128
+ - **要哪一版宿主**:以 [package.json](package.json) 的 `engines.dsh` 为准 —— 那个范围写明本插件覆盖**哪几条宿主线**(含上限,上限之外不受支持)。需要配置界面就把宿主升到最新那条线:`npm install -g @deepseek-ai/dsh@next`。
129
+ - **声明按线显式枚举**:只承诺 `engines.dsh` 里列出的那几条线;跨到上限之外的新线,要先在 [compat.yml](.github/workflows/compat.yml) 的矩阵里实测过、再把它写进声明,不自动跟着宿主走。**已列线内的补丁版本(含预发布)不需要动声明**。
130
+ - **兼容性是实测出来的**:每周由 [compat.yml](.github/workflows/compat.yml) 在声明的那条宿主线上跑一遍测试,另有一步单独核对声明范围是否还罩得住;承诺线红了会开一条跟踪 issue。结论与处置见 [兼容性](docs/PUBLISHING.md#兼容性)。
131
+
132
+ ## 许可
133
+
134
+ [MIT](LICENSE)。
135
+
136
+ ## 贡献
137
+
138
+ 缺陷与需求走仓库 Issues。
139
+
140
+ 维护者文档地图 → [AGENTS.md](AGENTS.md)。
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 用 dsh 官方存储接缝实现 {@link CoreStore}。
3
3
  *
4
- * 关键约束(见 docs/backend-architecture.md §10):
4
+ * 关键约束(见 docs/BACKEND-CONTRACTS.md §10):
5
5
  * - `open` 每进程只能一次,重名抛 `already-open`;
6
6
  * - **`close()` 必须由调用方在 `ctx.effect` 的 disposer 里调用**,否则热重挂会锁死;
7
7
  * - 打开失败要**降级**而不是抛出去 —— 未观察的 rejection 曾把宿主整个拖下水。
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 用 dsh 官方存储接缝实现 {@link CoreStore}。
3
3
  *
4
- * 关键约束(见 docs/backend-architecture.md §10):
4
+ * 关键约束(见 docs/BACKEND-CONTRACTS.md §10):
5
5
  * - `open` 每进程只能一次,重名抛 `already-open`;
6
6
  * - **`close()` 必须由调用方在 `ctx.effect` 的 disposer 里调用**,否则热重挂会锁死;
7
7
  * - 打开失败要**降级**而不是抛出去 —— 未观察的 rejection 曾把宿主整个拖下水。
@@ -26,16 +26,37 @@ export interface HostAccountClient {
26
26
  readonly locale: string;
27
27
  readonly timezoneOffsetSeconds: number;
28
28
  }
29
+ /**
30
+ * 宿主账号资料查询的结果形状(对齐 `AccountDetails['profile']`)。
31
+ *
32
+ * 只声明本插件真的会读的三个字段:名字、头像、脱敏联系方式。
33
+ * 宿主还会给 `id`,但账号 id 走 {@link HostAccountFace.getPlatformSession} 那条路
34
+ * (它不发起请求),所以这里不声明。
35
+ */
36
+ export type HostAccountProfile = {
37
+ readonly status: 'ready';
38
+ readonly value: {
39
+ readonly name?: string | null;
40
+ readonly avatarUrl?: string | null;
41
+ readonly contact?: string | null;
42
+ };
43
+ } | {
44
+ readonly status: 'failed';
45
+ };
29
46
  /**
30
47
  * 宿主账号服务的最小面。
31
48
  *
32
- * 三个方法的语义逐字对齐宿主 `DeepSeekAccount` 的公开面;`null` 一律表示**此刻没有可用账号**
49
+ * 四个方法的语义逐字对齐宿主 `DeepSeekAccount` 的公开面;`null` 一律表示**此刻没有可用账号**
33
50
  * (未登录,或凭据在查询途中被换掉),不是「余额为零」。
51
+ *
52
+ * **`getProfile` 每次都会真打 Platform**(宿主实现里只有「上一次失败」才用同一 grant 的
53
+ * 缓存兜底),所以调用方必须缓存它的结果 —— 界面渲染一次问一次是不行的。
34
54
  */
35
55
  export interface HostAccountFace {
36
56
  getState(): Promise<{
37
57
  readonly status?: string;
38
58
  } | undefined>;
59
+ getProfile(client: HostAccountClient): Promise<HostAccountProfile | null>;
39
60
  getBalance(client: HostAccountClient): Promise<HostAccountBalance | null>;
40
61
  getPlatformSession(): Promise<{
41
62
  readonly userId?: string | null;
@@ -53,6 +53,19 @@ export function createAccountSource(options) {
53
53
  return null;
54
54
  }
55
55
  },
56
+ async profile() {
57
+ const result = await service.getProfile(client());
58
+ // `null` = 未登录或查询途中换了凭据;`failed` = 上游读不到。
59
+ // 两者在界面上是**同一件事**(「资料暂不可用」),所以都不抛,只回 null。
60
+ if (result === null || result.status !== 'ready')
61
+ return null;
62
+ const { name, avatarUrl, contact } = result.value;
63
+ return {
64
+ name: typeof name === 'string' && name !== '' ? name : null,
65
+ avatarUrl: typeof avatarUrl === 'string' && avatarUrl !== '' ? avatarUrl : null,
66
+ contact: typeof contact === 'string' && contact !== '' ? contact : null,
67
+ };
68
+ },
56
69
  async readBalance() {
57
70
  const result = await service.getBalance(client());
58
71
  if (result === null)
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 服务端盐的读写。
3
3
  *
4
- * `accountTag` 由它派生,所以**它丢了账本就会孤立**:见 docs/backend-architecture.md §19 第 5 条。
4
+ * `accountTag` 由它派生,所以**它丢了账本就会孤立**:见 docs/BACKEND-CONTRACTS.md §19 第 5 条。
5
5
  * 文件权限 0600;路径由组装点用 `@deepseek-ai/dsh-home-paths` 的 `dshHomePath()` 拼出来。
6
6
  * @module dsh-ds-balance/adapters/salt-file
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 服务端盐的读写。
3
3
  *
4
- * `accountTag` 由它派生,所以**它丢了账本就会孤立**:见 docs/backend-architecture.md §19 第 5 条。
4
+ * `accountTag` 由它派生,所以**它丢了账本就会孤立**:见 docs/BACKEND-CONTRACTS.md §19 第 5 条。
5
5
  * 文件权限 0600;路径由组装点用 `@deepseek-ai/dsh-home-paths` 的 `dshHomePath()` 拼出来。
6
6
  * @module dsh-ds-balance/adapters/salt-file
7
7
  */