Repository navigation
Releases
dsh-usage-heatmap v0.2.0
dsh-usage-heatmap v0.2.0 — 模型计费与明细版式
新增「模型消耗」卡的计费能力,以及全模型明细视图;同时继续削减扫描与渲染的固定开销。
新增:计费
- 按
provider/model汇总 token 消耗,并换算为名义成本(USD 与 CNY 双显,汇率可配置) - 价目表三源合并:pi-ai 内置单价(1540 条)+ OpenRouter 公开价(后台拉取,只补空缺)+ 本地覆盖表(自定义路由单价);启动瞬时失败会自动重试一次
- 成本可核对:
ModelCost带四桶单价与用量,明细成本行悬停显示「单价 × token ÷ 1e6」算式 - 诚实口径:金额为「按公开单价估算的名义成本」;未匹配单价的模型显示「未定价」,其 token 不计入金额但保留在用量统计中;差额行披露「已删除会话与投影缓存无明细」的部分
新增:明细版式
模型卡第三个页签「明细」——全模型表格(不再 top8 + 其他),按 provider 分组可折叠,列含未缓存入 / 输出 / 缓存读 / 缓存写 / 合计 / 占比 / 成本;表头可切换按 token 或按成本排序。短名冲突时用 provider 区分同名模型。
「按日期」图表重做
- 连续日历轴:首日→末日逐日补列,柱位与日期严格成正比(实测 66 列,列宽与间距全一致)
- 等距日期刻度:约 9 个 + 末列必标,实测 10 刻度、0 重叠
- 段序按全期排名稳定排列:修掉相邻两日同色块上下颠倒(「一会左一会右」的主因)
- 图例等宽网格:名称左、provider 右,逐行左缘对齐
- 修图例悬停闭包 bug(所有条目曾指向最后一个模型);
mShort取最后一段以适配op/minimax/...这类路由名
性能
- 客户端 bail-out 修复:
updatedAt与source.scanMs每轮必变,原比较串包含它们导致「内容没变 → 复用引用」从未生效,15s 轮询把整棵面板树(775 vnode)重渲染。现排除易变遥测,实测宿主比较键稳定 - 目录枚举 memo 升级:全命中轮零
path.join/path.relative(原约 305 次/轮) - 派生聚合复用:全命中且未跨日、分类集合未变时复用上轮
dayTotals/metrics/models/dayModels,不再每轮重跑四个聚合 - 交错 A/B ×3(同数据、同命令、仅切换源码):扫描中位 13.69ms → 9.28ms(1.47×)
- 数据口径零变化:面板不变量
sum(days)==totalTokens每请求校验
其他
npm test扩到 27 条(新增目录路径 memo、派生聚合复用/失效、计费合并与成本公式等回归)- README 补三张实拍截图(总览 / 按日期 / 按模型)与「模型消耗分析」条目
- 计费脚注简化为「按公开单价估算的名义成本 · 未定价 X tokens 不计入金额」
升级方式:dsh plugin add dsh-usage-heatmap(npm)或从 Release 资产安装。统计口径与热力图/洞察部分无变化;首次加载会因价目表与全模型明细略微增大 payload(约 44KB)。
v0.1.4 — 扫描与获取延迟优化
dsh-usage-heatmap v0.1.4 — 扫描与获取延迟优化
性能
- 扫描每轮固定开销再削减两项:
- 目录成员记忆化:未变化的目录不再每轮重新枚举(mtime/ctime/ino 三重校验失效;仍逐轮 stat 目录与日志,新增、删除、替换即时可见)
- 投影扫描按耗时让出:原来每 4 个文件无条件让出一次事件循环(全命中时每轮也要排几十次宏任务),改为 8ms 耗时预算——命中时零让出,昂贵读取仍让出
- 实测(同机、210 日志全命中稳态):
- 交错 A/B 对拍:扫描中位 84.8ms → 52.1ms(1.63×)
- 含目录枚举的独立基准:176.9ms → 69.3ms
- 数据口径零变化:新旧实现全量聚合结果逐字段相等(10 组交错对拍 assert 全过);面板不变量
sum(days)==totalTokens每请求校验
数据获取延迟
- 面板可见时,15s 轮询直接携带
fresh=1:原来普通轮询拿到宿主旧缓存后要再等一轮后台扫描、再一轮才显示(最坏 ~45s),现在 15s 直接见新值 - 隐藏页暂停轮询:后台标签页不再消耗扫描
- 手动刷新不再被在途旧请求吞掉:强刷排队在普通请求收口后发一次真正的 fresh 请求;多个强刷自动合并
- 完全相同的响应也续客户端缓存 TTL,避免重复请求
其他
- 新增
npm test回归套件(14 条):目录失效语义(mtime/ctime/ino/成员增删/缺失目录)、投影让出预算、客户端请求调度(强刷排队与合并、隐藏页跳过、错误保留旧状态)、隔离内存文件系统上的端到端口径不变性(append / 新增日志 / 删除会话) - 文档纠偏:增量续解采样守卫(头尾各 512KB + 长度)的检测范围如实标注——长前缀中部改写是盲区,正确性依赖 DSH 日志仅追加的契约
升级方式:dsh plugin add dsh-usage-heatmap(npm)或从 Release 资产安装;统计口径与界面样式无任何变化,可放心直升。
v0.1.3
dsh-usage-heatmap v0.1.3
新增:模型消耗卡
- 位于热力图与活动洞察之间,按
provider/model汇总 token 消耗(本机实测 44 个模型键) - 双版式可切换:
- 按日期(默认):堆叠多色柱状图,横轴为本地日,柱内段为模型;8 色调色板 + 图例
- 按模型:垂直柱状图,数值标签贴柱顶、模型短名
- 悬停交互:段 / 日柱 / 柱 / 图例条目均显示三行明细(模型全名、当日 tokens 与占当日比、全期总量与占比);悬停图例联动高亮全部柱中对应模型段,其余段变淡
- 差额行诚实披露:已删除会话与投影缓存无模型明细的部分不计入图表,以「另有 X tokens 未按模型计入」显示;按日期版式另按逐日缺口口径披露
改进
- 指标卡图标 15→18px,更清晰
- 「最活跃星期」洞察附大头日期证据(如:主要来自 10月1日(31.35亿)、9月24日(17.11亿)等 6 天),数字自证
修复
- 修复按日期版式少计约 1.70 亿 tokens:旧口径归档条目(源日志已删)缺日×模型明细,单日条目现精确重建;无法无偏归属的多日条目(6.67 亿)由差额行披露,不做估算
- 修复 Windows 下模型卡同串文字观感割裂(非标字重 550 触发跨字面映射),全卡统一真实字面字重
性能与内部
- 扫描成本画像(63% zstd 解码 / 37% 行折叠);回退实测无效的字节级快路径并清理死代码,增量续扫维持 fresh 全扫 ~50ms
- 聚合器新增日×模型
dayModels维度(口径版本 MODELS_V 2→3,一次性自动全量重折自愈)
v0.1.2
面板高度自适应修复:height:100% 贴满宿主滚动区(消除双滚动条与底部空白);max-height 回退上限校准 100vh-150px → 100vh-85px;洞察卡 flex 只 grow 不 shrink(修复内容溢出压瘪);纵向密度压缩(指标卡 5 列自适应、间距收紧)。洞察列表保持单列。
v0.1.1 — 适配 0.2.0-rc 内核线
v0.1.1 — 适配 0.2.0-rc 内核线
宿主要求(peerDependencies)更新至最新内核线:@deepseek-ai/dsh-tools 与 @deepseek-ai/dsh-client-ui-slots 追加 || >=0.2.0-rc.1 <2 段。旧 0.1.x 分段范围原样保留(向后兼容);新增段覆盖 0.2.0-rc.1 起的预发布线(node-semver 预发布规则下,旧段无法匹配 0.2.0-rc.2,故必须显式加段)。
本机实测通过:DSH Desktop 0.4.4(@deepseek-ai/dsh 0.2.0-rc.2 / cordis 4.0.4 / schemastery 3.18.4)——typecheck 0 错误、热重载正常、sum(days)==metrics.totalTokens 不变量成立(21,236,180,567 == 21,236,180,567)。
安装:dsh plugin --profile web add "https://github.com/zeng6125-rgb/dsh-usage-heatmap/releases/latest/download/dsh-usage-heatmap.tgz"
v0.1.0 — 改名发布 npm + 增量续解
v0.1.0 — 改名发布 npm(下载量可统计)+ 增量续解
改名(unscoped,为发 npm)
包名 @dsh-external/dsh-usage-heatmap → dsh-usage-heatmap。原因:npm 上
@dsh-external scope 不可由本账号发布,而市场下载量统计链路(probe-npm.mjs)读的正是
仓库 package.json 的 name——包名必须等于已发布的 npm 包名。运行时行为零变化:
路由前缀 → /dsh-usage-heatmap/api、status 工具名 → _dsh_usage_heatmap_status、
cordis.patch / tsdown banner / lib 全同步改名。
已发布 npm:dsh-usage-heatmap@0.1.0(https://www.npmjs.com/package/dsh-usage-heatmap)
本版本含的性能修复(增量续解)
会话日志是仅追加的 zstd 帧格式,但旧版缓存只要文件涨一点就整份重解码
(42MB 文件单次全折实测 5.7s)。现改为按帧边界增量续解:持久化「已消费帧边界
- 前缀 sha256 守卫 + 折叠状态快照」,只折叠尾部新帧;守卫不符自动回退全量(自愈)。
实测?fresh=1从 6.8~12s 降到 ~50ms,且增量输出与全量逐字节恒等。
安装(三选一)
dsh plugin add dsh-usage-heatmap # npm(新增)
dsh plugin add github:zeng6125-rgb/dsh-usage-heatmap # GitHub
dsh plugin add https://github.com/zeng6125-rgb/dsh-usage-heatmap/releases/latest/download/dsh-usage-heatmap.tgzv0.0.5 — 增量续解(刷新提速 ~100×)
v0.0.5 — 增量续解(刷新提速 ~100×)
根因
会话日志是仅追加格式(dsh-session-persistence-jsonl:committed events are never
rewritten,每批次 append 一个新 zstd 帧),但旧版缓存失效判定只有 (mtime, size) 两级
⇒ 活跃大文件只要涨几十 KB,就把整个文件从第一帧重新解码重折叠(42MB 文件单次全折
实测 5.7s;真实环境 ?fresh=1 端到端 6.8~12s,会话越多越慢)。
修法
每个文件在缓存里持久化「已消费完整帧边界 r + 前缀 sha256 + 折叠状态快照 (u/t)」:
- 前缀守卫:
digestPrefix(buf, r)不符(改写/格式迁移/压缩转换)⇒ 自动回退全量,自愈 - 撕裂尾帧不计入消费边界;撕裂 carry 非空 ⇒ 下次全量(防半行计错)
- 旧缓存条目缺字段 ⇒ 各自第一次变更时全量折叠一次并补齐(自动升级,无需清缓存)
实测收益
| 场景 | v0.0.4 | v0.0.5 |
|---|---|---|
| ?fresh=1(活跃文件有增长) | 6,828~11,952ms | 51ms |
| 15.3MB 文件变更一次 | 全折 814ms | 续解 107ms |
| 稳态轮询/心跳(全命中) | 26~40ms | 8~17ms |
恒等保证(口径一个 token 没变)
- 夹具黄金等价 6 项全过:增量 ≡ 全量(dayTotals+metrics 逐字节)、守卫回退恒等、
撕裂尾 dropped 不污染、补全续解收敛恒等 - 真实规模夹具(38.4MB):增量 ≡ 删缓存全量黄金
- 宿主实机:不变量 sum(days)==totalTokens 成立;顶层 5 键 / metrics 27 键零变化
- lib/index.js、lib/client.js 逐字节未变(仅 aggregate 侧改动)
v0.0.4 — 设置页导航图标
v0.0.4 — 设置页导航图标(齿轮 → 热力图)
背景
settings.section 槽位契约只有 id/order/label,没有 icon 字段;宿主按 section id
硬编码图标映射,未知 id 一律回落齿轮。借用官方 id 会顶替掉官方分区,不可行。
做法与生态既有插件一致(dshmarket 的 settings-nav-icon,另有 dsh-better-sidebar /
dsh-skill-mcp-panel 同款):JS 按自家 label 文本认领导航行 → 打标记 → 独立样式表
用 CSS mask 画出图标。background:currentColor 跟随主题色;宿主 DOM 若变则静默失效。
图标迭代(无头浏览器实测 + PIL 量测)
| 版本 | 规格 | 结果 |
|---|---|---|
| v1 | 网格全出血 16×16 | 偏大 |
| v2 | 墨迹 14×14(4px 格 + 1px 隙) | 对齐齿轮 |
| v3 | 墨迹 13×13(3px 格 + 2px 隙) | 还可小一点 |
| v4 | 墨迹 11×11(3px 格 + 1px 隙) | 定稿:11.0×11.0 CSS,填充率 64%(齿轮 13.3×14.0 / 43%) |
验证
结构断言(齿轮隐藏、::before + mask 生效、兄弟行零误伤)、数据口径/契约/滚动配方
零影响、typecheck exit 0。改动仅 src/client/index.ts。
含 v0.0.3 的 usage:null 修复(lib/aggregate.js = 510840C1…,lib/index.js 未变)。
v0.0.3 — usage:null 修复
v0.0.3 — usage: null 修复
问题
三处判空写的是 !== undefined,而 null !== undefined 为 true,于是 null 一路穿过所有守卫,在 bucketsFrom 的 Number(u.inputTokens) 抛错:
TypeError: Cannot read properties of null (reading 'inputTokens')
该异常被 runScan 的 per-file try/catch 吞掉,后果不是丢一行,而是整个会话文件被跳过 —— 该文件此前所有行的记账一并丢失,且保留旧缓存使问题静默。
修复
三处判空统一改为宽松判空,使 null 与 undefined 完全同义(都表示"本次调用未上报 usage"),其余值一律原样透传 ⇒ 口径零变化。
快路径(readAssistantData 的 typeof usage !== 'object')原本就能拦下 null 并回退全量解析,缺口只在回退路径;本次补齐,两层防线一致。
验证
夹具 A/B(自造多帧 zstd 日志,驱动真实构建产物,对照上一版构建):
| 夹具 | 内容 | 修复前 | 修复后 |
|---|---|---|---|
| A | 正常 3 条 | 660 | 660 |
| B | 中间夹 1 条 usage:null |
整份丢失 | 440 ✓ |
| C | 流尾 chunk.usage = null |
整份丢失 | 440 ✓ |
| 合计 | 660(decoded=1) | 1540(decoded=3) |
⇒ 同一输入,修复前丢 880 token,修复后零丢失。
真实 ~/.dsh 回归(各自 force 全量重扫):历史 20 天逐 token 完全相等(差异 0/20,历史合计 4,739,309,532 两侧恒等);唯一差异出现在今天——7.1 秒窗口内 +640,540 token、steps +3、会话数不变 ⇒ 既有会话持续写入的自然增长。
不变量 / 契约:sum(days) === totalTokens === 四桶求和;HTTP 200 / no-store / 顶层 5 键 / metrics 27 键 / ?fresh=1 正则 12 边界全对;宿主 API 调用形态不变;无新依赖;typecheck exit 0。
v0.0.2 — 行标对齐修复与性能优化
v0.0.2 — 行标对齐修复与性能优化
UI 对齐(两轮反馈,两个独立缺陷)
① 行标与格子逐行错位
根因:.uh-wdLabels 与 .uh-cells 各自一套行轨道,且 height:calc(100% - 17px) 的百分比高度遇 height:auto 包含块不解析(计算高度恒为 109px)。
改为几何同源:--uh-tracks 由 .uh-cal 单点声明供两个子 grid 消费;行标并入 .uh-cells 作为第 1 列 grid 成员。删除全部镜像常量。
| 场景 | 修复前 | 修复后 |
|---|---|---|
| 真实面板 480/768/1200/1600 | 6.500 / 5.594 / 6.500 / 6.500 px | 0 / 0 / 0.008 / 0.008 px |
| 夹具 1600px 极端 | 82.055 px | 0.000 px |
| 320px 溢出(日/周) | 537 / 589 px | 0 / 4 px |
② 行标字形墨迹偏下
height:0 + align-items:center 居中的是行盒,而看到的是字形墨迹;本字体 ascent=10 / descent=2 不对称使墨迹中心落在行盒中心下方。像素量测(阈值簇法 +0.536px、强度质心法 +0.590px,两法互证)后加光学修正 transform:translateY(-0.0667em)。
取值经 DPR=1 与 DPR=4 双档定标:DPR=1 下 -0.5px 会被栅格化舍入完全吞掉,必须 ≤-0.6px 才翻到 -1 设备像素。修正后 +0.085px / +0.138px。
性能(host 端)
assistant/message免全量JSON.parse快路径(26,466 行 / 447MB,命中率 95.47%,字段差异全 0)- 冷扫 maxGap 3,689 → 383 ms(-90%);RSS 336 → 142 MB(-58%);热扫 -67%;增量 maxGap -97%
- 修复快照 dirty 门控永不生效(遥测字段参与比对 → 6/6 次无谓重写 → 0 次)
makeLevelFn线性扫描改二分;POLL_MS 60000 → 15000(与宿主STATE_TTL_MS对齐)
不变量
输出与基线字节级恒等(81/81 解码文本相同、81/81 折叠相同、metrics 对象 JSON 字节级相同);sum(days) === totalTokens;对外路由 / 工具名 / 字段名 / ?fresh=1 正则未变;无新依赖;宿主 API 调用形态不变;滚动配方未回退(长帧 0)。
安装
dsh plugin add github:zeng6125-rgb/dsh-usage-heatmap
# 或
dsh plugin add https://github.com/zeng6125-rgb/dsh-usage-heatmap/releases/latest/download/dsh-usage-heatmap.tgz