@kenz1117/dsh-ui-usage-billing 1.6.2 → 1.6.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/README.en.md CHANGED
@@ -9,6 +9,7 @@
9
9
  <a href="https://www.npmjs.com/package/@kenz1117/dsh-ui-usage-billing"><img alt="npm version" src="https://img.shields.io/npm/v/@kenz1117/dsh-ui-usage-billing?logo=npm"></a>
10
10
  <a href="https://www.npmjs.com/package/@kenz1117/dsh-ui-usage-billing"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@kenz1117/dsh-ui-usage-billing?logo=npm"></a>
11
11
  <a href="https://github.com/kenz1117/dsh-ui-usage-billing/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/kenz1117/dsh-ui-usage-billing/actions/workflows/ci.yml/badge.svg"></a>
12
+ <a href="https://github.com/kenz1117/dsh-ui-usage-billing/blob/main/COMPATIBILITY.md"><img alt="DSH compat" src="https://img.shields.io/badge/DSH-0.1.2_%7E_0.2.1--rc.2_%7C_0.1.0--rc.8%2B-blue"></a>
12
13
  <a href="https://github.com/kenz1117/dsh-ui-usage-billing/blob/main/LICENSE"><img alt="License MIT" src="https://img.shields.io/github/license/kenz1117/dsh-ui-usage-billing"></a>
13
14
  <a href="https://github.com/kenz1117/dsh-ui-usage-billing/pulls"><img alt="PRs welcome" src="https://img.shields.io/badge/PRs-welcome-brightgreen"></a>
14
15
  <a href="https://github.com/kenz1117/dsh-ui-usage-billing"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/kenz1117/dsh-ui-usage-billing?logo=github"></a>
@@ -38,7 +39,7 @@ Most billing plugins stop at "token count × unit price". dsh-ui-usage-billing t
38
39
  Usage is aggregated live from persisted session logs — never fabricated (an empty snapshot shows until real data arrives); daily official-balance deltas are cross-checked against the local ledger, and deviations beyond the threshold prompt a review — a bill that survives scrutiny.
39
40
 
40
41
  ### Live prices, history never rewritten
41
- A live models.dev catalog + a built-in catalog of 77 models across 24 vendors + user-defined prices in the settings panel (bindable per relay origin) mean new models never wait for a release; DeepSeek time-of-day prices are **segmented by official change boundaries** (base price before 08-17, weekend peak hours 08-17~08-23, weekend all-day off-peak from 08-23) and later price changes never rewrite old bills.
42
+ A live models.dev catalog + a built-in catalog of 110 models across 25 vendors + user-defined prices in the settings panel (bindable per relay origin) mean new models never wait for a release; DeepSeek time-of-day prices are **segmented by official change boundaries** (base price before 08-17, weekend peak hours 08-17~08-23, weekend all-day off-peak from 08-23) and later price changes never rewrite old bills.
42
43
 
43
44
  ### Peak/off-peak aware, alerts follow the model
44
45
  The billing channel is detected from the current session's model: DeepSeek metered uses time-of-day prices (weekday 9-12 / 14-18 peak ×2, weekend all-day off-peak), Zhipu Coding Plan uses credit windows (weekday 14-18 peak at full rate, off-peak at **50% of base credits**) — the channel layer is extensible for more providers; a popover / system notification fires automatically before each switch, and only sessions whose current model actually involves peak/off-peak get alerted or show the tier section — no watching the clock.
@@ -57,12 +58,13 @@ The billing channel is detected from the current session's model: DeepSeek meter
57
58
 
58
59
  ## 📊 Dashboard
59
60
 
60
- - **Sidebar trigger card**: persistent above the Settings button — month cost as the headline number with a 7-day sparkline mini-trend, second line "Today / This week"; collapses to an icon button; hover reveals a quick-look card.
61
- - **Six-tab dashboard**: Overview / Trends / Detail / Stats / Rates / Settings — hero figures + comparisons + month projection + KPIs + usage heatmap, 7/30-day trends switching cost / tokens, plus the model rate table, budget and peak/off-peak alerts; restrained tones, dark/light adaptive.
61
+ - **Sidebar trigger card**: persistent above the Settings button — a single headline figure (today / this week / this month, selectable in settings, optional day-over-day badge) with a 7-day sparkline mini-trend and a today-vs-average gauge needle; collapses to an icon button; hover reveals a quick-look card (updated-at + metric grid + top spenders / quota alerts).
62
+ - **Six-tab dashboard**: Overview / Trends / Detail / Stats / Rates / Settings — hero figures + comparisons + month projection + KPIs (hover for the metric definition) + usage heatmap, 7/30-day trends switching cost / tokens, plus the model rate table, budget (global + per-model) and peak/off-peak alerts; the Settings tab has full-text search (keyword-filters sections in either language, empty state when nothing matches); restrained tones, dark/light adaptive.
62
63
 
63
64
  ![Overview: month cost hero, budget progress, KPIs and usage heatmap](screenshots/1.png)
64
- - **Live cost bar**: persistent "this turn / session" cost below the composer; the peak/off-peak tier & countdown section appears only when the current model involves peak/off-peak pricing; subscription low-quota chips appear at ≤20% remaining, red at ≤10%; hideable via the settings-tab toggle (display-only preference persisted locally; stats and alerts unaffected).
65
+ - **Live cost bar**: persistent "this turn / session" cost with three positions (composer toolbar row / above / below, toolbar by default); the peak/off-peak tier & countdown section appears only when the current model involves peak/off-peak pricing; subscription low-quota chips appear at ≤20% remaining, red at ≤10%; hideable via the settings-tab toggle (display-only preference persisted locally; stats and alerts unaffected).
65
66
  - **Peak/off-peak switch alert**: a popover plus an optional system notification before a switch; lead time / position / mode / preview configurable; copy differs by billing channel (DeepSeek price halves, Zhipu credits at 50%).
67
+ - **Session completion notification**: an optional system notification when a session transitions running → completed (off by default, enable it in the panel); multi-window / multi-instance dedup through the claim endpoint, so each session notifies once.
66
68
  - **Plugin info card**: a persistent "About" card in the Settings tab — version read server-side from the package's `package.json` (single source of truth, correct on publish), author / repo / npm / license one click away.
67
69
 
68
70
  ## 💰 Billing engine
@@ -73,12 +75,12 @@ The billing channel is detected from the current session's model: DeepSeek meter
73
75
  ![Rates: model rate table (peak/off-peak split and live rate)](screenshots/5.png)
74
76
  - **Custom unit prices**: set real paid prices (miss / cache-hit / output, optional USD and off-peak columns) for uncatalogued or repriced models; bindable per relay origin; an out-of-catalog model is priced as soon as you fill it in.
75
77
  - **Official vs third-party buckets**: the detail cost column splits official direct / third-party relay ("official x / third y" when mixed); the Stats tab has a summary card; web-search assist calls count as official.
76
- - **Monthly budget + tier alerts**: budget bar ≥80% amber, over-budget red pulse; one alert per 50/80/100% crossing; a balance below the CNY threshold alerts once a day.
78
+ - **Monthly budget + tier alerts**: budget bar ≥80% amber, over-budget red pulse; one alert per 50/80/100% crossing; a balance below the CNY threshold alerts once a day. **Per-model budgets**: set a CNY cap per top-spending model of the month (independent of the global budget), with one alert per model per 80% / 100% crossing.
77
79
  - **Cost-spike attribution**: last-40-turn cost bars, amount at bar top, peak/off-peak background bands, >2× spikes flagged with attribution.
78
80
 
79
81
  ## 🔌 Subscriptions & balance
80
82
 
81
- - **Subscription quota**: auto-detects subscription providers (Kimi / Z.ai / OpenCode Go / MiniMax / OpenRouter / Xiaomi / Volcano…); those with a quota API show remaining % and reset time live, exhausted in red, otherwise "not wired"; subscription-channel model cost is 0, and plan tiers are recognized by the built-in knowledge base (e.g. OpenCode Go $10/mo + $30 weekly). **MiniMax note**: use `minimax-token-plan-cn` for the CN domain (`api.minimaxi.com`), `minimax` / `minimax-token-plan` international; override `baseUrl` per provider if needed.
83
+ - **Subscription quota**: auto-detects subscription providers (Kimi / Z.ai / OpenCode Go / MiniMax / OpenRouter / Xiaomi / Volcano…); those with a quota API show remaining % and reset time live, exhausted in red, otherwise "not wired"; subscription-channel model cost is 0, and plan tiers are recognized by the built-in knowledge base (e.g. OpenCode Go $10/mo + $30 weekly). **MiniMax note**: use `minimax-token-plan-cn` for the CN domain (`api.minimaxi.com`), `minimax` / `minimax-token-plan` international; override `baseUrl` per provider if needed. **Claude subscription**: auto-discovered after signing in to Claude Code locally (reads the OAuth token from `~/.claude/.credentials.json`), showing 5-hour / weekly window usage; a metered `anthropic` route in llm-pi-ai is not misdetected and stays token-billed. **CommandCode**: set `apiKeyEnv` (a `user_`-prefixed key) on the `commandcode` route in llm-pi-ai to see the 5-hour / weekly windows and monthly Credits.
82
84
  - **Multi-provider balance**: built-in official balances for DeepSeek / Kimi / StepFun / SiliconFlow / xAI / Zhipu GLM, with an "≈N days" estimate from the 7-day daily burn; **Tencent Cloud TokenHub Token Plan** goes through the cloud-API control plane (TC3-signed, `src/tc3.ts`) — set the credential to a `<SecretId>:<SecretKey>` key pair (not the inference key) and name the route `tencent-tokenhub` / `tokenhub` / `tencent` / `tencentcloud`; a percentage window is produced only when both remaining and total quotas parse (never guessed).
83
85
  - **Custom provider balance**: configure any HTTP endpoint (`extract` supports constant / dot-path / arithmetic, header `{{ENV}}` via the credentials seam).
84
86
  - **Declared endpoints + balance reconcile**: `declaredEndpoints` self-declares balance/quota interfaces for vendors absent from the built-in table — dot-paths only ("where the number is"), no expressions; safety bounds (single-slash absolute path, GET only, no cross-origin redirects, response-size/timeout caps, credentials from the matched provider only) are enforced by `src/declarative.ts`; a wrong path is marked `declared` with a reason. **Balance reconcile** (`reconcilePath`) cross-checks the official balance change against the local ledger, flagging drift above the threshold (0.3 CNY and >15%); top-ups / grants / currency changes reset the baseline instead of alerting, and a flat balance (subscription spend) stays silent.
@@ -90,7 +92,7 @@ The billing channel is detected from the current session's model: DeepSeek meter
90
92
 
91
93
  ## 📈 Usage visualizations
92
94
 
93
- - **Session detail + heatmap**: sessions sorted by cost (title / project / calls / cost / last active); month / half-year / year calendar heatmap (5-color scale, hover detail; the year view is ~52 weeks, GitHub-style, and the **half-year view uses 26 weeks of large cells** — half a year of intensity in one screenshot-ready chart) with a **cost / tokens metric switch**; total, active-day and streak counts on top.
95
+ - **Session detail + heatmap**: sessions sorted by cost (title / project / calls / cost / last active); "view all N sessions" opens a full-screen viewer (substring search by title / project / id, capped at 100 rows); month / half-year / year calendar heatmap (5-color scale, hover detail; the year view is ~52 weeks, GitHub-style, and the **half-year view uses 26 weeks of large cells** — half a year of intensity in one screenshot-ready chart) with a **cost / tokens metric switch**; total, active-day and streak counts on top.
94
96
  - **Performance metrics**: per-model TTFT mean / P50 / P90, generation speed (tokens/s), total-latency mean; per-hour × per-model comparison curves — metric tabs, clickable model chips (top-5 by samples lit by default), hover snapping to the nearest hour with a crosshair and per-model values, broken lines for missing-sample hours (never fabricated); view preferences persist locally.
95
97
  - **Token insights**: the daily token chart switches between two views — "Structure" (cache-miss / cache-hit / output, including reasoning) and "By model" (the toggle hides itself when snapshots lack per-day-per-model detail); hover shows the day's exact breakdown (thousand-separated); clicking a legend swatch or a model-table row focuses that model (click again to release); structural KPIs (cache-hit rate / reasoning share / input-output ratio / peak day); per-day CSV and JSON export (JSON includes per-day-per-model detail).
96
98
 
@@ -102,7 +104,8 @@ The billing channel is detected from the current session's model: DeepSeek meter
102
104
  ## 🛡️ Robustness & privacy
103
105
 
104
106
  - **Real usage aggregation**: incremental server-side aggregation (only written sessions recompute), per-session corruption tolerance, snapshot fallback; the optional `usage_stats` tool queries today / month / current session / cumulative spend, plus `bySite` (relay-attributed) and `relay` (relay-only) summaries.
105
- - **Model health + uncatalogued annotation**: provider connection dots (green / red / grey); uncatalogued models are marked and priced at the fallback, with the provider inferred (e.g. `mi-mimo-2.5` → Xiaomi); estimated-price models are labeled "estimated".
107
+ - **Model health + uncatalogued annotation**: provider connection dots use tri-state shape + color coding (online = filled ●, failing = double ring ◎, unknown = hollow ○, with status text — colorblind-safe); uncatalogued models are marked and priced at the fallback, with the provider inferred (e.g. `mi-mimo-2.5` → Xiaomi); estimated-price models are labeled "estimated".
108
+ - **Keyboard accessible**: every interactive element in the dashboard and the sidebar trigger card shares a unified focus-visible outline (appears only for keyboard Tab, never on mouse click).
106
109
  - **Multi-language + three currencies**: language (EN / 中) and currency (¥ CNY / $ USD / € EUR) switch **independently**, both plugin-only — neither leaks into the host UI. The rate table, the sidebar card and the composer capsule all convert to the selected currency, and both choices persist locally. On first upgrade the language is seeded once from the stored currency (“$” → English), so no existing user’s interface language changes silently.
107
110
  - **Security hardening**: every HTTP endpoint enforces loopback-only access via a dual check of the peer socket address and an exact Host-header match, rejecting `127.0.0.1.evil.com`-style DNS-rebinding names (reverse-proxy deployments can allow specific names with `trustedHosts`; the peer-socket check stays mandatory); write paths additionally validate a loopback Origin and Content-Type with a body-size cap against cross-site rewrites; balance / subscription / pricing fetches carry bounded retries with per-upstream circuit breaking (auth failures are config issues and do not trip the breaker).
108
111
  - **Export injection guard**: CSV cells starting with `=` / `+` / `-` / `@` get a leading single quote and full escaping, so they cannot execute as formulas in Excel / WPS.
@@ -145,13 +148,13 @@ Browser Server (Node)
145
148
  │ ├─ attributes a call to its preceding request/header model
146
149
  │ ├─ buckets tokens by cache hit / miss
147
150
  │ └─ estimates cost (CNY) from the live rate table
148
- ├─ GET /api/billing/pricing ────────────▶ ├─ live USD→CNY rate and model prices
151
+ ├─ GET /api/billing/pricing ────────────▶ ├─ models.dev model prices + Tencent Finance FX (tiered fallback)
149
152
  ├─ GET /api/billing/balance ────────────▶ ├─ DeepSeek official balance API (credentials seam)
150
153
  ├─ llm.models health probe ─────────────▶ └─ returns aggregated stats JSON
151
154
  └─ renders the dashboard
152
155
  ```
153
156
 
154
- - **Server** (`src/index.ts`): injects `webServer`, `sessionPersistence` and `credentials`, and registers `GET /api/billing/usage-stats`, `/api/billing/pricing`, `/api/billing/balance`, `/api/billing/subscriptions`, `/api/billing/relay-quotas`. The aggregator caches folded results per session: each LLM call is attributed to the model of its preceding `request/header`, tokens split into cache-hit / cache-miss buckets, dates bucketed by the local timezone; a log file with unchanged mtime+size reuses its cached fold, only written sessions are re-folded, and the whole document has a 5s TTL to coalesce heavy polling. Every successfully folded session is also atomically written to an independent durable usage ledger, so permanently deleting a session no longer removes its historical cost or tokens. Aggregation logic lives in `src/aggregate.ts`.
157
+ - **Server** (`src/index.ts`): injects `webServer`, `sessionPersistence` and `credentials`, and registers `GET /api/billing/usage-stats`, `/api/billing/pricing`, `/api/billing/balance`, `/api/billing/subscriptions`, `/api/billing/relay-quotas`, `/api/billing/notify-claim` (cross-instance claim for completion notifications) and `/api/billing/usage-tool` (read/write of the `usage_stats` tool switch). The aggregator caches folded results per session: each LLM call is attributed to the model of its preceding `request/header`, tokens split into cache-hit / cache-miss buckets, dates bucketed by the local timezone; a log file with unchanged mtime+size reuses its cached fold, only written sessions are re-folded, and the whole document has a 5s TTL to coalesce heavy polling. Every successfully folded session is also atomically written to an independent durable usage ledger, so permanently deleting a session no longer removes its historical cost or tokens. Aggregation logic lives in `src/aggregate.ts`.
155
158
  - **Browser** (`src/client/`): requests the endpoints above to render the dashboard and probes each provider connection via `llm.models`. Until real data arrives it shows an all-zero empty snapshot, never fabricated samples.
156
159
 
157
160
  ## 💡 Billing details
@@ -165,29 +168,38 @@ cost (CNY) = (missInput × p_input + cacheHit × p_cacheHit + output × p_output
165
168
 
166
169
  `input` in the stats is total input (cacheHit + cacheMiss); estimation splits it into hit / miss to avoid double counting. Models with two-band billing are mixed by `DEFAULT_PEAK_SHARE` (default 0.5); weekends (Beijing Sat/Sun) are charged at the off-peak rate all day.
167
170
 
168
- ### Supported models (2026-08-21 lineup, OpenAI-compatible)
169
-
170
- | Provider | Models |
171
- | -------- | ------------------------------------------------------------------------------------------- |
172
- | DeepSeek | V4.1 Flash, V4 Pro (priced per official change boundary: base tier → peak/off-peak v1 → weekend off-peak) |
173
- | Zhipu AI | GLM-5.3, GLM-5.2, GLM-5.1, GLM-5, GLM-5-Turbo, GLM-4.7, GLM-4.6, GLM-4.5-Air, GLM-5V-Turbo |
174
- | Aliyun | Qwen3.8 Max, Qwen3.7-Max, Qwen3.7-Plus, Qwen3.7-Flash, Qwen3.5-Plus, Qwen3.5-Flash, Qwen3-Coder 480B |
175
- | Doubao | Seed-2.0 Pro, Seed-2.0 Mini, Seed-1.6 |
176
- | Moonshot | Kimi K3, K2.7 Code, K2.7 Code HighSpeed, K2.6, K2.8 Preview |
177
- | Xiaomi | MiMo V2.6 Pro, MiMo V2.6 Flash, MiMo V2.6 Pro UltraSpeed |
178
- | MiniMax | MiniMax-M3, MiniMax-M2.7, MiniMax-M2.7-highspeed |
179
- | Baidu | ERNIE-5.1 |
180
- | Tencent | Hunyuan T1, Hunyuan Hy3 |
181
- | 01.AI | Yi-Lightning |
182
- | StepFun | Step 3.7 Flash |
183
- | iFlytek | Spark 4.0 Ultra (plan-based)¹ |
184
- | SenseTime | SenseNova 6.5 (beta)¹ |
185
- | Baichuan | Baichuan M3-Plus |
186
- | OpenAI | GPT-6 Astra, GPT-5.6 Sol / Terra / Luna |
187
- | Google | Gemini 3.1 Pro, 3.6 Flash (Standard / Flex two-band, Flex = −50%) |
188
- | xAI | Grok 4.7, Grok 4.6, Grok 4.3 |
189
- | Meta | Llama 4 Maverick, Scout |
190
- | Other | Unified fallback pricing for uncatalogued models |
171
+ ### Supported models (2026-10 lineup, OpenAI-compatible series, 110 models)
172
+
173
+ The full catalog lives in the Rates tab and in `BUILTIN_MODEL_CATALOG` of `src/builtin-catalog.ts` (109 active + 1 retired model kept for historical repricing); representative models per vendor below.
174
+
175
+ | Provider | Representatives |
176
+ | -------- | -------------------------------------------- |
177
+ | DeepSeek | V4.1 Flash, V4 Pro (3 models; priced per official change boundary: base tier → peak/off-peak v1 → weekend off-peak) |
178
+ | Zhipu AI | GLM-5.3, GLM-5.2 (13 models) |
179
+ | Aliyun | Qwen3.8 Max, Qwen3-Coder 480B (11 models) |
180
+ | Doubao | Doubao Seed-2.1 Pro, Doubao Seed-2.0 Pro (9 models) |
181
+ | Moonshot | Kimi K3, Kimi K2.7 Code (10 models) |
182
+ | Xiaomi | MiMo V2.6 Pro (5 models) |
183
+ | MiniMax | MiniMax-M3, MiniMax-M2.7 (4 models) |
184
+ | Unisound | U2 Flash, Unisound U2 (3 models) |
185
+ | Baidu | ERNIE-5.1, ERNIE-4.5 300B (2 models) |
186
+ | Tencent | Hunyuan Hy3, Hunyuan T1 (3 models) |
187
+ | Anthropic | Claude Opus 4.6, Claude Sonnet 4.6 (12 models) |
188
+ | Mistral AI | Mistral Large 3, Mistral Small 4 (3 models) |
189
+ | Cohere | Command A, Command R (2 models) |
190
+ | OpenAI | GPT-6 Astra, GPT-5.6 Sol / Terra / Luna (10 models) |
191
+ | Google | Gemini 3.1 Pro, Gemini 3.6 Flash (4 models) |
192
+ | xAI | Grok 4.7, Grok 4.6 (5 models) |
193
+ | Meta | Llama 4 Maverick (2 models) |
194
+ | Meituan | LongCat 2.0 (estimated) |
195
+ | ModelBest | MiniCPM-V 4.5 (estimated) |
196
+ | Xiaohongshu | Dots3-Note Preview (estimated) |
197
+ | 01.AI | Yi-Lightning |
198
+ | StepFun | Step 3.7 Flash |
199
+ | iFlytek | Spark 4.0 Ultra (plan-based)¹ |
200
+ | SenseTime | SenseNova 6.5 (beta)¹ |
201
+ | Baichuan | Baichuan M3-Plus |
202
+ | Other | Unified fallback pricing for uncatalogued models (cost 0) |
191
203
 
192
204
  > ¹ iFlytek and SenseTime have not published per-token prices — the table shows estimates; cost is 0 when these models go through a subscription channel (coding / token plan / opencode), and recalibrates automatically when official pricing is published. Subscription channels align with pi-ai built-in providers (kimi-coding, zai-coding-cn, opencode, opencode-go, qwen/xiaomi token-plan regional variants), overridable via `subscriptionProviders`.
193
205
 
@@ -195,7 +207,7 @@ To add a model: append an entry to `BUILTIN_MODEL_CATALOG` in `src/builtin-catal
195
207
 
196
208
  ## 🔌 HTTP API
197
209
 
198
- The public HTTP endpoints and field definitions are documented in source: `GET /api/billing/pricing`, `/api/billing/balance`, `/api/billing/usage-stats`, `/api/billing/subscriptions`, `/api/billing/relay-quotas` (see `src/index.ts`, `src/aggregate.ts`, `src/relay.ts`). The `usage-stats` payload carries `bySite` (relay-attributed usage distribution: `site:<origin>` / `direct:<provider>` / `unknown`) and `unpricedModels` (ids of models with no price); `relay-quotas` returns `quotas` plus `diagnostics` (per-route origin / kind classification, for "why is my relay not showing"). All endpoints accept loopback requests only (peer socket address + Host header verified).
210
+ The public HTTP endpoints and field definitions are documented in source: `GET /api/billing/pricing`, `/api/billing/balance`, `/api/billing/usage-stats`, `/api/billing/subscriptions`, `/api/billing/relay-quotas`, `/api/billing/notify-claim` (cross-instance claim for completion notifications) and `/api/billing/usage-tool` (`usage_stats` tool switch, GET/POST) (see `src/index.ts`, `src/aggregate.ts`, `src/relay.ts`). The `usage-stats` payload carries `bySite` (relay-attributed usage distribution: `site:<origin>` / `direct:<provider>` / `unknown`) and `unpricedModels` (ids of models with no price); `relay-quotas` returns `quotas` plus `diagnostics` (per-route origin / kind classification, for "why is my relay not showing"). All endpoints accept loopback requests only (peer socket address + Host header verified).
199
211
 
200
212
  ## ⚙️ Configuration
201
213
 
@@ -204,7 +216,7 @@ The public HTTP endpoints and field definitions are documented in source: `GET /
204
216
  | `statsPath` | unset | Absolute path to a fallback `.dsh-usage-stats.json` (used when `sessionPersistence` is unavailable) |
205
217
  | `ledgerPath` | `<harness home>/.dsh-usage-ledger.json` | Independent durable ledger path; stores folded metrics only (no message bodies or session titles), so deletion does not erase recorded usage. The default root follows the host harness home (`DSH_HOME` env first, falling back to `~/.dsh`), so isolated environments never share ledger data (issue #52) |
206
218
  | `balanceApiKeyEnv` | `DEEPSEEK_API_KEY` | Credential ref for the DeepSeek balance query; only used as a fallback when llm-pi-ai has no `apiKeyEnv` for deepseek |
207
- | `subscriptionProviders` | 11 built-ins (incl. `tencent-token-plan`) | Subscription (coding / token plan) provider id list — tokens counted, cost 0; aligned with the subscription-card recognition |
219
+ | `subscriptionProviders` | built-in channel list (incl. `tencent-token-plan`) | Subscription (coding / token plan) provider id list — tokens counted, cost 0; aligned with the subscription-card recognition |
208
220
  | `routeAliases` | not set | Historical route aliases (old provider route name -> current route): renamed/deleted routes relocate into their channel instead of the "unknown" bucket. Example: `{ "deepseek-official": "tencent" }` |
209
221
  | `modelKeyAliases` | not set | User model aliases (log model id -> billing catalog key, value must be an existing `MODEL_CATALOG` key): bind uncatalogued ids without waiting for a release. Example: `{ "hy4-preview": "hunyuan" }` |
210
222
  | `monthlyBudget` | unset | Default monthly budget (CNY); sent with usage-stats as the budget bar's initial amount (user UI settings take precedence and persist locally) |
@@ -213,6 +225,7 @@ The public HTTP endpoints and field definitions are documented in source: `GET /
213
225
  | `subscriptionPlans` | auto-detect | Subscription quota adapter whitelist (`{ provider, baseUrl?, region? }`); when unset, auto-detects all subscription providers from `llm-pi-ai` (queries those with a quota API, marks the rest) |
214
226
  | `declaredEndpoints` | unset | Declared endpoints (`{ displayName, origin, path, fields?, windows?, raw? }`): self-declare balance/quota interfaces for providers absent from the built-in table, writing only dot-paths ("where the number is") with no expressions; the request URL is built from the matched same-origin provider's `origin` and safety bounds (single-slash absolute path, GET only, reject cross-origin redirects, response-size/timeout caps, credentials only from the matched provider's own `apiKeyEnv`) are enforced by `src/declarative.ts` |
215
227
  | `reconcilePath` | `<harness home>/.dsh-usage-reconcile.json` | Balance-delta reconcile baseline path (default root also follows `DSH_HOME` / `~/.dsh`); cross-checks the official (DeepSeek-direct only) balance change against the local ledger's official-channel cost for the day, and flags a drift above the threshold (0.3 CNY and >15%); top-ups / grants / currency changes reset the baseline instead of alerting |
228
+ | `searchCallEstimateCny` | `0.02` | Per-call cost estimate for web-search requests (`web/deepseek-search-llm-request`, which log no usage events) in CNY; set to 0 to disable the estimate (calls still counted, not billed) |
216
229
 
217
230
  ## 🛠 Development
218
231
 
@@ -220,19 +233,24 @@ Requirements: Node.js ^22.19 || >=24, pnpm.
220
233
 
221
234
  ```sh
222
235
  pnpm install
223
- pnpm --filter @kenz1117/dsh-ui-usage-billing bundle # builds lib/index.js and lib/client.js
224
- npx vitest run packages/client/ui-usage-billing/tests # unit tests
236
+ pnpm test # unit + API-contract mock + UI component tests (vitest + jsdom)
237
+ pnpm lint # discipline guards: types / logging / empty catch / CSS↔TSX class parity
238
+ pnpm run build # tsc -b && tsdown, produces lib/index.js and lib/client.js
225
239
  ```
226
240
 
241
+ For on-machine debugging: `dsh plugin --profile web add "link:<absolute path to this repo>"` points the host at this working tree — afterwards edit code → `pnpm run build` → restart the host, no npm publish needed (see [docs/DEV-MODE.md](docs/DEV-MODE.md) for the loading chain). HTTP-contract e2e: `pnpm test:e2e` (needs a local dev host running). Engineering conventions (two-line release strategy, host-upgrade SOP, acceptance checklists) live in [AGENTS.md](AGENTS.md).
242
+
227
243
  ## 📦 Release
228
244
 
229
- This package is a standalone npm package that other DeepSeek Harness hosts can install once published.
245
+ This package is a standalone npm package. Releases go through the preview line (`latest` + `alpha` tags switched together); the stable line (`stable`) is frozen — see [COMPATIBILITY.md](COMPATIBILITY.md).
230
246
 
231
247
  ```sh
248
+ pnpm test && pnpm run build # full tests + build before release
232
249
  npm publish --access public
250
+ npm dist-tag add @kenz1117/dsh-ui-usage-billing@<version> alpha
233
251
  ```
234
252
 
235
- The host discovers the browser side automatically via the `dsh.client` declaration (`platform: web`) and the `exports["./client"]` bundle in `package.json` — no registry registration needed.
253
+ The host discovers the browser side automatically via the `dsh.client` declaration (`platform: web`) and the `exports["./client"]` bundle in `package.json` — no registry registration needed. The compatibility matrix is declared per version from real-device testing (`dsh.compatibility.dshReleases`); run `node scripts/check-compat.mjs --peer package.json` before and after publishing to re-verify.
236
254
 
237
255
  ## 🔐 Permissions & Compatibility (DSH STORE)
238
256
 
@@ -253,7 +271,7 @@ None. This plugin is a pure UI surface: it registers no tools, injects no system
253
271
  - **Balance queries cover DeepSeek / Moonshot (Kimi) / StepFun / SiliconFlow / xAI / Zhipu GLM (Z.ai CN region) / Tencent Cloud TokenHub (token-plan quota)**: the first six use a standard Bearer API key; Tencent Cloud uses the cloud-API key pair (`<SecretId>:<SecretKey>`, TC3-signed management API). Other providers expose no public balance API or need non-Bearer auth (Xiaomi MiMo via console Cookie, SenseTime via AccessKey signing, MiniMax/Doubao via quota or AK/SK), so they currently show "not configured"; the extension point is `src/balance.ts` (add a querier per provider balance API).
254
272
  - **Relay quota depends on upstream private schemas**: New API / Sub2API interface fields are not public, so an unreadable station is labeled "no quota" rather than fabricating an amount; if a station's response fields differ, extend the parsers in `src/relay.ts`. An "unknown route" means that route exists neither in the current provider config nor in the host llm registry (deleted config, logs older than the install, …); historical call data is not lost — re-adding the same-named route restores attribution automatically. Cost in the unknown-route bucket is always 0 (issue #82): the spending party cannot be verified — same posture as uncatalogued models and subscription channels — while tokens are still counted, and the panel shows "—" for the group cost with an explanatory note. Channels registered by another plugin through `ctx.llm.registerAdapter` (e.g. CommandCode) are **not** unknown routes: the plugin discovers them from the host llm registry and bills them in the `direct:<provider>` bucket at the model's official catalog price (issue #91); the registry is read through `ctx.get('llm')` (no `inject` requirement), and an unreadable or empty registry warns once (panel numbers and the unknown policy are unchanged) so this class of failure is never silent again.
255
273
  - **Overspend notifications rely on the browser Notification API**: when permission is denied or the platform lacks support, only the in-UI red-pulse fallback remains — no host-level notification channel; notifications are capped at once per day.
256
- - **Session rows are not navigable**: clicking a session row does not open that session (cross-plugin navigation needs a host session-selection channel); sessions are capped at 100 rows and the panel shows the top 20.
274
+ - **Session rows are not navigable**: clicking a session row does not open that session (cross-plugin navigation needs a host session-selection channel); the panel shows the top 20 by default and the "view all" full-screen viewer is capped at 100 rows.
257
275
  - **Cost is a catalog estimate**: models without published per-token pricing (iFlytek, SenseTime, Xiaomi) use estimates (feature-list footnote ¹); official billing is authoritative.
258
276
  - **The ledger starts at its first successful aggregation**: sessions permanently deleted before the upgrade and absent from the old snapshot cannot be recovered. Manually deleting `.dsh-usage-ledger.json` and its `.bak` clears independently retained history. Only calls successfully observed by this plugin are retained.
259
277
 
package/README.md CHANGED
@@ -9,6 +9,7 @@
9
9
  <a href="https://github.com/kenz1117/dsh-ui-usage-billing/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/kenz1117/dsh-ui-usage-billing?logo=github"></a>
10
10
  <a href="https://www.npmjs.com/package/@kenz1117/dsh-ui-usage-billing"><img alt="npm version" src="https://img.shields.io/npm/v/@kenz1117/dsh-ui-usage-billing?logo=npm"></a>
11
11
  <a href="https://www.npmjs.com/package/@kenz1117/dsh-ui-usage-billing"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@kenz1117/dsh-ui-usage-billing?logo=npm"></a>
12
+ <a href="https://github.com/kenz1117/dsh-ui-usage-billing/blob/main/COMPATIBILITY.md"><img alt="DSH 兼容" src="https://img.shields.io/badge/DSH-0.1.2_%7E_0.2.1--rc.2_%7C_0.1.0--rc.8%2B-blue"></a>
12
13
  <a href="https://github.com/kenz1117/dsh-ui-usage-billing/blob/main/LICENSE"><img alt="License MIT" src="https://img.shields.io/github/license/kenz1117/dsh-ui-usage-billing"></a>
13
14
  <a href="https://github.com/kenz1117/dsh-ui-usage-billing/pulls"><img alt="PRs welcome" src="https://img.shields.io/badge/PRs-welcome-brightgreen"></a>
14
15
  <a href="https://github.com/kenz1117/dsh-ui-usage-billing"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/kenz1117/dsh-ui-usage-billing?logo=github"></a>
@@ -38,7 +39,7 @@
38
39
  用量从持久化会话日志实时聚合,绝不伪造样本(数据到达前显示空快照);官方余额当日变动与本地账本交叉对账,偏差超阈值主动提示核对——账单经得起质疑。
39
40
 
40
41
  ### 价格是活的,历史不重算
41
- models.dev 实时目录 + 内置 24 厂商 77 款模型 + 设置面板自定义单价(可按中转站绑定同模型不同价),新模型无需等发版;DeepSeek 分时价按官方变更节点**分段计价**(8-17 前基础价、8-17~8-23 周末计峰、8-23 起周末全谷),价格调整永不回写旧账。
42
+ models.dev 实时目录 + 内置 25 厂商 110 款模型 + 设置面板自定义单价(可按中转站绑定同模型不同价),新模型无需等发版;DeepSeek 分时价按官方变更节点**分段计价**(8-17 前基础价、8-17~8-23 周末计峰、8-23 起周末全谷),价格调整永不回写旧账。
42
43
 
43
44
  ### 峰谷全感知,提醒跟着模型走
44
45
  计费通道按当前会话使用的模型自动识别:DeepSeek 按量走分时价(工作日 9-12 / 14-18 高峰 ×2、周末全天低谷),智谱 Coding Plan 走积分峰谷(工作日 14-18 高峰全额、非高峰**积分 5 折**),通道层可扩展、更多厂商逐步接入;切档前弹窗 / 系统通知自动提醒,且只有当前模型真正涉及峰谷才会提醒、费用条才显示档位——不用你盯时间表。
@@ -58,12 +59,13 @@ DeepSeek / Kimi / 智谱 GLM / 腾讯云 TokenHub 等 7 家官方余额、Coding
58
59
 
59
60
  ## 📊 仪表盘
60
61
 
61
- - **侧边栏触发卡**:设置按钮上方常驻本月费用主数字 + 近 7 天 sparkline 迷你趋势,副行「今日 / 本周」;折叠栏自动切为图标钮,悬停浮现速览卡。
62
- - **六区仪表盘**:概览 / 趋势 / 明细 / 统计 / 费率 / 设置——Hero 大数字 + 环比 + 本月预计 + KPI + 用量热力图,趋势 7/30 天可切费用 / Token,模型单价表、预算与峰谷提醒都在;克制冷调、深浅主题自适应。
62
+ - **侧边栏触发卡**:设置按钮上方常驻单值主数字(今日 / 本周 / 本月统计范围在设置里选,可选涨跌徽章),配近 7 天 sparkline 迷你趋势与当日水位仪表指针;折叠栏自动切为图标钮,悬停浮现速览卡(更新时间 + 指标网格 + 主力消耗 / 额度提醒)。
63
+ - **六区仪表盘**:概览 / 趋势 / 明细 / 统计 / 费率 / 设置——Hero 大数字 + 环比 + 本月预计 + KPI(悬停显示口径说明)+ 用量热力图,趋势 7/30 天可切费用 / Token,模型单价表、预算(全局 + 按模型)与峰谷提醒都在;设置页支持全文搜索(中英关键词过滤分区,全不命中显示空态);克制冷调、深浅主题自适应。
63
64
 
64
65
  ![概览:本月费用 Hero、预算进度、KPI 与用量热力图](screenshots/1.png)
65
- - **即时代费用条**:输入框下方常驻「本轮 / 会话」费用;峰谷档位与切换倒计时只在当前模型涉及峰谷时出现;订阅额度预警 chips 剩余 ≤20% 浮现、≤10% 标红;可在设置 Tab 整条隐藏(偏好本地持久化,统计与提醒不受影响)。
66
+ - **即时代费用条**:常驻「本轮 / 会话」费用,位置三档可选(输入框内部工具行 / 上方 / 下方,默认工具行);峰谷档位与切换倒计时只在当前模型涉及峰谷时出现;订阅额度预警 chips 剩余 ≤20% 浮现、≤10% 标红;可在设置 Tab 整条隐藏(偏好本地持久化,统计与提醒不受影响)。
66
67
  - **峰 / 谷切换提醒**:切档前弹窗 + 可选系统通知,提前量 / 位置 / 模式 / 预览均可配;文案按计费通道区分(DeepSeek 价格减半、智谱积分 5 折)。
68
+ - **会话完成提醒**:会话 running → completed 时弹系统通知(默认关闭,面板设置开启);多窗口 / 多实例按认领端点去重,同一会话只提醒一次。
67
69
  - **插件信息卡**:设置 Tab 常驻「关于」卡——版本号服务端读自包 `package.json`(单一来源,发布自动正确),作者 / 仓库 / npm / 许可证一键可达。
68
70
 
69
71
  ## 💰 计费引擎
@@ -74,7 +76,7 @@ DeepSeek / Kimi / 智谱 GLM / 腾讯云 TokenHub 等 7 家官方余额、Coding
74
76
 
75
77
  ![费率:模型单价表(峰谷分时与实时汇率)](screenshots/5.png)
76
78
  - **官方 vs 三方分桶**:明细费用列按官方直连 / 第三方中转分解(混合时「官 x / 三 y」),统计 Tab 有汇总卡;联网搜索辅助请求计入官方。
77
- - **月度预算 + 分档提醒**:预算条 ≥80% 琥珀、超支红脉;跨 50 / 80 / 100% 各提醒一次;余额折算 CNY 低于阈值每天提醒一次。
79
+ - **月度预算 + 分档提醒**:预算条 ≥80% 琥珀、超支红脉;跨 50 / 80 / 100% 各提醒一次;余额折算 CNY 低于阈值每天提醒一次。**按模型预算**:为本月消耗 Top 模型逐个设人民币上限(与全局预算相互独立),单模型跨 80% / 100% 各提醒一次。
78
80
  - **成本突增归因**:最近 40 轮费用柱状图,金额贴柱顶、峰谷背景分带、超 2 倍红标归因。
79
81
 
80
82
  ## 🔌 订阅与余额
@@ -91,7 +93,7 @@ DeepSeek / Kimi / 智谱 GLM / 腾讯云 TokenHub 等 7 家官方余额、Coding
91
93
 
92
94
  ## 📈 用量可视化
93
95
 
94
- - **会话明细 + 热力图**:按会话费用倒序(标题 / 项目 / 调用 / 费用 / 最后活跃);月 / 半年 / 年三档日历热力图(5 档色阶、悬停明细,年视图近 52 周 GitHub 风格,**半年视图 26 周大格**——一张图看完近半年强度,截图即用),**费用 / Token 双口径**切换,头部显示区间合计、活跃天数 / 连续使用天数。
96
+ - **会话明细 + 热力图**:按会话费用倒序(标题 / 项目 / 调用 / 费用 / 最后活跃);「查看全部 N 个会话」打开全屏浮层(按标题 / 项目 / id 子串搜索,封顶 100 行);月 / 半年 / 年三档日历热力图(5 档色阶、悬停明细,年视图近 52 周 GitHub 风格,**半年视图 26 周大格**——一张图看完近半年强度,截图即用),**费用 / Token 双口径**切换,头部显示区间合计、活跃天数 / 连续使用天数。
95
97
  - **性能指标**:每模型 TTFT 均值 / P50 / P90、生成速度(tokens/s)、总延迟均值;按小时 × 模型对比曲线——指标 tab 切换、模型 chip 点击开关曲线(默认点亮样本数前 5)、悬停吸附最近小时显示十字线与逐模型数值,缺失样本小时断线不造假;视图偏好本地持久化。
96
98
  - **Token 统计洞察**:每日 token 堆叠双视角——「按结构」(输入未命中 / 命中 / 输出三桶,含 reasoning)与「按模型」(旧快照缺明细时自动隐藏切换);悬停显示当日精确明细(千分位不缩写),点击图例色块或 Token 表行聚焦单模型(再点解除);结构 KPI(缓存命中率 / 思考占比 / 输入输出比 / 峰值日);按日 CSV 与 JSON 导出(JSON 含按日 × 模型明细)。
97
99
 
@@ -103,7 +105,8 @@ DeepSeek / Kimi / 智谱 GLM / 腾讯云 TokenHub 等 7 家官方余额、Coding
103
105
  ## 🛡️ 健壮性与隐私
104
106
 
105
107
  - **真实用量聚合**:服务端增量聚合(只重算写过的会话),单会话损坏容错、快照落盘回退;`usage_stats` 工具让模型自查今天 / 本月 / 当前会话 / 累计费用,还可查 `bySite`(按站点归组)与 `relay`(只看中转站)汇总。
106
- - **模型健康 + 未收录标注**:厂商接入状态圆点(绿 / 红 / 灰);未收录模型显著标注、按兜底价估算、厂商自动推断(如 `mi-mimo-2.5` → 小米);估算价模型标注「估算价」。
108
+ - **模型健康 + 未收录标注**:厂商接入状态点三态形色双编码(在线实心 ● / 失效双环 ◎ / 未知空心 ○,附状态文本,色弱可辨);未收录模型显著标注、按兜底价估算、厂商自动推断(如 `mi-mimo-2.5` → 小米);估算价模型标注「估算价」。
109
+ - **键盘可达**:仪表盘全部交互元素与侧栏触发卡统一 focus-visible 焦点描边(仅键盘 Tab 时出现,鼠标点击不干扰)。
107
110
  - **多语种 + 三币种**:语言(EN / 中)与币种(¥ CNY / $ USD / € EUR)**各自独立切换**,均仅本插件生效、不影响宿主全局 UI;费率表、侧边栏卡片与输入框胶囊均按所选币种换算,两项选择均本地持久化。老用户首次升级时语言由已存币种播种一次(选 $ 即英文),界面语言不会静默改变。
108
111
  - **安全加固**:全部 HTTP 端点强制回环访问——peer socket 地址 + Host 头精确匹配双重校验,拒绝 `127.0.0.1.evil.com` 形式的 DNS rebinding(反向代理部署可用 `trustedHosts` 显式放行特定主机名,peer socket 校验仍为强制);写操作额外校验 Origin 回环与 Content-Type 并限制 body 上限,杜绝跨站改写;余额 / 订阅 / 定价拉取带有限重试与按上游维度熔断(鉴权失败属配置问题、不计入熔断)。
109
112
  - **导出防注入**:CSV 对 `=` / `+` / `-` / `@` 开头单元格前置单引号并完整转义,防止在 Excel / WPS 中被当作公式执行。
@@ -146,13 +149,13 @@ DeepSeek / Kimi / 智谱 GLM / 腾讯云 TokenHub 等 7 家官方余额、Coding
146
149
  │ ├─ 按 request/header 归属模型
147
150
  │ ├─ token 按缓存命中 / 未命中分桶
148
151
  │ └─ 按实时单价表估算费用(人民币)
149
- ├─ GET /api/billing/pricing ────────────▶ ├─ 腾讯财经 / OpenRouter 实时汇率与模型价
152
+ ├─ GET /api/billing/pricing ────────────▶ ├─ models.dev 模型价 + 腾讯财经汇率(逐级降级)
150
153
  ├─ GET /api/billing/balance ────────────▶ ├─ DeepSeek 官方余额 API(凭据 seam 取 key)
151
154
  ├─ llm.models 健康探测 ─────────────────▶ └─ 返回聚合统计 JSON
152
155
  └─ 渲染仪表盘
153
156
  ```
154
157
 
155
- - **服务端**(`src/index.ts`):注入 `webServer`、`sessionPersistence` 与 `credentials`,注册 `GET /api/billing/usage-stats`、`/api/billing/pricing`、`/api/billing/balance`、`/api/billing/subscriptions`、`/api/billing/relay-quotas`。聚合器按会话缓存折叠结果:一次 LLM 调用归属到其前置 `request/header` 记录的模型,token 拆分到缓存命中 / 未命中桶,日期按本机时区归天;日志文件 mtime+size 不变则直接复用缓存,只有写过的会话重新折叠,整份文档另有 5 秒 TTL 合并密集轮询。每个成功折叠的会话同时原子写入独立的持久用量账本,永久删除会话后历史费用与 token 仍保留。
158
+ - **服务端**(`src/index.ts`):注入 `webServer`、`sessionPersistence` 与 `credentials`,注册 `GET /api/billing/usage-stats`、`/api/billing/pricing`、`/api/billing/balance`、`/api/billing/subscriptions`、`/api/billing/relay-quotas`、`/api/billing/notify-claim`(完成提醒跨实例认领)与 `/api/billing/usage-tool`(`usage_stats` 工具开关读写)。聚合器按会话缓存折叠结果:一次 LLM 调用归属到其前置 `request/header` 记录的模型,token 拆分到缓存命中 / 未命中桶,日期按本机时区归天;日志文件 mtime+size 不变则直接复用缓存,只有写过的会话重新折叠,整份文档另有 5 秒 TTL 合并密集轮询。每个成功折叠的会话同时原子写入独立的持久用量账本,永久删除会话后历史费用与 token 仍保留。
156
159
  - **浏览器端**(`src/client/`):请求上述接口渲染仪表盘,通过 `llm.models` 探测各厂商连接状态。真实数据到达前显示全零空快照,不展示伪造样本。
157
160
 
158
161
  ## 💡 计费细节
@@ -170,27 +173,28 @@ cost(CNY)= (missInput × p_input + cacheHit × p_cacheHit + output × p_outp
170
173
 
171
174
  **自定义单价(设置 Tab,issue #16)**:结构化条目表(模型 + 可选来源 + 输入/缓存命中/输出 + 币种),不再手编 JSON。来源(中转站域名)留空 = 该模型默认价;填入中转站域名(如 `https://api.my-relay.com`)= 仅该来源的同名模型用此价(同名模型可同时存在默认价与多个来源价,互不覆盖)。显示层按「模型 × 来源」精确匹配重算,命中不到来源时回落该模型默认价,再无则用内置目录价。
172
175
 
173
- ### 支持模型(2026-09 主流阵容,OpenAI 兼容系列,共 77 款)
176
+ ### 支持模型(2026-10 主流阵容,OpenAI 兼容系列,共 110 款)
174
177
 
175
- 完整目录见费率 Tab 及源码 `src/client/pricing.ts` 的 `MODEL_CATALOG`,此处每厂商仅列代表型号。
178
+ 完整目录见费率 Tab 及源码 `src/builtin-catalog.ts` 的 `BUILTIN_MODEL_CATALOG`(109 款在售 + 1 款退役型号保留历史回算),此处每厂商仅列代表型号。
176
179
 
177
180
  | 厂商 | 代表模型 |
178
181
  | -------- | -------------------------------------------- |
179
182
  | DeepSeek | V4.1 Flash、V4 Pro(等 3 款;按官方变更节点分段计价:基础价 → 峰谷 v1 → 周末全谷) |
180
- | 智谱 AI | GLM-5.3、GLM-5.2(等 12 款) |
181
- | 阿里通义 | Qwen3.8 Max、Qwen3-Coder 480B(等 10 款) |
182
- | 字节豆包 | Doubao Seed-2.1 Pro、Doubao-Seed-Evolving(等 8 款) |
183
+ | 智谱 AI | GLM-5.3、GLM-5.2(等 13 款) |
184
+ | 阿里通义 | Qwen3.8 Max、Qwen3-Coder 480B(等 11 款) |
185
+ | 字节豆包 | Doubao Seed-2.1 Pro、Doubao Seed-2.0 Pro(等 9 款) |
183
186
  | 月之暗面 | Kimi K3、Kimi K2.7 Code(等 10 款) |
184
- | 小米 | MiMo V2.6 Pro(等 4 款) |
185
- | MiniMax | MiniMax-M3、MiniMax-M2.7(等 3 款) |
187
+ | 小米 | MiMo V2.6 Pro(等 5 款) |
188
+ | MiniMax | MiniMax-M3、MiniMax-M2.7(等 4 款) |
189
+ | 云知声 | U2 Flash、Unisound U2(等 3 款) |
186
190
  | 百度文心 | ERNIE-5.1、ERNIE-4.5 300B(等 2 款) |
187
- | 腾讯混元 | 混元 T1、混元 Hy3(等 2 款) |
188
- | Anthropic | Claude Opus 4.6、Claude Sonnet 4.6(等 5 款) |
191
+ | 腾讯混元 | 混元 Hy3、混元 T1(等 3 款) |
192
+ | Anthropic | Claude Opus 4.6、Claude Sonnet 4.6(等 12 款) |
189
193
  | Mistral AI | Mistral Large 3、Mistral Small 4(等 3 款) |
190
194
  | Cohere | Command A、Command R(等 2 款) |
191
- | OpenAI | GPT-6 Astra、GPT-5.6 Sol / Terra / Luna(等 4 款) |
192
- | Google | Gemini 3.1 Pro、Gemini 3.6 Flash(等 2 款) |
193
- | xAI | Grok 4.7(等 2 款) |
195
+ | OpenAI | GPT-6 Astra、GPT-5.6 Sol / Terra / Luna(等 10 款) |
196
+ | Google | Gemini 3.1 Pro、Gemini 3.6 Flash(等 4 款) |
197
+ | xAI | Grok 4.7、Grok 4.6(等 5 款) |
194
198
  | Meta | Llama 4 Maverick(等 2 款) |
195
199
  | 美团 | LongCat 2.0(估算价) |
196
200
  | 面壁智能 | MiniCPM-V 4.5(估算价) |
@@ -217,7 +221,7 @@ cost(CNY)= (missInput × p_input + cacheHit × p_cacheHit + output × p_outp
217
221
  | `statsPath` | 未设置 | 回退统计文件 `.dsh-usage-stats.json` 的绝对路径(`sessionPersistence` 不可用时生效) |
218
222
  | `ledgerPath` | `<harness home>/.dsh-usage-ledger.json` | 独立持久用量账本的绝对路径;只保存折叠后的统计(不保存消息正文或会话标题),永久删除会话不会删除已记录的费用与 token。**默认根跟随宿主 harness home**(`DSH_HOME` 环境变量优先,回退 `~/.dsh`),自定义 `DSH_HOME` 的多套隔离环境互不污染(issue #52) |
219
223
  | `balanceApiKeyEnv` | `DEEPSEEK_API_KEY` | DeepSeek 余额查询的凭据引用;仅在 llm-pi-ai 未配置 deepseek 的 `apiKeyEnv` 时兜底使用 |
220
- | `subscriptionProviders` | 内置 11 项(含 `tencent-token-plan`) | 订阅制(coding / token 套餐)provider id 列表,照常统计 token、费用记 0;与订阅卡识别口径对齐 |
224
+ | `subscriptionProviders` | 内置订阅通道清单(含 `tencent-token-plan`) | 订阅制(coding / token 套餐)provider id 列表,照常统计 token、费用记 0;与订阅卡识别口径对齐 |
221
225
  | `routeAliases` | 未设置 | 历史路由别名(旧 provider 路由名 → 当前路由名):改名/删除过的路由,其历史用量原落「未知路由」桶且订阅/官方判定失效;配置后按目标路由归位。例:`{ "deepseek-official": "tencent", "tencent-cloud": "tencent" }` |
222
226
  | `modelKeyAliases` | 未设置 | 用户自定义模型别名(真实日志 model id → 计费目录键,值须为 `MODEL_CATALOG` 既有 key):目录外新模型无需等发版,配一条别名即完成识别与计价。例:`{ "hy4-preview": "hunyuan" }` |
223
227
  | `monthlyBudget` | 未设置 | 月度预算默认金额(人民币元);随 usage-stats 下发,作为仪表盘预算条的初始金额(用户在界面上的设置优先并本地持久化) |
@@ -234,19 +238,24 @@ cost(CNY)= (missInput × p_input + cacheHit × p_cacheHit + output × p_outp
234
238
 
235
239
  ```sh
236
240
  pnpm install
237
- pnpm --filter @kenz1117/dsh-ui-usage-billing bundle # 构建 lib/index.js 与 lib/client.js
238
- npx vitest run packages/client/ui-usage-billing/tests # 单元测试
241
+ pnpm test # 单元 + API 契约 mock + UI 组件测试(vitest + jsdom)
242
+ pnpm lint # 纪律守卫:类型 / 日志 / 空 catch / CSS↔TSX 类名 parity
243
+ pnpm run build # tsc -b && tsdown,产出 lib/index.js 与 lib/client.js
239
244
  ```
240
245
 
246
+ 本地真机调试:`dsh plugin --profile web add "link:<本仓绝对路径>"` 把宿主指向本仓,此后改代码 → `pnpm run build` → 重启宿主即生效,无需发 npm(加载链路详解见 [docs/DEV-MODE.md](docs/DEV-MODE.md))。HTTP 契约 e2e 用 `pnpm test:e2e`(需本地 dev host 在跑)。工程约定(双线发布策略、宿主升级 SOP、验收清单)见 [AGENTS.md](AGENTS.md)。
247
+
241
248
  ## 📦 发布
242
249
 
243
- 本包为独立 npm 包,发布后即可被其他 DeepSeek Harness 宿主安装。
250
+ 本包为独立 npm 包,发布走预览线(`latest` + `alpha` 双 tag 同步切换);稳定线(`stable`)已冻结,详见 [COMPATIBILITY.md](COMPATIBILITY.md)。
244
251
 
245
252
  ```sh
253
+ pnpm test && pnpm run build # 发版前全量测试 + 构建
246
254
  npm publish --access public
255
+ npm dist-tag add @kenz1117/dsh-ui-usage-billing@<版本> alpha
247
256
  ```
248
257
 
249
- 宿主通过 `package.json` 的 `dsh.client` 声明(`platform: web`)与 `exports["./client"]` bundle 自动发现浏览器端,无需注册中心登记。
258
+ 宿主通过 `package.json` 的 `dsh.client` 声明(`platform: web`)与 `exports["./client"]` bundle 自动发现浏览器端,无需注册中心登记。兼容矩阵以真机实测为准、逐版本精确声明(`dsh.compatibility.dshReleases`),发布前后跑 `node scripts/check-compat.mjs --peer package.json` 复核。
250
259
 
251
260
  ## 🔐 权限与兼容声明(DSH STORE)
252
261
 
@@ -267,7 +276,7 @@ npm publish --access public
267
276
  - **余额查询已接入 DeepSeek / 月之暗面(Kimi)/ 阶跃星辰(StepFun)/ 硅基流动 / xAI / 智谱 GLM(Z.ai 国内域)/ 腾讯云 TokenHub(Token Plan 余量)**:前六家用标准 Bearer API key,腾讯云用云 API 密钥对(TC3 签名)。其余厂商因无公开余额接口或需非 Bearer 鉴权(小米 MiMo 走控制台 Cookie、商汤走 AccessKey 签名、MiniMax/字节豆包走额度制或 AK/SK),暂显示「未配置」;扩展点在 `src/balance.ts`(按厂商余额 API 增加查询器)。
268
277
  - **中转站额度依赖上游私有 schema**:New API / Sub2API 的接口字段未公开,读不出时标「未读出额度」而非臆造金额;若某中转站响应字段不同,需按 `src/relay.ts` 的解析器扩展。未知路由表示该路由在当前 provider 配置与宿主 llm 注册表里都不存在(配置已删、日志比安装更早等),历史调用数据未丢,重新配置同名路由即可自动归位。未知路由桶的费用一律记 0(issue #82):支出主体无法核实,与未收录模型、订阅通道同姿态——token 照常统计,面板组头费用显示「—」并附说明。由独立插件经 `ctx.llm.registerAdapter` 注册的通道(如 CommandCode)不属于未知路由:插件从宿主 llm 注册表发现它们,按 `direct:<provider>` 桶以模型官方目录价计费(issue #91);注册表读取走 `ctx.get('llm')`(免 `inject` 声明),读不到/读到空集合时告警一次(面板数字不变,unknown 口径不变),避免这类失效无声无息。
269
278
  - **超支通知依赖浏览器 Notification**:权限被拒绝或平台不支持时只有界面红色脉冲兜底,没有宿主级通知通道;通知上限为每天一次。
270
- - **会话明细不可跳转**:点击会话行不会打开对应会话(跨插件导航需要宿主会话选择通道);会话数封顶 100 行、面板只显示前 20 行。
279
+ - **会话明细不可跳转**:点击会话行不会打开对应会话(跨插件导航需要宿主会话选择通道);面板默认只显示前 20 行,「查看全部」全屏浮层封顶 100 行。
271
280
  - **费用为目录价估算**:讯飞 / 商汤 / 小米等未公布按量单价的模型使用估算价(特性表脚注 ¹),正式定价以厂商账单为准。
272
281
  - **账本从首次成功聚合开始生效**:升级前已经永久删除且不在旧快照中的会话无法恢复;手动删除 `.dsh-usage-ledger.json` 及其 `.bak` 会清空独立保留的历史。账本只保留本插件已经成功观测过的调用。
273
282
  - **历史回放预热**:插件加载 3 秒后台自动全量折叠宿主全部历史会话日志(账本幂等,重复折叠不重复计数),首次打开面板即可看到完整历史统计,无需等一遍首次折叠。历史会话按「首次折叠时的模型单价」计价;厂商改价前的历史消耗不会按新价重算(价格目录无历史时点价,属估算口径)。