dsh-usage-state 0.4.2 → 0.4.4
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 +85 -0
- package/README.en.md +47 -15
- package/README.md +48 -16
- package/docs/adapters.md +2 -18
- package/lib/client.js +93 -17
- package/package.json +2 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# 更新日志(Changelog)
|
|
2
|
+
|
|
3
|
+
所有对外可见的变更按版本记录于此。每条决策"为什么改"的来龙去脉见 [`docs/design-changelog.md`](docs/design-changelog.md)(修订记录);发布与验证的操作记录见 [`docs/release.md`](docs/release.md)。
|
|
4
|
+
|
|
5
|
+
格式参照 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/);版本号遵循语义化版本。`0.3.0` 起发布 npm(此前仅 GitHub 安装)。
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
### 0.4.4(待发布)
|
|
10
|
+
|
|
11
|
+
- **纯文档发布**:README 与实际行为对齐(SVG 进度环、输入框上方独立一行、版本清单补全),文档结构重组(架构 / 平台事实 / 发布 / 待办 / 设计修订各自成档);`CHANGELOG.md` 自本版起随包发布。`lib/` 与 0.4.3 逐字节相同,无任何运行时变更。
|
|
12
|
+
|
|
13
|
+
## [0.4.3] - 2026-10-05
|
|
14
|
+
|
|
15
|
+
- **进度显示改为 SVG 圆环**:平台 `ContextMeter` 同款几何(14×14、r=5.5、2px 描边、12 点起弧),替代 `█`/`░` 文字条(其字形回落宽度不可控,见修订 21/23)。阈值变色经 `currentColor` 传导到环上;`display.progressBar` 配置键保留(关掉即隐藏环)。
|
|
16
|
+
- **排版对齐平台统计行**:字号/行高照抄 `StatsPills` 的显式表达式(修订 22)。
|
|
17
|
+
- **折行修复**:分隔符与它引导的段落同盒(`data-usage-part`),折行不再留下孤立的 `·`(修订 21)。
|
|
18
|
+
- 数据模型:`StatusSegment.bar?: string` → `progress?: number`。
|
|
19
|
+
|
|
20
|
+
## [0.4.2] — 2026-10-05
|
|
21
|
+
|
|
22
|
+
- 状态行迁到 **`conversation.input.dock`**(输入框上方、与输入卡片同宽的独立一行,`order: 200`)。0.2 里 `conversation.composer.dock` 是与平台统计、上下文计量器共排的一排 pill,不存在"输入框之下"的整行位置(修订 20)。
|
|
23
|
+
|
|
24
|
+
## [0.4.1] — 2026-10-05
|
|
25
|
+
|
|
26
|
+
- **修复 0.4.0 读数全缺**:客户端 RPC contribution 的参数 codec 缺少 0.2 要求的 `create()` 工厂,`remote.usageState` 从未挂载,界面误报 `Mode not supported`(修订 18)。**0.4.0 用户必须升级。**
|
|
27
|
+
- 挂载失败不再被静默吞掉(`console.error` + 写入 store);catalog 未到时显示"读取中"而不是"模式不支持"。
|
|
28
|
+
- dock 布局适配:与平台 `.pill` 同构,不再挤压/裁切平台统计(修订 19)。
|
|
29
|
+
- 新增**真实 0.2 registry 契约测试**(源码与构建产物各一条,修订 18)。
|
|
30
|
+
|
|
31
|
+
## [0.4.0] — 2026-10-05
|
|
32
|
+
|
|
33
|
+
- **迁移到 DSH 0.2 原生设置模型**:宿主 `Config = z.any().volatile()` + `configForms` + `configEditor`;0.2 删除了 `settingsScope` / `settings.register`,两套 API 无重叠(修订 17)。`engines.dsh` 收紧为 `>=0.2.0-rc.2 <0.3.0-0`;0.1 线用户请停在 `0.3.2`。
|
|
34
|
+
- `peerDependencies` 新增 `@deepseek-ai/dsh-settings`(让 0.1.x 宿主在**安装时**被运行时闸门拒绝,而不是装上后启动崩溃)与 `@deepseek-ai/schemastery`。
|
|
35
|
+
- `cordis.patch.yml` 插入行补 `config: {}`,避免新装实例状态行沉默。
|
|
36
|
+
- ⚠️ 本版有读数缺失缺陷(见 0.4.1)。
|
|
37
|
+
|
|
38
|
+
## [0.3.2] — 2026-09-30
|
|
39
|
+
|
|
40
|
+
- 仅放宽 `engines.dsh` 到 `>=0.1.5-rc.1 <0.3.0-0`;源码与产物零改动(修订 16)。
|
|
41
|
+
- ⚠️ **0.1 线末版**。它声称的 0.2 兼容后来被真机推翻(0.2 删除了 `settingsScope`,装上会让 web 启动失败,修订 17)——0.2 宿主请装 `0.4.x`。
|
|
42
|
+
|
|
43
|
+
## [0.3.1] — 2026-09-22
|
|
44
|
+
|
|
45
|
+
- 移除 `peerDependencies.react`:浏览器半边的 React 由平台运行时注入,不走 node_modules,声明它只会产生 `missing peer` 警告(修订 15)。
|
|
46
|
+
|
|
47
|
+
## [0.3.0] — 2026-09-22
|
|
48
|
+
|
|
49
|
+
- **移除回合行**:账户级读数不能诚实地描述单个回合,`conversation.chat.*` 上的展示整体否决(修订 13;可行性实验见修订 8)。
|
|
50
|
+
- 去掉 `private`,**首次发布 npm** 并被 dsh-market 收录(分类 `usage`,修订 14);`engines.dsh` 随包声明(市场徽标与兼容判定读它)。
|
|
51
|
+
|
|
52
|
+
## [0.2.3] — 2026-09-22
|
|
53
|
+
|
|
54
|
+
- 设置页卡头部改两列网格:provider 名过长时只截断灰色的 id(悬停看全文),`↑ ↓ 模式` 控件永不换行(修订 12)。
|
|
55
|
+
- README 增补对上游 `dsh-cost-meter` 的溯源致谢。
|
|
56
|
+
|
|
57
|
+
## [0.2.2] — 2026-09-21
|
|
58
|
+
|
|
59
|
+
- 三处健壮性修复;不再轮询已删除的 provider。
|
|
60
|
+
|
|
61
|
+
## [0.2.1] — 2026-09-21
|
|
62
|
+
|
|
63
|
+
- 修复"幽灵 provider 行"(已删除的 provider 仍出现在设置页)。
|
|
64
|
+
|
|
65
|
+
## [0.2.0] — 2026-09-21
|
|
66
|
+
|
|
67
|
+
- 新增数据源 **OpenCode Zen Go**(5h / 7d / 30d;修订 11)。通往同一账户的两条 DSH 路由按 `source:mode` 去重,只发一次请求。
|
|
68
|
+
|
|
69
|
+
## [0.1.0] — 2026-09-21
|
|
70
|
+
|
|
71
|
+
- 首版:数据源适配器框架 + DeepSeek / z.ai / Kimi / Sub2API 四家、composer 状态行(余额 / 5h·7d 已用百分比 + 倒计时 + 阈值变色)、设置页(provider 四态 + 排序 + 密钥写入)、凭据探测与直读兜底、Typert RPC 快照通道、中英双语、`node:test` 单测。
|
|
72
|
+
|
|
73
|
+
[Unreleased]: https://github.com/takboo/dsh-usage-state/compare/0.4.3...HEAD
|
|
74
|
+
[0.4.3]: https://github.com/takboo/dsh-usage-state/compare/0.4.2...0.4.3
|
|
75
|
+
[0.4.2]: https://github.com/takboo/dsh-usage-state/compare/0.4.1...0.4.2
|
|
76
|
+
[0.4.1]: https://github.com/takboo/dsh-usage-state/compare/0.4.0...0.4.1
|
|
77
|
+
[0.4.0]: https://github.com/takboo/dsh-usage-state/compare/0.3.2...0.4.0
|
|
78
|
+
[0.3.2]: https://github.com/takboo/dsh-usage-state/compare/0.3.1...0.3.2
|
|
79
|
+
[0.3.1]: https://github.com/takboo/dsh-usage-state/compare/0.3.0...0.3.1
|
|
80
|
+
[0.3.0]: https://github.com/takboo/dsh-usage-state/compare/0.2.3...0.3.0
|
|
81
|
+
[0.2.3]: https://github.com/takboo/dsh-usage-state/compare/0.2.2...0.2.3
|
|
82
|
+
[0.2.2]: https://github.com/takboo/dsh-usage-state/compare/0.2.1...0.2.2
|
|
83
|
+
[0.2.1]: https://github.com/takboo/dsh-usage-state/compare/0.2.0...0.2.1
|
|
84
|
+
[0.2.0]: https://github.com/takboo/dsh-usage-state/compare/0.1.0...0.2.0
|
|
85
|
+
[0.1.0]: https://github.com/takboo/dsh-usage-state/releases/tag/0.1.0
|
package/README.en.md
CHANGED
|
@@ -5,7 +5,7 @@ See your **account balance** or **coding-plan quota** at a glance in [DSH (DeepS
|
|
|
5
5
|
> 中文说明见 [README.md](README.md)。
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
its own line above the composer input: z.ai / GLM · 5h 12% (4h0m)
|
|
8
|
+
its own line above the composer input: z.ai / GLM · ◔ 5h 12% (4h0m) · ◔ 7d 59% (3d17h)
|
|
9
9
|
DeepSeek · ¥58.13
|
|
10
10
|
hover any segment: Source DeepSeek · Mode API balance · Granted 0 · Topped up 58.13
|
|
11
11
|
```
|
|
@@ -23,7 +23,7 @@ hover any segment: Source DeepSeek · Mode API balance · Granted 0 ·
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
25
25
|
**Requirements**: DSH `0.2.0-rc.2` or a later 0.2 release, Node ≥ 20, installed into the `web` profile. The package **ships the prebuilt `lib/`**, so installation has no build step.
|
|
26
|
-
**On the 0.1 line install `0.3.2` instead**: DSH 0.2 replaced the whole settings API (`settingsScope` / `settings.register` → `configForms` / the plugin's own `Config`), and the two share no surface, so `0.4.0` and up support the 0.2 line only (see revision 17 of [`docs/design-
|
|
26
|
+
**On the 0.1 line install `0.3.2` instead**: DSH 0.2 replaced the whole settings API (`settingsScope` / `settings.register` → `configForms` / the plugin's own `Config`), and the two share no surface, so `0.4.0` and up support the 0.2 line only (see revision 17 of [`docs/design-changelog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/design-changelog.md)).
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
# 1) install (npm package)
|
|
@@ -49,7 +49,7 @@ dsh plugin --profile web add /path/to/dsh-usage-state
|
|
|
49
49
|
|
|
50
50
|
It is also listed in [dsh-market](https://github.com/dsh-market/dsh-market): search for `usage state` (or `takboo`) and install it in one click — the plugin is on the [awesome-dsh-plugin](https://awesome-dsh-plugin.com) curated list under Usage & Billing.
|
|
51
51
|
|
|
52
|
-
Nothing showing up after installing? See the troubleshooting table at the end of [`docs/adapters.md`](docs/adapters.md).
|
|
52
|
+
Nothing showing up after installing? See the troubleshooting table at the end of [`docs/adapters.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/adapters.md).
|
|
53
53
|
|
|
54
54
|
## Quick start
|
|
55
55
|
|
|
@@ -63,9 +63,9 @@ A very long provider name never pushes the controls around: the card header stay
|
|
|
63
63
|
|
|
64
64
|
## Screenshots
|
|
65
65
|
|
|
66
|
-
The reading
|
|
66
|
+
The reading on its own line above the composer (shown here with OpenCode Zen Go's three windows; the row under the card is DSH's own statistics, untouched by this plugin — hover any segment for source, mode and the absolute reset time):
|
|
67
67
|
|
|
68
|
-

|
|
69
69
|
|
|
70
70
|
Settings: one row per provider; **Auto** detects the data source and its primary mode:
|
|
71
71
|
|
|
@@ -87,12 +87,14 @@ Expanding **Advanced** lets you override the source and endpoint, name a credent
|
|
|
87
87
|
|
|
88
88
|
- **z.ai is regional**: a coding-plan key only works on its own region (`open.bigmodel.cn` for China, `api.z.ai` globally). China is the default; the other host is tried as a mirror, and you can pin an endpoint in the settings.
|
|
89
89
|
- **OpenCode Zen Go** reads `rolling` / `weekly` / `monthly` from `opencode.ai/zen/go/v1/usage`. Both DSH routes into the same account (built-in `opencode-go` and the custom `opencode-go-deepseek`) produce one reading and one request. A missing subscription or a rejected key is reported as an auth failure, never as 0%.
|
|
90
|
-
- Other vendors (Claude Pro/Max, MiniMax, OpenRouter, Codex, Antigravity, Volcengine Ark, …) are not implemented, but the adapter contract and a candidate list are ready: see [`docs/adapters.md`](docs/adapters.md).
|
|
90
|
+
- Other vendors (Claude Pro/Max, MiniMax, OpenRouter, Codex, Antigravity, Volcengine Ark, …) are not implemented, but the adapter contract and a candidate list are ready: see [`docs/adapters.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/adapters.md).
|
|
91
91
|
|
|
92
92
|
## Display, refresh, credentials
|
|
93
93
|
|
|
94
|
-
- **Placement**:
|
|
95
|
-
- **Elements**: provider label · balance + currency · each window (5h / 7d / 30d) used %
|
|
94
|
+
- **Placement**: its own full-width line **above** the composer input, as wide as the input card (the `conversation.input.dock` slot on DSH 0.2). The line is always visible — it never depends on hover or a click — and wraps between segments on narrow windows instead of clipping.
|
|
95
|
+
- **Elements**: provider label · balance + currency · each window (5h / 7d / 30d): an SVG progress ring + used % + reset countdown · threshold colours (defaults: amber ≥80%, red ≥95%, configurable; the colour applies to the whole segment and carries into the ring).
|
|
96
|
+
|
|
97
|
+
The ring copies the geometry of the platform's own context meter (a 14×14 circle whose arc starts at twelve o'clock), replacing the earlier `█`/`░` text bar — a vector shape has no glyph metrics, so it cannot be inflated by font fallback; it can be turned off in the settings.
|
|
96
98
|
- **Semantics**: percentages are always *used*; balances only appear in API mode, and coding-plan mode shows the windows the source actually has (5h / 7d for z.ai and Sub2API, plus 30d for OpenCode Zen Go); a stale reading shows its age instead of hiding.
|
|
97
99
|
- **Refresh**: 2s after a turn ends, plus a 5-minute idle fallback; at most one real request per source per 60s, in-flight calls are shared, failures are not throttled.
|
|
98
100
|
- **Credentials**: override → the provider's declared `apiKeyEnv` → the source's built-in ref → DSH credential store. Keys are written to `~/.dsh/.credentials.yaml`; **this plugin never stores a plaintext key** and the browser never receives a key value.
|
|
@@ -101,18 +103,21 @@ Expanding **Advanced** lets you override the source and endpoint, name a credent
|
|
|
101
103
|
|
|
102
104
|
- **0.2 line only**: `engines.dsh` = `>=0.2.0-rc.2 <0.3.0-0` (this is what dsh-market's badge and install gate read). On an earlier host, install `0.3.2`.
|
|
103
105
|
- `peerDependencies` carry `@deepseek-ai/dsh-settings` (`^0.2.0-rc.2`) and `@deepseek-ai/schemastery` (`^3.18.2`). The first one is deliberate: the runtime install gate only reads `@deepseek-ai/dsh*` peers, so declaring it makes a 0.1.x host **refuse the install** instead of accepting it and then failing to boot. Both are platform-provided; pnpm may print a `missing peer` warning for them, which is expected.
|
|
106
|
+
- Version `0.4.4`: docs-only release — the README matches actual behaviour and `CHANGELOG.md` ships with the package; `lib/` is byte-identical to `0.4.3`.
|
|
107
|
+
- Version `0.4.3`: progress becomes the **platform-style SVG ring** (replacing the `█`/`░` text bar, with threshold colours carried onto the ring), typography copied from the platform stats row, and wraps no longer leave an orphaned `·` (revisions 21–23).
|
|
104
108
|
- Version `0.4.2` moves the status line to `conversation.input.dock`, giving it **its own line above the composer input** — DSH 0.2 turned the old below-the-input position into a shared row of pills next to the platform's stats and context meter (revisions 19/20).
|
|
105
109
|
- Version `0.4.1` fixes `0.4.0`'s missing readings: the browser half's RPC contribution lacked the `create()` factory 0.2 requires, so `remote.usageState` never mounted — the UI showed **no readings at all** and mislabelled the cause as `Mode not supported`. The same release stops swallowing a rejected mount, says "reading" while the catalog is absent, and adds **real 0.2 registry contract tests** (revision 18). **Use `0.4.1`, not `0.4.0`.**
|
|
106
|
-
- Version `0.4.0` migrates to the 0.2 settings model (`Config` + `configForms`, with cross-entry config read through `configEditor`).
|
|
110
|
+
- Version `0.4.0` migrates to the 0.2 settings model (`Config` + `configForms`, with cross-entry config read through `configEditor`). Changes: [CHANGELOG](CHANGELOG.md); verification: [`docs/release.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/release.md); rationale: [`docs/design-changelog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/design-changelog.md) revision 17.
|
|
107
111
|
- Version `0.3.2` (last of the 0.1 line) only widened `engines.dsh`; **its claimed 0.2 compatibility was wrong** — on `0.2.0-rc.2` it fails the entire web boot because `settingsScope` does not exist there.
|
|
108
112
|
- Published to npm as [`dsh-usage-state`](https://www.npmjs.com/package/dsh-usage-state); GitHub installs work too.
|
|
109
113
|
|
|
110
114
|
## Limitations
|
|
111
115
|
|
|
112
116
|
- **Kimi and Sub2API are not verified against live accounts yet** (no credentials on the author's machine); their `/v1/usage` style endpoints are undocumented and parsed defensively.
|
|
117
|
+
- **The threshold colours (amber/red) have no real-machine sample yet**: implemented and pinned by tests, but live readings have stayed below the thresholds; set the amber threshold to 10 temporarily to see them.
|
|
113
118
|
- **Clicking the line does not open settings** (the platform exposes no public "open settings panel" service); details are in the hover tooltip.
|
|
114
119
|
- **Current reading only**: the line reports the account's latest value. The plugin keeps no per-turn and no per-time history, so scrolling back through old turns shows no "balance at that moment". Account history, if ever added, would be keyed by time rather than by turn — a separate decision.
|
|
115
|
-
- Full list: [`docs/
|
|
120
|
+
- Full list: [`docs/backlog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/backlog.md).
|
|
116
121
|
|
|
117
122
|
## Development
|
|
118
123
|
|
|
@@ -124,21 +129,48 @@ npm run build # tsdown → lib/ (host index.js + typert.js, browser clien
|
|
|
124
129
|
npm run watch # rebuilds client.js only; client changes hot-reload, no page refresh
|
|
125
130
|
```
|
|
126
131
|
|
|
132
|
+
**Local loop (no release needed)**: `scripts/dev-local.sh` creates a throwaway profile under `/tmp/dsh-dev` (override with `DSH_HOME`), installs this repository into it as a `link:` and boots a host on its own port with the Desktop app's bundled CLI. Your real profiles are never touched.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npm run build # lib/ must exist
|
|
136
|
+
scripts/dev-local.sh # creates/reuses the dev profile, prints the token URL
|
|
137
|
+
# second terminal:
|
|
138
|
+
npm run watch # rebuilds client.js on save
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Because the profile links this working tree, a rebuild is picked up by the running host: client changes are hot-swapped by `dsh-client-hmr` (the host stat-polls every bundle at 500ms and tells the browser to reload the module over `/plugins/events`) — no restart, no release. Host-side changes (`src/host/**`, `src/index.ts`, `cordis.patch.yml`) need this script restarted.
|
|
142
|
+
|
|
143
|
+
⚠️ **This profile has no credentials**: `$DSH_HOME/.credentials.yaml` is home-level, and a fresh home starts without keys and without your other plugins (a font plugin changes the very glyph metrics a layout depends on). It is for **structural / host-side** checks only. To judge how something *looks*, install the same build into a profile that already has your keys and plugins — still without publishing:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npm pack --pack-destination /tmp --cache /tmp/npm-cache
|
|
147
|
+
dsh plugin --profile web add /tmp/dsh-usage-state-<version>.tgz # file: install
|
|
148
|
+
dsh plugin --profile web add "$PWD" # link: install, for hot reload
|
|
149
|
+
dsh plugin --profile web add dsh-usage-state@<published> # back to the published build
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Bump the version and publish only after you have **seen** the change work.
|
|
153
|
+
|
|
127
154
|
Host-side changes need a DSH restart; client-side changes do not. The `lib/` output is **committed on purpose**: `dsh plugin add github:...` installs straight from the repository with no build step, and `npm test` guards the bundle envelope, the require allow-list and the `exports` targets.
|
|
128
155
|
|
|
129
156
|
## Docs
|
|
130
157
|
|
|
131
158
|
| Document | Contents |
|
|
132
159
|
|---|---|
|
|
133
|
-
| [
|
|
134
|
-
| [`docs/
|
|
135
|
-
| [`docs/
|
|
136
|
-
| [`docs/
|
|
160
|
+
| [CHANGELOG](CHANGELOG.md) | Changes per version |
|
|
161
|
+
| [`docs/architecture.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/architecture.md) | Code map, decision → code → test → verification traceability (Chinese) |
|
|
162
|
+
| [`docs/adapters.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/adapters.md) | Adding a data source: contract, workflow, pitfalls, troubleshooting (Chinese) |
|
|
163
|
+
| [`docs/design-consensus.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/design-consensus.md) | The design as it currently stands (Chinese) |
|
|
164
|
+
| [`docs/design-changelog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/design-changelog.md) | Design revision log: every decision change with its reasoning (Chinese) |
|
|
165
|
+
| [`docs/release.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/release.md) | Release process, end-to-end verification, acceptance checklist, market listing (Chinese) |
|
|
166
|
+
| [`docs/platform-notes.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/platform-notes.md) | Measured facts about DSH platform behaviour (Chinese) |
|
|
167
|
+
| [`docs/backlog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/backlog.md) | Backlog, candidate data sources, explicit non-goals (Chinese) |
|
|
168
|
+
| [`docs/research/README.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/research/README.md) | Read-only research index (vendor APIs, the replaced plugin, DSH RPC contract) |
|
|
137
169
|
|
|
138
170
|
## Acknowledgements
|
|
139
171
|
|
|
140
172
|
- **[`dsh-cost-meter`](https://github.com/Han-1413141/dsh-cost-meter)** by Han-1413141 (MIT): this plugin is a **simplified replacement** for it. It keeps the "show me my balance / coding-plan quota" need and drops everything else — cost accounting, pricing catalog, history, budgets, peak/off-peak alerts.
|
|
141
|
-
The data-source endpoints, the meaning of the response fields and several compatibility pitfalls (OpenCode Zen Go needs a browser UA, z.ai reports auth failure as HTTP 200 + `{success:false}`, the legacy `coding_plan/usage` fallback, sub2api's `rate_limits[]` shape, …) come from a **read-only analysis** of `dsh-cost-meter@1.7.28`, recorded in [`docs/research/dsh-cost-meter-analysis.md`](docs/research/dsh-cost-meter-analysis.md). The implementation here is independently written TypeScript rather than copied source, but those behaviours are upstream's work and credit belongs there.
|
|
173
|
+
The data-source endpoints, the meaning of the response fields and several compatibility pitfalls (OpenCode Zen Go needs a browser UA, z.ai reports auth failure as HTTP 200 + `{success:false}`, the legacy `coding_plan/usage` fallback, sub2api's `rate_limits[]` shape, …) come from a **read-only analysis** of `dsh-cost-meter@1.7.28`, recorded in [`docs/research/dsh-cost-meter-analysis.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/research/dsh-cost-meter-analysis.md). The implementation here is independently written TypeScript rather than copied source, but those behaviours are upstream's work and credit belongs there.
|
|
142
174
|
If the upstream author wants a clearer attribution or a different arrangement, open an issue and it will be fixed.
|
|
143
175
|
- **[DSH (DeepSeek Harness)](https://github.com/deepseek-ai)**: the host platform. The plugin relies on its settings namespace, credential store, Typert RPC, slot system and UI primitives (`@deepseek-ai/dsh-client-ui-primitives` and friends).
|
|
144
176
|
|
package/README.md
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
在 [DSH(DeepSeek Harness)](https://github.com/deepseek-ai) 里一眼看到你的**账户余额**或**套餐额度**——就在输入框上方、与输入卡片同宽的一行(原生统计行与其弹窗原样保留、不做替换)。
|
|
6
6
|
|
|
7
|
-
> A minimal DSH plugin that shows your account **balance** (API mode) or **coding-plan quota** (5h / 7d / 30d) for the model you are using, right
|
|
7
|
+
> A minimal DSH plugin that shows your account **balance** (API mode) or **coding-plan quota** (5h / 7d / 30d) for the model you are using, on its own line right above the composer input.
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
输入框上方独立一行: z.ai / GLM · 5h 12% (4h0m)
|
|
10
|
+
输入框上方独立一行: z.ai / GLM · ◔ 5h 12% (4h0m) · ◔ 7d 59% (3d17h)
|
|
11
11
|
DeepSeek · ¥58.13
|
|
12
12
|
悬停任意一段: Source DeepSeek · Mode API balance · Granted 0 · Topped up 58.13
|
|
13
13
|
```
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
## 安装
|
|
26
26
|
|
|
27
27
|
**前置条件**:DSH `0.2.0-rc.2` 或更新的 0.2 线、Node ≥ 20,装进 `web` profile。包内**自带预构建的 `lib/`**,安装时没有构建步骤。
|
|
28
|
-
**用 0.1 线请装 `0.3.2`**:DSH 0.2 换掉了整套设置 API(`settingsScope` / `settings.register` → `configForms` / 插件自带 `Config`),两套 API 没有重叠,所以 `0.4.0` 起只支持 0.2 线(原因见 [`docs/design-
|
|
28
|
+
**用 0.1 线请装 `0.3.2`**:DSH 0.2 换掉了整套设置 API(`settingsScope` / `settings.register` → `configForms` / 插件自带 `Config`),两套 API 没有重叠,所以 `0.4.0` 起只支持 0.2 线(原因见 [`docs/design-changelog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/design-changelog.md) 修订 17)。
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
31
|
# 1) 安装(npm 包)
|
|
@@ -51,7 +51,7 @@ dsh plugin --profile web add /path/to/dsh-usage-state
|
|
|
51
51
|
|
|
52
52
|
也可以在 [dsh-market](https://github.com/dsh-market/dsh-market) 里搜索 `usage state`(或 `takboo`)一键安装——本插件已收录在精选列表 [awesome-dsh-plugin](https://awesome-dsh-plugin.com) 的「用量与计费」分类。
|
|
53
53
|
|
|
54
|
-
装好后界面没有出现?见 [`docs/adapters.md`](docs/adapters.md) 末尾的排查表。
|
|
54
|
+
装好后界面没有出现?见 [`docs/adapters.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/adapters.md) 末尾的排查表。
|
|
55
55
|
|
|
56
56
|
## 快速开始
|
|
57
57
|
|
|
@@ -65,9 +65,9 @@ dsh plugin --profile web add /path/to/dsh-usage-state
|
|
|
65
65
|
|
|
66
66
|
## 截图
|
|
67
67
|
|
|
68
|
-
输入框上方独占一行的账户读数(图示为 OpenCode Zen Go
|
|
68
|
+
输入框上方独占一行的账户读数(图示为 OpenCode Zen Go 的三个窗口;卡片下方那排是 DSH 原生统计,两者互不干扰。悬停任意一段可看数据源、模式与绝对重置时刻):
|
|
69
69
|
|
|
70
|
-

|
|
71
71
|
|
|
72
72
|
设置页:每个 provider 一行,默认「自动」会识别数据源与主模式:
|
|
73
73
|
|
|
@@ -89,13 +89,15 @@ dsh plugin --profile web add /path/to/dsh-usage-state
|
|
|
89
89
|
|
|
90
90
|
- **z.ai 分区域**:coding plan 的 key 只在自己区域的站点有效(国内 `open.bigmodel.cn` / 国际 `api.z.ai`)。默认国内站,失败时自动镜像重试;也可在设置里钉死端点。
|
|
91
91
|
- **OpenCode Zen Go**:读 `opencode.ai/zen/go/v1/usage` 的 `rolling` / `weekly` / `monthly`;通往同一账户的两条 DSH 路由(内置 `opencode-go` 与自定义 `opencode-go-deepseek`)只产生一个读数、只发一次请求。无订阅或密钥无效时报鉴权失败,而非 0%。
|
|
92
|
-
- **其他厂商**(Claude Pro/Max、MiniMax、OpenRouter、Codex、Antigravity、Volcengine Ark…)未实现,但适配器契约与候选清单已备好,见 [`docs/adapters.md`](docs/adapters.md)。
|
|
92
|
+
- **其他厂商**(Claude Pro/Max、MiniMax、OpenRouter、Codex、Antigravity、Volcengine Ark…)未实现,但适配器契约与候选清单已备好,见 [`docs/adapters.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/adapters.md)。
|
|
93
93
|
|
|
94
94
|
## 显示与交互
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
**位置**:输入框**上方**、与输入卡片同宽的独立一行(DSH 0.2 的 `conversation.input.dock` 槽位)。读数**始终可见**,不依赖悬停,也不需要点击;窗口过窄时在段与段之间折行,不会裁切。
|
|
97
97
|
|
|
98
|
-
**元素**:供应商标签 · 余额金额 + 币种 · 各窗口(5h / 7d / 30d
|
|
98
|
+
**元素**:供应商标签 · 余额金额 + 币种 · 各窗口(5h / 7d / 30d):SVG 进度环 + 已用百分比 + 重置倒计时 · 阈值变色(默认 ≥80% 琥珀、≥95% 红,可在设置里改;颜色作用于整段并传导到圆环)。
|
|
99
|
+
|
|
100
|
+
进度环取平台上下文计量器(`ContextMeter`)同款几何(14×14 圆环、弧从 12 点开始),替代早期的 `█`/`░` 文字条——矢量没有字形度量,不会因字体回落而撑爆排版;设置里可整体关闭。
|
|
99
101
|
|
|
100
102
|
**口径**:百分比一律是**已用**(与 z.ai / Claude 官方一致);API 模式显示余额,Coding Plan 模式显示该数据源实际提供的窗口(z.ai 与 Sub2API 是 5h / 7d,OpenCode Zen Go 多一个 30d)。
|
|
101
103
|
|
|
@@ -125,18 +127,21 @@ dsh plugin --profile web add /path/to/dsh-usage-state
|
|
|
125
127
|
|
|
126
128
|
- **只支持 DSH 0.2 线**:`engines.dsh` = `>=0.2.0-rc.2 <0.3.0-0`(市场读它做徽标与"可安装"判定)。0.2 之前的宿主请装 `0.3.2`。
|
|
127
129
|
- `peerDependencies` 里有 `@deepseek-ai/dsh-settings`(`^0.2.0-rc.2`)与 `@deepseek-ai/schemastery`(`^3.18.2`):前者是**故意的**——平台的运行时安装闸门只读 `@deepseek-ai/dsh*` 的 peer,声明它可以让 0.1.x 宿主在**安装时**就拒绝,而不是装上之后把启动搞崩;两者都由平台提供,pnpm 可能为此打一行 `missing peer` 警告,属预期。
|
|
130
|
+
- 版本 `0.4.4`:纯文档发布——README 与实际行为对齐、`CHANGELOG.md` 随包发布;`lib/` 与 `0.4.3` 逐字节相同。
|
|
131
|
+
- 版本 `0.4.3`:进度显示改为**平台同款 SVG 圆环**(替代 `█`/`░` 文字条,阈值变色经颜色传导到环上)、排版照抄平台统计行字号、折行不再留下孤立的 `·`(修订 21–23)。
|
|
128
132
|
- 版本 `0.4.2`:状态行迁到 `conversation.input.dock`,成为**输入框上方的独立一行**(0.1 时代它在输入框之下,而 0.2 把那个位置改成了与平台统计、上下文计量器共排的一排 pill——见修订 19/20)。
|
|
129
133
|
- 版本 `0.4.1`:修 `0.4.0` 的读数缺失——客户端 RPC contribution 的参数 codec 少了 0.2 要求的 `create()`,`remote.usageState` 因此从未挂载,界面表现为**没有任何读数**并误报 `Mode not supported`。同一轮还让挂载失败不再被静默吞掉、catalog 未到时改说「读取中」,并把**真实 0.2 registry 契约测试**写进单测(修订 18)。**请用 `0.4.1`,不要用 `0.4.0`。**
|
|
130
|
-
- 版本 `0.4.0`:迁到 0.2 原生设置模型(`Config` + `configForms`,宿主侧 `configEditor`
|
|
134
|
+
- 版本 `0.4.0`:迁到 0.2 原生设置模型(`Config` + `configForms`,宿主侧 `configEditor` 读跨条目配置)。变更明细见 [CHANGELOG](CHANGELOG.md),验证方式与结论见 [`docs/release.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/release.md)、决策见 [`docs/design-changelog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/design-changelog.md) 修订 17。
|
|
131
135
|
- 版本 `0.3.2`(0.1 线末版):仅放宽 `engines.dsh`;**它声称的 0.2 兼容是错的**(0.3.2 在 0.2.0-rc.2 上会因 `settingsScope` 不存在而让整个 web 启动失败)。
|
|
132
136
|
- 同名发布在 npm([`dsh-usage-state`](https://www.npmjs.com/package/dsh-usage-state)),也可从 GitHub 直接安装。
|
|
133
137
|
|
|
134
138
|
## 已知限制
|
|
135
139
|
|
|
136
140
|
- **Kimi、Sub2API 未经真机验证**(本机无凭据),代码与单测已就绪;Sub2API 的 `/v1/usage` 属未文档化接口,已按易错接口做容错。
|
|
141
|
+
- **阈值变色(琥珀/红)尚无真机视觉样本**:代码已实现且被单测钉住,但真机读数长期低于阈值;把设置里黄色阈值临时改成 10 即可确认。
|
|
137
142
|
- **点击状态行不会打开设置**(客户端没有公开的"打开设置面板"服务);细节通过悬浮提示呈现。
|
|
138
143
|
- **只在输入框上方展示,不覆盖历史**:状态行给出的是账户**当前**读数;插件不按回合、也不按时间保存历史读数,因此翻看旧回合时看不到"当时的余额"。若将来要做,会是以时间轴(而不是回合)为口径的单独决定。
|
|
139
|
-
- 完整清单见 [`docs/
|
|
144
|
+
- 完整清单见 [`docs/backlog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/backlog.md)。
|
|
140
145
|
|
|
141
146
|
## 开发
|
|
142
147
|
|
|
@@ -148,6 +153,28 @@ npm run build # tsdown → lib/(宿主 index.js + typert.js,浏览器
|
|
|
148
153
|
npm run watch # 只重建 client.js;客户端会被 HMR 热替换,无需刷新页面
|
|
149
154
|
```
|
|
150
155
|
|
|
156
|
+
**本地回路(不需要发版)**:`scripts/dev-local.sh` 会在 `/tmp/dsh-dev` 建一个**一次性 profile**,把本仓库以 `link:` 装进去并起一个独立端口的宿主;你的真实 profile 完全不受影响。
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm run build # 先有 lib/
|
|
160
|
+
scripts/dev-local.sh # 建/复用 dev profile + 起宿主,打印带 token 的 URL
|
|
161
|
+
# 另一个终端:
|
|
162
|
+
npm run watch # 保存即重建 client.js
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
客户端改动由 `dsh-client-hmr` 热替换(宿主每 500ms 轮询 bundle,经 `/plugins/events` 通知浏览器重载模块)——**不用重启、不用发版**;宿主改动(`src/host/**`、`src/index.ts`、`cordis.patch.yml`)需要重启该脚本。
|
|
166
|
+
|
|
167
|
+
⚠️ **这个 profile 没有凭据**:`$DSH_HOME/.credentials.yaml` 是 home 级的,全新 home 里没有 key,也没有你其它插件(**字体插件会改变排版所依赖的字形度量**)。所以它只适合**结构/宿主侧**核对。要看**实际观感**,把同一份构建装进已有 key 与插件的 profile,同样不用发版:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npm pack --pack-destination /tmp --cache /tmp/npm-cache
|
|
171
|
+
dsh plugin --profile web add /tmp/dsh-usage-state-<version>.tgz # file: 安装
|
|
172
|
+
dsh plugin --profile web add "$PWD" # 想热迭代就用 link:
|
|
173
|
+
dsh plugin --profile web add dsh-usage-state@<已发布版本> # 回到线上版本
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
只有当你**亲眼确认**改动可用之后,才值得动版本号与 npm 发布。
|
|
177
|
+
|
|
151
178
|
宿主机改动需要重启 DSH;客户端改动 `npm run watch` 即可。`lib/` 产物**必须提交进仓库**——`dsh plugin add github:...` 直接装仓库、没有构建步骤(`npm test` 里的构建守卫会检查信封、require 白名单与 `exports` 指向)。
|
|
152
179
|
|
|
153
180
|
```
|
|
@@ -162,15 +189,20 @@ tests/ 与 src 对应;tests/build 校验的是产物本身
|
|
|
162
189
|
|
|
163
190
|
| 文档 | 内容 |
|
|
164
191
|
|---|---|
|
|
165
|
-
| [
|
|
166
|
-
| [`docs/
|
|
167
|
-
| [`docs/
|
|
168
|
-
| [`docs/
|
|
192
|
+
| [CHANGELOG](CHANGELOG.md) | 按版本的变更记录 |
|
|
193
|
+
| [`docs/architecture.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/architecture.md) | 代码地图、决策→实现→测试→验证追溯 |
|
|
194
|
+
| [`docs/adapters.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/adapters.md) | 添加数据源:契约、四步流程、约定与坑、排查表 |
|
|
195
|
+
| [`docs/design-consensus.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/design-consensus.md) | 当前有效的设计共识 |
|
|
196
|
+
| [`docs/design-changelog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/design-changelog.md) | 设计修订记录(每条决策变更的来龙去脉) |
|
|
197
|
+
| [`docs/release.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/release.md) | 发布流程、端到端验证、人工验收清单、市场收录 |
|
|
198
|
+
| [`docs/platform-notes.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/platform-notes.md) | DSH 平台行为的实测事实 |
|
|
199
|
+
| [`docs/backlog.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/backlog.md) | 待办、候选数据源、明确不做的否决护栏 |
|
|
200
|
+
| [`docs/research/README.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/research/README.md) | 只读侦察报告索引(各厂商接口、被替代插件剖析、DSH RPC 契约) |
|
|
169
201
|
|
|
170
202
|
## 致谢与参考
|
|
171
203
|
|
|
172
204
|
- **[`dsh-cost-meter`](https://github.com/Han-1413141/dsh-cost-meter)**(作者 Han-1413141,MIT 许可):本插件是它的**简化替代品**——只保留「看余额 / 看 Coding Plan 额度」这个展示需求,砍掉计费、价格目录、历史账单、预算与峰谷提醒等全部逻辑(见上面的「只做显示」)。
|
|
173
|
-
数据源端点、响应字段语义与若干兼容陷阱(OpenCode Zen Go 必须带浏览器 UA、z.ai 用 HTTP 200 + `{success:false}` 表达鉴权失败、旧 `coding_plan/usage` 兜底路径、sub2api 的 `rate_limits[]` 形态等)来自对 `dsh-cost-meter@1.7.28` 的**只读分析**,记录见 [`docs/research/dsh-cost-meter-analysis.md`](docs/research/dsh-cost-meter-analysis.md)。本仓库的实现是独立编写的 TypeScript,不是对其源码的照搬;但那些行为语义确实源自上述分析,应归功于上游。
|
|
205
|
+
数据源端点、响应字段语义与若干兼容陷阱(OpenCode Zen Go 必须带浏览器 UA、z.ai 用 HTTP 200 + `{success:false}` 表达鉴权失败、旧 `coding_plan/usage` 兜底路径、sub2api 的 `rate_limits[]` 形态等)来自对 `dsh-cost-meter@1.7.28` 的**只读分析**,记录见 [`docs/research/dsh-cost-meter-analysis.md`](https://github.com/takboo/dsh-usage-state/blob/main/docs/research/dsh-cost-meter-analysis.md)。本仓库的实现是独立编写的 TypeScript,不是对其源码的照搬;但那些行为语义确实源自上述分析,应归功于上游。
|
|
174
206
|
若上游作者认为某处需要更明确的署名或授权,请提 issue,我会立刻调整。
|
|
175
207
|
- **[DSH(DeepSeek Harness)](https://github.com/deepseek-ai)**:宿主平台。插件使用它的设置命名空间、凭据库、Typert RPC、插槽系统与 UI 原语(`@deepseek-ai/dsh-client-ui-primitives` 等)。
|
|
176
208
|
|
package/docs/adapters.md
CHANGED
|
@@ -68,25 +68,9 @@ export interface UsageSource {
|
|
|
68
68
|
| OpenCode Zen Go | Coding Plan | `GET https://opencode.ai/zen/go/v1/usage` | **必须带浏览器 UA**(否则 Cloudflare error 1010 → 403,实测)。根对象是 `usage.{rolling,weekly,monthly}`(文档写作 `data.usage`,两种都接受),字段 `percent` 已是 0..100 已用百分比(用 `clampPercent`,**不要**用 `normalizePercent`,否则 `1` 会变成 100%),`resetsAt` 是 ISO 串。窗口名 `rolling/weekly/monthly` → 规范键 `5h/7d/30d`。401/403 = 无订阅或密钥无效(**不是** 0%)。`resolveProvider` 会把 provider 声明的 `baseURL` 归一成 origin、`normalizeBaseUrl` 会剥掉尾部 `/vN`,所以请求前还要再剥掉 `/zen/go` 尾段,否则出现 `/zen/go/zen/go/v1/usage` |
|
|
69
69
|
| Sub2API(自建) | API + Coding Plan | `GET {base}/v1/usage` | 未文档化的内部接口,字段曾出现前后端漂移;所有字段可选、未知结构降级。一个接口覆盖两种模式:`quota.remaining` 或钱包 `balance` 视为 USD 余额,`rate_limits[]` 的 `window` 直接是 `5h`/`1d`/`7d`(美元计价,百分比自算 `used/limit`)。`requiresBaseUrl: true` |
|
|
70
70
|
|
|
71
|
-
##
|
|
71
|
+
## 候选数据源
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
| 厂商 | 端点 | 为什么还没做 |
|
|
76
|
-
|---|---|---|
|
|
77
|
-
| Anthropic Claude Pro/Max | `GET https://api.anthropic.com/api/oauth/usage` | 必须 OAuth 访问令牌(`user:profile`),普通 API key 无法调用;需要新增 OAuth 凭据的存取通道。返回 `five_hour` / `seven_day` 的 `utilization` + `resets_at`,是最标准的 5h/7d 形态 |
|
|
78
|
-
| Codex / ChatGPT 订阅 | `GET https://chatgpt.com/backend-api/wham/usage` | 需要 ChatGPT OAuth;`rate_limit.primary_window`(18000s)与 `secondary_window`(604800s) |
|
|
79
|
-
| MiniMax Token Plan | `GET https://www.minimaxi.com/v1/token_plan/remains` | 纯 API key,**可以**按本模板实现:`current_interval_remaining_percent` / `current_weekly_remaining_percent`(注意是"剩余",要反转) |
|
|
80
|
-
| Kimi Code 国际版 | `GET https://api.kimi.com/coding/v1/usages` | 与已实现的国内版同端点,无需新增 |
|
|
81
|
-
| OpenRouter | `GET {base}/api/v1/credits`、`/api/v1/key` | 余额接口按官方 OpenAPI 需要 management key;`/key` 的 `limit_remaining/limit` 可换算已用 %,但无 5h/7d 概念 |
|
|
82
|
-
| SiliconFlow | `GET https://api.siliconflow.cn/v1/user/info` | 纯 CNY 余额,可照模板实现 |
|
|
83
|
-
| CommandCode | `GET https://api.commandcode.ai/alpha/billing/credits` | 返回 `windowLimits.{fiveHour,weekly}.{used,cap,resetAt}`,形态与我们的窗口模型几乎一致 |
|
|
84
|
-
| Volcengine Ark Coding Plan | `open.volcengineapi.com` 控制面 | 需要 AK/SK HMAC 签名,凭据形态超出 v1 |
|
|
85
|
-
| Gemini Code Assist / Antigravity | 私有端点 / 本地语言服务 | OAuth 或本地进程通信,且 Google 已关闭个人版 CLI OAuth |
|
|
86
|
-
|
|
87
|
-
> OpenCode Zen 已实现(见上表),不再是候选;它只差一个 `user-agent` 就能直连,不需要 OAuth。
|
|
88
|
-
|
|
89
|
-
**优先级建议**:MiniMax → CommandCode → SiliconFlow(都是纯 API key、返回结构简单),再考虑为 Anthropic / Codex 增加 OAuth 凭据通道。
|
|
73
|
+
以下接口已侦察确认存在但**尚未实现**——候选清单、各家的"为什么还没做"与优先级建议统一维护在 [`backlog.md`](backlog.md) §3,此处不重复。新增适配器前先读它,再回到上面的「加一个适配器的步骤」。
|
|
90
74
|
|
|
91
75
|
## 排查
|
|
92
76
|
|
package/lib/client.js
CHANGED
|
@@ -1056,7 +1056,6 @@ window.__ModuleLoader__.load({
|
|
|
1056
1056
|
CNY: "¥",
|
|
1057
1057
|
USD: "$"
|
|
1058
1058
|
};
|
|
1059
|
-
const PROGRESS_WIDTH = 8;
|
|
1060
1059
|
/** `¥66.28`, `$6.80`, `EUR 1.50`; an unknown code keeps its numeric form. */
|
|
1061
1060
|
function formatBalance(balance) {
|
|
1062
1061
|
const amount = balance.amount.toFixed(2);
|
|
@@ -1088,10 +1087,6 @@ window.__ModuleLoader__.load({
|
|
|
1088
1087
|
const minutes = Math.floor(seconds / 60);
|
|
1089
1088
|
return minutes >= 1 ? `${minutes}m` : `${seconds}s`;
|
|
1090
1089
|
}
|
|
1091
|
-
function progressBar(percent, width = PROGRESS_WIDTH) {
|
|
1092
|
-
const filled = Math.min(width, Math.max(0, Math.round(percent / 100 * width)));
|
|
1093
|
-
return "█".repeat(filled) + "░".repeat(width - filled);
|
|
1094
|
-
}
|
|
1095
1090
|
function severityOf(usedPercent, display) {
|
|
1096
1091
|
if (usedPercent >= display.thresholdCriticalPercent) return "critical";
|
|
1097
1092
|
if (usedPercent >= display.thresholdWarnPercent) return "warn";
|
|
@@ -1162,7 +1157,7 @@ window.__ModuleLoader__.load({
|
|
|
1162
1157
|
severity: severityOf(window.usedPercent, display)
|
|
1163
1158
|
};
|
|
1164
1159
|
if (window.resetsAt !== void 0 && window.resetsAt > now) segment.resetsAt = window.resetsAt;
|
|
1165
|
-
if (display.progressBar) segment.
|
|
1160
|
+
if (display.progressBar) segment.progress = Math.min(100, Math.max(0, window.usedPercent));
|
|
1166
1161
|
segments.push(segment);
|
|
1167
1162
|
}
|
|
1168
1163
|
return segments;
|
|
@@ -1245,7 +1240,7 @@ window.__ModuleLoader__.load({
|
|
|
1245
1240
|
percent: segment.percent,
|
|
1246
1241
|
severity: segment.severity,
|
|
1247
1242
|
...countdown === void 0 ? {} : { countdown },
|
|
1248
|
-
...segment.
|
|
1243
|
+
...segment.progress === void 0 ? {} : { progress: segment.progress },
|
|
1249
1244
|
...tooltipOf([resetHint, context]) === void 0 ? {} : { tooltip: tooltipOf([resetHint, context]) }
|
|
1250
1245
|
});
|
|
1251
1246
|
break;
|
|
@@ -1283,8 +1278,21 @@ window.__ModuleLoader__.load({
|
|
|
1283
1278
|
alignItems: "center",
|
|
1284
1279
|
justifyContent: "center",
|
|
1285
1280
|
gap: "6px",
|
|
1286
|
-
|
|
1287
|
-
|
|
1281
|
+
/**
|
|
1282
|
+
* Exactly the typography the platform's own stats row uses under the card
|
|
1283
|
+
* (`StatsPills.module.css`, `.root`), copied expression for expression:
|
|
1284
|
+
*
|
|
1285
|
+
* font-size: calc(var(--dsh-content-font-size-secondary, 13px) - 1px)
|
|
1286
|
+
* line-height: calc(20px + var(--dsh-content-font-delta-secondary, 0px))
|
|
1287
|
+
*
|
|
1288
|
+
* `font: inherit` looked right in the dock row (the platform's pills inherit there)
|
|
1289
|
+
* but not above the card: this element is a child of `.composerStack`, so it
|
|
1290
|
+
* inherited the *input card's* `--dsh-content-font-size` (14px) and rendered a size
|
|
1291
|
+
* larger than the row below it. Font family is deliberately left alone, so a
|
|
1292
|
+
* UI-font plugin still applies.
|
|
1293
|
+
*/
|
|
1294
|
+
fontSize: "calc(var(--dsh-content-font-size-secondary, 13px) - 1px)",
|
|
1295
|
+
lineHeight: "calc(20px + var(--dsh-content-font-delta-secondary, 0px))",
|
|
1288
1296
|
fontVariantNumeric: "tabular-nums",
|
|
1289
1297
|
whiteSpace: "nowrap",
|
|
1290
1298
|
flexWrap: "wrap",
|
|
@@ -1296,6 +1304,65 @@ window.__ModuleLoader__.load({
|
|
|
1296
1304
|
};
|
|
1297
1305
|
const LABEL_STYLE = { color: "var(--dsw-alias-label-tertiary)" };
|
|
1298
1306
|
const SEPARATOR_STYLE = { color: "var(--dsw-alias-separator-primary, var(--dsw-alias-label-dimmed))" };
|
|
1307
|
+
/**
|
|
1308
|
+
* One segment and the separator that introduces it, boxed together.
|
|
1309
|
+
*
|
|
1310
|
+
* The line wraps between these boxes, never inside one: with the separator as a
|
|
1311
|
+
* sibling of the segments, a wrap ended a line on a dangling `·` while the segment it
|
|
1312
|
+
* introduces moved to the next line.
|
|
1313
|
+
*/
|
|
1314
|
+
const PART_STYLE = {
|
|
1315
|
+
display: "inline-flex",
|
|
1316
|
+
alignItems: "center",
|
|
1317
|
+
gap: "6px"
|
|
1318
|
+
};
|
|
1319
|
+
/**
|
|
1320
|
+
* The platform's own ring geometry (`ContextMeter.module.css`): a 14x14 viewBox with
|
|
1321
|
+
* two circles of radius 5.5 and a 2px stroke, the filled one rotated so the arc
|
|
1322
|
+
* starts at twelve o'clock.
|
|
1323
|
+
*/
|
|
1324
|
+
const RING_RADIUS = 5.5;
|
|
1325
|
+
const RING_CIRCUMFERENCE = 2 * Math.PI * RING_RADIUS;
|
|
1326
|
+
/**
|
|
1327
|
+
* How full a window is, drawn rather than typed.
|
|
1328
|
+
*
|
|
1329
|
+
* This replaced an eight-cell `█`/`░` text bar. Those glyphs are not covered by the
|
|
1330
|
+
* shell's UI font, so a fallback served them at roughly twice the advance width and
|
|
1331
|
+
* three bars wrapped the line — and pinning them to a monospace stack only made the
|
|
1332
|
+
* width predictable, not small. An SVG ring has no glyph metrics at all, and it
|
|
1333
|
+
* matches the context meter sitting in the platform's stats row.
|
|
1334
|
+
*
|
|
1335
|
+
* The stroke uses `currentColor`, so the severity colour on the segment carries into
|
|
1336
|
+
* the ring; the track copies the platform's `--dsw-alias-border-l3`.
|
|
1337
|
+
*/
|
|
1338
|
+
function ProgressRing({ percent }) {
|
|
1339
|
+
const filled = RING_CIRCUMFERENCE * Math.min(100, Math.max(0, percent)) / 100;
|
|
1340
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
1341
|
+
viewBox: "0 0 14 14",
|
|
1342
|
+
width: "14",
|
|
1343
|
+
height: "14",
|
|
1344
|
+
"aria-hidden": "true",
|
|
1345
|
+
style: { flex: "none" },
|
|
1346
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1347
|
+
cx: "7",
|
|
1348
|
+
cy: "7",
|
|
1349
|
+
r: RING_RADIUS,
|
|
1350
|
+
fill: "none",
|
|
1351
|
+
stroke: "var(--dsw-alias-border-l3)",
|
|
1352
|
+
strokeWidth: "2"
|
|
1353
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1354
|
+
cx: "7",
|
|
1355
|
+
cy: "7",
|
|
1356
|
+
r: RING_RADIUS,
|
|
1357
|
+
fill: "none",
|
|
1358
|
+
stroke: "currentColor",
|
|
1359
|
+
strokeWidth: "2",
|
|
1360
|
+
strokeLinecap: "round",
|
|
1361
|
+
strokeDasharray: `${filled} ${RING_CIRCUMFERENCE}`,
|
|
1362
|
+
transform: "rotate(-90 7 7)"
|
|
1363
|
+
})]
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1299
1366
|
function severityColor(severity) {
|
|
1300
1367
|
if (severity === "critical") return "var(--dsw-alias-state-error-primary)";
|
|
1301
1368
|
if (severity === "warn") return "var(--dsw-alias-state-warn-primary)";
|
|
@@ -1325,11 +1392,16 @@ window.__ModuleLoader__.load({
|
|
|
1325
1392
|
children: part.text
|
|
1326
1393
|
}, key);
|
|
1327
1394
|
case "window": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1328
|
-
style: {
|
|
1395
|
+
style: {
|
|
1396
|
+
color: severityColor(part.severity),
|
|
1397
|
+
display: "inline-flex",
|
|
1398
|
+
alignItems: "center",
|
|
1399
|
+
gap: "4px"
|
|
1400
|
+
},
|
|
1329
1401
|
children: [
|
|
1402
|
+
part.progress === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProgressRing, { percent: part.progress }),
|
|
1330
1403
|
part.text,
|
|
1331
|
-
part.countdown === void 0 ? "" : ` (${part.countdown})
|
|
1332
|
-
part.bar === void 0 ? "" : ` ${part.bar}`
|
|
1404
|
+
part.countdown === void 0 ? "" : ` (${part.countdown})`
|
|
1333
1405
|
]
|
|
1334
1406
|
}, key);
|
|
1335
1407
|
case "state": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -1402,11 +1474,15 @@ window.__ModuleLoader__.load({
|
|
|
1402
1474
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1403
1475
|
"data-usage-state": "dock",
|
|
1404
1476
|
style: DOCK_STYLE,
|
|
1405
|
-
children: fullParts.map((part, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
children: "
|
|
1409
|
-
|
|
1477
|
+
children: fullParts.map((part, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1478
|
+
"data-usage-part": index === 0 ? "first" : "following",
|
|
1479
|
+
style: PART_STYLE,
|
|
1480
|
+
children: [index > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1481
|
+
style: SEPARATOR_STYLE,
|
|
1482
|
+
"aria-hidden": "true",
|
|
1483
|
+
children: "·"
|
|
1484
|
+
}) : null, withTooltip(renderPart(part, t, index), part.tooltip, index)]
|
|
1485
|
+
}, index))
|
|
1410
1486
|
});
|
|
1411
1487
|
}
|
|
1412
1488
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-usage-state",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DSH plugin: show account balance (API mode) or coding-plan quota (5h/7d/30d) for the model in use",
|
|
6
6
|
"license": "MIT",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"README.md",
|
|
75
75
|
"README.en.md",
|
|
76
76
|
"LICENSE",
|
|
77
|
+
"CHANGELOG.md",
|
|
77
78
|
"docs/adapters.md"
|
|
78
79
|
],
|
|
79
80
|
"keywords": [
|