# 更新日志 / Changelog

`@feiyang666/dsh-usage-plugin` — DeepSeek Harness 用量与消耗插件

本文件按版本记录每一次更新的详细内容（新功能 / 优化 / 修复 / 界面 / 性能）。每次发布到 GitHub 时，请据此填写「版本发布」（GitHub Releases）的更新说明。

> 版本规范：本插件按「语义化版本」递增，`主.次.补丁`。功能新增/界面变化 → 升次版本（x.y.x → x.y+1.0）；仅 bug 修复 → 升补丁。

---

## v2.0.0 (2026-11-01) —— 大版本：修复 + 计费口径 + 界面重构 + 性能 + 适配

> 本次是**一次对外发布**：下面「v1.19.0 ~ v1.24.0」是这次大版本在开发过程中的内部分步记录，
> 均未单独发布到 npm / GitHub Release。对外版本号统一为 **2.0.0**。
> 之所以升主版本：面板的**信息架构整体重排**（页签从"按数据来源"改为"按用途"），
> 老用户的操作路径会变；其余改动向后兼容。

### 一句话概览

修掉了 4 个用户报告的问题（#15 / #16 / #17 / #19），并入了 1 个社区 PR（#18），
价格口径按官方 2026-11-01 价目页重新核对，界面按「瘦身 → 重排 → 视觉规范」三步重构，
查询与渲染性能做了针对性优化，并且**首次支持按面板自身宽度自适应**。

### 修复 / Fixed

- **Desktop 端费用恒为 ¥0**（[#19](https://github.com/feiyang-dev/dsh-usage-plugin/issues/19)）：桌面端官方账号的 provider id 是 `deepseek-account`，而代码只认 `deepseek-official` / `deepseek` 两个字面量，导致这类记录被判成"未知 provider"——费用恒为 0 且从不冻结单价。改为 `isDeepseekProvider()` 前缀匹配（`deepseek` / 任意 `deepseek-*`），历史记录一并算对。
- **多币种账户只显示一种货币**（[#17](https://github.com/feiyang-dev/dsh-usage-plugin/issues/17)）：`/user/balance` 会按币种各返回一条 `balance_infos`，旧实现只取 `[0]`，另一种币种静默消失且刷新时来回跳。现在保留完整列表并按币种逐行展示（总计 / 充值 / 赠送）。
- **用量日历整月日期错位一天**：`monthOffset()` 先取"北京零点"对应的时刻、再 `getUTCDay()` 读星期，而那个时刻在 UTC 上已退回前一天 16:00 —— 整月日期因此集体左移一列（2026-11 的 1 号是周日，却画在"周六"列）。改为直接用 `Date.UTC(y, m, 1)` 计算。
- **趋势图 X 轴日期在窄图下重叠**（采纳 [PR #18](https://github.com/feiyang-dev/dsh-usage-plugin/pull/18)，[@vb2250158](https://github.com/vb2250158)）：按 canvas 实测文本宽度贪心排布，首尾日期优先，放不下时只保留最近日期。
- **余额查询整体报错 `maxRedirections is not supported`**：宿主进程内改用 undici 直连时传了 undici v7 已移除的参数，导致每次余额/汇率请求都在客户端直接抛错。已移除该参数，且不跟随重定向（3xx 按非 200 原样报出）。
- **多币种 / 余额通道**：`queryMode: 'unsupported'` 的服务商改为各自携带 `unsupportedMessage`，不再共用写死 AMD 的提示。

### 计费与价格 / Pricing

- **官方价目页 2026-11-01 复核**：`deepseek-flash` / `deepseek-v4-pro` 的模型单价与 1.17.0 落地的 `peakValleyV41` 完全一致，**无需调价**；本次新增的是 Search / Fetch 的**按次计费**（¥5 / 1000 次成功请求）。该调用次数 Harness 不持久化、插件取不到，因此**只做口径声明、不计入费用**（宁可少算，不编一个看起来精确的数字）。
- **法定节假日纳入峰谷判定**：官方口径是「周一至周五（不含中国法定节假日）」，此前只处理了周末。内置 2026 年国务院公布的放假日期，可在 `pricing.json` 用 `holidays` 覆盖；**自 2026-11-01 00:00 起生效**，之前的历史调用不追溯改写。
- **价格表历史快照 `pricing-history.json`**：每次改价 / 恢复默认自动追加一条完整快照（最多 200 条，只增不改），价格页可折叠查看「某个时刻用的是哪套价」。快照**不参与任何金额计算**。
- **历史费用不被改写**：改价只影响之后产生的记录；每条记录继续冻结写入时生效的三个单价，`repriceAll` 仍是唯一会改写历史的显式入口。

### 界面重构（三步）/ UI

**Step 1 瘦身**
- 概览页 12 个数字块 → 5 个：「一行摘要条（本月已消耗 + 预算进度 + 当前时段）」+ 4 张关键卡（总消耗 / 调用次数 / 缓存命中率 / 总 token）。
- 两张 11 列的重复表合并为一张 + 视图切换。
- 口径提示（`web_search 估算` / `历史价格提示`）合并为一个可折叠块，默认收起。
- 导出 / 导入 / 目录 / 数据路径从"每个页签底部常驻"收进一处。

**Step 2 信息架构重排**
- 页签由「概览 / 用量日历 / 缓存命中列表 / 价格表」改为**「用量 / 日历 / 明细 / 设置」**——按用途而非数据来源划分；配置类内容（价格、汇率、预算、快照、口径、导出）统一进「设置」。
- 抽出公共聚合 `aggregateRecords()`，概览与明细共用同一套口径；`BreakdownView` 独立成组件。

**Step 3 视觉规范**
- 颜色收敛为 4 类语义（`ok` / `warn` / `danger` / `accent`）+ 中性线条填充；渐变与叠加元素归入 `G`。此前同一个"蓝"有 4 种写法、同一个"红"有 3 种。
- 字号规范成 7 档（`FS.xs…display`），59 处裸数字字号全部改为 `fs(FS.*)`。
- 卡片分主次两级（`Card` 新增 `primary`）。
- 清掉 15 条随重构失效的死样式；`tdTotal` / `tdTotalFirst` 原本定义两遍（后者覆盖前者）已合并。

### 性能 / Performance

- **轮询不再每 10 秒拉全量**：新增轻量 `stat` 动作（只回 `count` / `latest` / `pricingVersion`），客户端比对指纹，数据真的变了才拉全量；页面在后台时跳过探测。这是"用着卡"的主因（此前每 10 秒重新投影 + 序列化 + parse + 全量重渲染上万条记录）。
- **聚合 memo 化**：`aggregateRecords()` 绑定真实输入，展开抽屉 / 切换视图不再重算全部记录。
- **余额查询提速**：余额 / 汇率 / 百炼配额三条请求由"每次起一个 `node -e` 子进程"（Windows 上 200~800ms）改为宿主进程内 undici 直连（带 `EnvHttpProxyAgent`，尊重 `HTTPS_PROXY`），子进程仅作 undici 不可用时的兜底。
- **用量查询提速**：`list` 不再无条件 `await` 汇率刷新（没有 DigitalOcean 记录时完全不碰网络）；`buildDays()` 复用投影结果，去掉与之完全重复的第二遍遍历。

### 适配 / Responsive

- **按面板自身宽度自适应**：面板常被停靠在约 590px 的侧栏里，而宿主窗口可能 1100px+。此前用**媒体查询（按窗口宽度）**，窗口够宽时一条都不生效，明细表 11 列被裁掉、「总消耗」直接看不见。改为**容器查询**：< 860px 隐藏「推理」；< 720px 再隐藏「高峰 / 空闲消耗」并贴合容器宽；< 560px 只保留前 3 个标识列 + 合计列。老引擎仍走媒体查询兜底。
- 面板内横向滚动区补了可见滚动条样式；余额页新增「百炼按量付费」页签（说明该余额在阿里云费用中心，API Key 查不到，并给入口）。

### 兼容性 / Compatibility

- **安装不再被 peer 依赖卡住**（[#16](https://github.com/feiyang-dev/dsh-usage-plugin/issues/16)）：`@deepseek-ai/cordis` 由 `^4.0.1` 放宽为 `>=4.0.1` 并标记为可选 peer；README 中英均补了"0.1.x 旧包 → 卸载重装"的处置步骤。
- 数据结构向后兼容：新增字段（`infos` / `multiCurrency` / `pricingHistory` / `version` 等）均为可选读取；旧记录可原样使用。
- **需要重启一次 dsh 服务**（host 侧新增 `stat` 动作与版本回传）。

### 测试 / Tests

- 新增 7 个测试文件：`provider-alias`（provider 别名与 #19 复现金额）、`calendar`（日历列位与闰年）、`ui-render`（四个视图真实渲染冒烟）、`design-tokens`（样式不得有裸色值 / 重复键 / 裸字号）、`perf-guards`（必须用 stat 探测、聚合必须 memo、正常路径不得起子进程）、`trend-ticks`（刻度不重叠）、以及原有套件的扩充。
- **总计 92 项，全部通过**；`scripts/check-package.js` 通过。

### 致谢 / Acknowledgements

- **[@vb2250158](https://github.com/vb2250158)**：提交 [PR #18](https://github.com/feiyang-dev/dsh-usage-plugin/pull/18)，给出趋势图刻度排布的完整方案与回归用例，已并入本版并加入 `contributors`。
- **[@Auskaismyfirstlove](https://github.com/Auskaismyfirstlove)**（[#19](https://github.com/feiyang-dev/dsh-usage-plugin/issues/19)）、**[@berkinbaser](https://github.com/berkinbaser)**（[#17](https://github.com/feiyang-dev/dsh-usage-plugin/issues/17)）、**[@heshuo527](https://github.com/heshuo527)**（[#15](https://github.com/feiyang-dev/dsh-usage-plugin/issues/15)）、**[@StrangerLi](https://github.com/StrangerLi)**（[#16](https://github.com/feiyang-dev/dsh-usage-plugin/issues/16)）：报告问题并给出可复现证据。

---

## 开发分步记录（1.19.0 ~ 1.24.0，未单独发布）

## v1.24.0 (2026-11-01)

### 修复 / Fixed

- **趋势图 X 轴日期在窄图下重叠**（`lib/client.js`，采纳自 PR [#18](https://github.com/feiyang-dev/dsh-usage-plugin/pull/18)）：原实现按固定步长 `ceil(series.length / 8)` 取日期，只看数量不看文字宽度——30 天视图在窄面板里最后两个日期会叠在一起（实测 `10/6` 与 `10/7` 重叠约 16px）。改为按 canvas 实测文本宽度做贪心排布，优先保证**首尾两个日期**可见；两者确实放不下时只保留最近的日期。新增 `test/trend-ticks.test.js`，覆盖 7/30/90 天 × 5 种宽度 × 3 种字宽，断言任意相邻刻度间距 ≥ 8px 且不出界。

### 致谢 / Acknowledgements

- **[@vb2250158](https://github.com/vb2250158)**：提交 PR [#18](https://github.com/feiyang-dev/dsh-usage-plugin/pull/18)，给出「按实测文本宽度排布 + 首尾优先」的完整思路与回归用例，本版按该方案落地并已加入 `package.json` contributors。

### 测试 / Tests

- 全部 **92/92** 通过。

---

## v1.23.1 (2026-11-01)

### 性能 / Performance

- **轮询不再每 10 秒拉全量数据**（`lib/index.js` + `lib/client.js`）：此前定时器直接调 `list`，等于每 10 秒把所有记录重新投影、序列化（上万条可达数十 MB）、`JSON.parse`、再全量重渲染一次面板——**数据完全没变时也在白跑**，这是"用着卡"的主因。新增轻量 `stat` 动作（只返回 `count` / `latest` / `pricingVersion`，几十字节），客户端比对指纹，只有真的变了才拉全量；页面在后台（`visibilityState === 'hidden'`）时直接跳过探测。
- **聚合结果 memo 化**（`lib/client.js`）：`aggregateRecords()` 每次 render 都会跑一遍全部记录（展开抽屉、切换「按模型/按服务商」都会触发）。现在用 `useMemo` 绑定真正影响结果的输入，这些交互不再重算。
- 新增 `test/perf-guards.test.js`：钉住"用 stat 探测而不是全量 list""聚合必须 memo""余额/汇率正常路径不得起子进程"三条，防止回退。

### 适配 / Responsive

- **修好窄面板下的表格裁切**（`lib/client.js`）：面板常被停靠在约 590px 的侧栏里，而宿主窗口可能 1100px+。此前的适配用的是**媒体查询（按窗口宽度）**，窗口够宽、面板很窄时一条都不生效，所以明细表 11 列被裁掉、最右的「总消耗」直接看不见。现在改成**容器查询（按面板自身宽度）**逐级折叠：
  - < 860px：隐藏「推理」
  - < 720px：再隐藏「高峰消耗 / 空闲消耗」，只留「总消耗」，表格贴合容器宽度
  - < 560px：只保留前 3 个标识列 + 最后一列合计
  - 同时给面板内的滚动区域加了可见滚动条样式；不支持容器查询的老引擎仍走媒体查询兜底。

### 测试 / Tests

- 全部 **89/89** 通过。

---

## v1.23.0 (2026-11-01)

### 视觉规范（Step 3）/ Design system

- **设计令牌 `C` / `FS` / `G`**（`lib/client.js`）：颜色此前散落成 12 个裸色值——同一个"蓝"有 `#5a8cff` / `#3d6bd6` / `#3a7bd5` / `rgba(90,140,255,…)` 四种写法，同一个"红"有 `#ff6b6b` / `#e74c3c` / `#ff9800` 三种语义混用。现在收敛为四类语义（`ok` 成功·命中 / `warn` 需注意·高峰 / `danger` 错误·超支 / `accent` 主操作·链接）+ 中性线条与填充；渐变与"叠在品牌色上的白色元素"归入 `G`。
- **字号阶梯**：把 12 个随手写的字号（10 / 10.5 / 11 / 11.5 / 12 / 12.5 / 13 / 14 / 15 / 18 / 20 / 26 / 32）规范成 7 档（`FS.xs…display`），**59 处 `fs(<数字>)` 全部改为 `fs(FS.*)`**，跟随宿主字号缩放的机制不变。
- **卡片分两级**：`Card` 新增 `primary` 变体（蓝色边框 + 淡底 + 强调色数字），概览页只给「总消耗」用；其余仍是次要卡。
- **清掉随重构失效的样式与重复键**：`heroUsage*` / `bigCards*` / `tokenBar*` 等 15 条死样式删除；`tdTotal` / `tdTotalFirst` 原本定义了两遍（后者覆盖前者，属"改了不生效"的典型坑），合并为一处。
- **语义色对齐**：环比徽章（涨红跌绿）、高峰/空闲徽章、错误框、警告框、合计行、图表峰值/空闲配色、PNG 导出渲染器全部走同一套 token——此前正文里的红和图表里的红是两个不同的红。

### 测试 / Tests

- 新增 `test/design-tokens.test.js`：① `st` 里不得出现裸 hex；② `st` 不得有重复键；③ 不得再出现 `fs(<数字>)`；④ 令牌块齐全。改样式时若绕过规范，测试会直接失败。
- 全部 **85/85** 通过。

---

## v1.22.1 (2026-11-01)

### 修复 / Fixed

- **余额查询整体报错 `maxRedirections is not supported, use the redirect interceptor`**（`lib/index.js`）：1.20.0 把余额/汇率请求从子进程改到宿主进程内直连时，给 `undici.request()` 传了 `maxRedirections`。undici v7 已把它移除（改由 redirect interceptor 处理），于是**每一次**余额与汇率请求都在客户端直接抛错。现在不再传该参数，也不跟随重定向：账单/配额端点都是直连，3xx 按非 200 处理并原样报出状态码。已用真实端点验证（无效 Key 返回 401 JSON，往返 365ms）。
- 新增回归用例：`test/ui-render.test.js` 扫描 `lib/index.js`，禁止再次出现 `maxRedirections`。

---

## v1.22.0 (2026-11-01)

### 界面重构（Step 2：信息架构重排）/ UI

- **四个页签按"用途"重排**：`概览 / 用量日历 / 缓存命中列表 / 价格表` → **`用量 / 日历 / 明细 / 设置`**。原结构把"看结论"和"改配置"混在同一层，且"缓存命中列表"既是明细又是独立页签，职责重叠。
  - **用量**：一行摘要条 + 4 张关键卡 + 趋势 / 占比图 + 会话排行（不再夹带明细表）。
  - **日历**：热力图 + 本月/范围统计（内容不变）。
  - **明细**：按模型 / 按服务商切换 + 缓存命中记录（原独立页签并入）。
  - **设置**：价格表 + 汇率 + 预算 + 历史快照 + 口径说明 + **导出/导入/数据目录**（从每个页签底部集中到这里）。
- **抽出 `aggregateRecords()` 公共聚合**（`lib/client.js`）：分组 / 合计 / 排名原本在概览页内联了 80 行，明细页要复用就只能复制一遍；现在两处共用同一份实现，口径天然一致。
- **`BreakdownView` 独立成组件**：11 列的模型/服务商表格从概览页迁出，概览页回到"结论页"的定位（摘要 → 指标 → 图表 → 排行）。

### 测试 / Tests

- `test/ui-render.test.js` 增加 `BreakdownView` 渲染用例；概览断言改为验证"只保留趋势、不再内联明细表"。
- 全部 **80/80** 通过。

---

## v1.21.0 (2026-11-01)

### 界面重构（Step 1：瘦身，不改信息架构）/ UI

- **概览页从 12 个数字块压到 5 个**（`lib/client.js`）：原来是「蓝色 hero 卡 + 3 张大卡 + 4 张卡 + 5 格 token 条」三层重复汇总同一批数字，且 hero 在月初几乎恒显示 ¥0.0000。现在改为「一行摘要条（本月已消耗 + 预算进度 + 当前时段徽标）+ 4 张关键卡（总消耗 / 调用次数 / 缓存命中率 / 总 token）」，高峰/空闲、未命中/输出/推理收进对应卡的 hint。
- **两张 11 列的重复表合并成一张**：`模型消耗明细` 与 `服务商×模型明细` 字段几乎相同却上下堆叠，现在是一张表 + 「按模型 / 按服务商」视图切换，并删掉两段重复的解释性小字。
- **口径提示合并、默认收起**：`web_search 估算` 与 `历史价格提示` 两个橙色告警块合并成一个可折叠的「统计口径提示」（仅在确有估算记录 / 无冻结单价记录时出现），计价说明并进同一抽屉。
- **导出区收进「导出与数据」抽屉**：CSV / JSON / PNG / 打开目录 / 导入 / 目标目录输入框此前在**每个子页签底部**常驻一整排，现在默认收起；数据持久化路径同时出现在「口径与版本」里。
- **价格页去重**：`WhyThisPrice` 内部已渲染 `OfficialLinks`，页面又单独渲染了一次（同一组外链出现两遍），已删除重复项；价格口径三段长文案 + 官方来源 + 第三方价格表合并进「价格口径与第三方价格」折叠区。
- 「帮助与说明」按钮改名为「口径与版本」，中断调用数改为显式文案（`· 213 次中断`），不再像未读消息条数。

### 测试 / Tests

- 新增 `test/ui-render.test.js`：用最小 React 替身把概览 / 价格 / 日历 / 缓存命中四个视图**真实渲染一遍**，兜住"语法没错、渲染时才报错"的问题。
- 全部 **79/79** 通过。

---

## v1.20.1 (2026-11-01)

### 修复 / Fixed

- **用量日历整体错位一天**（`lib/client.js`）：`monthOffset()` 先取「北京零点」对应的时刻、再 `getUTCDay()` 读星期，而那个时刻在 UTC 上已退回前一天 16:00 —— 读出来的是前一天的星期，于是整月日期集体左移一列（2026-11 的 1 号是周日，却被画在“周六”列）。星期几属于日历日期，现在直接用 `Date.UTC(y, m, 1)` 计算，不做时区平移。
- 顺手删掉 `lib/client.js` 里被整块复制两遍的 `exports.__i18n` 赋值。

### 新增 / New

- **面板显示插件版本号**：`lib/index.js` 直接读自己的 `package.json` 得到版本（不在代码里再写死一份，避免“面板显示旧版本、实际跑新版本”），顶部标题旁显示 `vX.Y.Z`，并在「帮助与说明」底部同时给出「插件版本 + 数据目录」，反馈问题时一眼可见。

### 测试 / Tests

- 新增 `test/calendar.test.js`：校验每月 1 号落在正确的星期列、2026 年每一天的列位置、以及闰年 2 月天数。
- 全部 **75/75** 通过。

---

## v1.20.0 (2026-11-01)

### 新增 / New

- **价格表历史快照 `pricing-history.json`**（`lib/index.js` + 价格页）：`pricing.json` 只保存"当前生效"的一张表，改价之后就再也回答不了"上周是按什么价算的"。现在每次改价 / 恢复默认都会往后追加一条完整快照（`at` / `kind` / `label` / 整张表 / 当时生效的节假日表），最多保留 200 条，价格页新增可折叠的「历史价格记录」。快照只用于**回看**，不会参与任何金额计算。
- **价格来源与核对信息**：`list` 新增 `pricingMeta`（官方价目页地址、核对日期 `2026-11-01`、Search/Fetch 按次计费口径、节假日规则生效时刻），价格页直接展示，避免"价格为什么变了"只能靠猜。

### 变更 / Changed

- **法定节假日纳入峰谷判定**（`lib/index.js`）：官方价目页明确高峰时段是「周一至周五（不含中国法定节假日）」，此前只处理了周末。现在 `isPeakAt(ts, holidays)` 支持节假日（内置 2026 年国务院公布的放假日期，可在 `pricing.json` 用 `holidays` 覆盖），**自 2026-11-01 00:00（北京时间）起生效**——生效前的历史调用仍按当时实现的规则计费，不追溯改写账单。
- **官方价格表复核结果（2026-11-01）**：`deepseek-flash` / `deepseek-v4-pro` 的模型单价与 1.17.0 落地的 `peakValleyV41` 完全一致，无需调价；本次新增的只有 Search / Fetch 的**按次计费**（¥5 / 1000 次成功请求）。该调用次数 Harness 不持久化、插件取不到，因此**只做口径声明、不计入费用**——宁可少算，也不编一个看起来精确的数字。

### 性能 / Performance

- **余额查询提速**（`lib/index.js`）：余额、汇率、百炼配额三条请求此前都用 `node -e` 起子进程发（Windows 上光启动就要 200~800ms）。现在统一走进程内 undici 请求（并带 `EnvHttpProxyAgent`，尊重 `HTTPS_PROXY`），仅在 undici 不可用时回落到子进程。典型场景从「一两秒」降到「一次普通 HTTP 往返」。
- **用量查询提速**（`lib/index.js`）：两处结构性浪费被去掉——① `list` 此前**无条件** `await refreshFxRate()`，没有 DigitalOcean 记录时也要起子进程拉汇率；现在只在确有 DO 记录时等待，且同一天只拉一次、并发调用合并成一次。② `buildDays()` 此前再遍历一遍原始记录、每条又算三次费用（与 `projectRecord` 完全重复，10 万条记录等于每次刷新 60 万次计算）；现在直接复用投影结果，并为单条记录的投影加了「价格表/汇率版本号」缓存。

### 测试 / Tests

- `test/period.test.js` 新增节假日用例：生效时刻后才按节假日打折、生效前不追溯、节假日键按北京时间取日期。
- 全部 **72/72** 通过。

---

## v1.19.0 (2026-11-01)

### 修复 / Fixed

- **Desktop 0.2.x 上费用恒为 ¥0**（issue #19，`lib/index.js`）：桌面端官方账号那一路的 provider id 是 `deepseek-account`，而 `unitSnapshotOf()` / `costFor()` 只认 `deepseek-official` / `deepseek` 两个字面量，于是这些记录全被判成"未知 provider"——费用恒为 0，且**从不写冻结单价**（概览页"历史价格提示"的条数等于记录总数）。新增导出函数 `isDeepseekProvider()`，按前缀命中所有 `deepseek-*`；`siliconflow` / `digitalocean` / `amd` / 千问在各自分支先行返回，行为不变。已落盘的历史记录（provider=`deepseek-account`、无 `unit`）也会按官方价目重新算对。
- **多币种账户余额只显示一种货币**（issue #17，`lib/balance.js` / `lib/client.js`）：官方 `/user/balance` 会为每个币种各返回一条 `balance_infos`，旧实现只取 `[0]`，另一种币种静默消失；而且显示哪一种取决于数组顺序，两次刷新之间来回跳。现在解析层保留完整列表并返回 `multiCurrency` 标记，余额面板按币种逐行展示（总计 / 充值 / 赠送）；单币种账户的界面与字段保持原样。

### 新增 / New

- **「百炼按量付费」页签**（issue #15，`lib/balance.js` / `lib/client.js`）：按量付费扣的是阿里云账户余额，百炼模型 API Key 查不到（配额走的另一条 Token Plan 通道，两回事）。新页签直接说明这一点并给出阿里云费用中心入口，替代过去"点查询只会看到失败"的体验。
- `queryMode: 'unsupported'` 的服务商改为各自携带 `unsupportedMessage`，不再共用一句写死 AMD 的提示文案。

### 兼容性 / Compatibility

- **安装不再被 peer 依赖卡住**（issue #16）：`@deepseek-ai/cordis` 由 `^4.0.1` 放宽为 `>=4.0.1` 并标记为可选 peer。安装时提示"0.1.x 与 DSH 不兼容"的情况来自旧包声明的 rc 依赖，README（中/英）均补充了卸载旧包 + 重装的处置步骤。
- 数据结构无变化：`infos` / `multiCurrency` 是新增的只读字段，旧版本读取逻辑不受影响。

### 测试 / Tests

- 新增 `test/provider-alias.test.js`：`isDeepseekProvider()` 的正反用例，并用 issue #19 的原始数据（5,900,672 / 15,979 / 17,534）复现应得的 ¥0.20。
- `test/balance.test.js` 新增多币种、单币种与「百炼按量付费」用例。
- 全部 **70/70** 通过。

### 致谢 / Acknowledgements

- **[@Auskaismyfirstlove](https://github.com/Auskaismyfirstlove)**：报告 issue [#19](https://github.com/feiyang-dev/dsh-usage-plugin/issues/19)，给出 provider id、`legacyPricingCount` 现象与预期金额，定位精准。
- **[@berkinbaser](https://github.com/berkinbaser)**：报告 issue [#17](https://github.com/feiyang-dev/dsh-usage-plugin/issues/17)，指出多币种账户会丢失另一种货币且刷新时来回切换。
- **[@heshuo527](https://github.com/heshuo527)**：报告 issue [#15](https://github.com/feiyang-dev/dsh-usage-plugin/issues/15)，暴露了「Token Plan 配额」与「按量付费余额」两条通道的混淆。
- **[@StrangerLi](https://github.com/StrangerLi)**：报告 issue [#16](https://github.com/feiyang-dev/dsh-usage-plugin/issues/16)，促使本版放宽 peer 依赖并在 README 补齐旧包清理步骤。

---

## v1.18.0 (2026-09-24)

### 修复 / Fixed

- **价格表改动不再改写历史费用**（`lib/index.js`、`lib/records.js`）：此前 `costFor()` 在计算**任何**记录时都读**当前**价格表，所以在价格表页保存一次新价、或直接改 `pricing.json` 后重启，全部历史费用都会被按新价重算——而过去那些调用的真实账单早已按当时的价结清。现在每条记录在落盘时**冻结当时生效的三个单价**（新增记录字段 `unit`：`{ hit, miss, out }`，DigitalOcean 另带 `fx`），`auto` 档计费一律优先读该快照；同时新增字段 `pricingTime`（计费时刻），历史回填 / 导入的记录也能借此冻结取价时点。旧记录缺这两个字段时行为不变（退回按当前价格表计算），概览页与价格页会提示这类记录的条数。
- **新增显式重算入口**：价格表页新增「用当前价格表重算全部历史」按钮；API 新增 `repriceAll` 动作（`setPrices` 也可传 `reprice: true`）。这是唯一会改写历史费用的入口，日常改价不再有副作用。
- **「缓存写入」不再用未命中数冒充**（`lib/index.js`）：DeepSeek 系 provider 不上报 `cacheWriteTokens`（官方计费里缓存写入按未命中价计、不单列），旧实现在记录层用 `inputTokens` 兜底，等于伪造一笔与未命中相等的缓存写入——四桶合计因此系统性多算一笔，插件「总 token」永远比宿主状态栏大一截。现在记录层只存上游真实上报值，「缓存写入」列显示 `—`，展示层也不再用其它字段冒充。
- **「总 token」不再重复计入 reasoning**（`lib/client.js`）：宿主 `outputTokens` 就是上游的 `completion_tokens`，`reasoningTokens` 是它的子集。概览页、会话消耗排行、消息底部 Token 弹窗此前都把 `reasoning` 再加一遍，现已统一为四桶互斥求和。
- **同毫秒记录不再互相覆盖**（`lib/records.js`）：导入 / 初始化 / 旧数据迁移此前一律按 `time` 去重，同一毫秒的两条不同请求会吞掉一条。改为按记录身份去重：新记录用 `recordId`，旧记录用「会话 + 时刻 + 模型 + 用途 + 四桶用量 + 结束原因」的复合指纹。
- **用量文件改为原子写 + 损坏保护**（`lib/storage.js`）：此前直接覆盖写入，且解析失败会被静默 catch 成空数组（随后用空数组覆盖整份历史）。现在写入走「临时文件 → 刷盘 → 原子替换」，失败不触碰原文件；读取时只有「文件不存在」才返回空，解析失败则把原件改名保留为 `usage-records.json.corrupt-<时间戳>.json` 并继续启动，插件不会因此不可用。

### 新增 / New

- **DeepSeek 搜索后端（`web_search`）计次与下限估算**（`lib/index.js`）：`web-search-deepseek` 在 Harness 内用原生 `fetch` 直连官方接口并绕过 `ctx.llm`，上游只持久化请求、丢弃响应 usage，这部分真实计费此前在插件里完全不可见（搜索密集场景下实测差额可达 15 倍，见 issue #12）。现在通过 `ctx.on('session/event')` 接住 `web/deepseek-search-llm-request`：**精确记录调用次数**，并按请求体给出**输入侧下限**估算，记录一律带 `origin: 'search-backend'` 与 `estimated: true`；输出侧不猜。概览页新增「统计口径：web_search 搜索后端未纳入精确统计」说明块，列出次数与估算下限，并提示以官方账单为准。
- **统计口径声明**：`README.md` / `README.zh.md` 新增「Metering scope / 统计口径声明」章节，逐项说明已精确统计与未纳入统计的来源、原因与处理方式。
- 导出 CSV 新增 `origin`、`estimated` 两列；`list` API 新增 `legacyPricingCount`（没有冻结单价的记录数）。

### 测试 / Tests

- 新增 `test/records.test.js`：归一化兼容性（旧记录不补假字段）、不再伪造缓存写入、身份去重、四桶求和排除 reasoning。
- 新增 `test/storage.test.js`：原子写替换、不留临时文件、写入失败不触碰原文件、损坏文件抛错而非返回空。
- 新增 `test/price-freeze.test.js`：冻结单价与当前价格表解耦、复现官方计费公式、旧记录回落、快照归一化往返。
- `test/client-i18n.test.js` 新增用例：统计口径与历史价格相关文案中英双语齐全。
- 全部 **64/64** 通过。

### 兼容性 / Compatibility

- 数据文件**不需要迁移**：`usage-records.json` 的新字段（`recordId` / `pricingTime` / `origin` / `estimated` / `unit`）全部可选，旧记录按缺省处理，可原样读取。
- 数据目录解析顺序未变。
- 新增行为：损坏的数据文件会被改名保留（见上），插件继续可用。

### 文档 / Docs

- **补全贡献者名单**（`package.json` contributors）：新增 [@zhiqiangme](https://github.com/zhiqiangme)（PR #14）。
- **README 新增「统计口径声明 / Metering scope」章节**：逐项列出已精确统计与未纳入统计的来源、原因与处理方式。
- **README 致谢补充**：[@zhiqiangme](https://github.com/zhiqiangme)（PR #14 的三项口径定位）、[@mumuer1024](https://github.com/mumuer1024)（新增 issue #12 的取证贡献）。

### 致谢 / Acknowledgements

- **[@zhiqiangme](https://github.com/zhiqiangme)**：提交大型 PR [#14](https://github.com/feiyang-dev/dsh-usage-plugin/pull/14)。其中「`cacheWriteTokens` 兜底导致四桶双计」「同毫秒记录按 `time` 去重会互相覆盖」「用量文件非原子写入且解析失败被静默清零」三项定位，成为本版计费口径修复的核心依据（本版为手工移植其修复，提交已附 `Co-authored-by` 署名）。
- **[@mumuer1024](https://github.com/mumuer1024)**：报告 issue [#12](https://github.com/feiyang-dev/dsh-usage-plugin/issues/12)，用官方账单交叉验证定位了 DeepSeek 搜索后端调用未计入统计、费用被低估约 15 倍的问题，直接促成本版的搜索后端计次与统计口径声明。

---

## v1.17.0 (2026-09-11)

### 新增 / New

- **适配 DeepSeek V4.1 Flash 新模型与新价格**（`lib/index.js`）：官方新增模型名 `deepseek-flash`（DeepSeek-V4.1-Flash），并同步下调了 Flash 档位价格；本版按官方公布的价格表完成适配。

### 变更 / Changed

- **模型档位按官方新命名归并**：计费档位由 `deepseek-v4-flash` / `deepseek-v4-flash-vision-exp` / `deepseek-v4-pro` 三项合并为 **`deepseek-flash`** 与 **`deepseek-v4-pro`** 两项。旧模型名 `deepseek-v4-flash`、`deepseek-v4-flash-vision-exp` 仍可调用（官方已将其路由到 DeepSeek-V4.1-Flash 并按 Flash 单价计费），插件会把它们归入 `deepseek-flash` 档位一并计费，历史记录与新增记录口径一致。
- **价格表按生效时间分三段**（新增 `peakValleyV41` 档）：
  - `base` —— 旧基础价（2026-08-17 00:00 之前）；
  - `peakValley` —— 第一版峰谷价（2026-08-17 00:00 ~ 2026-09-10 12:00）；
  - `peakValleyV41` —— **V4.1 Flash 调价后的峰谷价（2026-09-10 12:00 北京时间起）**：
    - `deepseek-flash`：空闲 缓存命中 **0.02** / 输入 **1.0** / 输出 **4.0** 元，高峰为其两倍（0.04 / 2.0 / 8.0）；
    - `deepseek-v4-pro`：价格不变（空闲 0.15 / 4.5 / 13.5，高峰 0.3 / 9.0 / 27.0）。
- **计费按记录发生时刻取对应版本**：`auto` 档按调用时间选档；记录一旦产生，其费用不会随后续调价而改变（历史记录在旧档、新记录在新档），导出 CSV / 概览 / 用量日历 / 缓存命中列表口径一致。
- `list` API 新增 `effectiveV41At` 字段（V4.1 调价生效时间戳），`effectiveAt` 语义不变（第一版峰谷价生效时间），向后兼容。

### 界面 / UI

- **价格表页适配分段峰谷价**（`lib/client.js`）：「峰谷价」档展示**当前生效**的一版峰谷价表；新增两段说明——峰谷价表分段规则与生效时刻、旧模型名与 `deepseek-flash` 合并计费的口径。
- 生效状态提示升级：在「新价格表（峰谷价）已生效（自 2026-08-17 起）」之后追加 **DeepSeek V4.1 Flash 调价**的生效时间与价格变化说明（调价前提示「将于 … 生效」）。
- 价格表行标签更新为 `deepseek-flash` / `deepseek-v4-pro`，与官方模型名、DSH 模型选择器一致。
- 新增文案已同步补充英文词典（`__T_EN`），中英双语即时可用。

### 测试 / Tests

- 新增 `test/pricing.test.js`（8 条）：校验生效时刻常量（2026-08-17 00:00 / 2026-09-10 12:00 北京时间）、V4.1 Flash 新价与「空闲价 = 高峰价一半」规则、V4 Pro 价格不变、第一版峰谷价与旧基础价保留、`peakValleyTableOf` 切换边界（精确到生效前一毫秒）、新旧模型名归并、价格表完整性（每个档位 × 每个模型字段齐全）、`defaultPricing()` 每次返回独立副本。
- 为便于回归测试，`lib/index.js` 新增导出：`PEAK_VALLEY_AT`、`V41_EFFECTIVE_AT`、`PRICE_REGIMES`、`PRICE_MODELS`、`defaultPricing()`、`modelKeyOf()`、`peakValleyTableOf()`；插件运行行为不变（价格表仍是每个 `apply()` 实例私有副本）。
- `test/client-i18n.test.js` 新增用例：V4.1 调价相关的新文案在中英两种语言下都能正确解析（英文界面不残留中文）。
- 全部 **39/39** 通过。

### 说明 / Notes

- 依据官方价格页：旧模型名 `deepseek-v4-flash`、`deepseek-v4-flash-vision-exp` 已下线但暂时路由到 V4.1 Flash；`deepseek-v4-pro` 官方已明确在 2026-09-14 之后继续提供且计费方式不变，故本版不对 Pro 档做时间路由，价格维持不变。
- 未引入新 npm 依赖。

---


### 新增 / New

- **概览页 Hero 主指标卡**：顶部新增「本月已消耗」渐变大数字卡 + 当前计费时段徽章；设置月度预算后同卡显示预算使用进度条（≥80% 黄色提醒，≥100% 红色超支告警并显示超支金额）。
- **核心指标卡片分层**：原 7 张等大统计卡改为「3 大主卡（总消耗 / 调用次数 / 缓存命中率）+ 4 小辅助卡（输入·未命中 / 输出 / 高峰消耗 / 空闲消耗）」，关键指标视觉权重突出。
- **近 30 天消耗趋势图**（canvas 堆叠柱状）：概览页新增按日消耗趋势，高峰（橙）/ 空闲（蓝）堆叠着色，悬停显示当日高峰/空闲/总消耗与调用数。
- **模型消耗占比环形图**：概览页新增各模型消耗占比环形图 + 图例（模型名 + 百分比）。
- **会话消耗排行 Top 10**：概览页新增按会话（sessionId）聚合的消耗排行，显示调用次数与消耗、相对进度条，便于定位「最烧钱」的对话。
- **缓存命中列表关键字搜索**：新增搜索框，按 模型 / 服务商 / 会话ID / 用途 实时过滤，与日期筛选叠加生效。
- **月度预算设置与超支预警**（`lib/index.js` + `lib/client.js`）：价格表页新增「月度预算」区块（输入金额保存 / 清除），持久化到数据目录 `budget.json`；概览页 Hero 显示当月已用/预算进度。新增 `setBudget` API，`list` 附带 `budget` 字段（向后兼容）。
- **说明信息收进可折叠抽屉**：原本首屏固定展示的「本地统计与官方后台的差异 / 高峰·空闲时段说明 / 计价说明」三段说明收进「▸ 帮助与说明」按钮（默认收起），有中断记录时按钮带数量角标；首屏直接展示数据。
- **底部工具条重组**：导出 CSV / JSON / PNG / 打开目录 / 选择文件导入 / 帮助与说明 合并为一行，导出目标目录输入独立一行。

### 修复 / Fixed

- 概览页 Hero 高峰时段徽章颜色修正（高峰 = 橙色）。

### 说明 / Notes

- 所有新 UI 文案均已补充英文词典（`__T_EN`），英文界面即时可用。
- 未引入新 npm 依赖；现有测试 30/30 全部通过。

---

## v1.15.0 (2026-08-29)

### 新增 / New

- **用量日历新增日期范围筛选**（`lib/client.js` CalendarView）：日历视图此前只有月份导航、无法只看指定区间；现在顶部新增与概览一致的筛选栏（今天 / 近7天 / 近30天 / 全部 + 自定义起止日期）。筛选激活时：
  - **每日消耗统计表跨月显示**范围内所有有记录的天（不再局限于当前月），标题显示所选范围；
  - 顶部「本月调用 / 本月消耗」卡片自动切换为「范围内调用 / 范围内消耗」并按范围汇总（含高峰/空闲拆分）；
  - 热力图仅对范围内日期着色，范围外显示为空（`—`）；
  - 空态文案随范围显示「该范围内暂无记录。」；
  - 预设按钮切换时自动清空自定义起止日期，避免残留范围误判。

---

## v1.14.1 (2026-08-29)

### 修复 / Fixed

- **中断调用兜底记录，使「调用次数」与 DeepSeek 官方后台对齐**（`lib/index.js`）：harness 在流被中断（aborted / error / timeout / 用户停止生成）时不会产出 `usage` chunk（usage 只在收到 `[DONE]` 哨兵后才由 adapter yield），导致这类调用此前完全不被插件记录——而官方后台仍会把该次请求计入「API 请求次数」并按实际 token 计费，于是插件统计的调用次数长期低于官方（如 8 月 27 日 985 vs 1033）。现在无 usage 但确为真实模型调用（通过 `isRealCall`，排除内部 `dsh2shell-*`/`fake`）的流，会在 `observe()` 的 `finally` 里补记一条 **0-token 的「中断调用」**（新增 `interrupted: true` 字段，`finishReason` 如实标记 `aborted`/`error`/`timeout`）。token 与费用均为 0，不会虚增消耗；调用次数与官方口径一致。
- **面板透明展示中断调用**（`lib/client.js`）：
  - 概览「调用次数」卡片新增 `· 中断 N（未计费）` 提示；
  - 缓存命中列表与用量日历当日明细中，中断调用行在模型名旁显示红色「中断」徽标、结束原因红色标注、消耗列显示 `—`；
  - PNG 导出报告同样在模型名旁标注「中断」、消耗列显示 `—`；
  - 结束原因新增 `aborted → 已中断 / Interrupted`、`timeout → 超时 / Timeout` 映射（中英双语）。
  - **用量面板顶部新增「本地统计与官方后台的差异」提示横幅**：说明本面板统计的是插件本地捕获的调用（官方价格 + 峰谷时段），与官方后台（platform.deepseek.com 用量页）相比金额可能更低——① 中断/出错/超时的调用官方仍按实际 token 计费而插件按 0 记录；② 账号下其他 API Key（其它应用/脚本）的调用不经过 DeepSeek Harness，官方包含而插件不包含；③ 精确对账可导出官方月度账单 CSV 对比。检测到中断调用时额外显示「当前记录中有 N 次中断调用（未计费）」红字提示。
- **持久化与 API 透传 `interrupted`**（`lib/index.js`）：`normalizeRecord` / `projectRecord` 均保留该字段，重启恢复、`/usage/api` list 输出、JSON 导出一致。

### 测试 / Tests

- 新增 `test/interrupt.test.js`：验证中断兜底仅记录真实模型调用（DeepSeek 官方 / 第三方真实 provider），内部 `fake`/`dsh*` 占位调用永不兜底记录。
- 全部 30/30 通过。

---

## v1.14.0 (2026-08-27)

### 新增 / New

- **消息底部「本轮 token」弹窗（两层统计）**：多轮完成后，助手消息底部操作行（复制 / 点赞 / 点踩 / 回复 那一排）新增「本轮 token」按钮，点击弹出 `Token 明细`：
  - **对话累计**：整场对话（当前会话）的 总 token / 总消耗 / 耗时 / 缓存命中率；
  - **本轮明细**：本次输出 / 本轮 token / 本轮消耗 / 本轮耗时 / 本轮缓存命中率 / **缓存命中长条图**（命中部分单独绿色渲染 + 百分比）/ **按模型卡片**（每模型：模型名 + 总成本，一行 输入·未命中 / 缓存命中 / 输出（+推理），有费用再一行 峰 / 谷）；
  - 时长统一按「X分Y秒」（英文 `Xm Ys`）显示；本轮窗口取该消息实际产出所在 step 的起止，本轮命中率与对话累计各自独立统计。
- **宿主记录带会话标识**：`llm/stream` 捕获每条记录时新增 `sessionId`（优先 `options.sessionId`，缺失回退当前 agent 会话）；新增 `tokenForMessage` API——按「会话 + 时间窗」返回本轮明细与对话累计两层聚合。
- **内部/工具调用单独分组**：`list` 同时返回 `toolCalls`（`model` 为 fake/unknown/空 或 `dsh*` 内部路由，如 `dsh2shell-*`/`fake`），概览「消耗明细」下方新增可折叠的「工具调用（内部）」分组（默认收起，显示 服务商·模型 / 调用数 / 总消耗），与真实模型调用分开。
- **语言跟随系统设置**：移除「用量与消耗」头部的中英文切换按钮，语言完全跟随宿主「通用设置 → 语言」，切换即时生效（`locale` 服务 `subscribe` + `locale/change`）；不再写 `localStorage`（`dsh-usage-lang`），旧残留值不再覆盖系统语言；「会话 / 设置」标签页名改为按渲染时读取的 thunk，随语言切换实时更新。
- **移动端适配**：表格在 ≤900px 贴合屏宽（`min-width:0 !important`）、不再出现横向滑条；宽表折叠中间列；弹窗统计卡与按模型卡片随宽度自适应；弹窗滚动条外观隐藏（仍可滚轮滚动）。
- **英文适配补全**：「高峰 / 空闲时段说明」整块与 19 个遗漏键（当前 · 工作日/周末时段、工作日高峰卡片提示、用量日历悬停提示、价格表两段长说明等）补上英译。

### 修复 / Fixes

- **弹窗不可见**：对话树祖先的 transform 会破坏 `position: fixed`，改用 `react-dom` 平台种子的 `createPortal` 把弹窗挂到 `document.body`。
- **整场会话聚合**：按 `messageId` 查找消息完成时间改为读取 `data.finalNode.messageId` / `data.closing.finalNode.messageId`，时间窗正确生效（不再把整场对话圈进来）。
- **语言切换失效**：不再持久化语言选择，宿主设置切回中文即时恢复、无需刷新。
- **表格显示**：宽表 `width:max-content`，列按内容撑开、外层容器横向滚动，数字不再被压到换行/重叠。

### 测试 / Tests

- 周末计费规则回归测试（issue #9）：宿主 `isPeakAt`（新增 `test/period.test.js`）+ 客户端 `isPeakNow` / `periodNow`（`test/client-i18n.test.js`），覆盖 issue 的 5 个时刻向量、生效时间边界、峰段窗口左右端点。
- i18n 测试改为覆盖「跟随宿主语言服务实时切换」「旧 localStorage 值不再覆盖宿主语言」。
- 全部 27/27 通过。

---

## v1.13.0 (2026-08-23)

### 新增 / New

- **英文界面（i18n 层）**（社区贡献，[@ayleen](https://github.com/ayleen)，[PR #7](https://github.com/feiyang-dev/dsh-usage-plugin/pull/7)）：Web 面板全部 UI 文案接入轻量 i18n——以原中文文案为键、内置英译词典；按浏览器语言自动选择（中文浏览器保持中文，其余默认英文），「用量与消耗」头部新增切换按钮，即时生效并保存于 localStorage。余额查询改为语义化字段（host 不再返回中文展示文案），缺失凭据错误不再泄漏内部键；日期 / 星期本地化（中文 `2026年8月22日`，英文 `Aug 22, 2026` 与 Mo–Su 表头）；瞬态提示与客户端校验错误渲染时翻译。
- **百炼（Qwen）Token Plan 配额查询**（社区贡献，[@wuhuqif176](https://github.com/wuhuqif176)，[PR #8](https://github.com/feiyang-dev/dsh-usage-plugin/pull/8)）：「剩余余额查询」新增「百炼 Token Plan」子页签——复用百炼 CLI（`bl`）的控制台 OAuth token（`~/.bailian/config.json`），无需阿里云 AccessKey；展示本周配额已用百分比（进度条 + `已用 xx.x%`）与本周开始 / 结束日期（连续线段，今天节点随日期动态移动）。新增依赖 `undici`。
- **本地改进**：消耗明细表顶部与底部各渲染一份分页条（长列表翻页更顺手）；DeepSeek 系 provider 未单独上报 `cacheWriteTokens` 时，「缓存写入」列改用未命中 token 数（`inputTokens`）兜底显示，避免长期为空。

### 文档 / Docs

- **补全贡献者名单**（`package.json` contributors）：新增 [@ayleen](https://github.com/ayleen)（PR #7 英文界面）与 [@wuhuqif176](https://github.com/wuhuqif176)（PR #8 百炼配额）。
- **新增 `.mailmap`**：把 PR #7 提交作者 `Ruslan R. Musakalimov <gitlab@letsweb.me>` 映射到 GitHub 账号 @ayleen，使仓库 Contributors 图与 git blame 正确归属历史提交。

### 致谢 / Acknowledgements

- **[@ayleen](https://github.com/ayleen)**：实现英文界面与响应式语言切换（PR #7）。
- **[@wuhuqif176](https://github.com/wuhuqif176)**：实现百炼 Token Plan 配额查询（PR #8）。

---

## v1.12.2 (2026-08-23)

### 修复 / Fixed

- **移动端宽表仍会逐字竖排（兜底加固）**（`lib/client.js`）：v1.12.1 的修复依赖运行时向 `document.head` **注入全局样式表**（`.dsh-usage-table{min-width:720px}` + `@media (max-width:540px)` 折叠中间列）。在部分移动端运行环境（如经 mobile-remote 进出的手机页面）下该样式表因加载时序 / CSP 未生效，导致 9–11 列宽表每列被压到约 1 字符宽、标题与单元格逐字竖排、数据无法阅读。本版把 `min-width:720px` **直接写进表格的内联样式**（内联样式必然生效），窄屏时表格保持 720px、外层 `overflow-x` 容器横向滑动，彻底不再依赖样式表注入；原有注入样式表与 ≤540px 折叠逻辑保留，作为进一步优化的增强项。

---

## v1.12.1 (2026-08-23)

### 修复 / Fixed

- **修复移动端「消耗表」「消耗明细」等宽表列标题逐字竖排的问题**（`lib/client.js`）：窄屏下 9–11 列宽表每列被压到极限宽度，`word-break` 把「调用」「API 服务商」「输入·未命中」等表头拆成单字竖排。现为所有用量表格注入响应式 CSS：表格强制 `min-width: 720px`，外层 `overflow-x` 容器正常横向滚动、不再逐字换行；极窄屏（≤ 540px）下对宽表自动隐藏第 4 列至倒数第 2 列，只保留「模型 / 服务商 / 调用 / 总消耗」等主标识列与合计列，价格表等窄表不折叠、保留横向滚动。

---

## v1.12.0 (2026-08-23)

### 新增 / New

- **SSE 实时推送端点**（`lib/index.js`）：新增 `GET /usage/api/events` 事件流端点，数据变化（新调用记录写入 / 导入 / 清除等，即 `persistNow` 落盘成功）时向订阅者推送 `data: {"type":"changed","at":<时间戳>}`。桌面端数据中心等客户端订阅该流即可**即时**感知用量更新（毫秒级），不再依赖轮询。无订阅者时零开销，插件独立使用完全不受影响。

---

## 开源贡献基础：合并 PR #6（@Martin-soaring-dev，2026-08-20）

> 本期（以及后续 v1.9.2 / v1.9.3）建立在社区贡献分支 **`Martin-soaring-dev/prepare_for_contribution`** 之上。该分支由用户上传、经你合并（GitHub Pull Request #6，合并 commit `12a52be`），是插件转向对外开源贡献的形态基础。

### 该分支带来的主要改动
- **多服务商余额查询**（`lib/balance.js` 新增 +205 行，新增余额适配器 `BalanceProviderAdapter`）：将原先仅 DeepSeek 的 `/user/balance` 查询扩展为可对接多个服务商的余额查询框架，新增 DeepSeek / SiliconFlow / DigitalOcean / AMD GPU Cloud 等 Provider 适配器。
- **按服务商展示余额与价格**（`lib/client.js` +258 行）：客户端新增「剩余余额查询」Tab 的多服务商 UI，可分别展示各服务商的「总余额 / 充值 / 赠送」并切换查看。
- **Provider 化计费**（`lib/index.js` +399 行重构）：注入 `settings` 服务用于服务商查找，调用计费改为 provider-aware，支持按不同服务商分别统计与计价。
- **插件装配与测试**：新增余额适配器单测（`test/balance.test.js`，+130 行）、`scripts/wire.js` 手动装配兜底、`cordis.patch.yml` 插件注册条目。

### 致谢
- **[@Martin-soaring-dev](https://github.com/Martin-soaring-dev)**：提交并筹备了上述开源贡献分支（PR #6），是后续公开发布版本的功能与结构基础。

---

## v1.11.1 (2026-08-23)

- **修复：数据加载后页面空白**：加载动画三目分支误用逗号表达式，只返回最后一个表达式值（`null`），导致加载完成后各子视图全部不渲染；改为将四个子视图作为容器 `div` 的并列子元素，加载完成后正常显示。
- **计费说明改为面板级固定显示**：「高峰 / 空闲时段说明」固定在用量面板子页签下方，概览、用量日历、缓存命中列表、价格表四个页面切换时始终可见（含数据加载期间）。
- **当前时段精确显示**：用量面板顶部徽标与价格表页顶部新增「当前 · 工作日高峰时段 / 工作日空闲时段 / 周末空闲时段」动态状态并附说明文字；周末（自 2026-08-23 起）全天按空闲价计费，规则生效前仍按原规则区分。

---

## v1.11.0 (2026-08-23)

- **高峰 / 空闲时段说明**：概览、用量日历、缓存命中列表、价格表四个页面顶部统一新增「高峰 / 空闲时段说明」，清楚区分**工作日高峰**（周一至周五 9:00–12:00、14:00–18:00）、**工作日空闲**（其余时间）与**周末全天空闲**（自 2026-08-23 起按空闲价，此前仍按原规则）。
- **加载动画**：用量面板首次进入、数据仍在加载时显示转圈加载动画与提示文字，避免白屏无反馈；余额查询加载中同步使用加载动画。
- **表格适配**：所有表格改为宽度自适应容器（`width:100%`），单元格内容按需换行，不再因内容超宽出现横向滚动条；极窄窗口下容器保留横向滚动兜底。窗口缩放、不同分辨率下查看更舒适。

---

## v1.10.0 (2026-08-23)

- **新增 DeepSeek 官方模型 `deepseek-v4-flash-vision-exp`（DeepSeek-V4-Flash-Vision-Exp）**：官方价格表、概览「按模型」表、按 API 服务商 × 模型明细、用量日历、缓存命中列表与 PNG 报告均自动按该模型计价；「价格表」页新增该模型一行，`modelKey` 识别优先匹配 `vision`（避免被误归入 `deepseek-v4-flash`）。
- **价格**（元 / 百万 tokens，与官方最新公布一致）：空闲时段 缓存命中 0.05 / 输入未命中 1.5 / 输出 4.5；高峰时段 缓存命中 0.10 / 输入未命中 3.0 / 输出 9.0（与 `deepseek-v4-flash` 同价）。
- **核对确认**：`deepseek-v4-flash` / `deepseek-v4-pro` 的峰谷价与官方最新公布完全一致，无价格变动；发送给该模型的图片按其尺寸换算成 token，与文本 token 一并计费。
- **周末统一按空闲（低谷）价计费（2026-08-23 00:00 起）**：新规则生效后，周末（周六、周日）全天不再区分峰谷时段，统一按空闲价计费；工作日仍按北京时间 9:00–12:00、14:00–18:00 高峰分段。新规则生效前的调用仍按原规则结算。插件的高峰时段判定、面板「当前时段」徽标、概览 / 日历 / 缓存列表的高峰与空闲分列统计、PNG 报告均按新规则自动判断。

---

## v1.9.4 (2026-08-20)

- **持久化不再落到工作目录（修复「数据又进了工作区」的反馈）**：之前插件的落盘走的是模型侧沙箱化的 `fs` 服务，在 `workspace-write` 模式下会被限制只能写工作区；当系统/用户目录因沙箱不可写时，数据会兜底写进 `<工作区>/dsh-usage`，于是切换工作区又出现「数据没了」的现象（即 issue #4 的本质）。
- **改动**：持久化改为由插件**宿主进程自身的 `node:fs`** 直接完成，完全绕过 `workspace-write` 沙箱约束。数据根解析优先级变为 `DSH_USAGE_DATA_DIR` > `%LOCALAPPDATA%\dsh-usage-plugin`（或 `%APPDATA%`）> `~/dsh-usage-data`，**工作区降级为绝对最后的兜底**，正常桌面环境下数据稳定落在 AppData / 用户主目录，与当前工作区无关，切换工作区不再丢失历史。导出、价格表、`.keep` 等写操作同样改为宿主进程 `node:fs`，不再依赖受沙箱子进程。
- **数据迁移**：原有 4558 条历史记录位于 `<工作区>/dsh-usage/usage-records.json`，首次以新版本启动时会被自动去重合并进新的固定数据根（`%LOCALAPPDATA%\dsh-usage-plugin\dsh-usage\usage-records.json`），无需手动处理。

## v1.9.3 (2026-08-20)

- **概览支持日期筛选**：概览 Tab 顶部新增筛选栏，可按「今天 / 近 7 天 / 近 30 天 / 全部」快速切换，或自定义起止日期区间；所有聚合统计（按模型表、服务商 × 模型明细、总计）均按所选范围实时计算，并展示当前范围的记录数与总消耗。
- **文档**：新增「如何更新插件」章节——桌面端 / 命令行 / 手动三种更新方式、版本锁定、已装版本校验，并提示**勿手改 `node_modules` 下文件**（每次更新会被 npm 覆盖）。

## v1.9.2 (2026-08-20)

> 修复 issue #4：持久化路径随会话工作区漂移，导致历史用量数据"消失/统计为 0"，且 UI 显示路径与实际落盘路径不一致。

### 背景（症状与根因）
- **症状**：切换会话工作区、或用不同工作区重开桌面端后，统计页的「历史用量 / 总消耗」变成 0、仿佛数据丢失；同时统计页顶部显示的「数据持久化」路径，与磁盘上真实写入的文件路径对不上。
- **根因**：旧版持久化根按 `agent.session.cwd` / `sandboxPolicy.workspaceRoot` 推导——无会话启动时常解析到用户主目录，插件激活后又切到当前工作区，且不同根之间不会互相合并，于是历史被「切走」到另一个目录而读不到；写盘还会受工作区沙箱策略约束。

### 修复
- **固定专用数据目录**：持久化根不再跟随 `agent.session.cwd` / `sandboxPolicy.workspaceRoot` 漂移。解析顺序为：环境变量 `DSH_USAGE_DATA_DIR` > 系统应用数据目录 `%LOCALAPPDATA%\dsh-usage-plugin`（仅 Windows；macOS/Linux 下该分支不生效，因 `LOCALAPPDATA`/`APPDATA` 未定义）> 用户主目录下专用文件夹 `~/dsh-usage-data`（Windows 为 `%USERPROFILE%\dsh-usage-data`，macOS/Linux 为 `~/dsh-usage-data`）。该目录独立于桌面端安装目录、`~/.dsh` 主目录与任何会话工作区，删除工作区或卸载 APP 都不会丢失数据。
- **启动时合并去重**：首次初始化与会话激活时，自动把散落在用户主目录、`.dsh`、各工作区旧路径里的 `usage-records.json` 按 `time` 去重合并进固定根（复用现有 `normalizeRecord`），不再只读当前根的那一份。
- **UI 路径一致**：统计页顶部显示的「数据持久化」路径恒等于真实落盘路径；写入不再绑定工作区沙箱策略，固定目录可正常写入。
- **数据迁移**：切换根目录时对旧根记录做真正合并（非复制/分裂），重启后自动恢复全部历史。

### 影响
- 旧版本落在 `%USERPROFILE%\dsh-usage`、`.dsh\dsh-usage`、各工作区 `dsh-usage` 下的历史记录，会在首次启动本版本时自动合并到固定目录，无需手动迁移。

---

## v1.9.1 (2026-08-16)

- **文档**: README 改为英文优先（`README.md` 英文 + 新增 `README.zh.md` 中文）；补充「npm 包名已更换」醒目通知（旧包名 `@feiyang666/deepseekharnessdesktop` → 新包名 `@feiyang666/dsh-usage-plugin`），并移除发布教程等无关内容；修正 tarball 测试命令为新包名文件名。

---

## 1.9.0 — 2026-08-16 · 面板宽度自动适配（最终方案）

> 解决「不同窗口/屏幕大小下，宽表最右列与合计列被窗口右缘裁掉、卡片只剩半张」的问题。该问题的根因是：会话视图容器没有宽度约束，面板被宽表格/卡片撑到 max-content 宽度（约 1300px+），超出窗口右缘后被窗口本身裁掉，因此表格内部也不会出现滚动条。

### 新增
- 面板宽度以**视口封顶**：页签容器 `max-width: min(1200px, calc(100vw - 24px))`，任何窗口/屏幕大小下面板都不会超出窗口右缘。
  - 大窗口下仍保持 1200px 水平居中；
  - 窄窗口下跟随视口宽度收缩。
- 宽表在容器内**横向滑动**：表格保持自然宽度（`width: max-content`），容器 `overflow-x: auto` 兜底展示完整列。

### 修复
- 修复「按模型」「按 API 服务商 × 模型」等宽表**最右列（空闲消耗 / 总消耗、合计列）显示不全**的问题——表格超出可视区时出现横向滚动条，不再被窗口裁掉。
- 修复顶部统计卡片行**第 6/7 张卡片只有一半**的问题（卡片网格随面板宽度自动换行）。

### 优化 / 界面
- 撤掉 1.8.0 引入的「整体 CSS zoom 缩放」方案：不再把表格缩到看不清，保持默认可读字号。
- 根容器 / 页签容器增加 `width:100% + max-width:100% + min-width:0 + box-sizing:border-box`，彻底打破 flex 宽度链导致的溢出。
- 设置页保留原有的「底部横向滑动条」交互；工作区「用量与消耗」同样采用滑动条方案。

---

## 1.8.0 — 2026-08-16 · 宽表自适应（中间方案，已被 1.9.0 取代）

> 首次尝试解决宽表被裁问题：引入 `FitTable` 自适应容器，表格超过容器宽度时用 CSS `zoom` 按比例缩小，配合 `ResizeObserver` 监听窗口尺寸。
>
> 该方案在设置页被证明「缩小得太多、字体过小、不便于阅读」，未符合预期，因此在 1.9.0 中被废弃并改为「面板宽度视口封顶 + 宽表容器内横向滚动」。**此版本不建议用于正式发布，仅保留过程记录。**

### 新增
- `FitTable` 组件：测量容器宽度与表格自然宽度，超宽时按比例缩放（下限 0.35），并监听 `ResizeObserver`/窗口 `resize` 自动恢复。
- 所有宽表（概览两表、日历两表、缓存列表、价格两表）套用 FitTable。

### 已知问题
- 设置页在网页缩放后表格显得很小，阅读体验差。

---

## 1.7.0 — 2026-08-16 · 价格表官方标注 + 服务商 × 模型明细钻取

### 新增
- **价格表标注为「DeepSeek 官方 API 价格表」**：明确说明本表为 DeepSeek 官方 API 价格（单位：元 / 百万 tokens），仅涵盖官方模型 `deepseek-v4-flash` 与 `deepseek-v4-pro`，价格按官方公布固定、不可编辑。
- **概览「按 API 服务商」升级为「按 API 服务商 × 模型」钻取明细表**：
  - 每个服务商为一组（灰底加粗组头行），显示该服务商小计：调用数、高峰/空闲次数、各 token 合计、高峰消耗、空闲消耗、总消耗；
  - 组头下逐行列出该服务商**每一个模型**的详细数据（调用、高峰/空闲、输入·未命中、缓存命中、输出、推理、高峰消耗、空闲消耗、总消耗），按消耗从高到低排序；
  - 服务商按消耗降序排列（deepseek-official → opencode-go → deepseek-modlens …）；
  - 表尾为「总费用合计」行。
- **PNG 导出报告**的「按服务商」一节同步升级为「按 API 服务商 × 模型」分组表（组头行 + 缩进模型行 + 总费用合计行）。
- 面板顶部新增**全局计价说明**：各模型与 API 服务商的消耗统一按 DeepSeek 官方 API 价格计费（因各厂商定价数据不完整，不按第三方另行计价；无 DeepSeek 官方价格的模型消耗按 0 统计）。

### 优化 / 界面
- 概览「按模型」表保留并继续分组展示；新增组头行样式（`tdGroup`/`tdGroupR`）。
- 模型名与 API 服务商均以请求参数为准如实显示。

---

## 1.6.0 — 2026-08-16 · 区分 API 服务商 + 总费用合计 + 缓存列表性能优化

### 新增
- **按 API 服务商统计消耗**：概览新增「按 API 服务商」表，显示每个服务商（deepseek-official、opencode-go、deepseek-modlens…）的调用次数、高峰/空闲次数、高峰消耗、空闲消耗、总消耗，按消耗降序；空服务商显示「未知服务商」。
- **总费用合计**：
  - 概览服务商表底部「总费用合计」行（含高峰/空闲/总消耗合计）；
  - 缓存命中列表表尾新增「总费用合计」行：整段筛选范围内的调用数、各 token 合计、命中率、高峰 + 空闲 + 总消耗。
- 用量日历当日明细：每行的模型列下方补充该条调用的 API 服务商小字。
- PNG 报告新增「按 API 服务商」一节。

### 性能（缓存命中列表卡顿优化）
- **分页渲染**：每页 100 条，上一页 / 下一页 + 页码指示，不再一次性渲染上千行 DOM（卡顿主因）。
- **自动刷新 3 秒 → 10 秒**：原每 3 秒全量拉取所有记录并整表重渲染；现仅 10 秒拉取一次并增量显示。
- 切换筛选 / 日期区间 / 清除区间时自动回到第 1 页；汇总与表尾合计仍按整个筛选范围计算，不受分页影响。

### 验证
- 实测 2700+ 条记录 → 28 页；即使接近 10 万条上限仍保持流畅。
- 已校验「各服务商消耗之和 == 总费用合计」「高峰 + 空闲 == 总消耗」恒成立。

---

## 1.5.0 — 2026-08-16 · 真实模型名 + 高峰/空闲分列消耗 + 界面字号自适应

### 新增 / 修复（用量）
- **非 DeepSeek 模型不再显示「未知模型」**：模型名改为以请求参数里的真实模型名为准如实显示（`modelName` 助手）；概览、用量日历、缓存命中列表、PNG 报告均以真实模型名分组。
  - 修复前：kimi-k3、qwen3.6-plus、glm-5.2、grok-4.5、minimax-m3 等全部合并显示为「未知模型」。
  - 修复后：各自成行、如实显示；无 DeepSeek 官方价格的模型消耗按 0 统计。

### 计价（高峰 / 空闲分列）
- 服务端 `buildDays` 每日聚合新增**高峰 / 空闲消耗拆分字段**（按 `base`/`peakValley`/`auto` 三档各记一桶：`basePeakCost`、`pvOffPeakCost`、`autoPeakCost` 等共 6 个），作为单一天数据源；前端有「按记录回退计算」兜底，旧 host 未升级时也能正确显示。
- **概览**：新增「高峰消耗」「空闲消耗」卡片，总消耗卡注明「高峰 + 空闲」；模型表新增高峰/空闲调用次数、高峰消耗、空闲消耗、总消耗列与合计行。
- **用量日历**：月份卡片新增高峰消耗/空闲消耗；每日统计表改为「高峰消耗 | 空闲消耗 | 总消耗(自动)」三列（替换原 消耗(自动/峰谷/基础) 三列，列数更少更不挤）；悬停详情与当日明细都列出高峰/空闲的条数与消耗。
- **缓存命中列表**：汇总行区分「高峰消耗 X · 空闲消耗 Y · 总消耗 Z」；每行消耗金额按峰谷着色（高峰橙 / 空闲蓝）。
- **PNG 报告**：头部与卡片新增高峰价/空闲价消耗；模型消耗表新增高峰消耗 / 空闲消耗 / 总消耗列；模型名用真实名称；底部注明按 DeepSeek 官方价格统一计价。

### 界面（显示大小自适应 + 去拥挤）
- 面板全部字号改为 **em 相对字号**（`fs()` 辅助），随宿主「显示大小」设置的字体基准自动缩放。
- 表格内边距加大（6px → 7px/10px）。
- 模型列允许换行（`tdWrap`），卡片网格加宽防挤压。
- 月份导航文字 / 日期标题同步 em 适配。

---

## 1.4.0 及更早（基线，未逐版本拆分）

> 本项目自本日志撰写时起有记录的版本为 1.4.0。1.0.x–1.3.x 为早期迭代，未保留逐版本改动记录，以下为 1.4.0 时的完整功能基线（也是后续各版本迭代的起点）：

### 插件主体
- **Host 半**（`lib/index.js`）：监听 `llm/stream` 瀑布事件，捕获每次模型调用的 token 用量与缓存命中（输入·未命中 / 缓存命中 / 缓存写入 / 输出 / 推理 / 结束原因），写入 `<会话工作区>/dsh-usage/usage-records.json`，实时落盘、上限 100000 条、重启自动恢复。
- **Client 半**（`lib/client.js`）：在 WebUI「对话」「轨迹」之后提供「用量与消耗」「剩余余额查询」两个 tab；设置页亦有对应入口。

### 计费
- DeepSeek 峰谷 / 基础价格表（`deepseek-v4-flash` / `deepseek-v4-pro`），支持在面板内编辑价格并持久化到 `pricing.json`，可一键恢复默认。
- 峰谷价生效时间：北京时间 2026-08-17 00:00；生效前按基础价，生效后按高峰/空闲时段（高峰 = 北京 9:00–12:00、14:00–18:00）。
- `auto / base / peakValley` 三档计费，导出中每行带三档费用与 `period` 标记。

### 界面
- 概览（总消耗卡片 + 按模型消耗表）；用量日历（月度热力图，按消耗或调用数着色，悬停详情、点击某天看明细 + 每日统计表）；缓存命中列表（今天/近7天/近30天/全部 + 自定义日期区间）；价格表（自动/峰谷/基础三档）。
- 剩余余额查询：用 `DEEPSEEK_API_KEY` 调 `/user/balance` 显示总余额/充值/赠送。

### 数据与导出
- CSV / JSON / PNG 长图导出（最新在前，最多 2000 条，超出提示），支持自定义导出目录（原生目录选择器）与「打开所在目录」。
- JSON / CSV 导入合并，按时间去重。
- Windows / macOS / Linux 跨平台路径与原生操作适配；启动诊断日志 `dsh-usage-boot.log`。
