dsh-balance-ledger
DSH 余额账本 — DeepSeek Harness 桌面端插件:余额常驻显示,并把每一笔消费记到真正花掉它的那个会话上。
它解决什么
DSH 里看余额要打开「设置 → 账户」,而且只能看到一个总数——不知道钱花在哪个会话上。
这个插件做两件事:
- 余额常驻:输入框下方那排(运行统计 / 上下文条旁边)显示「余额 ¥xx.xx」,有赠金时附带显示。点一下打开「余额去向」小窗。
- 按会话记账:小窗按主会话列出消费、占比、最近扣费时间;子代理 / 子会话的消费并入所属主会话,展开可看「本体 + 各子会话」的明细。支持按时间 / 消费、正序 / 倒序排序。
金额是怎么来的(重要)
DSH 本地没有「每个会话花了多少钱」的货币口径——dsh-token-meter 在文档里明确说明它的数字「不是计费记录」,真正的扣费只发生在 Platform 侧。
所以本插件不做 token × 单价估算,而是用唯一真实的金额信号:账号余额的实际下降。
- 每次读到余额比上一次低,就把这段下降记到当时正在运行的会话上;
- 没有会话在运行时发生的下降 → 记为「未归属」,不会硬塞给某个会话;
- 多个会话并发 → 均摊并打「均摊」标签;
- 应用关闭期间的消费 → 无法观察,也会落到「未归属」。
台账保存在浏览器 localStorage(键:dsh-balance-chip.ledger.v1),插件不上传任何数据,也不读取设置页的 DOM。
关于那个
dsh-balance-chip键名:这是插件改名前的历史键,故意保留,否则升级后用户已记录的台账会丢失。
安装
要求:DSH 桌面版 0.2.x,并已登录 DeepSeek 账号(未登录时贴片自动隐藏)。
# 本地目录
dsh plugin --profile <your-profile> add "C:\path\to\dsh-balance-ledger"
# 或 git 地址
dsh plugin --profile <your-profile> add https://github.com/<owner>/dsh-balance-ledger
也可以在 DSH 的「设置 → 插件」里用管理页面安装。
安装后 profile 的 package.json 会多一条依赖,并在 dsh.profile.bundles 里追加 @local/dsh-balance-ledger。
结构
| 文件 | 作用 |
|---|---|
client.js |
全部实现:余额贴片、弹窗、余额读取、消费归属、排序、样式(只用主题令牌) |
index.js |
Host 半侧占位,export function apply() {} |
cordis.patch.yml |
bundle 层,插入 balance-ledger 这一行 |
package.json |
dsh.bundle.patch + dsh.client(platform: web、immediately、依赖的客户端包) |
locale/{zh,en}.json |
Plugin Manager 卡片上的标题与描述 |
test/smoke.mjs |
冒烟测试 |
为什么 Host 半侧是空的:DSH 的浏览器插件必须先有一个 Loader 条目,
dsh-client-modules才会为该包提供./clientbundle;所以需要一个只导出apply()的 Host 半侧。
实现要点
- 数据来源:
ctx.remote.account.watch()订阅账号状态,getBalance()读钱包;与「设置 → 账户」同一份数据。 - 实时性:
api-session/status转发事件标记每个 agent 回合的开始 / 结束;回合内每 2s 轮询,空闲降到 20s,页面隐藏时完全停止。 - 失败降级:读取失败保留上一次数字,不会闪成 0 或「不可用」。
- 子会话归并:按会话摘要的
parentId向上走到顶层主会话,并在记账时把 owner 冻结进台账,避免会话列表变化后分组错乱。 - UI 位置:贴片占
conversation.composer.dock;弹窗占shell.overlay,遮罩与卡片复用应用Modal的主题令牌(--dsw-alias-bg-mask-1、--dsw-mask-blur、--dsw-alias-bg-layer-2、--dsw-elevation-prominent),不引入@deepseek-ai/dsh-client-ui-primitives。
开发与测试
node test/smoke.mjs # 或 npm test
测试用替身 React / Cordis 驱动真实的 client.js,41 项断言覆盖:
- 模块 id = 包名、bundle 只注册一次、注入的服务齐全
- 贴片保持原始
span结构、默认不打开弹窗、点击可打开 - 子会话消费并入主会话(0.50 + 0.30 = 0.80)、折叠 / 展开、本体行
- 时间格式
MM/DD HH:mm、扣费列固定宽度 - 两种排序键 × 两个方向的首行顺序、活动按钮状态
- 归属规则:回合内下降归该会话、宽限期外的下降归「未归属」
- 台账持久化、子会话
root冻结 - hook 顺序守卫:同一组件前后渲染的 hook 数变化即判失败(曾用它抓到把
useSyncExternalStore写在提前return之后的崩溃)
已知限制
- 台账从安装之后开始记录,没有历史数据。
- 归属是「看到下降时谁在跑」的推断,不是 Platform 的账单;同一时刻的多笔扣费会被合并成一次下降。
- 如果某个子会话的父会话已从会话列表彻底消失,且它的台账是早期版本记录的(没有冻结
root),它会暂时单独占一行。 - 余额接口被限流时贴片沿用上一次数字;轮询间隔可在
client.js顶部POLL_RUNNING_MS/POLL_IDLE_MS调整。 CLIENT_VERSION只作为 Platform 请求头里的客户端版本,不是 DSH 版本门禁。
兼容性
在 DSH 桌面版 0.2.0-rc.2 ~ 0.2.1-rc.2(Windows)上验证。用到的接口:conversation.composer.dock / shell.overlay 插槽、ctx.locale、ctx.remote.account.getBalance + account.watch、api-session/status 转发事件、ctx.sessions.list。
License
MIT
English
dsh-balance-ledger is a DeepSeek Harness client plugin: the account balance stays visible under the composer, and a small popup shows where the balance went, per session.
The host records no per-session price (the token meter is explicitly not a billing record), so the plugin does not estimate. It charges every observed drop in the account balance to the sessions that were running at that moment, rolls sub-agent sessions into their main session, and keeps anything unattributable in an "unattributed" bucket.
The ledger lives in localStorage under the legacy key dsh-balance-chip.ledger.v1 (kept from before the rename so existing history survives). Nothing is uploaded.
Install into a DSH profile through the Plugin Manager or dsh plugin --profile <name> add <path-or-git-url>.
No comments yet. Be the first to write one.