DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-token-usage

G

dsh-token-usage

Manifest valid

📊 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 Settings panel token usage statistics plugin

UI (client)hasBundlePatch

📊 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 ▾]  │
├───────────────────────────────────────────────────────────────┤
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐       │
│ │  Total 🧮 │ │  Input ⬇️  │ │ Output ⬆️  │ │  Calls 📞 │       │
│ │   986.2M  │ │   610.0M  │ │    8.4M   │ │    947    │       │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘       │
│                                                               │
│ 📈 Trend (line chart)     ✦ hover any day → per-model details │
│     80M ┤            ╭─╮                                      │
│     40M ┤   ╭──╮  ╭──╯ ╰──╮       ─── total                  │
│         ┼───┴──┴──┴───────┴───      ─── alpha-chat            │
│          06-02    06-06    06-10     ─── beta-reason           │
│                                                               │
│ 🏆 Model ranking (bar chart)                                  │
│     alpha-chat       ████████████████░░░░  62.4%              │
│     beta-reason      █████░░░░░░░░░░░░░░░  31.8%              │
│     gamma-mini       ▍                      5.8%              │
└───────────────────────────────────────────────────────────────┘

🖼️ Schematic of the UI. The real thing follows DSH's theme tokens and looks great in both light and dark mode.

🎯 Features

AreaWhat you get
📅 GranularityFlip between Day / Week / Month — Monday-start weeks, calendar months; only day buckets are stored, so switching is instant and free
🗓️ Custom rangePresets (last 7 / 30 days, 12 weeks, 12 months, all time) + pick your own start & end dates — chart any window you like
📈 Line chartBold total line + thin per-model lines, crosshair hover breaks down every day, click legend chips to toggle models
🏆 Bar chartHorizontal model ranking with share % — spot your biggest token sink at a glance 💸
🔁 RebuildOne-click full re-scan — idempotent, watermarks guard against double-counting and gaps
🛡 AccountingDirty counters fail closed, retried attempts are billed too, fork inheritance never double-counts, compaction is included

🚀 Install

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

dsh plugin --profile web add github:GIN0076/dsh-token-usage

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 46 fixtures):

  • ✅ Counted: assistant/message (including stream usage), assistant/attempt — retries cost money too!, compaction/summary
  • 🏷️ Attribution: messages carry their own provider/model; attempts & compaction fall back to 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)
       - status → { backfill, rebuilding, storageOk, dataSpan }
       - rebuild → full re-scan (pauses live folding + buffered replay to avoid races)
      ▼ 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
FileResponsibility
stats.jsPure aggregation; node stats.fixtures.mjs runs 46 fixtures (accounting / dedup / week-month buckets / custom ranges / rollup consistency)
host.jsHost half: folding, backfill, rebuild, storage, RPC
client.jsClient half: section, controls, two SVG charts
cordis.patch.ymlBundle patch row (relative specifier ./host.js)
locale/{zh,en}.jsonPlugin 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 testsnode stats.fixtures.mjs (46 fixtures)
Syntax checknode --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)

PitfallSymptomRoot cause & fix
connection not injectedEvery RPC returns an empty 400Cordis 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 disposerDomain stuck already-open after every removectx.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 checkRetry gave up after one attemptDomainError.code='already-open' (hyphen) vs message="… is already open" (space) — check both
One-shot storage failurestorageOk:false foreverAdded lazy recovery: retry attachStorage on later requests; when memory already holds data, skip hydrate (double-count guard) and overwrite disk instead
Ghost domainA dead generation holds the reservationstorageDomain.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.

Comments

Loading…

From the same category

archify

by tt-a1i

Agent skill for beautiful, verifiable architecture, workflow, sequence, data-flow, and lifecycle diagrams—self-contained HTML with motion and crisp export.

Workflow & AutomationTools & CapabilitiesDevelopment & InfrastructureManifest valid

★ 73.4k

↓ 5.1k/wk

MIT

JavaScript

Sep 28, 2026

dsh plugin --profile agent add @tt-a1i/archify-dsh

DeepSeek Harness plugin for Reactive Resume: bridges your resumes and job applications into a Harness session over MCP.

Tools & CapabilitiesManifest valid

★ 41.7k

↓ 292/wk

MIT

Aug 24, 2026

dsh plugin --profile web add dsh-plugin-reactive-resume

by Tencent

Open-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.

Development & InfrastructureTools & CapabilitiesManifest valid

★ 30.9k

↓ 1.1k/wk

NOASSERTION

Go

Sep 28, 2026

dsh plugin --profile web add @wxg-prc-cpg/dsh-weknora

by anywhere-labs

为 DeepSeek Harness (DSH) 插件生态打造的现代化桌面端解决方案。万物皆「插件」,桌面本身也是「插件」。

Tools & CapabilitiesManifest valid

★ 29.3k

↓ 195/wk

MIT

TypeScript

Sep 28, 2026

dsh plugin --profile web add dsh-plugin-desktop

deepseek-harness-desktop is a interface plugin for DeepSeek Harness. See the repository documentation for its documented capabilities.

Tools & CapabilitiesUI & Experience

★ 28.6k

MIT

Index only — not installable

by titanwings

Distilly — Distill how they think into reusable Skills for any Agent or Bot. Formerly Colleague Skill(原同事 Skill).

Tools & Capabilities

★ 25.1k

MIT

TypeScript

Sep 22, 2026

Index only — not installable