dsh-plugin-balance-panel
September 2, 2026 · View on GitHub
DeepSeek Harness cordis 插件:通用型多 provider 余额/用量面板 —— 查询各主流 API 账户余额与 Coding Plan 用量,并统计每日金额花费与 Token 消耗,右下角挂一枚液态玻璃气泡(点击展开明细面板)。
/balance [KEY_ENV]— 汇总所有已配置余额 provider 的余额(指定 KEY_ENV 时按 DeepSeek 格式查询单个凭证)/balance alert [<金额>|off]— 查看 / 设置 / 关闭每日花费告警阈值(越过阈值时面板顶部红色横幅 + console 告警 + 桌面系统通知,同一 provider 同日同阈值只告警一次)/plan— 汇总所有已配置的 Coding Plan 用量(OpenCode Go / Z.ai / Kimi:5h 滚动 / 每周 / 每月窗口 + 重置时间)/stats [days=7]— 读取历史统计:每日 Token 消耗 + 各 provider 金额花费(本地数据,无需联网;1-60 天)/cost [<会话ID前缀>]— 会话级成本统计:无参看近 7 天按会话汇总的金额(未定价模型列出 token 数),带前缀看单会话明细(调用次数、输入/缓存命中/缓存写入/输出/推理 token 分量、按模型金额与合计)/cost price— 查看/管理模型单价表:/cost price sync一键同步 DeepSeek 官方价目(各模型峰时单价 USD + 官方峰谷规则;手动设置的单价不被覆盖,冲突时列出);/cost price <模型前缀> <缓存命中> <未命中> <输出> [币种=CNY]手动设单价(每 1M tokens),/cost price <前缀> off删除覆盖;改价后整个历史按新价重算/cost export [csv|json] [天数=60]— 用量/成本导出:CSV=逐调用明细(五路 token 分量、峰谷系数、现算金额,电子表格友好),JSON=全量(价表分层 + 峰谷 + 会话聚合 + 明细);写入$DSH_HOME/exports/并返回路径- 右下角气泡 + 点击展开的明细面板(按 provider 分区)
- 每日消费估算图(近 14 天,金额;按余额差分估算,非平台账单)与每日 Token 用量图(近 14 天,所有对话合计的 tokens),悬浮柱子即时显示当日数值
- DSH 设置页「余额面板」分区:开关消费/Token 图表与悬浮数值,改动即时生效并持久化
支持的 provider
只需在 $DSH_HOME/.credentials.yaml 或进程环境变量里配置对应凭证,插件自动探测并显示已配置的 provider(未配置的自动隐藏,无需任何插件配置):
| provider | 类型 | 凭证环境变量 | 余额/用量端点(默认) | baseUrl 覆盖 |
|---|---|---|---|---|
| DeepSeek API | 余额 | DEEPSEEK_API_KEY | GET /user/balance | DEEPSEEK_API_BASE |
| Moonshot (Kimi) | 余额 | MOONSHOT_API_KEY | GET /v1/users/me/balance | MOONSHOT_API_BASE |
| 智谱 GLM | 余额 | ZHIPU_API_KEY | GET /api/paas/v4/balance | ZHIPU_API_BASE |
| OpenRouter | 余额 | OPENROUTER_API_KEY | GET /api/v1/credits | OPENROUTER_API_BASE |
| OpenCode Go | Coding Plan 用量 | OPENCODE_GO_API_KEY | GET /v1/usage | OPENCODE_GO_API_BASE |
| Z.ai / 智谱 GLM Coding Plan | Coding Plan 用量 | ZAI_CODING_CN_API_KEY | GET /api/monitor/usage/quota/limit(5h 滚动 / 每周 / 每月) | ZAI_CODING_API_BASE |
| Kimi Coding Plan(Kimi Code 平台) | Coding Plan 用量 | KIMI_CODING_API_KEY | GET /usages(5h 滚动 + 每周;密钥须为 sk-kimi- 前缀) | KIMI_CODING_API_BASE |
Z.ai / Kimi 的 Coding Plan 用量密钥与按量付费密钥不通用(Kimi 须 Kimi Code 控制台创建的
sk-kimi-密钥); 月度会员额度(Kimi 订阅页额度)无公开 API,Kimi 只展示 API 可查的 5h 滚动 + 每周窗口。
OpenAI / Anthropic / Gemini 等按量后付费服务没有公开的余额查询端点,无法内置; 如需展示,可先用任一余额 provider 的网关/中转(如 OpenRouter、Kimi、智谱)。
GUI
- 气泡(折叠态):液态玻璃质感(毛玻璃 + 高光),内装水;水位 = Coding Plan 剩余用量(100 − 月用量;无月窗口的 provider 用 5h 滚动,如 Kimi),未配置 plan 时显示第一个余额 provider 的余额;水色按剩余量渐变(充足蓝 → 告警黄 → 耗尽红);DSH 推理/流式输出期间水面波动;可拖动(位置记忆),点击打开面板(Enter/Space 键盘亦可)。金额一律以符号展示(¥38.17),币种代码(CNY)只出现在接口/存储层。
- 面板(展开态):按 provider 分区排列 —— 每个余额 provider 一张卡片(账户可用状态 + 各币种总额/赠送/充值 + 该 provider 的每日消费估算图),每个 Coding Plan provider 一组用量窗口(进度条 + 重置倒计时);面板底部是所有对话合计的每日 Token 用量图;头部可拖动,位置独立记忆(默认右下角锚定,不超出屏幕;记忆位置超出视口时自动钳回);Esc 或 × 收起。面板金额以「符号 + 缩写」展示(¥ CNY / ¥6.9 CNY),气泡保持纯符号(¥36.70)。
- 柱状图悬浮数值:鼠标悬停在柱子上即时显示该日数值(消费图「5-28 · 估算 ¥3.33」、Token 图「5-28 · 12345 tokens」),fixed 层跟随指针并钳制在视口内(portal 到 body,不受面板 overflow 裁剪);设置页关闭后回退为原生 title 提示。
- DSH 设置页「余额面板」分区:三个布尔开关 —— 显示「每日消费估算」图 / 显示「每日 Token 用量」图 / 悬浮柱状图显示数值;改动即时生效(面板与设置页共享同一 settings scope 实例),持久化到 settings 域(
settings.json)。host 侧经ctx.settings注册balance-panelnamespace(schemastery schema),settings 服务为可选依赖:缺失时插件其余功能不受影响,面板按默认值(全部开启)渲染。 - 每 30s 自动刷新(失败时 10s 快速重试,恢复后回到 30s;已有数据时后台刷新不闪烁「加载中」),可手动刷新;页面隐藏时暂停轮询,恢复可见立即刷新。
- 陈旧回退:某 provider 上游查询失败但上次有成功数据时,面板继续显示上次数据并提示「数据可能已过期」,而不是整块报错;从未成功过才显示错误。
- 每日消费估算:每次成功拉到余额时记录采样点(1 小时节流、保留 60 天,含总额/赠送/充值三字段),按相邻采样差分解算:
消费估算 = max(0, 注入 − Δ总额),其中注入 = max(0,Δ充值) + max(0,Δ赠送)—— 消费无论从充值金还是赠送金扣减都能正确计入,充值/发放本身不计为花费;页面未打开的断档日按覆盖天数均摊,不会把整段花费堆到恢复日造成虚假尖峰。每个余额 provider 各自统计。(观测极限:充值/发放与消费同日发生时低估;赠送金回收会虚增——平台不提供逐笔账单时的固有近似。) - 每日 Token 用量统计:监听 DSH 会话事件里 provider 报告的真实 token 用量(
assistant/message的usage),按自然日聚合,所有对话合计显示在一起(不区分 provider)。 - 每日花费告警:
/balance alert <金额>设置每日花费阈值(0/off 关闭、无参查看)。面板每次拉到新鲜余额后检查:某 provider 今日花费越过阈值即 console 告警 + 面板顶部红色横幅(列出所有越界的 provider 与金额)+ 桌面系统通知(写共享配置$DSH_HOME/desktop-shell.json的notifyRequest,由 dsh-desktop-shell Electron 外壳弹出并清空;协议与 dsh-plugin-desktop-control 一致但互不依赖代码,未装外壳时写入无害),同一 provider 同日同阈值只告警一次(改阈值当天重新武装)。口径与花费图表一致(余额差分估算、断档按日均摊),阈值按各 provider 币种比较。 - 会话级成本统计(
/cost):每次模型调用的 usage 分量(未命中输入/缓存命中/缓存写入/输出/推理)连同模型名(data.message.source.model)按 session 落库(保留 60 天,与统计存储同文件);金额不落库,查询时按当前单价表现算 —— 改单价后历史整体重算。单价按模型前缀最长匹配(大小写不敏感),单位为每 1M tokens,与社区插件 dsh-cost-tracker 的口径对齐(未命中=inputTokens、命中=cacheReadTokens,推理 token 已含在输出里不另计价)。内置 DeepSeek 估算价(命中 0.5 / 未命中 2 / 输出 4 CNY,建议/cost price sync校准为官方价),其余模型默认未定价(照常记 token,提示补价)。峰谷计费(官方 2026-09 规则):工作日(周一至五)峰时窗口 09:00-12:00、14:00-18:00(UTC+8)内按标价,其余时段含整个周末 ×0.5(谷时窗口与系数随/cost price sync从官方页自动更新;旧版「夜间谷窗」口径已落盘的配置保持兼容,sync 后升级);窗口换算不随宿主机时区变化。 - 官方价目同步与导出:
/cost price sync拉取 api-docs.deepseek.com 静态价目页,解析各模型峰时单价(USD)与峰谷规则写入价目表——不覆盖手动设置的单价(synced标记区分来源,冲突时跳过并列出,手动设价即接管);/cost export [csv|json] [天数]把逐调用明细(CSV)或全量数据(JSON,含价表分层/峰谷/会话聚合)写到$DSH_HOME/exports/。 - 统计数据持久化在
$DSH_HOME/plugins/dsh-plugin-balance-panel/spend-history.json(v2:按 provider 分桶 + tokens + calls + cost 字段,旧版自动迁移;可用DSH_BALANCE_SPEND_FILE覆盖),纯本地、不上传、无需平台 token。
数据来自插件注册的 GET /plugins/balance/state(exact 路由,优先于 client-modules 的 /plugins 前缀):每个 provider 独立容错(一个查询失败不影响另一个分区),结果带 5s TTL 内存缓存 + 并发 single-flight(多视图轮询不会重复打上游),响应带 cache-control: no-store,非 GET 请求返回 405。
凭证
- 通过 DSH 的 credentials 服务解析(
ctx.credentials.resolve),支持$DSH_HOME/.credentials.yaml与进程环境变量;密钥绝不出现在对话、日志或任何 HTTP 响应中。 - 自动探测:插件用
ctx.credentials.describe(只返回是否已配置,不暴露值)判断每个 provider 是否启用 —— 配置了凭证的 provider 才会被查询与展示。 - 各 provider 的端点 baseUrl 可用上表的环境变量覆盖(如
MOONSHOT_API_BASE),无需改代码。
输出示例
DeepSeek API:账户可用:是
¥:总额 110.00(赠送 10.00 + 充值 100.00)
Moonshot (Kimi):账户可用:是
¥:总额 55.50(赠送 5.00 + 充值 50.50)
OpenCode Go:每月 97%(5h 16% / 每周 12%)
Z.ai Coding Plan(lite):每月 100%(5h 0% / 每周 —%)
OpenCode Go 套餐用量:
5h 滚动:16%,2026-08-14 11:54 重置
每周:12%,2026-08-17 08:00 重置
每月:97%,2026-08-21 19:08 重置
Z.ai Coding Plan(lite) 套餐用量:
5h 滚动:0%,重置时间未知
每月:100%(exhausted),2026-08-24 15:44 重置
== 会话成本(近 7 天)==
a1b2c3d4 ¥4.50 · 12 次 · 最近 9-1 11:00
e5f6a7b8 未定价 · 6 次 · 最近 9-1 10:30
合计 ¥4.50
未定价模型(已计 token 未折算金额):glm-4.7 3,000,000 tokens
提示:/cost price sync 同步官方价目;/cost price <模型前缀> <缓存命中> <未命中> <输出> 手动设单价(每 1M tokens)
== 会话 sess-alpha 成本 ==
时间 9-1 10:12 ~ 9-1 11:00 · 15 次调用
输入 1,000,000 · 缓存命中 1,000,000 · 缓存写入 0 · 输出 500,000 · 推理 0 tokens
deepseek-chat:9 次,¥4.50
合计 ¥4.50
实现机制
- host half:
/balance、/plan命令(dsh-commands 契约,{ kind, text }结果)+ 数据路由(dsh-host-webserver 的 exact 路由)。所有注册(命令、路由、session/event监听)包在ctx.effect生命周期里 —— 插件停止 / HMR 重载时自动注销,重载不会因 exact 路由重名而失败。 - 适配器表:每个 provider 一个适配器(id/label/kind/keyEnv/path/defaultBase/parse),baseUrl 支持
<ID>_API_BASE覆盖;响应解析统一为balances[]/windows[]两种结构,解析失败只影响该 provider。 - client half:注册进
shell.overlay(list/root,order: 110)与settings.section(DSH 设置页「余额面板」分区,id: balance-panel);服务声明inject: ['slots', 'locale', 'settingsScope'];样式用 DSH 设计 token(--dsw-alias-*)自动适配深浅主题,<style>注入带data-plugin去重守卫;插件自身 DOM 的 mutation 被过滤,不干扰推理中检测。面板偏好通过ctx.settingsScope.bind({ namespace: 'balance-panel' })绑定 host 注册的 namespace。 - 取消语义:命令调用方的
AbortSignal与 10s 上游超时合并(AbortSignal.any),取消时返回「操作已取消」。
与同品类插件的差异(调研结论)
对 DSH / cordis / 相邻生态(Koishi、OpenCode、Pi)的同类余额插件调研后,本插件的定位与取舍:
| 能力 | 本插件 | 说明 |
|---|---|---|
| 多 provider 余额(DeepSeek/Kimi/智谱/OpenRouter) | ✅ | 凭证自动探测,未配置即隐藏 |
| Coding Plan(OpenCode Go / Z.ai / Kimi)用量窗口 | ✅ 独有 | 5h 滚动 / 每周 / 每月 + 重置倒计时;Z.ai 含套餐档位(lite/pro…) |
| 气泡 + 可拖拽面板形态 | ✅ 独有 | 其他插件走统计条/侧边栏/文字命令 |
| provider 独立容错 + 陈旧回退 | ✅ | 失败时回退上次成功数据并标记 stale,不把面板打成错误态 |
| 每日消费估算图(近 14 天) | ✅ 本地估算 | 差分口径 max(0, 注入−Δ总额):消费扣充值金/赠送金均正确计入,断档日均摊 |
| 每日 Token 用量图(近 14 天,所有对话合计) | ✅ 真实数据 | 来自 DSH 会话事件中 provider 报告的 usage |
会话级成本(/cost,按模型单价 + 峰谷) | ✅ | 按调用分量落库、改价重算历史;对标 dsh-cost-tracker / dsh-session-cost |
| 官方价目一键同步 + 数据导出 | ✅ | /cost price sync(不覆盖手动价、峰谷窗口随官方更新)+ /cost export CSV/JSON;对标 dsh-cost-meter / dsh-ui-usage-billing |
| i18n(zh/en 随 DSH 语言切换) | ✅ | 见「国际化」一节 |
| 设置页分区(图表开关 + 悬浮数值) | ✅ 独有 | settings.section + settingsScope(设置页与面板共享 scope,实时生效) |
| 页面隐藏时暂停轮询 | ✅ | 恢复可见立即刷新 |
调研对象(同品类):npm dsh-balance(统计条余额 + 会话估算)、dsh-balance-meter、koishi-plugin-deepseek-usage(花费图表)、opencode-provider-balance(TUI 侧边栏)。注意 npm 上的 dsh-balance 已被同名插件占用,本插件按 DSH 生态惯例命名为 dsh-plugin-balance-panel(dsh-plugin-* 前缀)。
国际化(i18n)
- GUI 全量中英双语:气泡与面板的所有文案走 DSH 的 locale namespace(
balance,zh 为键集源、en 逐键对照,与上游dsh-client-locale约定一致);槽位注册声明locale: 'balance',框架把绑定该 namespace 的t()注入组件 props,随 DSH「设置 → 语言」即时切换,无需重启。 - 用量窗口标签按
key(rolling/weekly/monthly)翻译,不直接展示 host 下发的 label。 - host 命令输出保持中文:上游 DSH 没有 host 侧运行时 i18n 服务(官方插件同样硬编码),按仓库 Chinese-first 约定以中文为命令输出语言;命令
description为英文(命令注册表发现 UI 的惯例)。
兼容性
- 平台:DSH web(
dsh web),dsh.client.platform = "web"。 - peerDependencies:
@deepseek-ai/cordis^4.0.1@deepseek-ai/dsh-commands^0.1.0-rc.6(/balance、/plan注册契约)@deepseek-ai/dsh-credentials^0.1.0-rc.6(凭证解析)@deepseek-ai/dsh-host-webserver^0.1.0-rc.6(数据路由)@deepseek-ai/dsh-client-locale^0.1.0-rc.6(locale namespace /t()注入)@deepseek-ai/dsh-client-ui-slots^0.1.0-rc.6(槽位契约)@deepseek-ai/dsh-client-ui-settings^0.1.0-rc.6(settingsScope 服务)@deepseek-ai/dsh-settings^0.1.0-rc.6(host 侧 settings 域;可选服务)- dependencies:
@deepseek-ai/schemastery^3.18.1(面板偏好 schema)
- client 声明:
inject: ['slots', 'locale', 'settingsScope'](服务级依赖),包级dsh.client.inject指向@deepseek-ai/dsh-client-locale与@deepseek-ai/dsh-client-ui-slots(模块表静态词)。 - 对上游的依赖仅限上述公开契约与各家官方余额/用量接口(见「支持的 provider」表);接口端点或格式变化时,该 provider 独立报错并可用 baseUrl 环境变量覆盖。
安装
方式一:DSH CLI 安装(推荐)
dsh plugin add dsh-plugin-balance-panel
(使用特定 profile 时加 --profile <name>;该命令依赖 pnpm,环境里没有时改用方式二。)
方式二:从 npm 安装
npm install -g dsh-plugin-balance-panel # 或装进 profile 的 node_modules
方式三:手动拷贝
构建后把整个插件目录复制到 profile node_modules:
cp -r dsh-plugin-balance-panel ~/.dsh/profiles/node_modules/
然后在 cordis.patch.yml 追加:
- insert:
- id: balance
name: dsh-plugin-balance-panel
重启 DSH 后输 /balance、/plan 验证;右下角气泡与面板共用同一数据路由。
开发与构建
client half 必须打包成 window.__ModuleLoader__.load({ id, factory }) 形式才能被
web 前端加载(dsh-client-modules 的 Node half 会扫描 loader 树里 enabled 插件,
resolve exports["./client"] 并 serve 进 /plugins boot graph)。
npm install # devDependencies: esbuild(+ host 测试所需的 dsh-credentials/cordis)
npm run bundle # scripts/bundle.mjs:esbuild 打包 → lib/client.js
npm test # node --test:host 命令/路由契约测试 + client bundle 契约测试
npm run check # node --check index.js + lib/client.js 语法校验
npm run preflight # 发布/部署前预检(files 完整性 / bundle 契约 / 陈旧产物守卫 / i18n 键集)
npm run smoke # 冒烟:mock ctx 实测已安装到 ~/.dsh/profiles 的实例(真实网络,需凭证文件)
host 测试不依赖真实网络:用 mock cordis ctx + mock
fetch实测命令、路由缓存、 single-flight、provider 独立容错与陈旧回退;client 测试在 vm 沙箱里验证__ModuleLoader__契约。
本地验证(改完即见)
把构建产物原子化同步到运行中的 DSH profile 并刷新页面(npm run sync:
先写临时文件再按「元数据先、bundle 后」顺序 rename,避免热载不一致的半成品;
可用 DSH_PROFILE_NODE_MODULES 覆盖 profile 路径):
npm run sync
刷新浏览器后 boot manifest 的 rev 变化即说明新 bundle 已被 serve(同步时可传 web 地址作为参数,脚本会打印新旧 boot rev)。
发布
当前状态:测试期私密发布。
package.json标记了"private": true, 不会(也不应)发布到公共 npm。测试期请用本地路径或 git 依赖安装:
dsh plugin --profile web add file:<本仓库路径> # 本地路径安装
# 或作为 git 依赖(私有仓库需 npm 凭证):
npm install git+https://<私有仓库地址>.git
插件转入稳定后:移除 "private": true,再执行 npm publish
(prepublishOnly 自动执行 preflight + 全量测试,未通过会中止发布)。
发布内容由 files 字段控制:index.js、lib/client.js、README.md、LICENSE
(源码与构建脚本、测试不随包发布)。
文件
index.js host half(命令 + 数据路由 + 凭证解析 + 缓存/陈旧回退/并发控制)
src/client.jsx client 源码(气泡 + 面板 + zh/en 字典)
lib/client.js client bundle(构建产物,勿手改)
scripts/bundle.mjs 本地构建脚本(esbuild)
scripts/preflight.mjs 发布/部署预检(含陈旧 bundle 守卫与 i18n 键集一致性)
scripts/sync-profile.mjs 原子化同步到 DSH profile
test/host.test.mjs host 契约测试(mock ctx + mock fetch)
test/client.contract.test.mjs client bundle 契约测试(vm 沙箱)
LICENSE MIT