dsh-token-monitor
简体中文 | English
🤖 AI 生成声明:本项目由 AI 辅助生成,仅供学习与技术交流使用,不构成任何形式的商业保证或支持承诺。
一个 DeepSeek Harness 插件:在侧边栏底部(设置图标旁)放一张 「今日用量」卡片,实时显示今日 token 总量(形如"今日用量:8888万");点击卡片即弹出完整统计窗口——今日 / 近 7 天 / 近 30 天总量、近 30 天按模型的堆叠用量图、按模型的使用排行(固定 30 天窗口)、以及会话数统计。不再占用设置页面,一键直达。

功能特性
- 🚀 一键直达 — 侧边栏「今日用量」卡片实时显示今日 token 总量(单行"今日用量:8888万",每 30 秒自刷新,折叠成窄栏时只显示数值);点击弹出统计窗口(支持 Esc / ✕ / 点遮罩关闭,背景滚动锁定)。
- 📊 近 30 天模型使用情况 — 30 天堆叠柱状图:每根柱子按模型分色堆叠(当天用量最高的模型在柱底,颜色按 30 天排名固定);图表区域铺满灰色点阵网格背景(每一天恰好两列点、垂直每 13px 一行,参考
temp/model-usage.png),有调用的柱子叠在点阵之上;横轴只显示每周一的基准日期;悬浮/点击某天弹出明细卡片(日期 / 总计 / 各模型色块行,样式参考temp/tooltip.png),无任何高亮/变灰/柱上标签效果。 - 🏆 模型使用排行 — 固定 30 天窗口:前 4 名 2×2 卡片(序号一行 / 模型名 + token 总数 / 提供商 + 占比右对齐,无增长与单位标签),悬停轻微放大。
- 💬 会话统计 — 今日 / 近 7 天 / 近 30 天开启的顶层对话数(不含子代理内部会话),副文字显示对应时段的模型请求次数。
- 🔄 自动刷新 — 页面每 30 秒轮询(带幂等重扫,数字自动修正),另有手动「刷新」与「回填历史」按钮。
- 💾 持久化 — 数据写入
$DSH_HOME/plugins/token-monitor/data.json,重启不丢(按天桶保留 181 天;每个桶内按模型细分)。 - 🕘 历史回填 — 会话日志是唯一数据源:启动 / 点击「回填历史」/ 30 秒轮询都会把窗口内全部会话用量幂等重扫进新桶(原子替换),把插件安装之前的用量也统计进来;重复运行不会重复计数,旧桶脏数据自动自愈,30 天堆叠图与模型排行立即可用。
- 🎨 DSH 原生风格 — 亮色主题、1px 细边框卡片、8–10px 圆角、无阴影;颜色走
--dsw-alias-*主题变量,跟随 DSH 深色主题。
安装
从本仓库安装:
dsh plugin --profile web add github:zhangzheng25/dsh-token-monitor
或从本地目录安装:
dsh plugin --profile web add E:\path\to\dsh-token-monitor
dsh plugin 会在 profile 目录中转发给 pnpm 安装,并自动调和 dsh.profile.bundles;包内 dsh.bundle.patch(cordis.patch.yml)把插件行插入宿主组合,dsh.client.platform: "web" 让 web 外壳加载 client/bundle.js。
安装后重启 DSH,侧边栏底部(设置图标旁)会出现「今日用量」卡片,点击即弹出统计窗口。
架构
┌────────────────────────── Host(Node.js)──────────────────────────┐
│ src/index.js │
│ • backfill() ← 会话日志为唯一数据源(幂等全量重建: │
│ sessionQuery 为 live-preferred,内存活跃会话 + 落盘日志都算, │
│ 每次把窗口内全部 assistant/message 的 usage 折叠进新桶并原子 │
│ 替换,重复运行不重复计数;启动 / 点「回填历史」/ 30 秒轮询都跑) │
│ (输入 / 输出 / 缓存命中 / 缓存未命中 / 推理,按天按模型分桶, │
│ 模型归属取 message.source,覆盖 181 天窗口) │
│ • buildSessionStats() ← 顶层对话统计(delegationDepth === 0)│
│ (20 秒缓存) │
│ • persist() ← 防抖写入(schema v3:按天按模型分桶, │
│ 保留 181 天) │
│ $DSH_HOME/plugins/token-monitor/data.json │
│ • webServer.register('/token-monitor/today') ← 轻量今日读数(不触发│
│ 重建,供侧边栏卡片轮询) │
│ • webServer.register('/token-monitor/snapshot') ← 供 Client 读取 │
│ (静态 bundle 模式,含 modelRank 三档聚合 + modelDaily30) │
└─────────────────────────────────────────────────────────────────────┘
│ fetch('/token-monitor/snapshot')
▼
┌────────────────────────── Client(浏览器)─────────────────────────┐
│ client/bundle.js — 手工构建的 web bundle,符合 client-modules 协议 │
│ (window.__ModuleLoader__.load) │
│ • slots.inject('sidebar.footer.action') → 侧边栏「今日用量」卡片 │
│ (点击弹出 fixed 模态,内容 = 完整统计面板;无 settings.section)│
│ • 指标卡 + 会话卡 + 30 天模型堆叠图 + 模型使用排行 │
│ • 卡片每 30 秒轮询 /token-monitor/today;弹窗打开时拉取快照并 │
│ 每 30 秒刷新,另有刷新 / 回填历史按钮 │
└─────────────────────────────────────────────────────────────────────┘
数据来源
- 唯一数据源 = 会话日志:会话日志中
assistant/message事件的usage字段(模型归属取自同事件message.source的provider/model),经ctx.sessionQuery读取。sessionQuery是 live-preferred 的——内存中的活跃会话和落盘日志都能读到,因此进行中的调用也会被统计,无需llm/stream实时钩子(旧版本同时用瀑布流实时捕获 + 日志回填,两者重叠导致同一调用被重复计数、数字虚高,v3 已移除实时路径并改为幂等全量重建)。 - 会话数:
sessionQuery.listSessions()的会话头部(cwd/createdAt/delegationDepth);只有顶层会话(delegationDepth === 0)计入对话。
开发
node --check src/index.js # Host 语法检查
node --check client/bundle.js # Client bundle 语法检查
Client bundle 为手工编写以匹配 client-modules bundle 协议,无需构建步骤。
No comments yet. Be the first to write one.