@konnga/dsh-hud 0.9.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +201 -5
- package/README.md +132 -85
- package/docs/images/balance-hover.webp +0 -0
- package/lib/client.js +2026 -49
- package/lib/client.js.map +1 -1
- package/lib/host/index.js +17 -1
- package/lib/host/provider-balance.js +311 -0
- package/lib/host/providers.js +531 -0
- package/lib/host/rpc.js +78 -0
- package/lib/host/services.js +89 -3
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -8,7 +8,7 @@ A read-only DeepSeek Harness status panel: branch, ahead/behind, changed files a
|
|
|
8
8
|
|
|
9
9
|
> Screenshots in this file were taken in the **Chinese UI**; the plugin's own labels follow your UI language, and every quoted label below is the English one you would actually see.
|
|
10
10
|
|
|
11
|
-

|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
@@ -26,7 +26,8 @@ For local development, point the profile at the checkout (host changes apply imm
|
|
|
26
26
|
| --- | --- | --- |
|
|
27
27
|
| **Git capsule** | Workspace name, branch, ahead/behind, change counts, files this session touched | Leftmost of the row above the composer (click to open the panel) |
|
|
28
28
|
| **Tools capsule** | What is running now (live seconds), per-tool call counts, skills used | Same row, middle |
|
|
29
|
-
| **Session timer capsule** | How long this session has been running; hover for model/tool wall time and turns | Same row, rightmost |
|
|
29
|
+
| **Session timer capsule** | How long this session has been running; hover for model/tool wall time and turns | Same row, rightmost (after the balance) |
|
|
30
|
+
| **Balance capsule** | **Follows the current session's model provider**: the official account for the platform ledger, that relay's own balance for a relay; `⚠` low-balance warning, **click to paste a dashboard token** (that is how the relay's current balance becomes readable), hover shows balance / API requests / account usage / key usage | Same row, before the timer |
|
|
30
31
|
| **Panel** | Change overview, change list, recent commits, tags; click any row for its diff | Click the Git capsule |
|
|
31
32
|
| **Diffs, commit detail, images** | Unstaged / staged, word wrap, copy diff; image side-by-side + zoom | Right of the panel, draggable |
|
|
32
33
|
| **Per-turn image changes** | Images touched this turn: click to view one, `⇄` for before/after | Next to the built-in "edited N files" card |
|
|
@@ -39,10 +40,10 @@ For local development, point the profile at the checkout (host changes apply imm
|
|
|
39
40
|
### Capsules (the row above the composer)
|
|
40
41
|
|
|
41
42
|
```
|
|
42
|
-
dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3 │ ✓ bash ×16 │ … │ ⏱ 2h 14m
|
|
43
|
+
dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3 │ ✓ bash ×16 │ … │ ⏱ 2h 14m │ ¥128.40+
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
> Hover tips on
|
|
46
|
+
> Hover tips on the capsules are **bubbles the plugin draws itself** — not the browser's native tooltip, which never showed up in the real app and whose delay and styling we cannot control anyway.
|
|
46
47
|
|
|
47
48
|
**Git** (leftmost)
|
|
48
49
|
|
|
@@ -63,7 +64,7 @@ dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3 │ ✓ bash ×16 │ …
|
|
|
63
64
|
- After `skills:` come skill *names* (so you can tell which skill, not just how many calls).
|
|
64
65
|
- At most 3 tools + 2 skills are laid out; the rest collapse into `+k`. Hover for the full list and the latest results.
|
|
65
66
|
|
|
66
|
-
**Session timer** (rightmost)
|
|
67
|
+
**Session timer** (rightmost, after the balance capsule)
|
|
67
68
|
|
|
68
69
|
```
|
|
69
70
|
⏱ 2h 14m
|
|
@@ -85,6 +86,201 @@ Here it is on a real machine:
|
|
|
85
86
|
|
|
86
87
|
*The same bubble is used by the Git and tools capsules (the Git one is multi-line: full path / upstream / per-type counts).*
|
|
87
88
|
|
|
89
|
+
**Account balance** (before the timer)
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
¥128.40+
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Balance** (before the timer) — it shows the ledger the current session is actually spending from:
|
|
96
|
+
|
|
97
|
+
| The session uses | Capsule shows | Example |
|
|
98
|
+
| --- | --- | --- |
|
|
99
|
+
| DeepSeek Platform account (`deepseek-account`) | the platform wallet balance | `¥128.40+` |
|
|
100
|
+
| Official API key (`deepseek-official`) | the wallet from `GET /user/balance` | `¥128.60+` |
|
|
101
|
+
| Third-party relay readable with an API key | whatever remaining quota that relay reports | `$2,265.33` |
|
|
102
|
+
| Relay that exposes the remainder only to a web session (web token configured) | the account balance from the site's own console | `$137.48` |
|
|
103
|
+
| Relay reports "unlimited" / no web token configured | **used** (remaining unknown, never invented) | `used $1.24` |
|
|
104
|
+
| Unrecognised relay (neither protocol answers) | the site id plus `--` (unreadable, said plainly) | `api404 --` |
|
|
105
|
+
| Not resolved yet (new session / just switched / host not ready) | `--` (**never** the platform account balance as a stand-in) | `--` |
|
|
106
|
+
|
|
107
|
+
With a dashboard credential configured, a relay capsule's hover looks like this — four readings coloured by meaning
|
|
108
|
+
(see below for why):
|
|
109
|
+
|
|
110
|
+

|
|
111
|
+
|
|
112
|
+
**DeepSeek account balance** (hover)
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
DeepSeek account balance
|
|
116
|
+
¥8.60
|
|
117
|
+
Bonus balance ¥2.00
|
|
118
|
+
-¥0.30 since last refresh (2026-10-27 08:45)
|
|
119
|
+
updated 2026-10-27 08:50
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The tip holds **readings only** — no usage instructions, no warning prose: the old "click to refresh / right-click for
|
|
123
|
+
the usage page / balance below … topping up" lines were removed (they pushed the block to seven lines and squeezed out
|
|
124
|
+
the numbers that actually move). Both actions remain: **click = refresh now**, **right-click = open the Platform usage
|
|
125
|
+
page** in a new tab. A low balance is signalled by the `⚠` and warning colour on the capsule alone, never restated in the tip.
|
|
126
|
+
|
|
127
|
+
- The number comes from DSH's own account API (`remote.account.getBalance` — the same data as Settings → Account). Read-only, never persisted.
|
|
128
|
+
- Formatting matches DSH's account card rule for rule: `¥0.00` / `<¥0.01` (less than a cent) / `¥1,234.56` (thousands separators, truncated toward zero at two decimals) / a leading `-` for negatives. The currency symbol comes from the amount itself (`¥` / `$`) and is never drawn twice.
|
|
129
|
+
- A trailing `+` means there is also bonus balance (the amount is in the hover tip). A trailing `?` in the warning colour means the last refresh failed and what you see is the previous number (the tip says from when).
|
|
130
|
+
- **Low-balance warning** — below the threshold (¥10 by default) the capsule gains a `⚠` and the amount turns warning-coloured (**on the capsule only — no text**).
|
|
131
|
+
The threshold can be overridden with the localStorage key `dsh-hud.balanceLow` (write a decimal number, e.g. `localStorage.setItem('dsh-hud.balanceLow', '50')`); reload the page to apply.
|
|
132
|
+
- **Change since last refresh** — the hover tip shows something like "-¥0.30 since last refresh (22:37)". This is the difference between **our own two samples**, not Platform's "today's spend";
|
|
133
|
+
it does not accumulate across restarts (we do not know what happened in between), which is why the wording says "since last refresh".
|
|
134
|
+
The subtraction aligns decimals and works on integers, so `8.6 - 8.3` is exactly `0.30` — never `0.2999999999999998`.
|
|
135
|
+
- It refreshes every 5 minutes (it costs a real Platform request, and the balance only moves by the minute); **click** to refresh immediately.
|
|
136
|
+
|
|
137
|
+
### Relay account balance: why some sites can only report usage
|
|
138
|
+
|
|
139
|
+
The new-api family (`ur` / `muyuan` / `happycoding` / `ccwu` all are) splits its data behind two different auth schemes:
|
|
140
|
+
|
|
141
|
+
| Endpoint | Accepts | Returns | Measured (`ur`) |
|
|
142
|
+
| --- | --- | --- | --- |
|
|
143
|
+
| `GET /dashboard/billing/subscription` | ✅ API key | the quota ceiling | `hard_limit_usd: 100000000` (a **placeholder**) |
|
|
144
|
+
| `GET /dashboard/billing/usage` | ✅ API key | cumulative usage of **this key** | `$479.44` |
|
|
145
|
+
| `GET /api/user/self` | ❌ **dashboard credential only** (PAT / login session; behind `UserAuth()`) | **account** balance + account cumulative usage + request count | `$855.69` / `$526.66` / `3685` |
|
|
146
|
+
| `GET /api/usage/token/` | ✅ API key | this key's own quota view (`unlimited_quota: true` here) | `total_available: -199583909` |
|
|
147
|
+
|
|
148
|
+
So the **account balance** (the console's "current balance") has exactly one readable path, and it rejects `sk` keys.
|
|
149
|
+
To see it, configure a **dashboard credential** for that site — **click the balance capsule** and a small panel appears:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
┌─ Add a dashboard access token ────── ur ─┐
|
|
153
|
+
│ This site only exposes its current │
|
|
154
|
+
│ balance to a dashboard session (API │
|
|
155
|
+
│ keys cannot read it). Create an access │
|
|
156
|
+
│ token with the profile:read scope, then │
|
|
157
|
+
│ paste it here. │
|
|
158
|
+
│ [••••••••••••••••••••] │
|
|
159
|
+
│ Will be written to UR_ACCESS_TOKEN │
|
|
160
|
+
│ [Save] [Cancel] │
|
|
161
|
+
└──────────────────────────────────────────┘
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- Where to get it: the site's "personal settings → access tokens", with the **`profile:read`** scope (long-lived).
|
|
165
|
+
Older deployments without that page also accept a login session token copied from the browser's `user.token` (expires).
|
|
166
|
+
- **No editing of `~/.dsh/.credentials.yaml`**: the reference name (`UR_ACCESS_TOKEN`) is derived from `UR_API_KEY`,
|
|
167
|
+
and the write goes through DSH's credentials service. Making users hand-edit that file turns "configure a token" into
|
|
168
|
+
"edit a config file" — one bad indent and the whole credential store stops parsing.
|
|
169
|
+
- The token is **never echoed**: a `password` input, never in localStorage, never in logs, never in the snapshot,
|
|
170
|
+
and the host never sends it back to the browser (the response carries only the reference name).
|
|
171
|
+
- Saving refetches immediately (bypassing the host's 60-second cache) and the panel closes itself.
|
|
172
|
+
- When the token expires (new device, sign-out, site reset) it **falls back to the usage path automatically**.
|
|
173
|
+
Sites without a credential keep reporting usage; a `ur —` capsule is the "no credential yet" state and opens the same panel.
|
|
174
|
+
|
|
175
|
+
- **No hardcoded conversion rate**: `quota` is an integer; dividing by the `quota_per_unit` the site publishes in `/api/status`
|
|
176
|
+
(measured `500000` on `ur`) gives the amount, and non-USD sites are converted with their own published `usd_exchange_rate`.
|
|
177
|
+
Only when the scale is unreadable does it fall back to new-api's default, and that fallback is logged.
|
|
178
|
+
(All four sites report `quota_display_type: USD`, so the non-USD branch is defensive code for them.)
|
|
179
|
+
- **Cross-checked digit for digit** (two independent passes, hours apart, each of the four numbers matching its own scale):
|
|
180
|
+
- `ur`: `427845000 / 500000 = $855.69`, `263330000 / 500000 = $526.66`, `request_count = 3685`;
|
|
181
|
+
- `happycoding` (the site in the screenshot above): `68725535 / 500000 = $137.45`, `3774465 / 500000 = $7.55`,
|
|
182
|
+
`request_count = 3525`, `total_usage = 127.0872 cents = $1.27` — the screenshot read `$137.48 / $7.51 / 3,514 / $1.24`,
|
|
183
|
+
and the difference is the usage that actually happened in those minutes (balance down, the other three up),
|
|
184
|
+
**not a conversion error**.
|
|
185
|
+
|
|
186
|
+
### When the capsule shows `--`
|
|
187
|
+
|
|
188
|
+
The capsule only draws a reading it actually has. When it has none — not yet, or not readable —
|
|
189
|
+
it draws `--` and **never** substitutes the platform account balance: that number may belong to a
|
|
190
|
+
different ledger than the one this session spends, so filling it in would report an unrelated figure.
|
|
191
|
+
|
|
192
|
+
| State | Capsule |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| Reading available | `$742.23` |
|
|
195
|
+
| Site known, unreadable (e.g. `api404`) | `api404 --` |
|
|
196
|
+
| Site not even known yet (new session, just switched, host warming up) | `--` |
|
|
197
|
+
| Host says the provider's ledger *is* the platform account | platform balance `⚠ ¥8.60` |
|
|
198
|
+
|
|
199
|
+
Switching sessions clears the ledger **synchronously**: the previous ledger is gone the instant the new
|
|
200
|
+
session binds (`unknown` → `--`), then the new session's model provider is queried. So a switch never
|
|
201
|
+
leaves the previous session's site and amount on screen — that is another ledger's money.
|
|
202
|
+
|
|
203
|
+
### The two "used" figures are two different ledgers
|
|
204
|
+
|
|
205
|
+
Once a dashboard credential is configured, the hover lists **account** and **this key** usage side by side — they differ:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
happycoding
|
|
209
|
+
balance $137.48 ← quota of /api/user/self ÷ quota_per_unit
|
|
210
|
+
API requests 3,514 ← request_count from the same response (right under the balance:
|
|
211
|
+
it is the only count on this screen, not money)
|
|
212
|
+
$7.51 used on this account ← used_quota from the same response (whole account)
|
|
213
|
+
$1.24 used on this key ← total_usage of /dashboard/billing/usage (this key only)
|
|
214
|
+
updated 2026-10-27 16:45
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
On one site the two can differ substantially (here: `$7.51` on the account vs `$1.24` on this key — the gap is other keys
|
|
218
|
+
on the same account; on `ur` it was `$526.66` vs `$479.44`), so they are **two fields and two lines**, not one field behind
|
|
219
|
+
a flag — collapsing them would throw away a real reading.
|
|
220
|
+
|
|
221
|
+
**Why three colours**: this screen holds three amounts and one count, so they are separated by meaning —
|
|
222
|
+
|
|
223
|
+
| Colour | What uses it | Why |
|
|
224
|
+
| --- | --- | --- |
|
|
225
|
+
| green | balance | the common reading of "how much is left" |
|
|
226
|
+
| blue | API requests | it is a **count**, not money; a third amount in the same colour reads as one |
|
|
227
|
+
| amber | both "used" lines | a category colour ("this is spending"), **not** a warning |
|
|
228
|
+
| grey | labels / site name / updated-at | timestamps and labels are not readings; colouring them means everything is coloured |
|
|
229
|
+
|
|
230
|
+
All colours come from DSH's own theme tokens (`state-success-primary` / `state-business-primary` / `state-warn-primary`),
|
|
231
|
+
which carry separate values for light and dark themes — no hardcoded hex.
|
|
232
|
+
|
|
233
|
+
The line order is `balance → API requests → account usage → this key's usage`: the request count sits right under the
|
|
234
|
+
balance because it is the only **count** on the screen rather than an amount, and sandwiched between two amounts it reads
|
|
235
|
+
like a third one.
|
|
236
|
+
|
|
237
|
+
### "Used" is not "this month"
|
|
238
|
+
|
|
239
|
+
These sites **ignore `start_date` / `end_date`** (measured across four sites and four windows — identical answers),
|
|
240
|
+
so the figure is cumulative. Since the range has no effect, the request asks for the full history and the label says cumulative —
|
|
241
|
+
never a monthly label hinting at monthly arithmetic.
|
|
242
|
+
|
|
243
|
+
### Balance for the current session's model provider
|
|
244
|
+
|
|
245
|
+
Switch models inside one session and you switch ledgers — so the capsule follows **the provider the current model belongs to**:
|
|
246
|
+
|
|
247
|
+
- **Which provider**: the host reads the session's `modelSelection` projection (`next ?? lastUsed`, so a model just picked in the menu counts before the first message is sent).
|
|
248
|
+
- **Where to query**: the `baseURL` and credential reference are read live from the **Settings → Models** projection — no second copy that could drift from the user's edits.
|
|
249
|
+
- **Credential**: resolved once from DSH's `credentials` service and sent **only to that provider's own baseURL**; never logged, never returned to the browser, never persisted.
|
|
250
|
+
- **Three protocols** (measured 2026-10-27 against a real local configuration):
|
|
251
|
+
|
|
252
|
+
| Source | Endpoint | Fields | Measured |
|
|
253
|
+
| --- | --- | --- | --- |
|
|
254
|
+
| Platform account | DSH `remote.account.getBalance` | wallet array | already in use; the host does not re-fetch |
|
|
255
|
+
| Official API key | `GET {origin}/user/balance` | `balance_infos[].total_balance` (+ `granted_balance`) | `200`, `-0.19 CNY` |
|
|
256
|
+
| Relay (one-api / new-api family) | `GET {base}/dashboard/billing/subscription` + `/usage` | `hard_limit_usd` (**remaining**) + `total_usage` (**cents**) | `muyuan` → remaining `2265.33`, used `212.74` |
|
|
257
|
+
|
|
258
|
+
Three things the implementation states plainly rather than papering over:
|
|
259
|
+
|
|
260
|
+
1. **`hard_limit_usd` is remaining quota, not a total** — so used is **not** subtracted again. Writing `limit - used` would understate the balance.
|
|
261
|
+
2. **`total_usage` is in cents** — measured `21274.26` matches the site's `$212.74`.
|
|
262
|
+
3. **`1e8` is an "unlimited" sentinel** — measured on `ur` / `ccwu` / `happycoding`: two probes both returned `100000000` while real usage was climbing. Remaining quota is then **not computable**, so the capsule reports "used" rather than passing off `1e8 - used` as a balance.
|
|
263
|
+
|
|
264
|
+
Boundaries:
|
|
265
|
+
|
|
266
|
+
- An unrecognised relay (measured `api404`: both paths 404/502) reports `unsupported` and the capsule renders `api404 --`.
|
|
267
|
+
**No number is drawn** (it never falls back to the platform account's balance — that is a different ledger), but the capsule does not vanish either:
|
|
268
|
+
a `—` is a reading ("this ledger can't be read"), while a blank is just a doubt that sends people off to check logs and reinstall.
|
|
269
|
+
- No currency conversion: relay fields are named `*_usd` but some sites account in CNY 1:1 internally; only the site's own stated figures are repeated.
|
|
270
|
+
- **Some sites expose remaining quota only to a web session** (measured on `ur`: `/api/user/self` answers `401 AUTH_UNAUTHORIZED`
|
|
271
|
+
while `/dashboard/billing/*` is readable with an API key). The capsule then reports usage only instead of pretending to know the remainder —
|
|
272
|
+
it neither guesses nor rides your web session (that would mean private requests with your account credentials, broken by any site change).
|
|
273
|
+
- Caching: 60 s client TTL, 60 s per-provider host cache, 8 s request timeout. Relays rate-limit aggressive polling, and that is how "can't read the balance" actually happens.
|
|
274
|
+
- The client re-asks every 30 s (actual requests are gated by the TTL: 60 s on success, 30 s on failure): the first read often lands before the session projection is ready, and waiting five minutes would leave the capsule blank for that long.
|
|
275
|
+
- A failed read keeps the previous numbers (a network blip must not make the capsule vanish); switching sessions re-reads immediately instead of reusing the previous session's ledger.
|
|
276
|
+
- **Nothing to show, nothing drawn**: signed out, no account plugin, or no wallet at all — the capsule simply does not appear. It never fakes `¥0.00`.
|
|
277
|
+
|
|
278
|
+
> Why spend totals are not in the capsule: DSH's account API returns **wallet balances only** (`getBalance`) plus the
|
|
279
|
+
> account projection — it carries no spending numbers at all; that data exists only on DeepSeek's own usage page
|
|
280
|
+
> (**right-click the capsule** to go straight there). The plugin does not scrape Platform-internal endpoints
|
|
281
|
+
> (which needs the account credential and breaks whenever Platform changes), nor does it multiply tokens by a
|
|
282
|
+
> self-invented price to produce a number that looks precise but is not.
|
|
283
|
+
|
|
88
284
|
### Panel (click the Git capsule)
|
|
89
285
|
|
|
90
286
|

|
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# dsh-hud
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@konnga/dsh-hud) [](#安装) [](LICENSE)
|
|
3
|
+
[](https://www.npmjs.com/package/@konnga/dsh-hud) [](#安装) [](LICENSE)
|
|
4
4
|
|
|
5
5
|
[English](./README.en.md) | **中文**
|
|
6
6
|
|
|
7
7
|
DeepSeek HUD 状态面板:分支、ahead/behind、改动清单与差异,外加「这个会话改过哪些文件、审到哪了、跑了什么工具」。
|
|
8
8
|
|
|
9
|
-

|
|
10
10
|
|
|
11
11
|
## 安装
|
|
12
12
|
|
|
@@ -20,27 +20,28 @@ DeepSeek HUD 状态面板:分支、ahead/behind、改动清单与差异,外
|
|
|
20
20
|
|
|
21
21
|
## 功能总览
|
|
22
22
|
|
|
23
|
-
| 功能 | 一句话
|
|
24
|
-
| ------------------------------ |
|
|
25
|
-
| **Git 胶囊** | 工作区名、分支、ahead/behind、改动计数、本会话改过几个文件
|
|
26
|
-
| **工具胶囊** | 正在跑什么(实时秒数)、各工具调用次数、用过的技能
|
|
27
|
-
| **会话计时胶囊** | 本次会话已运行多久;悬停给模型 / 工具墙钟与轮次
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
23
|
+
| 功能 | 一句话 | 在哪儿 |
|
|
24
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------ |
|
|
25
|
+
| **Git 胶囊** | 工作区名、分支、ahead/behind、改动计数、本会话改过几个文件 | 输入框上方那一行,最左(点它开面板) |
|
|
26
|
+
| **工具胶囊** | 正在跑什么(实时秒数)、各工具调用次数、用过的技能 | 同一行,中间 |
|
|
27
|
+
| **会话计时胶囊** | 本次会话已运行多久;悬停给模型 / 工具墙钟与轮次 | 同一行,最右(余额之后) |
|
|
28
|
+
| **余额胶囊** | **跟着当前会话的模型来源走**:用官方账号就查账号余额,用中转站就查那家的余额;低余额 `⚠` 提醒,**点一下可填后台令牌**(拿得到"当前余额"),悬停给余额 / API 请求 / 账号已用 / 本 Key 已用 | 同一行,计时之前 |
|
|
29
|
+
| **面板** | 改动概览、改动清单、最近提交、标签;点任意一行看差异 | 点 Git 胶囊 |
|
|
30
|
+
| **差异与提交明细** | 未暂存 / 已暂存、自动换行、复制差异;图片并排对比 + 缩放 | 面板右侧,可拖动 |
|
|
31
|
+
| **轮尾「本轮图片改动」** | 这一轮动过的图:点开看单张,`⇄` 看前后对比 | 内置「已编辑 N 个文件」卡片旁 |
|
|
32
|
+
| **侧栏会话行** | 悬停或点 `⋯` 展开:git 摘要 + 本会话归因 | 侧栏每个会话行 |
|
|
33
|
+
| **键盘** | 面板内 `↑↓` `Enter` `[ ]` `n p` `Space` `v` `r` `Esc` | 面板激活后 |
|
|
34
|
+
| **输入框 `↑` 召回** | 空输入框按 `↑` 带回上一条 prompt | 输入框里 |
|
|
34
35
|
|
|
35
36
|
## 你会看到什么
|
|
36
37
|
|
|
37
38
|
### 胶囊(输入框上方那一行)
|
|
38
39
|
|
|
39
40
|
```
|
|
40
|
-
dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3 │ ✓ bash ×16 │ … │ ⏱ 2h 14m
|
|
41
|
+
dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3 │ ✓ bash ×16 │ … │ ⏱ 2h 14m │ ¥128.40+
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
>
|
|
44
|
+
> 几枚胶囊的**悬停提示是插件自己画的气泡**(不用浏览器原生 tooltip —— 它在真机上不出现,延迟与样式也控制不了)。
|
|
44
45
|
|
|
45
46
|
**Git**(最左)
|
|
46
47
|
|
|
@@ -61,7 +62,7 @@ dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3 │ ✓ bash ×16 │ …
|
|
|
61
62
|
- `skills:` 后面是技能名(看得出是哪一个,不是"技能调了几次")。
|
|
62
63
|
- 最多铺 3 个工具 + 2 个技能,其余收成 `+k`;悬停里有完整清单与最近几条结果。
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
**会话计时**(最右,余额胶囊之后)
|
|
65
66
|
|
|
66
67
|
```
|
|
67
68
|
⏱ 2h 14m
|
|
@@ -83,95 +84,141 @@ dsh-hud · git:(main*) ↑1 ↓2 M4 A1 ?1 │ ●3 │ ✓ bash ×16 │ …
|
|
|
83
84
|
|
|
84
85
|
*同一套气泡也用在 Git 与工具胶囊上(Git 那颗是多行的:完整路径 / 上游 / 各类型计数)。*
|
|
85
86
|
|
|
86
|
-
|
|
87
|
+
**余额**(计时之前)—— 它画的是**当前会话真正在用的那个账本**:
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
| 会话用的是 | 胶囊显示 | 例 |
|
|
90
|
+
| -------------------------------------------------- | -------------------------------- | ---------------- |
|
|
91
|
+
| DeepSeek 平台账号(`deepseek-account`) | 平台账号钱包余额 | `¥128.40+` |
|
|
92
|
+
| 官方 API Key(`deepseek-official`) | `GET /user/balance` 的钱包 | `¥128.60+` |
|
|
93
|
+
| 第三方中转站,API Key 就能读到剩余 | 那家自己报的剩余额度 | `$2,265.33` |
|
|
94
|
+
| 第三方中转站,剩余额只给网页登录态(配了网页令牌) | 账号余额(站点后台那个数) | `$137.48` |
|
|
95
|
+
| 中转站把额度写成"无限"占位 / 没配网页令牌 | **已用**(剩余未知,不编) | `已用 $1.24` |
|
|
96
|
+
| 认不出的站(两套协议都不通) | 站名 + `--`(读不到就直说) | `api404 --` |
|
|
97
|
+
| 还没查出来(新会话 / 刚换会话 / 宿主还没就绪) | `--`(**不拿官方账号余额顶上**) | `--` |
|
|
89
98
|
|
|
90
|
-
|
|
99
|
+
配好后台凭据之后,中转站那一枚的悬停长这样 —— 四个读数按语义上色(下面说为什么):
|
|
91
100
|
|
|
92
|
-
1.
|
|
93
|
-
2. **改动概览** —— 按类型分组的彩色计数;干净时写「工作区干净」。
|
|
94
|
-
3. **本会话改了哪些** —— 一行计数加开关:`只看本会话改的`、`只看最近一轮`;有审阅标记时还有 `已审 3/8` 与 `清空已审`。
|
|
95
|
-
4. **改动清单** —— 每行 `标记 状态字母 路径`,重命名读作 `旧 → 新`。
|
|
96
|
-
- 行首 `●` 确定改过 · `◐` 可能相关(从命令里看出来,悬停给出那条命令)· `○` 与本会话无关。
|
|
97
|
-
- 行尾 `○` / `✓` 是审阅标记,点一下或按 `v` 切换;`✓` 变黄说明改动又变了,需要重看。
|
|
98
|
-
- 点任意一行看这个文件的差异。
|
|
99
|
-
5. **最近提交** —— `短sha 标题 [HEAD] 2026-10-16 14:18`;点一行看这次提交,再点一次收起。
|
|
100
|
-
6. **标签** —— 新的在前;点一行看它指向的提交。没有标签时写一行「这个仓库还没有标签」。
|
|
101
|
+

|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
**DeepSeek 平台账号**的悬停(中转站那一路换成上面那五行,没有赠送余额那两行):
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-

|
|
105
|
+
```
|
|
106
|
+
DeepSeek 账号余额
|
|
107
|
+
¥8.60
|
|
108
|
+
赠送余额 ¥2.00
|
|
109
|
+
较上次刷新 -¥0.30(2026-10-27 08:45)
|
|
110
|
+
更新于 2026-10-27 08:50
|
|
111
|
+
```
|
|
113
112
|
|
|
114
|
-
|
|
113
|
+
气泡里只有**读数**,没有操作说明、也没有提醒话术:那几句"点一下刷新 / 右键开用量页 / 余额低于 …… 记得充值"
|
|
114
|
+
都已删掉(它们会把整块明细撑成七行、还挤掉真正会变的那几个数)。两个动作仍然在:**左键点击 = 立即刷新**,
|
|
115
|
+
**右键 = 在新标签打开平台用量页**。低余额也只由胶囊上的 `⚠` + 警示色表达,不在气泡里复述。
|
|
115
116
|
|
|
116
|
-
|
|
117
|
+
- 余额来自 DSH 自己的账号接口(`remote.account.getBalance`,与「设置 → 账号」是同一份数),**只读**、不落盘。
|
|
118
|
+
- 显示规则与 DSH 账号卡片逐条一致:`¥0.00` / `<¥0.01`(不足一分)/ `¥1,234.56`(千分位、向零截断两位)/ 负数带 `-`。币种符号由金额本身带(`¥` / `$`),不会再额外多画一个。
|
|
119
|
+
- 末尾 `+` —— 还有赠送余额;具体多少在悬停里。末尾 `?` 颜色发黄 —— 最近一次刷新失败,屏幕上是上一次的数(悬停里会说是什么时候的)。
|
|
120
|
+
- **低余额提醒** —— 低于阈值(默认 ¥10)时胶囊前面加 `⚠`、金额变成警示色(**只在胶囊上,不写文案**)。
|
|
121
|
+
阈值可用 localStorage 键 `dsh-hud.balanceLow` 覆盖(写十进制数,例如 `localStorage.setItem('dsh-hud.balanceLow', '50')`),刷新页面生效。
|
|
122
|
+
- **变化量** —— 悬停里给「较上次刷新 -¥0.30(22:37)」。这是**我们自己两次采样之间**的差,不是平台的"今日消耗";
|
|
123
|
+
跨重启不累计(中间发生过什么我们并不知道),所以措辞写的是"较上次刷新"。
|
|
124
|
+
减法按十进制对齐做整数运算,`8.6 - 8.3` 就是 `0.30`,不会出现 `0.2999999999999998`。
|
|
125
|
+
- 平时 5 分钟刷一次(它背后是平台的一次真实网络请求,余额也按分钟变);**左键点击**可立即刷新。
|
|
126
|
+
- **读不到就不画**:没登录、没有账号插件、一个钱包都没有时这枚胶囊不出现,也不会画 `¥0.00` 冒充"没钱"。
|
|
117
127
|
|
|
118
|
-
|
|
128
|
+
### 中转站的「账号余额」:为什么有的站只给得出用量
|
|
119
129
|
|
|
120
|
-
-
|
|
121
|
-
- 点 `⇄` → 打开本插件的面板,看这张图的**前后对比**(内置预览只有当前这一版);
|
|
122
|
-
- 只列**这一轮**改过的图片,最近改的在前,最多 4 张 + `还有 N 个`;这一轮没动过图片就整条不渲染;
|
|
123
|
-
- 归因两档都收:工具改的算确定,从 shell 命令里认出来的标 `◐`(悬停给出那条命令)—— 图基本是脚本产出的,只收确定档等于收不到。
|
|
130
|
+
new-api 家族(`ur` / `muyuan` / `happycoding` / `ccwu` 都是)把数据分在两套鉴权后面:
|
|
124
131
|
|
|
125
|
-
|
|
132
|
+
| 接口 | 认什么 | 给什么 | 实测(`ur`) |
|
|
133
|
+
| --------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------- |
|
|
134
|
+
| `GET /dashboard/billing/subscription` | ✅ API Key | 额度上限 | `hard_limit_usd: 100000000`(**占位值**) |
|
|
135
|
+
| `GET /dashboard/billing/usage` | ✅ API Key | **这枚 Key** 的累计用量 | `$479.44` |
|
|
136
|
+
| `GET /api/user/self` | ❌ **只认后台凭据**(PAT / 登录会话;挂在 `UserAuth()` 下) | **账号**余额 + 账号累计用量 + 请求数 | `$855.69` / `$526.66` / `3685` |
|
|
137
|
+
| `GET /api/usage/token/` | ✅ API Key | 这枚 Key 的额度口径(若为"无限"则 `unlimited_quota: true`) | `total_available: -199583909` |
|
|
126
138
|
|
|
127
|
-
|
|
139
|
+
所以**账号余额**(后台「当前余额」那个数)只有一条路能读,而那条路不认 `sk` 开头的 Key。
|
|
140
|
+
要看到它,给某个站配一枚**后台凭据** —— **点一下余额胶囊就会弹出设置面板**,粘进去即可:
|
|
128
141
|
|
|
129
142
|
```
|
|
130
|
-
|
|
131
|
-
|
|
143
|
+
┌─ 天机访问令牌 ────────────── ur ─┐
|
|
144
|
+
│ 这个站的「当前余额」只对后台登录态可见 │
|
|
145
|
+
│ (API Key 读不到)。去站点「个人设置 → │
|
|
146
|
+
│ 访问令牌」新建一枚,权限勾 profile:read, │
|
|
147
|
+
│ 粘进来就行。 │
|
|
148
|
+
│ [••••••••••••••••••••] │
|
|
149
|
+
│ 将写入 UR_ACCESS_TOKEN │
|
|
150
|
+
│ [保存] [取消] │
|
|
151
|
+
└──────────────────────────────────────────┘
|
|
132
152
|
```
|
|
133
153
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
154
|
+
- 令牌去哪拿:站点「个人设置 → 访问令牌」新建一枚,scope 勾 **`profile:read`**(长期有效)。
|
|
155
|
+
老版本站点没有访问令牌页面时,也可以从浏览器 localStorage 的 `user.token` 复制一枚登录令牌(会过期)。
|
|
156
|
+
- **不用碰 `~/.dsh/.credentials.yaml`**:引用名(`UR_ACCESS_TOKEN`)由插件从 `UR_API_KEY` 推导,
|
|
157
|
+
写入走 DSH 的凭据服务。让用户手改那个文件等于把"配一个令牌"变成"改一个配置文件"——
|
|
158
|
+
手滑一个缩进整份凭据就读不出来。
|
|
159
|
+
- 令牌**不回显**:输入框是 `password`,不进 localStorage、不进日志、不进快照,
|
|
160
|
+
宿主也从不把它回传给浏览器(答复里只有引用名)。
|
|
161
|
+
- 存好立刻重取一次(跳过宿主 60 秒缓存),面板自动收起 —— 粘完就能看见数字变出来。
|
|
162
|
+
- 令牌过期(换设备 / 退出登录 / 站点重置)时**自动退回用量那一路**,不会整枚消失。
|
|
163
|
+
没配凭据的站照旧只报用量;`ur —` 也是"没配凭据"的样子,点它同样弹面板。
|
|
164
|
+
- **兑换率不写死**:`quota` 是整数,除以站点公开在 `/api/status` 的 `quota_per_unit`(实测 `ur` = `500000`)才是金额;
|
|
165
|
+
站点用非美元显示时按它自己公布的 `usd_exchange_rate` 换算。拿不到口径时才退回 new-api 的默认值,并在日志里留痕。
|
|
166
|
+
(这四个站实测 `quota_display_type` 全是 `USD`,非美元那条换算分支对它们用不到,属防御性代码。)
|
|
167
|
+
- **逐位对过账**(两次独立核对,间隔数小时,四个数各自按自己的口径对得上):
|
|
168
|
+
- `ur`:`427845000 / 500000 = $855.69`、`263330000 / 500000 = $526.66`、`request_count = 3685`;
|
|
169
|
+
- `happycoding`(就是上面那张效果图那台):`68725535 / 500000 = $137.45`、`3774465 / 500000 = $7.55`、
|
|
170
|
+
`request_count = 3525`、`total_usage = 127.0872 分 = $1.27` —— 截图时是 `$137.48 / $7.51 / 3,514 / $1.24`,
|
|
171
|
+
相差的就是这十几分钟里真实用掉的量(余额降、其余三个升),**不是换算误差**。
|
|
172
|
+
|
|
173
|
+
### 什么时候显示 `--`
|
|
174
|
+
|
|
175
|
+
胶囊只画**读到的读数**。还没读到、或读不到的时候画 `--`,**绝不拿平台账号的余额顶上** ——
|
|
176
|
+
那个数未必是这次会话要花的钱,填进来等于报一个与本次会话无关的数。
|
|
177
|
+
|
|
178
|
+
| 状态 | 胶囊 |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| 读到余额 | `$742.23` |
|
|
181
|
+
| 只知道站、读不到(如 `api404`) | `api404 --` |
|
|
182
|
+
| 连站都还不知道(新会话、刚换会话、宿主还没就绪) | `--` |
|
|
183
|
+
| 宿主明确说"这个提供方的账本就是平台账号" | 平台账号余额 `⚠ ¥8.60` |
|
|
184
|
+
|
|
185
|
+
换会话是**同步清空**的:绑定新会话那一瞬旧账本就没了(`unknown` → `--`),紧接着按新会话的
|
|
186
|
+
模型来源查一次。所以切换时不会出现"屏幕上还写着上一个会话的站名和金额"——那是另一个账本的钱。
|
|
187
|
+
|
|
188
|
+
### 悬停里那两个「已用」是两本账
|
|
189
|
+
|
|
190
|
+
配好后台凭据之后,悬停里同时列出**账号**与**本 Key** 两个已用 —— 它们是两个不同的数(上面那张效果图就是这一屏):
|
|
137
191
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
| `Space` | 折叠 / 展开当前 hunk |
|
|
147
|
-
| `v` | 把当前行标成「这一版我审过了」(再按取消) |
|
|
148
|
-
| `r` | 重新读取 |
|
|
149
|
-
| `Esc` | 退一层:先收右栏(差异 / 提交明细),再按才收面板 |
|
|
150
|
-
|
|
151
|
-
看提交明细时,`↑ ↓ Enter [ ]` 作用于明细那一栏的清单。
|
|
152
|
-
|
|
153
|
-
### 输入框里按 `↑` 召回上一条 prompt
|
|
192
|
+
```
|
|
193
|
+
happycoding
|
|
194
|
+
余额 $137.48 ← /api/user/self 的 quota ÷ quota_per_unit
|
|
195
|
+
API 请求 3,514 ← 同一个响应的 request_count(紧跟余额:它是唯一一个次数,不是钱)
|
|
196
|
+
账号已用 $7.51 ← 同一个响应的 used_quota(整个账号)
|
|
197
|
+
本 Key 已用 $1.24 ← /dashboard/billing/usage 的 total_usage(只有这枚 Key)
|
|
198
|
+
更新于 2026-10-27 16:45
|
|
199
|
+
```
|
|
154
200
|
|
|
155
|
-
|
|
201
|
+
同一个站上这两个数能差出一截(这台上:账号 `$7.51` vs 本 Key `$1.24`,差的那部分是账号下另一个 Key 的用量;
|
|
202
|
+
`ur` 上则是 `$526.66` vs `$479.44`),所以它们是**两个字段、两行**,不是靠一个标记二选一 ——
|
|
203
|
+
塞进一个字段就必须丢掉一个真实读数。
|
|
156
204
|
|
|
157
|
-
|
|
158
|
-
- **数据来自会话日志**(内置 `turnOutline` 投影),不是插件自己记一份 —— 重启、分页、压实都不影响,**在别的客户端发过的话也能召回**。宿主的投影没有时,整个功能静默不启用。
|
|
159
|
-
- **输入框非空时完全不接管**,多行草稿里的 `↑` 永远只是移动光标,也不会跟 `/` 命令、`@` 提及的弹窗打架。带修饰键、输入法组合中、有选区时同样让路。
|
|
160
|
-
- 你一打字就退出历史模式,草稿不会被错还原。
|
|
205
|
+
**数字为什么分三种颜色**:这一屏里三个是钱、一个是次数,所以按语义分开 ——
|
|
161
206
|
|
|
162
|
-
|
|
207
|
+
| 颜色 | 谁用它 | 为什么 |
|
|
208
|
+
| --- | --- | --- |
|
|
209
|
+
| 绿 | 余额 | "还剩多少"的通行读法 |
|
|
210
|
+
| 蓝 | API 请求 | 它是**次数**不是金额;同一个颜色会被读成第三个金额 |
|
|
211
|
+
| 琥珀 | 两个「已用」 | 分类色("这是消耗"),**不是在报警** |
|
|
212
|
+
| 灰 | 标签 / 站名 / 更新时间 | 时间戳和标签不是读数,染上就等于满屏是色、没有重点 |
|
|
163
213
|
|
|
164
|
-
|
|
214
|
+
颜色全部取自 DSH 自己的主题令牌(`state-success-primary` / `state-business-primary` / `state-warn-primary`),
|
|
215
|
+
深浅色主题各有一套取值,不写死十六进制。
|
|
165
216
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
- 约定:`src/` 全是源码,`lib/` 全是产物 —— `pnpm run build` 一次重建两半(`tsc -p tsconfig.host.json` + `rolldown`),产物与源码一起提交(DSH 与本机 profile 直接读 `lib/`)。
|
|
169
|
-
- `pnpm test`:类型检查(浏览器半与宿主半都是**全量 `strict`**)+ 全部用例。
|
|
170
|
-
- `pnpm run format`:Prettier 统一源码格式(`.prettierrc.json`;`lib/` 是产物、不格式化),`pnpm run format:check` 只检查。
|
|
171
|
-
- 包管理器是 pnpm:`pnpm-lock.yaml` 入库;`pnpm-workspace.yaml` 关掉 `autoInstallPeers` —— DSH 的客户端服务由宿主提供,不随包安装。
|
|
172
|
-
- `docs/dock-slot-host.md`:把输入框上方那一行做成「可注册行内宿主」的提案,给上游看的。
|
|
173
|
-
- **发版**:`pnpm run tag && pnpm publish`。`prepublishOnly` 先跑测试,再校验「版本号 ↔ git tag」(工作区要干净、`v<版本>` 要存在且指向 HEAD),对不上就发不出去。
|
|
217
|
+
行序是 `余额 → API 请求 → 账号已用 → 本 Key 已用`:请求数紧跟余额,因为它是这一屏里唯一一个**次数**而不是金额,
|
|
218
|
+
夹在两个金额中间容易被读成第三个金额。
|
|
174
219
|
|
|
175
|
-
|
|
220
|
+
### 「已用」不是「本月」
|
|
176
221
|
|
|
177
|
-
|
|
222
|
+
这些站**都忽略 `start_date` / `end_date`**(实测四个站、四个区间回的完全一样),
|
|
223
|
+
所以那个数不是「本月」而是**累计**。既然区间不生效,请求就发全历史区间、标签写「累计」——
|
|
224
|
+
不写一个按月的标签去暗示它按月算。
|
|
Binary file
|