dsh-all-usage 1.1.14 → 1.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  All notable changes to `dsh-all-usage` are documented here.
4
4
 
5
+ ## [1.1.16] - 2026-09-29
6
+
7
+ ### Added
8
+
9
+ - **DSH 0.2.0-rc.2 is a supported runtime.** The real Cordis smoke passes on it — every route, the session hooks, the ledger flush, the revision fast path and disposal — so `dsh.compatibility.runtime` gains `>=0.2.0-rc.2 <0.2.1-0`, `0.2.0-rc.2` joins the verified list (now six runtimes) and the CI smoke matrix (Node 22/24, twelve jobs). The line keeps the 0.1.7 Cordis pairing (cordis 4.0.4 / loader 1.0.5 / timer 1.1.6) and the abstract settings seam instead of the file-backed provider, which is exactly what the smoke runs against. README (both languages, including the badge and the verified matrix) follows the new declaration.
10
+ ## [1.1.15] - 2026-09-28
11
+
12
+ ### Added
13
+
14
+ - **Chinese statutory holidays can price as a full off-peak day.** A peak plan now carries an explicit `holidays` date list (China Standard Time calendar days: validated, sorted, de-duplicated, at most 400 entries, and part of the policy hash so the existing audit/repricing rules apply unchanged). On those days no rule can claim an instant, and each cost snapshot records `pricingHoliday`, so the ledger distinguishes a holiday off-peak band from an ordinary one. The panel exposes it as a switch plus a date list that also accepts `start..end` ranges, and `POST /api/all-usage/pricing/holidays` fetches one year of the State Council arrangement (the holiday-cn dataset: jsDelivr first, GitHub raw as a fallback, 24-hour host-side cache) so the list can be filled with one click; the fetch writes nothing — only saving freezes the dates (plus a provenance note that stays out of the policy hash) into the plan. The built-in DeepSeek peak plan now ships the 2026 arrangement itself (33 off-days taken from the State Council notice, with the provenance stored next to the dates), because DeepSeek's own rule is "Monday to Friday excluding Chinese public holidays": first-party and mapped DeepSeek routes therefore price holidays as off-peak with no configuration at all, and snapshots priced under the previous plan are migrated once. The official wording keeps weekends off-peak in full, so swapped-in working weekends (调休) need no extra handling.
15
+
16
+ ### Changed
17
+
18
+ - **Cost Settings is now one editable price table.** The separate "Model mappings" and "Explicit price overrides" sections are gone: every ledger model gets a row whose four price boxes write that model's manual price, whose official-model column sets or clears the identity mapping (and previews the target rates immediately), and whose two chips expand a context-rate-band editor and a UTC peak/off-peak editor. Rows that exist only in the saved configuration (an override or mapping with no ledger usage yet) are returned with `usageBacked: false` so they stay visible, editable and removable.
19
+ - **Peak/off-peak plans are editable per model.** `GET /api/all-usage/pricing` now carries `temporalSchedules` (deduplicated like `tierSchedules`) plus `temporalExplicit`, `temporalBuiltin` and `temporalConfigInvalid` on every row, so the panel can show whether a row uses the built-in DeepSeek table or a custom plan, copy the built-in table for customisation, restore it, or drop the plan. Changing a plan reconciles that model's history against the new policy (the documented audit semantics); price edits still never rewrite existing positive costs, and the panel says so.
20
+
21
+ ### Fixed
22
+
23
+ - The pricing configuration round-trips `providerId` and `temporalPricing` on overrides. Dropping `providerId` from the snapshot turned a provider-scoped manual price into a provider-agnostic one on the next save and stopped it from being found as a mapping target, so a saved mapping could silently fall back to the catalog price.
24
+ - `GET /api/all-usage/pricing/models` returns `rates`, `providerName`, `tiered`/`tierCount` and `builtinTemporal` per match, so the mapping column can preview a price before saving.
25
+
26
+ ### Internal
27
+
28
+ - The compact `/api/all-usage` snapshot keeps its shape: temporal detail, schedule ids and configuration-only rows are only emitted for the detailed pricing payload, and `test/pricing-editor.test.js` guards that boundary.
5
29
  ## [1.1.14] - 2026-09-27
6
30
 
7
31
  ### Fixed
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![stars](https://img.shields.io/github/stars/ParticleLight/dsh-all-usage?label=stars&logo=github)](https://github.com/ParticleLight/dsh-all-usage/stargazers)
7
7
  [![license](https://img.shields.io/github/license/ParticleLight/dsh-all-usage?label=license&color=green)](LICENSE)
8
8
  [![CI](https://github.com/ParticleLight/dsh-all-usage/actions/workflows/ci.yml/badge.svg)](https://github.com/ParticleLight/dsh-all-usage/actions/workflows/ci.yml)
9
- [![DSH](https://img.shields.io/badge/DSH-0.1.1--0.1.7-4D6BFE)](#兼容性与已知限制)
9
+ [![DSH](https://img.shields.io/badge/DSH-0.1.1--0.2.0-4D6BFE)](#兼容性与已知限制)
10
10
  [![status](https://img.shields.io/badge/status-stable-brightgreen)](https://github.com/ParticleLight/dsh-all-usage/releases)
11
11
 
12
12
  [中文](#中文) · [English](#english)
@@ -20,7 +20,7 @@ DeepSeek Harness 全量用量看板:按模型、供应商、工作区和时间
20
20
  - **热力图**:53 周使用热力图;按工作区筛选并查看每日回合与 Token 明细
21
21
  - **模型统计**:支持混合查看、按模型合并、按供应商汇总三种维度,展示调用次数、各类 Token 与缓存命中率;模型行与筛选下拉显示真实厂商品牌 SVG 图标(未知/混牌保持中性)
22
22
  - **摘要与工作区**:Token 用量、缓存命中、估算成本、账户余额、连续使用、工作区 Token 分布和明细
23
- - **成本统计**:从 models.dev 同步模型价格;按输入、输出、缓存读取和缓存写入四个桶计算,保存价格快照,明确区分已计价、免费模型和未计价调用
23
+ - **成本统计 / 价格表**:从 models.dev 同步模型价格;按输入、输出、缓存读取和缓存写入四个桶计算,保存价格快照,明确区分已计价、免费模型和未计价调用。成本设置是一张可编辑的价格表:每行一个账本模型,价格框直接编辑即写入该模型的手工价,「官方模型」列选定映射后该行自动改用官方目录价,并可为每行配置**上下文费率档位**与**分时段(UTC 峰谷)计费**;配置里存在但账本暂无用量的行同样可见、可改、可删。峰谷规则可额外开启「中国法定节假日全天按谷时计价」,节假日日期以显式列表保存在该模型的峰谷计划里(按北京时间 UTC+8 日历日判定,支持 2026-10-01..2026-10-07 区间写法,也可一键「从公开日历载入」当年放假安排后冻结进策略)。内置 DeepSeek 峰谷表已自带 2026 年官方放假安排(随插件版本更新),官方直连或已映射到官方条目的行无需任何配置即按节假日谷价计价;非官方直连的中转行仍按静态价,映射后生效
24
24
  - **导出**:按当前时间范围和模型聚合方式导出 CSV
25
25
  - **时间范围**:今日、近 30 天、近 90 天、全部,或在全部可扫描历史日数据中自定义起止日期;热力图始终展示最近 53 周
26
26
  - **工作区别名**:在侧栏入口打开看板后管理,持久化保存到 $DSH_HOME/storages 的 KV 单元 `all_usage_aliases`
@@ -33,17 +33,18 @@ DeepSeek Harness 全量用量看板:按模型、供应商、工作区和时间
33
33
  - **趋势折线图**:按当前范围、时区、工作区、供应商和模型显示输入、缓存读写、输出、推理及总处理量;单日范围按小时聚合并显示小时轴,跨日范围按日聚合;使用平滑单调曲线与入场动画,悬停查看精确值,图例可切换曲线,点击点位进入当日明细
34
34
  - **统一筛选与审计**:工作区、供应商、模型和日期筛选贯穿摘要、热力图、趋势、表格与 CSV;工作区、供应商、模型三个筛选维度可独立自由组合,工作区、供应商和模型选项只展示当前日期范围内实际使用过的值;切换范围后失效筛选会自动清除;请求日志以紧凑分页表常驻显示,选择单条后查看分组 Token 详情
35
35
  - **Token 口径**:输入按「未含缓存命中」计,缓存命中 / 写入与推理独立成桶;全 0 用量的重放事件不会覆盖已记录的真实用量,仅缓存命中的请求也会计入
36
- - **成本口径**:模型价格来自 models.dev 的 USD / 1M Token 目录;成本快照按 DSH 已归一化的 fresh input 和四类价格桶计算,倍率只作用于最终总价,已有正成本历史不会因价格更新重算;只按模型选择官方厂商条目,未找到官方价格时显示为未计价
36
+ - **成本口径**:模型价格来自 models.dev 的 USD / 1M Token 目录;成本快照按 DSH 已归一化的 fresh input 和四类价格桶计算,倍率只作用于最终总价,已有正成本历史不会因价格更新重算;只按模型选择官方厂商条目,未找到官方价格时显示为未计价。同一官方模型的价格在所有行之间共享:价格框写入的是该模型的手工价条目;价格改动永不重算已有正成本,而峰谷规则改动会按新政策重新对账该模型历史
37
37
 
38
38
  ### 兼容性与已知限制
39
39
 
40
40
  - **运行环境**:需要 Node.js `>=22 <25`;CI 会在 Node 22 和 Node 24 上运行测试、语法检查和 npm 包内容检查。
41
- - **DSH 兼容**:`package.json` 声明 DSH runtime `>=0.1.1-rc.1 <0.1.5-0 || >=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.2 <0.1.8-0`,已使用 `0.1.7-rc.2`、`0.1.5-rc.2`、`0.1.5-rc.1`、`0.1.1-rc.2` 和 `0.1.1-rc.1` 的真实 Cordis 服务链验证,且全部纳入 CI smoke 矩阵(Node 22/24 双档);`0.1.2-rc.1` 已通过实际使用验证兼容,但未纳入 CI smoke 矩阵。声明按元组拆成三段而非写成单一区间,是因为 node-semver 只有在范围里存在与目标版本同 `major.minor.patch` 且自身带预发布标签的比较符时,才会放行该预发布版本 —— 例如必须写成 `>=0.1.7-rc.2` 才能让 `0.1.7-rc.2` 进入范围。
41
+ - **DSH 兼容**:`package.json` 声明 DSH runtime `>=0.1.1-rc.1 <0.1.5-0 || >=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.2 <0.1.8-0 || >=0.2.0-rc.2 <0.2.1-0`,已使用 `0.2.0-rc.2`、`0.1.7-rc.2`、`0.1.5-rc.2`、`0.1.5-rc.1`、`0.1.1-rc.2` 和 `0.1.1-rc.1` 的真实 Cordis 服务链验证,且全部纳入 CI smoke 矩阵(Node 22/24 双档);`0.1.2-rc.1` 已通过实际使用验证兼容,但未纳入 CI smoke 矩阵。声明按元组拆成四段而非写成单一区间,是因为 node-semver 只有在范围里存在与目标版本同 `major.minor.patch` 且自身带预发布标签的比较符时,才会放行该预发布版本 —— 例如必须写成 `>=0.2.0-rc.2` 才能让 `0.2.0-rc.2` 进入范围。
42
42
  - **桌面客户端(Electron,Windows)**:本插件在 DSH 桌面客户端上实测运行正常(实测 `@deepseek-ai/dsh-desktop` `0.1.7-rc.2`)。桌面客户端会在窗口顶部为自身的最小化 / 最大化 / 关闭按钮保留一条 40px 顶栏,并在文档上标记 `data-windows-titlebar` 与 `--dsh-windows-titlebar-height`;面板据此从该条**下方**开始绘制,所以桌面端自己的关闭按钮永远不会被面板盖住。浏览器端没有该标记,不留白。顶栏高度优先取宿主声明,其次取 Window Controls Overlay 矩形,最后退回 UA;需要微调时可在 DevTools 执行 `localStorage.setItem('dsh-all-usage:topInset', '48')` 后刷新(`0` 表示不留白),无需重新构建。桌面客户端自带运行时,其运行时 `0.1.7-rc.2` 已纳入声明区间与 CI smoke 矩阵(见下表)。
43
43
  - **Web 服务依赖**:Host 将 `webServer` 声明为必需依赖,确保服务晚挂载时由 DSH 等待后再执行插件;该包面向 DSH Web profile,不提供无 WebServer 的 headless 路由。HTTP 守卫还会检查真实 socket peer,反向代理只有在连接本身来自 loopback 时才会被接受。
44
44
 
45
45
  | DSH runtime | Node.js 支持 | 真实 Cordis smoke | 结论 |
46
46
  | --- | --- | --- | --- |
47
+ | `0.2.0-rc.2` | `>=22 <25`,CI 覆盖 22/24 | 通过(真实 Cordis 服务链,CI 覆盖 Node 22/24) | 已声明、已验证(DSH 官方 `next` 线;本机 web profile 即运行于此版本) |
47
48
  | `0.1.7-rc.2` | `>=22 <25`,CI 覆盖 22/24 | 通过(真实 Cordis 服务链,CI 覆盖 Node 22/24) | 已声明、已验证(DSH 桌面客户端即运行于此版本) |
48
49
  | `0.1.5-rc.2` | `>=22 <25`,CI 覆盖 22/24 | 通过(真实 Cordis 服务链,CI 覆盖 Node 22/24) | 已声明、已验证 |
49
50
  | `0.1.5-rc.1` | `>=22 <25`,CI 覆盖 22/24 | 通过(真实 Cordis 服务链,CI 覆盖 Node 22/24) | 已声明、已验证 |
@@ -115,11 +116,10 @@ node scripts/replay-fixture.mjs fixtures/usage-events.json
115
116
 
116
117
  ### 最近更新
117
118
 
118
- **v1.1.14**
119
+ **v1.1.16**
119
120
 
120
- - **`deepseek-flash`(DeepSeek V4.1 Flash)现在正确按峰谷计价**:它与 `deepseek-v4-flash` 同 family、同基础价(0.15 / 0.6 / 0.003),但内置峰谷表里只有 v4 那几个 id,导致它的每条记录都按静态价计、面板显示「静态价(无峰谷计划)」—— 峰值时段成本被少算约 **57%**。现已把该模型写入内置表(峰值档 0.44 / 1.32 / 0.014);非峰值费率仍取目录实时值,峰谷计划仍只对第一方路由生效。由 @baileyh8 在 #2 报告。
121
- - **历史记录自动修正**:升级后首次启动时,此前以「无峰谷计划」结论落盘的记录会被 `reconcileTemporalPricing()` 按各自用量发生时刻一次性迁移重算并回写账本,无需手动操作(已带档位的记录不会被目录刷新改写,仍需显式 `repriceTemporal`)。
122
- - README 顶部徽章更新:npm 版本 / **全量下载** / stars / license / CI / DSH 兼容 / status。
121
+ - **正式支持 DSH 0.2.0-rc.2**:真实 Cordis 服务链 smoke 在该运行时上全部通过(全部路由、session 钩子、账本 flush、revision 快路径、dispose),声明区间新增 `>=0.2.0-rc.2 <0.2.1-0`,已验证列表增至 6 个运行时,CI smoke 矩阵扩到 **6 个版本 × Node 22/24 = 12 个作业**;该运行时线沿用 0.1.7 的 Cordis 组合(cordis 4.0.4 / loader 1.0.5 / timer 1.1.6)与抽象 settings seam,插件无需代码改动。
122
+ - 本版只改**兼容性声明、CI 矩阵与文档**(README 中英同步:声明引用、验证表、徽章)。上一个版本的功能(1.1.15:可编辑价格表、中国法定节假日全天谷价、面板性能修复)见 CHANGELOG。
123
123
 
124
124
  完整版本记录见 [CHANGELOG.md](CHANGELOG.md)。
125
125
 
@@ -170,10 +170,11 @@ dsh plugin --profile web add github:ParticleLight/dsh-all-usage
170
170
  - `GET /api/all-usage/records` — 按 scope 分页返回脱敏 canonical usage rows
171
171
  - `GET /api/all-usage/balance?force=1` — 账户余额(复用 `llm-deepseek` 的 API Key 配置)
172
172
  - `POST /api/all-usage/alias` — 设置工作区别名
173
- - `GET /api/all-usage/pricing` — 查看 models.dev 同步状态、已用模型匹配和显式覆盖
174
- - `GET /api/all-usage/pricing/models?q=...` — 检索官方模型 ID 与名称匹配结果
175
- - `POST /api/all-usage/pricing` — 保存同步、mapping 和显式价格覆盖(含 context tier 档位)
173
+ - `GET /api/all-usage/pricing` — 读取可编辑价格表所需的完整配置:逐模型的生效费率与状态、映射、手工价、峰谷计划(含内置表来源与完整规则)以及仅存在于配置中的行
174
+ - `GET /api/all-usage/pricing/models?q=...` — 检索官方模型 ID 与名称匹配结果(含预览费率、是否分层计费、是否有内置峰谷表)
175
+ - `POST /api/all-usage/pricing` — 保存同步、mapping、手工价,以及上下文费率档位与峰谷时段规则(请求形状不变)
176
176
  - `POST /api/all-usage/pricing/sync` — 手动同步 models.dev 并回填未计价调用
177
+ - `POST /api/all-usage/pricing/holidays` — 按年份抓取中国法定节假日安排(holiday-cn 数据集,jsDelivr 主源、GitHub raw 兜底,主机侧缓存 24 小时),只返回放假日日期列表与来源;**不写入任何配置**,由客户端冻结进峰谷计划
177
178
  - `GET /api/all-usage/client-env` — 客户端环境诊断上报(UA、窗口控件遮罩高度、预留顶栏值**及其来源**、视口、面板矩形);客户端在加载与打开面板时各上报一次,只在内存保留
178
179
  - **Client 端**:可读源码位于 `src/client.js`,`npm run build:client` 使用固定版本 Terser 生成 `window.__ModuleLoader__` 工厂格式的 `lib/client.js` 浏览器 bundle,并注册侧边栏「用量统计」入口(`sidebar.footer.action` 槽位)。所有 API 仅接受本机 loopback 请求并拒绝显式跨域请求;余额读取与别名写入还要求插件启动时生成、仅在当前进程有效的令牌(余额 GET 兼容浏览器省略 Origin)。英文模式的日期分桶、范围筛选、连续使用、热力图和导出时间统一按 UTC;中文模式按本地时区。
179
180
 
@@ -189,9 +190,11 @@ dsh plugin --profile web add github:ParticleLight/dsh-all-usage
189
190
  - records 接口只返回短 hash、时间、工作区 ID、结构化模型身份、turn/step、Token buckets 和当前物化来源,不返回原始 session ID、路径、提示词、回复或凭据
190
191
  - 看板中的总处理量 = 输入 + 输出 + 缓存读写 + 推理;缓存命中表示复用的上下文 Token,不等于新生成 Token 或实际费用
191
192
  - 成本计算沿用 cc-switch 的四桶公式:输入、输出、缓存读取和缓存写入分别乘每百万价格,四项相加后再乘倍率;context tier 在输入上下文严格大于阈值时为整次请求切换四项费率,不做渐进分段;DSH 的 reasoning 字段不再次加到 output,避免底层 completion/thoughts 已含推理时重复计费
193
+ - 分时段计费以 UTC 周几与半开时间窗判定:命中规则的请求使用峰时四项费率,未命中时使用该行基础价(谷时=基础价);生效起点之前的用量没有可验证档位,会失败关闭为未计价而不会套用今天的费率;同一峰谷计划被所有使用该价格条目的行共享;开启节假日规则后,节假日当天不再命中任何峰时规则,成本快照会记下 pricingHoliday,明细里显示为「节假日谷时」而不是普通「谷时」
192
194
  - 历史账本中带 `tiered` 标志的旧 flat 成本会在加载升级时迁移为 `unsupported`(`tiered-pricing-not-modeled`),不再继续显示为当前精确 priced;Token 统计不受影响。
193
- - 价格同步默认关闭;models.dev 不可用时保留最近一次成功目录,未匹配模型不会套用默认价格;成本设置可展开查看官方档位,并为显式 override 增删 context tier;看板范围与明细视图保存在浏览器本地,6 小时自动同步开关会立即写入受保护的 pricing API
195
+ - 价格同步默认关闭;models.dev 不可用时保留最近一次成功目录,未匹配模型不会套用默认价格;成本设置的价格框即手工价入口(同一官方模型的所有行共享该价格),每行可展开配置上下文档位与 UTC 峰谷规则(含可选的中国法定节假日全天谷价),内置 DeepSeek 峰谷表可一键复制后自定义、也可恢复;看板范围与明细视图保存在浏览器本地,6 小时自动同步开关会立即写入受保护的 pricing API
194
196
  - Mapping 语义:带 `identityKey` 的 mapping 只对精确路由身份生效;不带身份键的 mapping 才按模型做全局回退;旧配置中的 `usageIdentityKey` 会在加载时归一化。
197
+ - 节假日日历只在用户点击「从公开日历载入」时抓取:目标主机是 `cdn.jsdelivr.net`(失败时 `raw.githubusercontent.com`),请求里只有年份,**不发送任何用量、会话或凭据数据**;返回的日期串在用户保存前不会生效,保存后连同来源说明一起冻结进该模型的峰谷计划(来源不参与政策哈希)
195
198
  - 余额查询走 DeepSeek 官方 `/user/balance` 接口;未配置 API Key 时卡片显示引导文案
196
199
  - 账本按 session ID 稳定 hash 到 32 个 JSON shard,单次 flush 只重写对应 shard;旧的 `all_usage_ledger.json` 会在首次加载时迁移,异步写失败或退出前未落盘不会丢失内存统计,只会让下次启动重新扫描
197
200
  - 仅统计能归属到已注册工作区(按会话 cwd 匹配)的会话
@@ -211,7 +214,7 @@ A full usage dashboard for DeepSeek Harness. Analyze tokens, cache behavior, est
211
214
  - **Heatmap**: a 53-week activity heatmap with workspace filters and daily turn/token details
212
215
  - **Model analytics**: mixed view, model-merged view, and provider summary with calls, token categories, and cache hit rate; model rows and the model filter dropdown render vendor brand SVG icons (neutral for unknown or mixed brands)
213
216
  - **Summary and workspaces**: processed tokens, cache hits, estimated cost, account balance, usage streaks, workspace distribution, and details
214
- - **Cost statistics**: sync model prices from models.dev, calculate four cost buckets, persist price snapshots, and distinguish priced, free, ambiguous, and unpriced calls
217
+ - **Cost statistics / price table**: sync model prices from models.dev, calculate four cost buckets, persist price snapshots, and distinguish priced, free, ambiguous, and unpriced calls. Cost Settings is one editable price table: each row is a ledger model, its price boxes write that model's manual price, the official-model column switches the row to the catalog price, and every row can carry context rate bands and time-of-day (UTC peak/off-peak) rules, including an optional "Chinese statutory holidays price as off-peak all day" switch whose explicit date list lives in that model's peak plan (China Standard Time calendar days, 2026-10-01..2026-10-07 ranges supported, and one click loads the year's arrangement from a public calendar before it is frozen into the policy); rows that exist only in the saved configuration stay visible, editable, and removable
215
218
  - **CSV export**: export data using the selected time range and aggregation mode
216
219
  - **Time ranges**: today, last 30 days, last 90 days, all time, or a custom start/end date across all available historical daily data; the heatmap always shows the latest 53 weeks
217
220
  - **Workspace aliases**: manage aliases from the sidebar dashboard; values persist in the $DSH_HOME/storages KV cell `all_usage_aliases`
@@ -229,12 +232,13 @@ A full usage dashboard for DeepSeek Harness. Analyze tokens, cache behavior, est
229
232
  ### Compatibility and Known Limitations
230
233
 
231
234
  - **Runtime**: Node.js `>=22 <25` is required. CI runs the test suite, syntax checks, and package-content checks on Node 22 and Node 24.
232
- - **DSH compatibility**: `package.json` declares DSH runtime `>=0.1.1-rc.1 <0.1.5-0 || >=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.2 <0.1.8-0`; the real Cordis service chain is verified on `0.1.7-rc.2`, `0.1.5-rc.2`, `0.1.5-rc.1`, `0.1.1-rc.2` and `0.1.1-rc.1`, all of them covered by the CI smoke matrix on Node 22 and 24. `0.1.2-rc.1` has also been verified compatible through real-world use, but is not covered by the CI smoke matrix. The declaration is split per tuple rather than written as one interval because node-semver only admits a prerelease version when some comparator shares its exact `major.minor.patch` tuple and itself carries a prerelease tag — `0.1.7-rc.2` is admitted only because the range says `>=0.1.7-rc.2`.
235
+ - **DSH compatibility**: `package.json` declares DSH runtime `>=0.1.1-rc.1 <0.1.5-0 || >=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.2 <0.1.8-0 || >=0.2.0-rc.2 <0.2.1-0`; the real Cordis service chain is verified on `0.2.0-rc.2`, `0.1.7-rc.2`, `0.1.5-rc.2`, `0.1.5-rc.1`, `0.1.1-rc.2` and `0.1.1-rc.1`, all of them covered by the CI smoke matrix on Node 22 and 24. `0.1.2-rc.1` has also been verified compatible through real-world use, but is not covered by the CI smoke matrix. The declaration is split per tuple rather than written as one interval because node-semver only admits a prerelease version when some comparator shares its exact `major.minor.patch` tuple and itself carries a prerelease tag — `0.2.0-rc.2` is admitted only because the range says `>=0.2.0-rc.2`.
233
236
  - **Desktop client (Electron, Windows)**: the plugin is verified running in the DSH desktop client (`@deepseek-ai/dsh-desktop` `0.1.7-rc.2` as measured). The desktop client keeps a 40px caption strip across the top of its window for its own minimise / maximise / close buttons and marks the document with `data-windows-titlebar` and `--dsh-windows-titlebar-height`; the panel draws from **below** that strip, so the client's own close button is never covered. Browsers carry no such marker and reserve nothing. The strip height comes from the host's declaration first, then the Window Controls Overlay rectangle, then the user agent; to tune it, run `localStorage.setItem('dsh-all-usage:topInset', '48')` in DevTools and reload (`0` reserves nothing) — no rebuild required. The desktop client ships its own runtime, and that runtime — `0.1.7-rc.2` — is now part of the declared range and of the CI smoke matrix below.
234
237
  - **Web service dependency**: the Host declares `webServer` as a required dependency, so DSH waits for a late-mounted service before applying the plugin; this package targets the DSH Web profile and does not expose routes without WebServer. The HTTP guard also checks the actual socket peer, so a reverse proxy is accepted only when the connection itself is loopback.
235
238
 
236
239
  | DSH runtime | Node.js support | Real Cordis smoke | Conclusion |
237
240
  | --- | --- | --- | --- |
241
+ | `0.2.0-rc.2` | `>=22 <25`, CI covers 22/24 | Passed (real Cordis service chain, CI covers Node 22/24) | Declared and verified (the current DSH `next` line; this machine's web profile runs it) |
238
242
  | `0.1.7-rc.2` | `>=22 <25`, CI covers 22/24 | Passed (real Cordis service chain, CI covers Node 22/24) | Declared and verified (the DSH desktop client runs this version) |
239
243
  | `0.1.5-rc.2` | `>=22 <25`, CI covers 22/24 | Passed (real Cordis service chain, CI covers Node 22/24) | Declared and verified |
240
244
  | `0.1.5-rc.1` | `>=22 <25`, CI covers 22/24 | Passed (real Cordis service chain, CI covers Node 22/24) | Declared and verified |
@@ -256,7 +260,7 @@ This plugin reports replayable statistics from local DSH event logs; it is not a
256
260
 
257
261
  - Local statistics read DSH `assistant/chunk`, final `assistant/message`, and related session events, then deduplicate and replace samples by logical `turn / step`. Official billing may use a provider tokenizer, rounding rules, discounts, free quotas, and billing periods.
258
262
  - A failed request is included locally whenever it leaves a usage chunk; whether the provider charged for that failed request must be checked against the official bill.
259
- - Prices come from the public models.dev catalog and local explicit overrides. Catalog prices can differ from provider prices, regional rates, and invoice discounts, so the cost field is an estimate.
263
+ - Prices come from the public models.dev catalog and local explicit overrides. Catalog prices can differ from provider prices, regional rates, and invoice discounts, so the cost field is an estimate. A price belongs to the model, so every row priced from the same official model shares one manual entry; price edits never rewrite existing positive costs, while a peak-plan change reconciles that model's history against the new policy.
260
264
  - Local statistics include registered workspaces only; old ledger rows for unregistered cwds are excluded. Usage recorded for a **deleted workspace** is kept and summed into one "Deleted" row, so removing a workspace never shrinks historical totals. Totals can still be lower than the official bill when logs are damaged, cleaned up, or the upstream emits no usage event.
261
265
 
262
266
  ### Reproducible Event Examples
@@ -306,11 +310,10 @@ The command loads the real plugin Host, calls its compatible APIs, checks the do
306
310
 
307
311
  ### Latest Update
308
312
 
309
- **v1.1.14**
313
+ **v1.1.16**
310
314
 
311
- - **`deepseek-flash` (DeepSeek V4.1 Flash) is now priced with the peak/off-peak plan**: models.dev lists it in the same `deepseek-flash` family and at the same standard rates as `deepseek-v4-flash` (0.15 / 0.6 / 0.003), but the built-in table only carried the v4 ids, so every record for it was priced flat — the cost panel said "static (no band plan)" and a peak-hour request was under-reported by roughly **57%**. The model is now declared in the built-in table (peak band 0.44 / 1.32 / 0.014); off-peak rates still come from the live catalog entry, and the plan still applies to first-party routes only. Reported by @baileyh8 in #2.
312
- - **Existing history is corrected automatically**: on the first start after upgrading, records stored with the "no band plan" verdict are migrated once by `reconcileTemporalPricing()` against their own usage instant and written back to the ledger — no manual step. Records that already carry a band are still never rewritten by a catalog refresh; those need an explicit `repriceTemporal`.
313
- - README badges updated: npm version / **total downloads** / stars / license / CI / DSH compatibility / status.
315
+ - **DSH 0.2.0-rc.2 is a supported runtime**: the real Cordis service chain smoke passes on it (every route, the session hooks, the ledger flush, the revision fast path and disposal), so the declaration gains `>=0.2.0-rc.2 <0.2.1-0`, the verified list grows to six runtimes and the CI smoke matrix to **six versions × Node 22/24 (twelve jobs)**. The line keeps the 0.1.7 Cordis pairing (cordis 4.0.4 / loader 1.0.5 / timer 1.1.6) and the abstract settings seam, so no plugin code change was needed.
316
+ - This release only touches the **compatibility declaration, the CI matrix and the documentation** (README in both languages: quoted range, verified table, badge). The feature work of v1.1.15 (the editable price table, Chinese statutory holiday pricing, panel performance fixes) is recorded in the changelog.
314
317
 
315
318
  See [CHANGELOG.md](CHANGELOG.md) for the complete version history.
316
319
 
@@ -353,10 +356,11 @@ The profile patch layer hot-reloads; save the file and refresh the page.
353
356
  - `GET /api/all-usage/records` — paginated privacy-safe canonical usage rows
354
357
  - `GET /api/all-usage/balance?force=1` — account balance using the configured `llm-deepseek` API key
355
358
  - `POST /api/all-usage/alias` — update workspace aliases
356
- - `GET /api/all-usage/pricing` — inspect models.dev sync status, used-model matches, and explicit overrides
357
- - `GET /api/all-usage/pricing/models?q=...` — search official model IDs and display-name matches
358
- - `POST /api/all-usage/pricing` — save sync, mappings, and explicit price overrides, including context-tier bands
359
+ - `GET /api/all-usage/pricing` — read the full editable price table: per-row effective rates and status, mappings, manual prices, peak plans (with their built-in/explicit origin and full rules), and rows that exist only in the configuration
360
+ - `GET /api/all-usage/pricing/models?q=...` — search official model IDs and display names, including preview rates, tiered-pricing flags, and whether a built-in peak table exists
361
+ - `POST /api/all-usage/pricing` — save sync, mappings, manual prices, context rate bands, and peak-window rules (request shape unchanged)
359
362
  - `POST /api/all-usage/pricing/sync` — sync models.dev and backfill unpriced calls
363
+ - `POST /api/all-usage/pricing/holidays` — fetch one year of the Chinese holiday arrangement (the holiday-cn dataset, jsDelivr first with a GitHub raw fallback, cached host-side for 24 hours) and return only the off-day list plus its source; **nothing is written to the configuration** — the client freezes the dates into a peak plan
360
364
  - `GET /api/all-usage/client-env` — client environment report (user agent, window-controls overlay height, the reserved strip **and its source**, viewport, panel rectangles); the client reports it at load and whenever the sheet opens, kept in memory only
361
365
  - **Client**: readable source lives in `src/client.js`; `npm run build:client` uses the pinned Terser version to generate the `window.__ModuleLoader__` bundle at `lib/client.js`, which registers the “Usage statistics” sidebar entry through the `sidebar.footer.action` slot. All API routes accept loopback requests and reject an explicit cross-origin Origin; balance reads and alias writes also require a process-scoped token generated when the plugin starts (the balance GET tolerates browsers omitting Origin).
362
366
 
@@ -372,9 +376,11 @@ The profile patch layer hot-reloads; save the file and refresh the page.
372
376
  - The records endpoint returns only a short hash, time, workspace ID, structured model identity, turn/step, token buckets, and current materialization source. It omits raw session IDs, paths, prompts, replies, and credentials
373
377
  - Processed tokens = input + output + cache read/write + reasoning; a cache hit means reused context, not newly generated tokens or actual cost
374
378
  - Cost follows the cc-switch four-bucket formula: input, output, cache-read, and cache-write tokens are priced independently, summed, then multiplied by the final multiplier; when input context is strictly greater than a context-tier threshold, all four rates switch for the whole request instead of progressive band splitting, and DSH reasoning is not added to output a second time
379
+ - Time-of-day pricing matches UTC weekdays against half-open windows: a matching request uses the rule's peak rates, anything else uses the row base rates (off-peak = base); usage before a plan's effective instant has no verifiable band and fails closed as unpriced instead of inheriting today's rates, and one plan is shared by every row priced from the same entry (for DeepSeek the built-in plan carries the official State Council holiday list, refreshed with plugin releases); with the holiday switch on, a statutory holiday never matches a peak window and the cost snapshot records pricingHoliday, so records show "Holiday off-peak" instead of a plain off-peak band. The built-in DeepSeek table already ships the 2026 arrangement (refreshed with plugin releases), so first-party or mapped DeepSeek rows price holidays as off-peak with no configuration; reseller routes stay static until they are mapped to the official entry
375
380
  - Legacy ledger costs carrying `tiered` are migrated to `unsupported` (`tiered-pricing-not-modeled`) on load instead of remaining falsely marked as current flat priced estimates; token statistics are unchanged.
376
- - Pricing sync is off by default; when models.dev is unavailable the last good catalog remains in use, and unmatched models never receive a guessed default price; Cost Statistics can expand official tier schedules and add or remove context tiers on explicit overrides; dashboard range and detail-view preferences are stored in browser storage, while the 6-hour sync toggle is immediately saved through the protected pricing API
381
+ - Pricing sync is off by default; when models.dev is unavailable the last good catalog remains in use, and unmatched models never receive a guessed default price; the Cost Settings price boxes are the manual-price entry point (shared by every row priced from the same official model), each row expands into context bands and UTC peak rules (including optional all-day off-peak pricing on Chinese statutory holidays), and the built-in DeepSeek table can be copied for customisation or restored; dashboard range and detail-view preferences are stored in browser storage, while the 6-hour sync toggle is immediately saved through the protected pricing API
377
382
  - Mapping semantics: a mapping with `identityKey` applies only to that exact route identity; a mapping without an identity key is the model-wide fallback. Legacy `usageIdentityKey` values are normalized when loaded.
383
+ - The holiday calendar is fetched only when the user clicks "Load from public calendar": the request goes to `cdn.jsdelivr.net` (falling back to `raw.githubusercontent.com`), carries nothing but the year, and **never includes usage, session, or credential data**; the returned dates stay inert until saved, and saving freezes them together with their source note into that model's peak plan (the source is excluded from the policy hash)
378
384
  - Balance data comes from DeepSeek’s official `/user/balance` endpoint; the card shows guidance when no API key is configured
379
385
  - English mode uses UTC for date buckets, range filters, streaks, heatmap dates, and export timestamps; Chinese mode uses local time
380
386
  - The ledger assigns each session ID to one of 32 stable-hash JSON shards, so a flush rewrites only its shard; the old `all_usage_ledger.json` is migrated on first load. An async write failure or an unflushed shutdown does not lose in-memory statistics; the next startup simply scans that session again
Binary file