DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

GIN0076 /

GIN0076/dsh-token-usage

Verified

๐Ÿ“Š Token usage dashboard for DeepSeek Harness Settings โ€” daily/weekly/monthly per-model token stats with line & bar charts. Local-first, zero deps, pure SVG. DSH ่ฎพ็ฝฎ้ขๆฟ่ฏๅ…ƒ็”จ้‡็ปŸ่ฎกๆ’ไปถ

โ˜… 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: master@13eda220

๐Ÿ“Š Token Usage for DSH

Bolt a fuel gauge onto your DeepSeek Harness Settings panel โ€” see exactly how many tokens every model burns, every day / week / month.

License: MIT DSH Plugin Version Zero Deps Local Only

English ยท ็ฎ€ไฝ“ไธญๆ–‡


โœจ Why you need this

DSH works hard for you โ€” but do you know what it costs you? The account page shows a balance, and raw logs are a pile of JSONL...

Now just open Settings โ†’ ๐Ÿ“Š Token Usage and the answer draws itself:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ๐Ÿ“Š Token Usage  ( Day | Week | Month )  [Last 30d โ–พ]  [Export] [Prices] [Settings] [โ†ป Rebuild] โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚
โ”‚ โ”‚ Total๐Ÿงฎโ”‚ โ”‚ ยฅ Cost โ”‚ โ”‚Input โฌ‡๏ธโ”‚ โ”‚Outputโฌ†๏ธโ”‚ โ”‚Cache rdโ”‚ โ”‚Cache % โ”‚          โ”‚
โ”‚ โ”‚ 1.14B  โ”‚ โ”‚ ยฅ3.42  โ”‚ โ”‚ 9.46M  โ”‚ โ”‚ 1.46M  โ”‚ โ”‚ 1.13B  โ”‚ โ”‚ 99.2%  โ”‚          โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                     โ”‚
โ”‚ โ”‚ Today  โ”‚ โ”‚ Month  โ”‚ โ”‚ Budget โ”‚ โ”‚ Calls  โ”‚ โ”‚Buckets โ”‚  โ† turns red when   โ”‚
โ”‚ โ”‚ 22.6M  โ”‚ โ”‚ 1.14B  โ”‚ โ”‚ยฅ1.5/ยฅ10โ”‚ โ”‚  3239  โ”‚ โ”‚    3   โ”‚    over budget      โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                     โ”‚
โ”‚                                                                            โ”‚
โ”‚ ๐Ÿ“ˆ Token Usage ยท Day ยท 3 buckets    2026-09-29 โ†’ 2026-10-01 (3d) ยท hover    โ”‚
โ”‚     80M โ”ค            โ•ญโ”€โ•ฎ                                                   โ”‚
โ”‚     40M โ”ค   โ•ญโ”€โ”€โ•ฎ  โ•ญโ”€โ”€โ•ฏ โ•ฐโ”€โ”€โ•ฎ       โ”€โ”€โ”€ total                                 โ”‚
โ”‚         โ”ผโ”€โ”€โ”€โ”ดโ”€โ”€โ”ดโ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€      โ”€โ”€โ”€ alpha-chat                         โ”‚
โ”‚          06-02    06-06    06-10     โ”€โ”€โ”€ beta-reason                        โ”‚
โ”‚                                                                            โ”‚
โ”‚ ๐Ÿ† Ranking ยท share          ( By model | By provider )  [By cost โ–พ]        โ”‚
โ”‚     alpha-chat       โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘  62.4% ยท ยฅ2.13                   โ”‚
โ”‚     beta-reason      โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘  31.8% ยท ยฅ1.09                   โ”‚
โ”‚     gamma-mini       โ–                      5.8% ยท ยฅ0.20                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ–ผ๏ธ Schematic of the UI. Cost / Budget / Today / Month cards only appear once you configure a price table (and optionally a budget). The real thing follows DSH's theme tokens and looks great in both light and dark mode.

๐ŸŽฏ Features

Area What you get
๐Ÿ“… Granularity Flip between Day / Week / Month โ€” Monday-start weeks, calendar months; only day buckets are stored, so switching is instant and free. Note: the summary cards and the ranking are totals for the whole range (they do not change with granularity) โ€” what changes is the line chart grouping and the Buckets card
๐Ÿ—“๏ธ Custom range Presets (last 7 / 30 days, 12 weeks, 12 months, all time) + pick your own start & end dates โ€” chart any window you like
๐Ÿ“ˆ Line chart Bold total line + thin per-model lines, crosshair hover breaks down every day, click legend chips to toggle models
๐Ÿ† Bar chart Horizontal model ranking with share % and cost โ€” spot your biggest token sink at a glance ๐Ÿ’ธ
๐Ÿ’ฐ Cost estimate Bring your own price table (~/.dsh/token-usage-prices.json, editable in the panel) priced per million tokens; no prices are baked in, so cost stays hidden until you configure it
๐Ÿ’ธ Budget & today/month Cards for today / this month (fixed windows); with a budget and a price table you also get a budget card (spent / limit) that turns red when over
๐Ÿท๏ธ Multiple dimensions Ranking and line chart toggle by model / by provider; ranking can also sort by cost once priced
โš™๏ธ Configurable Edit ~/.dsh/token-usage-config.json right from the panel's Settings: refresh interval / budget / retention
๐Ÿ“Š Numbers Cards: total / cost / input / output / cache read / cache write / reasoning / cache hit rate / calls / models
๐Ÿ“ค Export Current range as CSV (bucket ร— model rows + model subtotals + grand total) or JSON, with copy & download
๐Ÿ”„ Auto refresh Every 60s while the tab is visible (silent, no spinner), instant refresh when you come back, zero requests while hidden
๐Ÿ” Rebuild One-click full re-scan โ€” idempotent, watermarks guard against double-counting and gaps; if the store holds history whose session logs are gone, a confirmation is required first (that part cannot be rebuilt)
๐Ÿ›ก Accounting Dirty counters fail closed, compaction summaries are attributed by their own provider/model, fork inheritance never double-counts

๐Ÿ’ฐ How cost is computed (optional)

No prices are baked in โ€” someone else's price list is not your bill. Fill in a table from the panel's Prices button:

{
  "currency": "$",
  "models": {
    "deepseek-account/deepseek-flash": { "input": 1, "output": 2, "cacheRead": 0.1, "cacheWrite": 1 }
  },
  "default": { "input": 1, "output": 2 }
}
  • Unit = price per million tokens (currency defaults to ยฅ); model keys are the provider/model strings shown in the panel
  • cacheRead / cacheWrite fall back to the input price; default covers models you did not list
  • Stored at ~/.dsh/token-usage-prices.json (written as temp file + atomic rename, never half-written)
  • โ€œInsert templateโ€ lists every model that appears in your current data so you only fill numbers
  • Unpriced models are counted separately and the panel says so โ€” no silent zeros
  • Clear the box and save to hide cost again

Cost is an estimate, not an invoice โ€” your provider's billing is the source of truth.

๐Ÿš€ Install

Option one ยท straight from GitHub (recommended, DSH's standard channel)

# desktop app (the profile the packaged app actually loads)
dsh plugin --profile desktop add github:GIN0076/dsh-token-usage
# or omit --profile to target the current default profile
dsh plugin add github:GIN0076/dsh-token-usage

โš ๏ธ Don't copy --profile web from older docs: that is the browser profile, while the desktop app reads desktop โ€” installing into the wrong profile looks like "command succeeded, panel missing".

Option two ยท clone & install locally (works offline; the channel this repo was built on)

git clone https://github.com/GIN0076/dsh-token-usage.git

Then run plugin_manager install_bundle in DSH with the clone directory as target, or use Plugins page โ†’ Install Bundle in the GUI. (Got ambiguous-install? remove_bundle first, then install โ€” a known leftover-link quirk.)

Hard-refresh the page (Ctrl+Shift+R) โ†’ open Settings โ†’ ๐Ÿ“Š Token Usage ๐ŸŽ‰

Uninstall: plugin_manager remove_bundle โ†’ @local/token-usage โ€” zero host residue; the data folder is yours to keep or delete.

๐Ÿค” How it works

 ~/.dsh/sessions session logs (the single source of truth, read-only)
      โ”‚  โ‘  live fold of session/event      โ‘ก startup backfill (watermark-idempotent,
      โ–ผ                                     skips sessions whose bytes never changed)
 Host half โ”€โ”€โ–ถ day ร— provider/model ร— six buckets โ”€โ”€โ–ถ storage-domain (persistent)
      โ”‚                                              (corrupt? backup-and-skip + rebuild)
      โ–ผ
 /token-usage-rpc  ๐Ÿ”’ connection auth + loopback Host + same-origin Origin
      โ–ผ same-origin fetch (data never leaves your machine)
 Client half โ”€โ”€โ–ถ Settings section + pure-SVG charts (no chart lib, no build, zero deps)

Accounting details (stats.js pure functions, guarded by 50 fixtures):

  • โœ… Counted: assistant/message (including stream usage), compaction/summary (attributed by the event's own provider/model)
  • โš ๏ธ Supported but not promised: assistant/attempt goes through the same folding path, but on 0.2.0-rc.2 that event carries no usage (18 sessions / 17 attempt events / 0 hits) โ€” the host never reports tokens for retried or failed calls, so retry cost is simply not observable here
  • ๐Ÿท๏ธ Attribution: messages carry their own provider/model; summaries prefer their own, then fall back to the latest request header; attempts use the latest request header
  • ๐Ÿšซ Skipped: unsafe integers, negatives, reasoning > output, totals that contradict buckets
  • ๐Ÿ• Buckets use the host's local timezone; fork-inherited prefixes are cut by inheritedEventCount โ€” your ancestors' tokens are never counted twice

๐Ÿ”’ Privacy

  • Local-first: statistics come only from ~/.dsh/sessions on this machine โ€” no network calls, no uploads, ever
  • Triple RPC fence: connection auth (cookie) + loopback Host + same-origin Origin
  • MIT licensed. No telemetry, no accounts, no backdoors.

๐Ÿงฉ Architecture (for the tinkerer)

 ~/.dsh/sessions session logs (the single source of truth, read-only)
      โ”‚  โ‘  live: ctx.on('session/event') folds post-commit events
      โ”‚  โ‘ก backfill: sessionQuery.listSessions + readSession (watermark-idempotent;
      โ”‚              skip sessions whose file bytes are unchanged)
      โ–ผ
 Host half host.js
   ยท storage-domain `token_usage` (per-record + backup-and-skip; path-safe base64url keys)
       - daily: day ร— provider/model ร— six counters
       - watermark: per-session { seq, route, bytes }
   ยท /token-usage-rpc exact route (connection auth + loopback Host + same-origin Origin)
       - stats {granularity, fromDay, toDay} โ†’ aggregation (stats.js pure functions, + cost when priced)
       - status โ†’ { backfill, rebuilding, storageOk, dataSpan, prices }
       - rebuild โ†’ full re-scan (pauses live folding + buffered replay to avoid races; **returns needsConfirm first when the store holds log-less history**)
       - prices / prices.save โ†’ read/write ~/.dsh/token-usage-prices.json (validated, atomic replace)
   ยท auth/origin rejections carry a JSON diagnostic body {error, hint, seen{host,origin,site,cookie}} (never the cookie value)
      โ–ผ same-origin POST fetch
 Client half client.js (static bundle, __ModuleLoader__)
   ยท settings.section entry (id: token-usage, order: 50)
   ยท Day/Week/Month segmented control + presets (7d/30d/12w/12m/all/custom dates) + rebuild
   ยท summary cards โ†’ trend line chart (bold total + per-model lines + crosshair + legend)
     โ†’ model ranking bar chart
   ยท price-table editor (template / validation / save) ยท export sheet (CSV/JSON) ยท 60s auto refresh
File Responsibility
stats.js Pure aggregation; node stats.fixtures.mjs runs 63 fixtures (accounting / dedup / routing / week-month buckets / custom ranges / rollup consistency / price table & cost)
host.js Host half: folding, backfill, rebuild, storage, RPC
client.js Client half: section, controls, two SVG charts
cordis.patch.yml Bundle patch row (relative specifier ./host.js)
locale/{zh,en}.json Plugin Manager display metadata; section copy lives inline in client.js

๐Ÿ› ๏ธ Developer cheat sheet

Want toโ€ฆ Do this
Change the Client half (UI / charts) Edit client.js โ†’ hard-refresh the page (client-hmr swaps the rev)
Change the Host half (stats / RPC) Edit host.js โ†’ restart DSH; hot-editing a running host is limited by Node's per-URL ESM cache, so swap the filename to force a new generation (see below)
Run tests node stats.fixtures.mjs (63) + node client.i18n.fixtures.mjs (257) + node client.smoke.mjs (51)
Syntax check node --check host.js && node --check client.js && node --check stats.js

Host hot-reload recipe (running, no restart): edit host.js โ†’ Copy-Item host.js host2.js โ†’ point the cordis.patch.yml row name at './host2.js' โ†’ remove_bundle + install_bundle. Why: Node caches ESM per URL in-process; a new filename = a fresh URL = freshly loaded code. Fresh installs and restarts are not affected by this at all.

โš ๏ธ Pitfalls we hit (all fixed; kept here as a field manual)

Pitfall Symptom Root cause & fix
connection not injected Every RPC returns an empty 400 Cordis Context is a strict proxy: touching a non-injected service throws, and the webserver's catch-all turns it into 400. Fix: add 'connection' to inject (same as open-in-app)
Broken disposer Domain stuck already-open after every remove ctx.inject() returns a fiber, not a function โ€” calling it threw a TypeError and aborted dom.close(), leaking the reservation. Fix: try/catch per step, close first, let the parent ctx cascade child fibers
Inconsistent error check Retry gave up after one attempt DomainError.code='already-open' (hyphen) vs message="โ€ฆ is already open" (space) โ€” check both
One-shot storage failure storageOk:false forever Added lazy recovery: retry attachStorage on later requests; when memory already holds data, skip hydrate (double-count guard) and overwrite disk instead
Ghost domain A dead generation holds the reservation storageDomain.get(name) returns the leaked handle โ€” close it directly (the facility is a singleton, so the holder must be a dead fiber); now built into the retry path

๐Ÿ“ฆ Restoring after a DSH update

Yes โ€” one command. The plugin source lives in your workspace, not in ~/.dsh, so an update never touches it; only the profile registration is cleared. Re-run the install command (remove first if you hit ambiguous-install). No peer constraints: the bundle declares no @deepseek-ai/dsh-* peers, so compatibility gates never block it, and every API it uses (settings.section / sessionQuery / storageDomain / webServer / connection / session/event) is stable upstream surface. After an update, run the four-step check:

  1. list_plugins โ†’ include:token-usage should be fiberPhase: active
  2. RPC returns 401 unauthenticated / 200 authenticated
  3. Hard-refresh โ†’ both charts render in Settings
  4. If you edited the Host half, confirm the filename in cordis.patch.yml still exists

Data: statistics are derived. Even if ~/.dsh is wiped, restoring the session logs makes the startup backfill rebuild everything โ€” or hit "Rebuild" for a full re-scan. The source of truth can't be lost, so the aggregates can always grow back.

๐Ÿ“œ License

MIT ยฉ 2026 GIN0076 โ€” issues and PRs welcome.

Inspired by the usage panel in ZCode Usage Stats and the accounting design of local-first trackers like ccusage / tokscale / token-history.

โ€”/ 5

No ratings yet

Verified DSH bundle

Commit 13eda220223c

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout