Repository navigation
Releases
v1.3.0
新增
当前时段:高峰还是空闲,一眼可见
以前只知道「今天花了多少」,但花费是按高峰/空闲两档算的,看不出现在这一刻按哪档计价。现在部件会直接告诉你在哪一档:
- 收起状态:「今日」那一行前多了一个实时徽标 —— 高峰时是
高峰时段 ×2(警示色),空闲时是空闲时段(弱化色),不展开也能看见。 - 展开面板:余额下方新增「当前时段」一节,显示当前档位、高峰倍数,以及
距切换 1h 30m → 空闲时段的倒计时,并附一行说明高峰时段的具体区间。 - 悬停提示:窄栏(56px)收起时,时段信息也一并进入提示文本。
时段判定与计价共用同一份窗口定义,因此显示的档位与算出的花费不可能不一致。判定使用宿主时钟,两个时间点(当前时刻、下次切换时刻)随响应一起下发,所以浏览器处于任何时区、即使本机时钟不准,倒计时也依然正确。周末会正确跳到下一个交易日的第一个窗口。
配置
新增 showWindow(默认 true):设为 false 只隐藏时段徽标与面板行,数字照旧显示。
config:
showWindow: true验证
- 单元测试 27 项(新增 4 项时段窗口用例:盘内切换、午休与傍晚、跨周末跳转、边界分钟归属),客户端 11 项(新增「徽标可见并可用配置关闭」),宿主 9 项,共 47 项全部通过。
- 客户端用例在 Node 中以真实模块加载握手渲染部件,并断言徽标位于「今日」行、倒计时由宿主下发的时刻计算、
showWindow: false时徽标消失而数字保留。
安装
dsh plugin --profile desktop add "https://github.com/ZeroOT-Liu/dsh-usage-widget/releases/latest/download/dsh-usage-widget.tgz"升级后需要重启 Harness(宿主半边只在进程启动时加载),然后刷新页面(Ctrl+R)。
部件端点新增了
window与hostNow字段。新版客户端 + 旧版宿主会安全降级为「不显示徽标」,不会报错。
v1.2.1
修复
排查「本月累计空白」时,顺带查出并修掉了两个数据正确性问题。它们都不是界面问题,而是宿主半边读会话日志时的缺陷。
1. 会话日志被重写时,旧数据会和新数据叠加
读取器靠 文件大小 < 已读偏移 来判断日志是否被重写(压缩、格式迁移都会重写)。但重写后的文件完全可能比原来更大——这时判断不成立,于是从旧偏移继续读。如果偏移恰好落在帧边界上,扫描不会报错,新内容就被静默地加到旧内容上。
测试里精确复现了这一点:把已索引的文件重写成另一份更大的内容后,合计变成 514(旧 500 + 新 7 + 7),而正确答案是 21。
修复方式是在每次读取前校验「已消费前缀的末尾 32 字节」是否仍然一致(编译后的帧让偶然相同几乎不可能)。不一致就判定为重写,从头重读。代价是每轮每个变化的文件多一次 32 字节的小读取。
2. 诊断信息里的错误永不消失
lastError 只写不清,一次瞬时失败之后它会永远挂在诊断里,让健康的索引看起来是坏的。这正是这次排查一开始把我引偏的原因——它报告的那个「解压失败」文件,当前其实完全正常。
现在每一轮扫描收集自己的错误并在结束时统一发布,干净的一轮会把上一次的错误清掉。
3. 短读会把文件尾部补零
stat() 与 read() 之间文件可能被改写。此前按 stat 的大小分配缓冲区并假定读满,一旦文件变小,尾部就是零字节,扫描器把这当成损坏。现在以实际读到的字节数为准。
验证
- 宿主测试 23 项(新增「重写恢复与诊断」4 项),客户端 10 项,宿主半边 9 项,共 42 项全部通过,发布流水线同样运行。
- 真实 Cordis 冷启动时序检查仍然通过。
- 发布产物与源码逐字节一致,并在下载到的字节上复跑全部测试。
安装
dsh plugin --profile desktop add "https://github.com/ZeroOT-Liu/dsh-usage-widget/releases/latest/download/dsh-usage-widget.tgz"升级后需要重启 Harness(宿主半边只在进程启动时加载),然后刷新页面(Ctrl+R)。
如果你的「本月累计」仍是空白,请确认应用是在本次发布之后启动的:宿主代码不会被热重载拾取。用进程启动时间与插件文件修改时间对比即可判断。
完整变更:v1.2.0...v1.2.1
v1.2.0
新增
-
本月累计 —— 本月至今的 tokens、花费、请求数、活跃天数与会话数。
收起状态下现在是三行,关键数字都直接可读:
余额 ¥5.83 · 赠送 ¥5.27 今日 20.3M tokens · ¥1.3 本月 221.3M tokens · ¥11.98展开面板新增「本月累计」区块(总 tokens、花费、请求数、活跃天数、会话数),当前会话区块也多了一行它自己的本月数字。
月份边界按本机时区划分,和「今日」一致;月度是从已有的按日聚合里并出来的,不额外读取日志。
-
新增配置
showMonth(默认true)—— 设为false可以隐藏收起状态的本月那一行,让页脚保持两行。
关于完整性
本月累计依赖日志保留窗口。默认 keepDays: 45 足以覆盖一个自然月,此时合计是完整的;若把它调到 32 以下,月初的数据可能已被清理,面板会明确标注「本月早期数据超出保留窗口,可能不完整」,而不会把一个不完整的数字当成完整的展示。
验证
- 宿主测试扩到 18 项:新增月度聚合用例,覆盖跨天求和、跨月隔离、按会话过滤、保留窗口不足时的
complete标记;并像「今日」一样,与真实日志的全量解码做交叉验证(本月 2 天 / 808 请求 / 2.21 亿 tokens / ¥11.98,逐字段一致)。 - 客户端测试扩到 10 项:收起三行、面板月度区块、当前会话本月数字、
showMonth: false时不显示该行。 - 三套测试共 37 项,全部通过,发布流水线同样运行。
安装
dsh plugin --profile desktop add "https://github.com/ZeroOT-Liu/dsh-usage-widget/releases/latest/download/dsh-usage-widget.tgz"升级后需要重启 Harness(宿主半边的改动不会被热重载拾取),然后刷新页面(Ctrl+R)。
完整变更:v1.1.2...v1.2.0
v1.1.2
修复
-
重启 Harness 之后部件显示「今日暂无用量」,余额也读不出来。
这两个症状是同一个根因:宿主半边没有声明它要用的服务。
插件在
apply()里读取ctx.webServer来注册汇总路由,却没有把这个服务写进inject。Cordis 对未声明的服务读取会直接抛错(cannot get property "webServer" without inject),而这段读取被try/catch吞掉,于是路由静默地从未注册。客户端拿不到任何数据,用量显示空、余额也显示失败。为什么安装时是好的、重启后才坏:
场景 结果 安装/热重载(Web 服务已在运行) 服务已就绪,读取成功,路由注册 —— 看起来正常 冷启动(重启 Harness) apply()先于服务可见时执行,读取被拒,路由从未注册 —— 部件失效修复方式是声明依赖
export const inject = ['webServer'],让 Cordis 等到服务就绪后再启用这一半;同时把原本被吞掉的失败改成显式报错,避免同类问题再次静默发生。 -
新增宿主半边的回归测试(
test/host-smoke.mjs,9 项):用模拟 Cordis 服务规则的假上下文,未声明inject会直接让测试失败,同时覆盖路由的方法限制、回环Host校验、跨站Origin拒绝、正常响应与卸载释放。
验证
除三套测试(11 + 9 + 9)外,另用真实的 Cordis 4.0.4 运行时复现了冷启动时序,三个场景全部符合预期:
- 先加载插件、后提供服务 → 路由在服务出现时注册(修复后的行为)
- 去掉
inject→ 激活被拒,抛出cannot get property "webServer" without inject,路由始终不存在(原 bug 精确复现) - 服务在加载时已就绪 → 路由注册(热重载路径,解释了为何安装时正常)
安装
dsh plugin --profile desktop add "https://github.com/ZeroOT-Liu/dsh-usage-widget/releases/latest/download/dsh-usage-widget.tgz"升级后需要重启 Harness(宿主半边的改动不会被热重载拾取),然后刷新页面(Ctrl+R)。
完整变更:v1.1.1...v1.1.2
v1.1.1
修复
-
LICENSE 中的版权人署名错误:写成了
lyt-6-666(本机ghkeyring 里的旧账号别名),已更正为仓库实际归属的ZeroOT-Liu。这是有法律意义的署名行。
package.json的author与 GitHub 仓库归属本来就是ZeroOT-Liu,只有 LICENSE 一处不一致,且该错误随 v1.0.0、v1.0.1、v1.1.0 的安装包一并发布过。现已修正,安装包内的 LICENSE 与仓库一致。许可证本身没有变化,仍是 MIT。
安装
dsh plugin --profile desktop add "https://github.com/ZeroOT-Liu/dsh-usage-widget/releases/latest/download/dsh-usage-widget.tgz"装好后刷新页面(Ctrl+R)。
完整变更:v1.1.0...v1.1.1
v1.1.0
新增
插件图标 —— 在插件管理器的插件列表与设置页的插件清单里显示。
设计上要同时表达两件事:它是 DeepSeek Harness 的插件,它讲的是用量。所以标记由两部分组成——上方是 Harness 的虎鲸尾鳍(取自官方应用图标的形态,但只保留尾鳍,不做成官方标记的复刻),下方是三根递增的柱表示 token 消耗与统计。底色用 Harness 主题里的品牌蓝 #4176e6(--dsw-alias-brand-primary-new-color),到 #5686fe 的渐变,使它在浅色与深色主题下都成立。
图标是 SVG(icon.svg),在 16px–256px 下都保持清晰;assets/icon.png 是同一图形的 256px 位图版本,供 README 使用。
为什么侧边栏里的小图标没跟着换
侧边栏左下角那个图标只有 16px 且是单色。把它换成新的尾鳍 + 柱状标记实测会变糊(柱太细、尾鳍太小),可读性明显不如原来的钱包图标。所以两处各用各的:插件图标负责在列表里被认出来,侧边栏图标负责在 16px 下把这一行讲清楚。
安装
dsh plugin --profile desktop add "https://github.com/ZeroOT-Liu/dsh-usage-widget/releases/latest/download/dsh-usage-widget.tgz"装好后刷新页面(Ctrl+R)。
完整变更:v1.0.1...v1.1.0
v1.0.1
修复
-
展开面板始终显示「未选中会话」,当前会话的用量明细因此不可用。
根因不是取值逻辑写错,而是客户端读取了一个未在
inject中声明的服务
(uiSession)。Cordis 对未声明服务的属性访问会直接抛错
(cannot get property "uiSession" without inject),而这段读取被try/catch
吞掉,于是当前会话 id 恒为空字符串。inject补上sessions与uiSession- 不再自行复刻「谁是当前会话」的规则,直接读取宿主自己的主视图绑定
uiSession.adapter.current - 同时订阅
sessions.list:侧边栏比对话界面先渲染,挂载那一刻宿主还在发布
空绑定,必须等会话就绪后重新解析。这是独立于上面那个原因的时序问题,一并处理
-
测试脚手架两处会造成假通过的缺陷(因此之前的绿灯不可信):
问题 后果 check()未等待异步断言失败会变成未处理的 rejection,而计数照报「通过」、进程还退出 0 textOf()从不渲染嵌套函数组件展开面板的内容其实从未被断言过,读到的永远是空字符串 修正后,原先那条「点击展开面板」的绿灯立刻变成了失败——真问题被暴露出来。
-
新增回归用例:会话在挂载后才出现时必须被重新解析。
-
测试用的假
ctx现在像 Cordis 一样对未声明的服务抛错,这类 bug 以后会在测试里就死掉。 -
用变异测试确认新断言确实会失败(改坏面板标题、去掉
inject中的服务),随后逐字节还原(sha256 一致)。
验证
- 全套 20 项测试通过(宿主 11 + 客户端 9),并在下载到的发布产物上复跑通过。
- 发布产物与源码逐字节一致。
安装
dsh plugin --profile desktop add "https://github.com/ZeroOT-Liu/dsh-usage-widget/releases/latest/download/dsh-usage-widget.tgz"装好后刷新页面(Ctrl+R)。
完整变更:v1.0.0...v1.0.1
v1.0.0
首个版本:在 DeepSeek Harness 侧边栏左下角(Settings 上方)显示账号余额、今日 token 消耗与今日花费。
功能
- 账号余额 —— 通过官方账号服务
ctx.deepseekAccount.getBalance读取,与「设置 → 账号」同源。充值余额与赠送余额都显示在收起状态的第一行,不需要展开。 - 今日 token 消耗 —— 全部会话合计,含输入(缓存命中 / 未命中)、输出与推理 token,并显示涉及会话数与请求数。
- 今日花费 —— 按官方价目表与高峰 / 空闲时段(北京时间,工作日 9:00–12:00、14:00–18:00 翻倍)换算。
- 悬停或点击展开 —— 余额、今日明细、按模型分组、当前会话今日明细、更新时间与刷新按钮。
- 窄栏适配 —— 侧边栏收起成 56px 轨道时缩为一个图标,完整数值在悬停提示里。
实现要点
- 会话日志是多帧 Zstandard(每批追加一帧),Node 的同步解压只吃第一帧。插件按帧边界扫描并增量读取,未写完的尾帧跳过、下一轮补上,因此不会重复计数。实测首轮扫描 287ms,之后每次约 4ms。
- 宿主只注册一个精确路由。它会优先于 API 网关的
/api前缀匹配,因此该路由自行执行与网关同等的信任判定:仅接受回环Host,拒绝跨站Origin,其余一律 403。 - 零依赖:只用 Node 内置模块与相对导入,样式仅引用
--dsw-alias-*主题 token,客户端不require任何 Harness Client 包。
安装
dsh plugin --profile desktop add "https://github.com/ZeroOT-Liu/dsh-usage-widget/releases/latest/download/dsh-usage-widget.tgz"装好后刷新页面(Ctrl+R)。
已知限制
- 花费是按价目表推算的参考值,不是账单;官方调价后需更新配置中的
models。 - 「今日」按宿主本机时区划分。
- 中国法定节假日不在高峰规则内,节假日按高峰计价。