htq20080119
dsh-token-stats
Token usage statistics plugin for DeepSeek Harness — per-window consumption metrics with an enable/disable switch, right in Settings.----------DeepSeek Harness 的 Token 用量统计插件:按时间窗统计消耗指标,设置页内随时启停。
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 15, 2026
- Updated
- Aug 15, 2026
Introduction
A Settings-page plugin that shows token consumption across all sessions, bucketed into time windows — with an enable/disable switch that persists to settings.yaml and hot-applies. No restart required.
🛡️ Community plugin — this is an independent, community-maintained plugin for the DeepSeek Harness. It is not an official DeepSeek project and is not affiliated with or endorsed by DeepSeek / the DeepSeek Harness team.
✨ Features
| 🪟 8 time windows | today · 3d · 7d · 15d · 30d · half-year (180d) · 1 year (365d) · all-time |
| 📈 9 metrics per window | total, input, output, cache-read, cache-write, requests, cache-hit requests, cache-hit rate |
| 🗂️ Summary cards | all-time totals: input / output / cache read / cache write / hit rate / requests |
| 🎚️ Enable / disable switch | right in the page — persisted to settings.yaml, hot-applied in seconds |
| 🔄 Auto refresh | polls every 30s, plus a manual refresh button |
| 📚 Official accounting | same (turn, step) dedup as the built-in tokenUsage session projection |
📸 Preview
Screenshot placeholder — replace with a capture of Settings → "Token 用量".
⚠️ Sample data below is illustrative only — not real usage.
The page shows summary cards (all-time totals) plus a per-window table:
| Time window | Total | Input | Output | Cache read | Cache write | Requests | Hit requests | Hit rate |
|---|---|---|---|---|---|---|---|---|
| Today | 1.24M | 1.18M | 56.2K | 1.12M | 0 | 87 | 85 | 96% |
| 3 days | 3.87M | 3.71M | 161K | 3.55M | 0 | 254 | 248 | 96% |
| 7 days | 8.93M | 8.62M | 312K | 8.31M | 0 | 589 | 577 | 97% |
| 15 days | 19.4M | 18.8M | 641K | 18.3M | 0 | 1,243 | 1,221 | 97% |
| 30 days | 38.7M | 37.5M | 1.22M | 36.7M | 0 | 2,467 | 2,431 | 97% |
| Half year | 214M | 208M | 5.9M | 205M | 0 | 13,988 | 13,812 | 98% |
| 1 year | 412M | 401M | 10.8M | 396M | 0 | 26,531 | 26,214 | 98% |
📦 Installation
The plugin is an external DSH package loaded through the web profile.
1. Make the package resolvable
Add it to the profile's package.json with pnpm:
# local development (symlinks the source — edits apply immediately)
pnpm --dir "C:\Users\<you>\.dsh\profiles\web" add "link:<path-to-this-repo>"
# or straight from GitHub (installs a packed copy)
pnpm --dir "C:\Users\<you>\.dsh\profiles\web" add "github:<owner>/dsh-token-stats"
The web profile lives under
%USERPROFILE%\.dsh\profiles\webby default.
2. Mount the entry
Append one entry to the profile's patch layer (cordis.patch.yml):
- insert:
- id: token-stats
name: dsh-token-stats
config: {}
The patch layer is hot-watched — the plugin mounts within seconds, no restart.
🚀 Usage
- Open Settings → "Token 用量" (refresh the page once so the client bundle is picked up)
- Read the summary cards and the per-window table (auto-refreshes every 30s)
- Use 停用 / 启用 in the page header to toggle aggregation:
| Action | Effect | Persisted to |
|---|---|---|
| 停用 (disable) | stops aggregating; page shows the disabled state | settings.yaml → token-stats: { enabled: false } |
| 启用 (enable) | resumes aggregation and the stats table | settings.yaml → token-stats: { enabled: true } |
The switch applies immediately — no restart needed.
🛠️ Development
# smoke test: host fold logic + client bundle registration
node smoke-test.mjs
| File | Role |
|---|---|
lib/index.js | Host half — zero third-party imports (see Architecture) |
lib/client.js | Client bundle — classic window.__ModuleLoader__.load({ id, factory }) script; the id must equal the loader entry name |
Applying changes: host code sits behind Node's ESM cache (keyed by resolved URL) — restart the web app to pick up host changes; client bundle changes only need a page refresh.
🧱 Architecture
- Data source —
assistant/messageevents carrydata.usage{ inputTokens, outputTokens, cacheReadTokens? }(the opencode-go gateway reports nocacheWriteTokens);uncachedInput = inputTokens - cacheReadTokens. - Host endpoints —
GET /token-stats→{ enabled, generatedAt, windows[] };POST /token-stats/config {"enabled": bool}flips the switch through thectx.settingsservice into the hot-watchedsettings.yaml. - Zero-dependency host — profile plugins resolve bare specifiers with no fallback, so
lib/index.jsimports nothing (thesettingsnamespace schema is a hand-rolled, schemastery-compatible object). package.jsonmust export./package.json—dsh-client-modulesresolves the client bundle viarequire.resolve("<pkg>/package.json"); without that export the package is negative-cached and the client bundle 404s until a web-app restart.
🤖 Model Experience
None — the plugin never assembles or sends a provider request. It only reads persisted session logs and serves a Settings page, so it adds no prompt, message, schema, tool, or model call.
KV Cache effect
None — no provider request is made; cache-read / cache-write figures are read-only metrics reported by the gateway in session logs.
⚠️ Known Limitations
web/deepseek-search-llm-requestevents carry nousage— search-tool tokens are not counted (matches the official projection).- Cache-write shows 0 when the gateway does not report it.
📄 License
MIT © 2026 本源不爱onani