dsh-cost-meter 1.7.13 → 1.7.15

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
@@ -6,7 +6,7 @@
6
6
 
7
7
  Per-conversation cost · daily totals · OpenCode Go subscription quota display · budget with usage percentage · official account balance · custom provider balance · balance progress bar · history · peak/off-peak pricing hours display (peak hours UTC 01:00–04:00, 06:00–10:00; from Aug 23, 2026 weekends are billed at off-peak prices all day, shown as “Weekend — all off-peak”) · pre-switch popup & system-notification alerts for peak/off-peak changes (position / lead time / alert type configurable) · one-click price sync from the official docs · Codex-style token usage heat grid · multi-vendor model pricing (built-in 90+ model price catalog with auto-matching) · mainstream Coding Plan quota queries & display (Anthropic / Z.ai / MiniMax / Kimi / OpenRouter / SiliconFlow / CommandCode / SCNet) plan/API dual-track billing (subscription quota vs pay-as-you-go money separated, per-1% & full-window token/equivalent-cost estimates with daily/weekly/monthly curves) · · quota strip above the input box (budget / Go / coding-plan usage in one row, toggleable)
8
8
 
9
- [![version](https://img.shields.io/badge/version-1.7.13-4176E6)](https://github.com/Han-1413141/dsh-cost-meter)
9
+ [![version](https://img.shields.io/badge/version-1.7.15-4176E6)](https://github.com/Han-1413141/dsh-cost-meter)
10
10
  [![npm](https://img.shields.io/npm/v/dsh-cost-meter?label=npm)](https://www.npmjs.com/package/dsh-cost-meter)
11
11
  [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
12
12
  [![dsh](https://img.shields.io/badge/DeepSeek%20Harness-dsh--plugin-4176E6)](https://github.com/deepseek-ai/deepseek-harness)
@@ -59,6 +59,8 @@ English | [中文](README.md)
59
59
 
60
60
  For Qianwen / Alibaba Cloud fund accounts, use **Add Qianwen / Alibaba Cloud balance** to query available funds with a RAM AccessKey signature. The card uses the currency returned by the API. See the [setup, permissions and balance definition](docs/qianwen-balance.md#english).
61
61
 
62
+ Local Qwen Token Plan credits include only the subscription providers `qwen`, `qwen-tokenplan`, `qianwen-tokenplan`, `qwen-token-plan` and `qianwen-token-plan` (case-insensitive, optional `llm-` prefix). Explicit API classifications are excluded. The `qianwen` pay-as-you-go provider does not consume estimated plan credits even when its model ID is identical. Use one of the supported subscription provider names; models outside the credits table need all three rates configured.
63
+
62
64
  The `extract` rules accept four forms: a numeric constant, a dot path string, `add`/`subtract` over multiple paths, and `divide` scaling by a `by` divisor. **`divide` fits NewApi and other endpoints that meter balance in integer quota** (1 USD = 500000 quota — the same conversion cc-switch uses).
63
65
 
64
66
  For NewApi `GET /api/usage/token` (response `{ "code": 200, "data": { "total_granted": ..., "total_used": ..., "total_available": ..., "unlimited_quota": false } }`):
@@ -254,22 +256,22 @@ Real captures from an actual DSH sidebar of the period strip and collapsed verti
254
256
  dsh plugin --profile web add dsh-cost-meter
255
257
  ```
256
258
 
257
- **PowerShell one-click script** (copy the whole line, paste, press Enter; pnpm is provisioned automatically, git is auto-detected — no clone needed; the install chain is **pinned to the release tag `v1.7.13`** — review the script before running):
259
+ **PowerShell one-click script** (copy the whole line, paste, press Enter; pnpm is provisioned automatically, git is auto-detected — no clone needed; the install chain is **pinned to the release tag `v1.7.15`** — review the script before running):
258
260
 
259
261
  ```powershell
260
- irm https://raw.githubusercontent.com/Han-1413141/dsh-cost-meter/v1.7.13/install.ps1 | iex
262
+ irm https://raw.githubusercontent.com/Han-1413141/dsh-cost-meter/v1.7.15/install.ps1 | iex
261
263
  ```
262
264
 
263
265
  **Or a plain command line** (the machine must already have pnpm and git; also pinned to the tag):
264
266
 
265
267
  ```sh
266
- dsh plugin --profile web add github:Han-1413141/dsh-cost-meter#v1.7.13
268
+ dsh plugin --profile web add github:Han-1413141/dsh-cost-meter#v1.7.15
267
269
  ```
268
270
 
269
271
  Without git, use the GitHub tag archive:
270
272
 
271
273
  ```sh
272
- dsh plugin --profile web add https://github.com/Han-1413141/dsh-cost-meter/archive/refs/tags/v1.7.13.tar.gz
274
+ dsh plugin --profile web add https://github.com/Han-1413141/dsh-cost-meter/archive/refs/tags/v1.7.15.tar.gz
273
275
  ```
274
276
 
275
277
  After installing, **restart** `dsh web` (plugin rows, the Typert manifest and the client bundle are all scanned at startup):
@@ -286,14 +288,16 @@ Cause: your environment (pnpm config or a policy bundled into the invoking insta
286
288
 
287
289
  Fix:
288
290
 
289
- 1. **Upgrade to a version with exact-pinned dependencies**: all three runtime dependencies (`@deepseek-ai/dsh-credentials`, `@deepseek-ai/dsh-home-paths`, `zod`) are now exact-pinned a pinned version's publish date never changes, so it satisfies any age threshold and this plugin can no longer trigger the error;
290
- 2. If the error is triggered by **another plugin's** dependencies instead, append an exclusion for the offending `name@version` printed in the error to the profile's `pnpm-workspace.yaml` (default `$DSH_HOME/profiles/web/pnpm-workspace.yaml`) and retry:
291
+ 1. **Upgrade the plugin and use the host's plugin installer**: `zod` remains exact-pinned. `@deepseek-ai/dsh-credentials` and `@deepseek-ai/dsh-home-paths` are now peer dependencies supplied by DSH, avoiding duplicate old host packages that can fail dependency preflight (issue #106). Pinning prevents version drift but cannot satisfy every age threshold;
292
+ 2. If an age restriction remains, wait until the version reaches the threshold, or review the exact package and version in the error before choosing to add an individual exclusion to the profile's `pnpm-workspace.yaml` (default `$DSH_HOME/profiles/web/pnpm-workspace.yaml`):
291
293
 
292
294
  ```yaml
293
295
  minimumReleaseAgeExclude:
294
296
  - '<name@version from the error>'
295
297
  ```
296
298
 
299
+ Host checks cover installation, startup, shared modules and removal on DSH `0.1.2-rc.1` and `0.1.3-alpha.2`. `0.1.3-alpha.1` remains unknown because its official npm version is unavailable. See the [compatibility record](docs/host-compatibility.md) for the environment and limits.
300
+
297
301
  ### Update / Uninstall
298
302
 
299
303
  ```sh
@@ -320,7 +324,7 @@ dsh plugin --profile web add link:./dsh-cost-meter # symlink; edit lib/client.j
320
324
  - **Historical billing correctness**: calls before 2026-08-16 16:00 UTC (the peak-era boundary) are billed at the base prices of that time, and later calls at the two-tier scheme;
321
325
  - The ledger always stores amounts in **USD**; currency and FX rate only affect display (default 1 USD = 7.2 CNY, configurable);
322
326
  - The session badge is **billed exactly** at the moment each call is made (host-exported per-call cost), just like daily/monthly/cumulative totals and the budget;
323
- - Billing sources are the `usage` block of every model call (including sub-agents, compression, title generation and other auxiliary calls), matching the billable view;
327
+ - Billing uses usage blocks reported through the host's `llm/stream`, including sub-agents, compression, title generation and other auxiliary calls in isolated LLM services. Child sessions retain their own `sessionId` and do not contribute to the parent badge; background calls without a `sessionId` contribute only to daily/monthly/lifetime totals. Memory or other plugins that call external APIs directly without reporting usage to the host cannot be tracked;
324
328
  - **Peak/off-peak tiers follow the request-initiation moment**: a streaming call can span the tier boundary hour; attributing by completion time would put a request started minutes earlier into the wrong tier;
325
329
  - **Peak effective-time anchoring**: the official pricing page no longer lists an effective time, and price sync no longer resets the peak effective moment to "now" — historical recomputes (session projection refolds / per-model backfill) always tier events against the 2026-08-16 16:00 UTC boundary, so peak-hour history is no longer re-costed at half price; ledgers polluted earlier are clamped back automatically on upgrade (idempotent migration);
326
330
  - **Switching pricing currency re-bases the whole history**: after the pricing-currency setting flips and re-syncs, historical entries are re-costed on the new price table in the background (days fully covered by session logs are replaced wholesale; sessions whose logs were cleaned keep their original basis), so history and the official bill share one basis, with a notice on completion; on upgrading to this version, existing ledgers that had switched currency and ended up with mixed bases are recomputed once automatically;
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  本会话费用 · 当日费用 · OpenCode Go 订阅额度显示 · 预算与已用百分比 · 官方账户余额 · 自定义 Provider 余额查询(可配任意 HTTP 端点) · 余额三段进度条 · 历史记录 · 峰谷计价时段显示(UTC 01:00–04:00、06:00–10:00 为峰时段;2026-08-23 起周末全天按谷价,显示「周末时段——全谷价」) · 峰/谷切换前弹窗与系统通知提醒(位置/提前量/提醒类型可配) · 官方价格一键同步 · 类 Codex Token 用量热图 · 多厂商多模型价格计费(内置 90+ 模型价格目录与自动匹配) · 主流 Coding Plan 额度查询与显示(Anthropic / Z.ai / MiniMax / Kimi / OpenRouter / SiliconFlow / CommandCode / SCNet / 火山方舟 九家,含 Volcano Ark AK/SK 签名) · Plan/API 双轨计费(订阅额度与按量金额分离统计,每 1% 额度与满窗的 token/等值金额估算及日/周/月曲线) · 输入框上方额度横条(预算/Go/Coding Plan 用量一条横排显示,可开关)
8
8
 
9
- [![version](https://img.shields.io/badge/version-1.7.13-4176E6)](https://github.com/Han-1413141/dsh-cost-meter)
9
+ [![version](https://img.shields.io/badge/version-1.7.15-4176E6)](https://github.com/Han-1413141/dsh-cost-meter)
10
10
  [![npm](https://img.shields.io/npm/v/dsh-cost-meter?label=npm)](https://www.npmjs.com/package/dsh-cost-meter)
11
11
  [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
12
12
  [![dsh](https://img.shields.io/badge/DeepSeek%20Harness-dsh--plugin-4176E6)](https://github.com/deepseek-ai/deepseek-harness)
@@ -60,6 +60,8 @@
60
60
 
61
61
  千问 / 阿里云资金账户余额可直接点击「添加千问 / 阿里云余额」,使用 RAM AccessKey 签名查询,显示接口返回的可用金与币种;配置步骤、所需权限及口径见[千问余额说明](docs/qianwen-balance.md)。
62
62
 
63
+ 千问 Token Plan 的本地 Credits 仅统计 `qwen`、`qwen-tokenplan`、`qianwen-tokenplan`、`qwen-token-plan`、`qianwen-token-plan` 订阅 provider(大小写不敏感,可带 `llm-` 前缀);显式归类为 API 的调用不计。`qianwen` 按量 provider 即使使用相同模型名也不会计入订阅额度。自定义渠道名需使用上述订阅名称之一,模型不在抵扣表中时需补充三项费率。
64
+
63
65
  自定义 Provider 余额的 `extract` 规则支持四种形式:数字常量、点路径字符串、`add`/`subtract` 多路径加减、`divide` 按 `by` 除数缩放。**`divide` 适用于 NewApi 等以 quota 整数计量的端点**(1 USD = 500000 quota,与 cc-switch 同款换算)。
64
66
 
65
67
  以 NewApi 的 `GET /api/usage/token` 为例(响应 `{ "code": 200, "data": { "total_granted": ..., "total_used": ..., "total_available": ..., "unlimited_quota": false } }`):
@@ -256,22 +258,22 @@
256
258
  dsh plugin --profile web add dsh-cost-meter
257
259
  ```
258
260
 
259
- **PowerShell 一键脚本**(复制整行粘贴回车;自动补齐 pnpm、自动探测 git,无需克隆仓库;安装链**固定到发布 tag `v1.7.13`**,建议先下载审阅再运行):
261
+ **PowerShell 一键脚本**(复制整行粘贴回车;自动补齐 pnpm、自动探测 git,无需克隆仓库;安装链**固定到发布 tag `v1.7.15`**,建议先下载审阅再运行):
260
262
 
261
263
  ```powershell
262
- irm https://raw.githubusercontent.com/Han-1413141/dsh-cost-meter/v1.7.13/install.ps1 | iex
264
+ irm https://raw.githubusercontent.com/Han-1413141/dsh-cost-meter/v1.7.15/install.ps1 | iex
263
265
  ```
264
266
 
265
267
  **或直接命令行**(机器上需已有 pnpm 与 git;同样固定到 tag):
266
268
 
267
269
  ```sh
268
- dsh plugin --profile web add github:Han-1413141/dsh-cost-meter#v1.7.13
270
+ dsh plugin --profile web add github:Han-1413141/dsh-cost-meter#v1.7.15
269
271
  ```
270
272
 
271
273
  没有 git 时可用 GitHub tag 打包直链:
272
274
 
273
275
  ```sh
274
- dsh plugin --profile web add https://github.com/Han-1413141/dsh-cost-meter/archive/refs/tags/v1.7.13.tar.gz
276
+ dsh plugin --profile web add https://github.com/Han-1413141/dsh-cost-meter/archive/refs/tags/v1.7.15.tar.gz
275
277
  ```
276
278
 
277
279
  安装后**重启** `dsh web`(插件行、Typert 清单与客户端 bundle 均在启动时扫描):
@@ -288,14 +290,16 @@ dsh web
288
290
 
289
291
  处理:
290
292
 
291
- 1. **升级到含依赖精确锁版的版本**:三个运行时依赖(`@deepseek-ai/dsh-credentials`、`@deepseek-ai/dsh-home-paths`、`zod`)已全部精确锁版——锁定版本的发布时间固定不变,对任意年龄阈值永远满足,本插件不再可能触发该错误;
292
- 2. 若报错由**其他插件**的依赖触发,可在 profile 目录的 `pnpm-workspace.yaml`(默认 `$DSH_HOME/profiles/web/pnpm-workspace.yaml`)按报错列出的条目追加排除后重试:
293
+ 1. **升级插件并使用宿主插件安装器**:独立运行依赖 `zod` 保持精确锁版;`@deepseek-ai/dsh-credentials`、`@deepseek-ai/dsh-home-paths` 改由宿主通过 peer dependency 提供,避免另装旧版宿主包触发依赖预检(issue #106)。精确锁版能防止版本漂移,但不能保证满足任意年龄阈值;
294
+ 2. 若仍出现年龄限制,可等待该版本达到阈值,或在核实报错中的具体包与版本后,由你决定是否在 profile `pnpm-workspace.yaml`(默认 `$DSH_HOME/profiles/web/pnpm-workspace.yaml`)加入单项排除:
293
295
 
294
296
  ```yaml
295
297
  minimumReleaseAgeExclude:
296
298
  - '<报错中的包名>@<版本>'
297
299
  ```
298
300
 
301
+ 宿主适配验证覆盖 DSH `0.1.2-rc.1`、`0.1.3-alpha.2` 的安装、启动、模块复用和卸载;`0.1.3-alpha.1` 无可获取的官方 npm 版本,暂标记为未知。验证环境及边界见[兼容记录](docs/host-compatibility.md)。
302
+
299
303
  ### 更新 / 卸载
300
304
 
301
305
  ```sh
@@ -322,7 +326,7 @@ dsh plugin --profile web add link:./dsh-cost-meter # 符号链接,改 lib/clien
322
326
  - **历史计费正确性**:2026-08-16 16:00 UTC(峰谷时代分界)之前的调用按当时的基础价计费,之后的调用按峰谷两档;
323
327
  - 账本金额恒以**美元**存储,币种/汇率仅影响显示(默认 1 USD = 7.2 CNY,可改);
324
328
  - 会话徽章与当日/月度/累计、预算一样,按每次调用的**实际时刻精确计费**(宿主导出的逐次成本);
325
- - 计费来源为每次模型调用的 usage 块(含子代理、压缩、标题等辅助调用),与账单口径一致;
329
+ - 计费来源为通过宿主 `llm/stream` 上报的 usage 块,包含隔离 LLM 服务中的子代理、压缩、标题等辅助调用。子会话按自己的 `sessionId` 记录,不并入父会话徽章;无 `sessionId` 的后台调用只计入日/月/累计总额。记忆等插件若直接请求外部 API、未向宿主上报 usage,本插件无法统计该部分消耗;
326
330
  - **峰谷档位按请求发起时刻判定**:流式调用可能跨峰谷边界整点,以完成时刻归档会把数分钟前发起的请求算进另一个峰位;
327
331
  - **峰谷生效时刻锚定**:官方价格页已不再标注生效时间,价格同步不再把峰谷生效时刻重置为「同步时刻」——历史重算(会话投影回放 / 按模型回填)一律按 2026-08-16 16:00 UTC 分界判档,峰时历史事件不再被按谷价半价重算;此前被污染的存量账本升级时自动钳制修复(幂等迁移);
328
332
  - **币种切换即全量换基准**:「价格币种」切换并同步后,历史账目按新价目在后台整体重算(会话日志覆盖完整的日子整体替换,日志已清理的会话保持原口径),历史与官方账单同基准,完成后有提示;升级到本版时,此前切换过币种而新旧口径并存的存量账本自动重算一次;
package/lib/backfill.js CHANGED
@@ -893,9 +893,10 @@ export async function importLegacyHistory(ledger, sessionsRoot) {
893
893
  * splitLedgerApiCost 重写(与 plan/api 分类口径对齐)。
894
894
  * @param ledger - 已打开的账本(config 已是目标币种价格表)。
895
895
  * @param sessionsRoot - 宿主会话根目录($DSH_HOME/sessions)。
896
+ * @param includeBucket - 可选的 (providerModelKey, date) 过滤器,仅修复目标价格路径。
896
897
  * @returns {{ scanned, recostedSessions, skippedSessions, recostedDays }}。
897
898
  */
898
- export async function recomputeLedgerPricingBasis(ledger, sessionsRoot) {
899
+ export async function recomputeLedgerPricingBasis(ledger, sessionsRoot, includeBucket) {
899
900
  const result = { scanned: 0, recostedSessions: 0, skippedSessions: 0, recostedDays: 0 }
900
901
  const bySession = new Map()
901
902
  for (const path of listSessionLogs(sessionsRoot)) {
@@ -912,7 +913,7 @@ export async function recomputeLedgerPricingBasis(ledger, sessionsRoot) {
912
913
  bySession.set(replayed.sessionId, replayed.days)
913
914
  continue
914
915
  }
915
- mergeDayMaps(existing.days, replayed.days)
916
+ mergeDayMaps(existing, replayed.days)
916
917
  }
917
918
  const touchedDates = new Set()
918
919
  const tokenFields = ['input', 'output', 'cacheRead', 'cacheWrite', 'reasoning', 'calls']
@@ -926,7 +927,7 @@ export async function recomputeLedgerPricingBasis(ledger, sessionsRoot) {
926
927
  const dayPm = day.byProviderModel !== null && typeof day.byProviderModel === 'object' ? day.byProviderModel : {}
927
928
  // 前置校验(全部通过才动账):键集合一致、逐键 token/calls 相等、日期聚合
928
929
  // 含全部键。任何一条不满足都保持旧口径,杜绝半改状态。
929
- let replaceable = newKeys.length > 0
930
+ let replaceable = newKeys.length > 0 && newKeys.length === Object.keys(oldPm).length
930
931
  for (const key of newKeys) {
931
932
  const oldBucket = oldPm[key]
932
933
  const dayBucket = dayPm[key]
@@ -941,18 +942,21 @@ export async function recomputeLedgerPricingBasis(ledger, sessionsRoot) {
941
942
  result.skippedSessions += 1
942
943
  continue
943
944
  }
944
- const totals = sumDayMap(pm)
945
- const oldCost = Number(row.cost) || 0
946
- const oldApi = Number(row.apiCost) || 0
947
- row.byProviderModel = cloneDayMap(pm)
948
- row.cost = totals.cost
949
- row.apiCost = totals.apiCost
950
- day.cost = (Number(day.cost) || 0) - oldCost + totals.cost
951
- day.apiCost = (Number(day.apiCost) || 0) - oldApi + totals.apiCost
952
- for (const key of newKeys) {
945
+ const selected = includeBucket ? newKeys.filter(key => includeBucket(key, date)) : newKeys
946
+ if (selected.length === 0) continue
947
+ // 只替换已验证的桶并逐差额调整容器;保留未选中模型和无明细残差。
948
+ row.byProviderModel = cloneDayMap(oldPm)
949
+ for (const key of selected) {
950
+ const costDelta = (Number(pm[key].cost) || 0) - (Number(oldPm[key].cost) || 0)
951
+ const apiDelta = (Number(pm[key].apiCost) || 0) - (Number(oldPm[key].apiCost) || 0)
952
+ row.byProviderModel[key] = { ...pm[key] }
953
+ row.cost = (Number(row.cost) || 0) + costDelta
954
+ row.apiCost = (Number(row.apiCost) || 0) + apiDelta
955
+ day.cost = (Number(day.cost) || 0) + costDelta
956
+ day.apiCost = (Number(day.apiCost) || 0) + apiDelta
953
957
  const dayBucket = dayPm[key]
954
- dayBucket.cost = (Number(dayBucket.cost) || 0) - (Number(oldPm[key].cost) || 0) + (Number(pm[key].cost) || 0)
955
- dayBucket.apiCost = (Number(dayBucket.apiCost) || 0) - (Number(oldPm[key].apiCost) || 0) + (Number(pm[key].apiCost) || 0)
958
+ dayBucket.cost = (Number(dayBucket.cost) || 0) + costDelta
959
+ dayBucket.apiCost = (Number(dayBucket.apiCost) || 0) + apiDelta
956
960
  }
957
961
  result.recostedSessions += 1
958
962
  touchedDates.add(date)