在右下角浮层显示 DeepSeek 账户余额与本会话花费,支持预算告警、峰时提醒,以及可选开启的官方价格同步。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:LinHyu-2006/dsh-balance-hud
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
English | 简体中文
dsh-balance-hud
DSH(DeepSeek Harness) Web GUI 右下角的常驻 HUD:一眼看到 DeepSeek 账户余额和本会话花费。
English · 设计说明 · Design notes · LICENSE

关于这些图片:它们不是运行中 DSH 窗口的真实截图,而是按插件自身的布局与配色 渲染出来的图(用的是真实样式取值与真实数字)—— 制作时没有可用的实时界面截图工具。 请把它们当作如实的布局参考,而不是"已装好并正在运行"的证据。 欢迎用真实截图替换。
# Windows —— 双击 tools\install.cmd,或在命令行里:
tools\install.cmd
# macOS / Linux:
sh tools/install.sh
两个启动器都会替你找 Node,包括 DSH 自带的那份运行时(它不在 PATH 上)。
如果你的机器完全没装 Node,它会明确告诉你怎么办,而不是丢一句 node: command not found。
换个 profile 用 --profile <目录>,只看不改用 --dry-run,卸掉用 --uninstall。
想自己跑也行 —— 下面这条假定 Node 已经在 PATH 上:
node tools/install.mjs # 安装到 ~/.dsh/profiles/desktop,然后重启 DSH
node tools/smoke.mjs # 离线冒烟套件(83 条断言),不需要装 DSH
装完必须重启 DSH。 装插件会改 profile 的 bundle 列表,那个列表不热加载 —— 只刷新页面不会生效。
- 账户余额 —— 充值余额 + 赠金余额,走的是「设置 → 账号与余额」同一个服务
(
ctx.deepseekAccount.getBalance())。 - 两条花费口径 —— 按官方价格表算的 token 预估,以及由真实余额减少量累计出的实际值。
- 付充值无感 —— 充值只抬高余额,不会打断花费计数。
- 按会话独立 —— 基线与计数按会话 id 分槽存储;刷新页面或切换会话都不会覆盖别的会话。
- 不碰凭据,默认不外联 —— 插件从头到尾不接触你的 API key;只有你开启价格同步后才会联网 (见 价格与同步),在此之前不产生任何外部请求。
- 前后各半、一条中继 —— 浏览器半边负责渲染,Host 半边开只读回环路由(余额、赠金信号、 价格同步、模型列表),浏览器本身只跟回环地址说话。
- 可配置、有预算 —— 「设置 → 通用」里有一行偏好,可改模型、轮询间隔、预算与提醒; 花费接近预算时卡片会亮起彩色描边,面板还会倒计时到下一次峰谷切换。
界面
┌──────────────────────────────┐
│ 账户余额 ¥43.42 │
│ 本会话预估 ¥0.59 │
└──────────────────────────────┘
把鼠标移到卡片上会展开明细面板:余额分项(充值 / 赠金 / 合计)、预估花费的三个计价分项、
实际值、token 用量,以及并行会话时的分摊行(本会话占比、其它会话、跟踪会话、
账户级合计)。展开面板用 4 位小数,小卡片用 2 位。
| 字段 | 含义 |
|---|---|
账户余额 |
账户合计(充值 + 赠金),2 位小数 |
本会话预估 |
本会话的预估花费;卡片 2 位、面板 4 位;会话还没有 token 用量时显示 — |
实际扣费 |
本会话累计的真实花费(单会话时;并行时改叫 本会话分摊) |
金额小于可显示的最小单位时,卡片显示 <¥0.01、面板显示 <¥0.0001 —— 花了钱就绝不会被抹成 0。
交互
- 悬停卡片展开明细面板。
- 卡片与面板是两个独立元素,中间留了 8 px 的视觉间隔。悬停判定挂在卡片和面板自己身上
(各自有 enter / leave),不挂在外层定位容器上;并用一个 140 ms 的待关闭定时器,
让指针落进那段间隔时面板的
mouseenter能取消卡片的mouseleave。 - 从卡片左边或面板左边滑出即收起。这是刻意的:容器在四周预留了空白, 把收起判定挂在容器盒子上会让面板停在"其实已经离开"的空白处不消失。
- 点击卡片折叠成角标(2 格:标签 + 余额),再点恢复。
- 键盘:卡片是
role="button"+tabIndex=0,Enter/空格切换折叠;面板是role="dialog"。 - 面板里有
刷新按钮(点击立刻显示忙碌文案,完成后给一个更新于 HH:MM:SS时间戳), 以及手动兜底的我刚充值了按钮(处理中显示查询状态)。 - HUD 里刻意没有任何
title属性。 原生浏览器 tooltip 会在悬停约一秒后弹出黑色方块盖住面板, 所以摘要写在aria-label里。冒烟测试把这条当回归守卫断言。
设置
插件往 DSH 的 settings.general.item 槽位注册一行偏好 —— 余额与花费 HUD。DSH 对这个槽位的
定义是「General 区里的一行偏好 —— 单个设置专用的增量座位,不需要独占一整页」(要整页请用
settings.section;DSH 自己的 Language、link-opening、performance-usage 几行也注册在这里)。
位置:设置 → 通用 → 余额与花费 HUD。它不会占用整个设置页。
| 设置项 | 取值 | 默认 | 作用 |
|---|---|---|---|
计价模型 |
deepseek-flash、deepseek-v4-pro |
deepseek-flash |
预估与分摊权重所用的价格表 |
自动同步价格 |
不自动(只手动) / 每 6 小时 / 每 1 天 / 每 3 天 / 每 7 天 | 不自动(只手动) | 官方价格表的自动同步节奏;不选就永远不会自动跑(见 价格与同步) |
前台刷新间隔 |
30 / 60 / 120 / 300 秒 | 60 秒 | 页面可见时的余额轮询节奏 |
后台(页面隐藏) |
30 / 60 / 120 / 300 秒 | 300 秒 | 标签页隐藏时的轮询节奏 |
峰前提醒 |
5 / 10 / 15 / 30 分钟 | 10 分钟 | 峰谷切换提醒提前多久出现 |
本会话预算(元) |
元,0 = 不设 |
0 | 本会话预估花费的预算 |
每日预算(元) |
元,0 = 不设 |
0 | 北京自然日确认花费的预算 |
显示账户级合计 |
开 / 关 | 开 | 并行会话时面板里的 账户级合计 行 |
峰时提醒 |
开 / 关 | 开 | 面板里的峰谷提醒行 |
预算超限发系统通知 |
开 / 关 | 关 | 首次达到某个预算档位时的可选系统通知 |
持久化。 这一行写的是 localStorage 的 dsh-balance-hud:settings:v1,与记账键
(dsh-balance-hud:tracker:v4)刻意分开,两者不可能互相干扰。
两个注册点,一个容器。 设置行(settings.general.item)与浮层(shell.overlay)是
两个独立的槽位注册,没有共同的 React 祖先,因此无法共享 React state。它们改用一个小的订阅
容器 —— createSettingsStore → get / set / subscribe:set 合并一份部分补丁、落盘、广播,
所以在任一处改动,另一处立刻同步 —— 不需要刷新,也不需要共享父组件。useSettings 是架在同一个
容器上的 React 绑定。
配置永不被信任。 normalizeSettings 逐字段对白名单校验:未知模型、不在选项内的间隔、
负数预算、非布尔开关,一律回落默认值,而不是传进界面;localStorage 里的 JSON 损坏时同样回落
默认、不抛错。配置是用户可写、且随版本变化的,所以每次读取都重新校验。
预算
在设置行里可以设本会话预算和/或每日预算(单位元;0 表示不设)。
evaluateBudget(spent, budget) 返回 { level, ratio, remaining },level 为
none | warn | critical | over:
| 使用率 | 档位 |
|---|---|
| < 75 % | none |
| ≥ 75 % | warn |
| ≥ 90 % | critical |
| ≥ 100 % | over |
remaining 夹在 0 以上,"超限"不会报出负数余额。worstBudgetLevel 再取"本会话"与"每日"两条预算
里更严重的一条,所以「今天已经用爆、但本会话还很便宜」同样会告警。
视觉。 预算达到或超过阈值时,卡片左侧出现 3 px 彩色描边 —— warn / critical 用主题的
警告色、over 用错误色。它刻意不是网格里多出来的一格:卡片网格必须保持 2 列 × 2 行,
冒烟测试用断言钉住了这一点。展开面板会多一行预算,显示「已用 / 预算」以及剩余金额或 已超限。
可选系统通知。 打开 预算超限发系统通知(默认关)后,每个档位在本次挂载内最多只发一次,
所以不会变成骚扰。它走浏览器 Notification API,只在权限已授权时才发;没有授权时静默降级为
只有描边变色,不影响其它功能。
每日预算用按天台账。 localStorage 键 dsh-balance-hud:daily:v1,内容是 { date, total },
其中 date 是北京自然日(beijingDateKey)—— 官方计费与峰谷窗口都按北京时间,日界跟着同一个
口径才不会错位。台账只累加确认花费(某次余额读数确认的那部分),不用递推显示值,因此同一笔钱
不会被重复计入。读到新的一天时台账归零。
峰时提醒
峰时 = 北京时间周一至周五 09:00–12:00 与 14:00–18:00;峰时价恰好是闲时价的 2 倍。
minutesUntilTierChange(now) 返回 { minutes, to },to 为 'peak'(即将进入贵的那档)
或 'off'(即将回到便宜的那档)。
当"下一次切换"落在配置的提前量以内时,面板显示一行提醒:
约 N 分钟后进入峰时,价格翻倍约 N 分钟后回到闲时价
一个 60 秒的滴答同时驱动倒计时与跨天重置,所以数字是活的。午休、跨夜、跨周末都算得对 —— 例如周五 18:30 → 周一 09:00 是 870 分钟 —— 冒烟测试断言了这些用例。
两条花费口径
| 口径 | 算法 | 性质 |
|---|---|---|
| 预估 | 会话 tokenUsage 投影 × 官方价格表 |
精确可算,但只覆盖模型 token |
| 实际 | 观测到的余额减少量累计求和,按会话存在 localStorage |
平台真实扣费,但有结算延迟 |
预估把用量拆成四类 token —— 未命中输入、缓存命中、缓存写、输出 —— 各自按峰谷两档价计价。 缓存写按未命中输入价计,与平台扣费口径一致。实际值是一个计数器,不是做减法: 每一次观测到的余额下降都加进当前会话的计数器,所以充值无法干扰它。
充值识别
原则:外部变动改变余额,但绝不能改变花费计数。
判据用的是 token 估算上界,而且它双向都成立:平台扣掉的钱不可能超过这段时间 消耗的 token 所值的钱;反过来,余额减少的量如果超过这个上界,多出来的部分也不可能来自消费。
余额升幅 > 全部会话 token 估算之和 + 0.02 → 外部加钱:充值 / 赠金到账 / 账单修正
余额降幅 > 全部会话 token 估算之和 + 0.02 → 外部减钱:赠金过期回收 / 退款 / 账单修正
其余 → 普通消费,照常累计
这样既不会因为"充值和消费同时发生"漏判,也不会因为正常消费波动误判。
为什么必须处理"减钱"那个方向:赠金会过期
赠金有有效期。到期未用完的部分会被平台回收,表现为余额凭空下降、却没有任何消费。
早期版本把任何余额下降都算成消费(delta < 0 → spend),于是 5 元赠金过期会被记成
5 元"本会话花费";而计数器只增不减,这个错误会一直留在记录里直到 30 天后被淘汰。
现在两个方向走同一条路径:只移动账户级字段(baseline / lastBalance),
spent 原封不动,并在 topups[] 里记下是哪一类变动。
多会话时,applyExternalChange 会把所有会话的账户级字段一起移动,但刻意不动 lastRead
(会话私有的"上次真正观测到的余额")。于是每个会话都会自愈:还没观测到这次变动的会话,
下次读数时仍能看到完整落差,从而自己判出这是外部变动,而不会把它摊到自己的消费上。
三层,按权威度排序
- token 上界判据 —— 纯客户端、始终生效,是权威判据(两个方向都是它说了算)。
- 官方赠金印证 ——
GET /api/balance-hud/bonuses读ctx.deepseekAccount.getUnnotifiedBonuses()。它是只读且刻意不回执的 (不调ackBonusNotified),因此不会消费掉 DSH 自己的赠金通知;数据保持可读, 客户端按orderId去重。即使这条路由不通,变动仍会被识别 —— 这一层只是印证。 注意:它只能印证"发放",官方没有"过期"的推送,所以减钱那个方向完全靠第 1 层。 顺带把官方给的expiresAt透出来,提示里会带上"最早到期"日期。 - 手动兜底 ——
我刚充值了按钮走同一条重锚路径,处理期间显示"查询中…"。
面板会显示约 12 秒的提示,两类都有:
- 加钱:
已识别充值 ¥50.00,花费继续累计(官方赠金 ¥5.00 印证),最早到期 2025-12-31。 - 减钱:
检测到 ¥5.00 非消费性扣减(赠金过期回收等),未计入花费。
并行会话与分摊
账户余额是账户级的:它不携带"这笔钱是哪个会话花的",所以单个会话的真实花费 在本地不可观测。插件用比例分摊:
本会话分摊 = 本会话累计花费 × (本会话 token 成本 / 全部会话 token 成本)
所有会话的 token 成本都用同一套四类计价 + 峰谷价,权重才可比。只有一个会话时权重恒为 1, 数值就退化成精确值。
这是估算。 两个会话的 token 消耗与平台结算并不同步,比例会漂移;有新会话加入分母时,
数字会下跳一次。面板里有 本会话占比、其它会话、跟踪会话 几行,能看到当时的权重是多少。
持久化
记录在 localStorage 的 dsh-balance-hud:tracker:v4 下,按会话 id 分槽:
{ "sessions": { "<会话id>": { "baseline": 43.42, "lastBalance": 43.12, "spent": 0.3, "ts": 0 } } }
| 情况 | 行为 |
|---|---|
| 刷新页面 / 重新挂载 | 从 localStorage 读回,计数器继续累计 |
| 切换会话 | 各会话有自己的记录,互不覆盖、互不清零 |
| 识别到充值 | 只移动基线,spent 不动 |
| 记录超过 30 天 | 写回时淘汰 |
| 超过 30 个会话 | 保留最近 30 个 |
localStorage 不可用 |
降级为仅内存,HUD 照常工作 |
页面存活期间,内存里的 store 还带着一个 topups[] 历史和一个 lastObservedBalance;
但当前写盘只持久化 sessions。老数据会自动迁移 —— v3 是 { sessions: { … } }、
v2 是扁平的 { [会话id]: { … } } 字典、v1 是单条 { sessionId, … } —— 迁完会删掉旧键。
余额默认每 60 秒拉一次(页面隐藏时 5 分钟),页面回到前台立刻补读, 失败按 1s → 2s → 5s → 10s → 20s 退避重试。未登录不算错误,也不会走快速重试。两个间隔都可以在 设置行里改(见 设置)。
除了记账键,还有三个互相独立的键:dsh-balance-hud:settings:v1(设置行,见
设置)、dsh-balance-hud:daily:v1(北京自然日台账,见 预算)和
dsh-balance-hud:prices:v1(同步来的价格表与它的 HTTP 校验器,见 价格与同步)。
清理或写坏其中一个,都不会影响其它几个。
架构
浏览器(客户端半边 lib/client.js) Host(Host 半边 lib/index.js)
注册 shell.overlay 槽位 inject: [deepseekAccount, webServer]
每 60 秒轮询一次 │
fetch ──────────────────────────────────────► GET /api/balance-hud/balance (只读)
GET /api/balance-hud/bonuses (只读)
GET /api/balance-hud/pricing (价格同步,需主动开启)
GET /api/balance-hud/models (模型列表,仅回环)
└─► ctx.deepseekAccount.getBalance()
ctx.deepseekAccount.getUnnotifiedBonuses()
└─► 官方 account platform
fetch(PRICING_DOC_URL) ← 仅主动开启同步时
└─► 官方价格文档页
为什么需要这条中继。 浏览器半边无法直接调 ctx.remote.account.getBalance:
不声明就访问会抛 cannot get property "remote.account" without inject;
而在客户端半边声明 inject = ["remote"] 又无法满足 —— fiber 永久挂起,插件根本不激活。
两条都在真实 @deepseek-ai/cordis 4.0.4 上复现过。所以由 Host 半边读余额,
再经仅回环、只读的路由交给浏览器。所有路由都只接受回环来源
(127.0.0.1、::1、IPv4 映射回环形式),其它一律 403;只支持 GET,
不改任何状态,不返回凭据,并带 cache-control: no-store。其中一条在用户主动开启后
才会产生对外请求 —— 价格同步。
| 返回 | 含义 | HUD 显示 |
|---|---|---|
{ kind: 'ready', currency, rechargeTotal, bonusTotal, total } |
已登录且有钱包 | ¥xx.xx |
{ kind: 'unavailable', reason } |
未登录 / 凭据在查询期间变更 | 未登录 |
{ kind: 'error', reason } |
查询失败、路由不可达、响应不合法 | 读取失败(原因在面板里) |
价格口径
单位 元 / 百万 tokens,取自官方 模型 & 价格;闲时价恰好是峰时价的一半。
| 模型 | 缓存命中输入 | 缓存未命中输入 | 输出 |
|---|---|---|---|
deepseek-flash |
闲 0.02 / 峰 0.04 | 闲 1 / 峰 2 | 闲 4 / 峰 8 |
deepseek-v4-pro |
闲 0.15 / 峰 0.30 | 闲 4.5 / 峰 9 | 闲 13.5 / 峰 27 |
- 峰时 = 北京时间周一至周五 09:00–12:00 与 14:00–18:00。其余时段(含周末与法定节假日) 按闲时计;只取本地时间的「星期 + 小时」换算,不引入时区库。
- 缓存写按未命中输入价计费。
- 价格表里两个模型都有;模型是一个设置项(默认
deepseek-flash),预估与分摊权重都跟着它走。 未知模型回落到 flash 价格(而不是归零),面板会说明这一点。 - 官方调价后,可以同步价格表(见 价格与同步),或者改
PRICES再刷新页面。 - 上表是内置快照,日期为 2026-09-29(
BUILTIN_PRICES_DATE);同步成功后就改用官方的新表。
价格与同步
预估所用的价格表内置在插件里,是一份有日期的快照(内置表日期 2026-09-29);除非你主动 要求,插件一直用它。官方随时可能调价,所以插件也可以同步官方价格表 —— 来源是 官方价格页,这也是它唯一会访问的外部主机。
两种触发方式,都必须由你主动选择:
- 设置行里的
同步价格按钮(英文名Sync prices):点一次,立刻同步一次; 自动同步价格下拉:选项是不自动(只手动)/每 6 小时/每 1 天/每 3 天/每 7 天(即off/ 6 小时 / 24 小时 / 3 天 / 7 天)。不选间隔就不会自动跑,出厂状态是「不自动」 (syncHours: 0)—— 装上插件后不碰这些控件,插件一个外部请求都不会发。 开启自动同步后,默认节奏是 24 小时(DEFAULT_SYNC_HOURS),理由是:官方调价会先在 changelog 里预告,价格页随后才改,所以这是「几个月一次」的事件,不是每天的事。价格页是 CDN 资源, 会回ETag与Last-Modified,同步时带上If-None-Match,页面没变就回304 Not Modified且没有响应体 —— 每次轮询只有几百字节。24 小时把「过期窗口」压到一天, 代价几乎为零。
抓取由 Host 半边执行,不是浏览器。 浏览器从不直接访问价格页,它调两条只读回环路由:
GET /api/balance-hud/pricing(同步价格)与 GET /api/balance-hud/models(DSH 已注册的模型)。
只有前者可能产生对外请求;后者完全不需要网络 —— 它读 DSH 自己的 llm 服务
(listProviders() / listModels()),设置行用它填充「计价模型」下拉,拿不到 llm 时回落内置选项。
算错价,比用旧价更糟。 页面由一个纯函数解析,它的每个判断都与页面编码无关 (抓取链路可能把 UTF-8 字节按 Latin-1 解开,中文标签会变成乱码),并且做语义校验: 官方规则是「闲时价 = 峰时价的一半」,所以峰时价必须严格大于闲时价。任何一项校验不过, 整次同步整体作废,插件继续用上一份好表 —— 内置表或上次同步成功的表。 半解析出来的表永远不会被用来算钱。
存在哪里、行里显示什么。 同步结果缓存在 localStorage 的 dsh-balance-hud:prices:v1,
一起存的还有 ETag、Last-Modified 与抓取时间戳;收到 304 时只刷新检查时间,不动价格表。
设置行会显示当前用的是哪一份、是哪天的 —— 当前价格:内置表(2026-09-29),
同步成功后变成 当前价格:已同步(YYYY-MM-DD)。
安装
这是一个本地 profile 插件,不发布到 npm。
node tools/install.mjs # 安装到 ~/.dsh/profiles/desktop
node tools/install.mjs --dry-run # 预览,不写任何文件
node tools/install.mjs --uninstall # 卸载
node tools/install.mjs --profile <dir> # 指定别的 profile
手工安装等价于:
- 把目录放到
~/.dsh/profiles/<profile>/plugins/dsh-balance-hud(客户端 bundle 是从 profile 提供的,所以必须真的在 profile 目录里)。 - 在 profile 的
dependencies加"dsh-balance-hud": "file:./plugins/dsh-balance-hud", 并在dsh.profile.bundles里加"dsh-balance-hud"。 - 把它链接进 profile 的
node_modules(Windows 用 junction,其它平台用符号链接)。 - 重启 DSH。
注意:profile 的
package.json不能带 UTF-8 BOM。带 BOM 时插件管理器会以Unexpected token '\ufeff'失败。tools/install.mjs会把清单重写成不带 BOM 的版本, 并保留一份package.json.bak-balance-hud备份。
改客户端半边(lib/client.js)只需刷新页面。改 Host 半边(lib/index.js,
例如赠金路由或价格抓取)需要重启 DSH,因为 profile bundles 不热加载。
开发
node tools/smoke.mjs # 离线冒烟套件,不需要装 DSH
node tools/verify-install.mjs --package # 打包自检,不需要装 DSH
node tools/verify-install.mjs # 校验真实安装
tools/smoke.mjs 会在假的 React 运行时、假 Host 响应、假 localStorage 和假 document
上求值真实的 lib/client.js,然后驱动组件走完整个 hook 周期。每项检查打印一行 ✓
(共 83 条),首个失败即非零退出;覆盖模块/槽位注册、卡片布局、悬停与折叠交互、
余额协议与全部路由失败模式、价格算术、显示精度、充值/过期两类外部变动判据、
持久化与迁移链,以及可见性驱动的补读。A1–A3 三个新功能各有守卫:两个槽位注册
(浮层 和 设置行)、设置默认值、脏配置的逐字段收敛、配置落盘往返、容器广播 + 部分合并 +
取消订阅、配置损坏回落、四档预算与剩余夹 0、两条预算取最严重、每日台账(累加 / 忽略 0 与负数 /
跨天归零 / 损坏回落),以及峰谷倒计时在峰时、闲时、跨午休与跨周末的正确性。价格同步也各有一条
守卫:解析器对真实页面的固定用例、以及对「UTF-8 被误按 Latin-1 解码」的乱码副本给出同一张表;
页面结构损坏或档位反常时整条放弃;resolvePrices 的来源可分辨;缓存落盘往返保留条件请求头;
以及默认零外联 —— 非法间隔收敛为关闭、24 小时 是默认档。
CI(.github/workflows/ci.yml)在 ubuntu / windows / macos 上用 Node 20 跑这两个离线脚本 ——
node tools/smoke.mjs 与 node tools/verify-install.mjs --package。两个脚本都完全离线:
不依赖 DSH 安装、不联网、不需要构建,所以能在干净容器里跑,也顺带证明行尾
(.gitattributes 锁 LF)、路径派生与 import.meta 用法都不依赖 Windows。
它不覆盖 Host 半边(lib/index.js 从未被加载,因此回环过滤、对外价格抓取、
If-None-Match/304 路径与模型列表路由都没有离线测试)、真实浏览器、真实 Cordis 注入和真实平台。
lib/client.js 是手写的 CJS 风格 bundle,格式就是官方的
window.__ModuleLoader__.load({ id, factory }),所以没有构建步骤。
| 文件 | 作用 |
|---|---|
package.json |
声明 dsh.bundle.patch(profile 条目树)与 dsh.client(platform: web,导出 ./client) |
cordis.patch.yml |
把插件作为一行插入 profile 条目树 |
lib/index.js |
Host 半边:只读回环路由(余额、赠金信号、可选的价格同步、模型列表) |
lib/client.js |
浏览器半边:shell.overlay HUD、settings.general.item 设置行、价格表解析与全部记账逻辑 |
tools/ |
安装脚本、安装校验、离线冒烟套件 |
.github/workflows/ci.yml |
离线冒烟 + 打包自检,跑 ubuntu / windows / macos |
docs/DESIGN.zh-CN.md |
贡献者设计说明 —— 记账模型的完整推导 |
隐私与安全
- 默认:零外部请求。 装上插件后不碰价格同步的控件,插件新增的网络流量就只有到
/api/balance-hud/…的回环 HTTP;它用内置价格表,不接触任何第三方。 - 唯一的例外是可选的价格同步。 只有你点了
同步价格,或主动选了自动同步间隔之后, 插件才会按你选的节奏去抓https://api-docs.deepseek.com/zh-cn/quick_start/pricing—— 官方的公开价格文档页。 这是它涉及的唯一外部主机,而且抓取由 Host 半边执行,不由浏览器发起(见 架构)。 - 永远不会发送的东西: 凭据、API key、账号 id、会话数据、cookie,以及任何能识别你的查询参数。
它只是对一个公开文档页发一个普通
GET;同步既不读取、也不上传你的余额。 - 本插件从不接触官方 API key。 涉及账号数据时,Host 半边只调
getBalance和getUnnotifiedBonuses,从不调resolveToken或getPlatformSession,凭据始终留在@deepseek-ai/dsh-deepseek-account-platform内部。 - 仓库里、
localStorage里、HUD 上都没有密钥、令牌或账号 id。同步价格缓存 (dsh-balance-hud:prices:v1)里只有价格、HTTP 校验器和时间戳,没有账号数据。 - 余额、赠金与模型列表三条路由都是仅回环、只读:对非回环调用者一律
403,只返回余额数字或 已注册的模型名。插件对平台的调用走的是 DSH 本来就用的账号服务。 - 赠金路由既只读又不回执,因此不可能吞掉 DSH 自己的赠金通知。
已知边界
- 预估只覆盖模型 token。 任何非 token 计费项(插件、检索等)都会让它偏低。
- 价格表是有日期的快照。 如果你一直不同步,官方调价后预估会继续用内置的 2026-09-29 表,
直到你同步、或改
PRICES再刷新。解析器读的是当前页面结构,文档改版可能让解析失败 —— 那时同步整体作废、继续用上一份好表:宁可用旧价,也不会用错价。 - 分摊是估算;凡是拿不到用量投影的会话在分母里权重为 0,会让占比失真。
- 赠金"部分过期"可能被算成消费。 判据是"降幅是否超过 token 上界":如果某笔赠金
只有一部分过期,且这笔降幅恰好落在上界以内,就会被当成消费。要彻底解决需要按钱包分项的
余额明细(哪个钱包、多少、何时过期),而
getBalance()返回的AccountWallet只有{ currency, balance },不含过期时间。所以这是"把误差压到不超过 token 估值", 不是消除。 - 拿不到 token 数据时判据会变紧。 上界退化为 0 附近,此时较大的真实消费有可能被 误判为外部减钱。实际运行中 token 用量每 5 秒读一次,这种情况罕见。
- 平台结算有延迟。 刚跑完任务时实际值可能还停在原处,而预估已经动了; 两者会在几十秒内收敛。
- 第一个基线略晚于会话开始,更早的花费由 token 预估覆盖。
- 账户级合计只是参照,不是某个会话的数字。
- 未登录是正常状态:卡片会说明,登录后下一次轮询自动恢复。
许可
MIT,见 LICENSE。
链接
同类插件
bowenliang123/dsh-context★ 3190
DSH 上下文洞察面板:Context 仪表盘 + /context命令 + Context 浏览器,查看 Context的分类组成、内容详情、演进趋势、压缩/注入事件、统计等一站式 Context 全生命周期管理。
Han-1413141/dsh-cost-meter★ 489
会话与当日 API 费用统计、预算图框(已用%)、官方余额、历史看板,支持峰谷计价与官方价格一键同步。
wssfk12138/dsh-damage-pulse★ 273
在 DSH Web 界面追踪 DeepSeek Token 用量、单次与会话费用及账户余额,并显示缓存感知的扣费动画。
zh667/TokenLedger★ 199
侧边栏用量面板:把 Token 归属到实际服务该请求的中转站,站点从已有的 provider 配置中读出,无需额外配置;含今日/本月/累计三窗口、按站点与模型下钻、一年活跃度热力图,以及 New API / Sub2API / DeepSeek 余额。
Ychris12138/dsh-usage-stats★ 183
多供应商用量看板:按供应商/模型统计 Token 与日期下钻,统一展示账户余额,并追踪 OpenCode Go / Z.ai 订阅额度。
PolinniZhong/dsh-personal-center★ 112
DeepSeek Harness 个人中心:跨会话用量统计、按模型成本估算、全局自定义指令、外观全局字号、数据驱动的桌面宠物(位图/矢量皮肤)与会话状态概览,纯本地离线运行。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。