Usage & Billing

dsh-token-usage-afap

AFAP/dsh-token-usage · ★ 1

AFAP

Token usage display for the DeepSeek Harness web GUI: per-session header pill plus a global daily/per-model consumption panel…

License
MIT
Added
2026-10-30
Maintenance
active
Install kind
github
Manifest details
Manifest status
Declared
Manifest path
package.json#dsh
Manifest checked
2026-10-30T09:38:20.038Z
Lifecycle scripts
None found

Static manifest checks report declarations only; they are not compatibility or security review.

安装

dsh plugin --profile web add 'github:AFAP/dsh-token-usage#4b2abdc896b661cee2ba6b1a82e6f044d1165f0b'

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. Screenshots
  2. One-click install (GitHub)
  3. Manual install from a source directory (equivalent, for verification)
  4. Verify it loaded
  5. Architecture & data flow
  6. Per-session pill (pure client)
  7. Global panel (host-side log scan + client render)
  8. Directory layout
  9. Usage
  10. License

A token-usage display plugin for the DeepSeek Harness Web GUI.

It shows token consumption in dsh web, in two surfaces:

  1. Per-session pill: on the right side of the session header — current session input/output tokens and context occupancy; click for the breakdown (provider usage, context composition, context pressure, session stats).
  2. Global consumption panel: opened from the "Token stats" button at the bottom of the sidebar — a yearly token-activity heatmap (GitHub-contribution style: one cell per day, grey = no usage, blue ramp = usage, ghosted = future days, year-by-year paging), per-model breakdown (input/output/cache/total/share), a per-day drilldown table, and the web-search sidecar call count. Data comes from the session logs, aggregated once on open; press ↻ in the header to re-read.

No configuration needed.

This plugin does not modify any files: the per-session pill only reads the session projections Harness pushes in real time; the global panel only read-scans the session logs under $DSH_HOME\sessions (no writes, no deletions, no changes to any log).

Screenshots

Global consumption panel (daily · per-model · per-day drilldown) Session-header token pill
Global consumption panel Session token pill

One-click install (GitHub)

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

Then restart dsh web to activate.

After install the plugin lives at $DSH_HOME\profiles\web\node_modules\dsh-token-usage (pnpm clones it from GitHub), independent of the source repo location.

Update: dsh plugin --profile web update dsh-token-usage

Uninstall: dsh plugin --profile web remove dsh-token-usage

Manual install from a source directory (equivalent, for verification)

dsh plugin --profile web add "D:\path\to\dsh-token-usage"

Verify it loaded

Open any session → the token pill appears in the header; the "Token stats" button appears at the bottom of the sidebar.

Architecture & data flow

Per-session pill (pure client)

The data path is entirely provided by built-in DeepSeek Harness components:

  1. @deepseek-ai/dsh-token-meter (built into the base layer) folds each request's token usage into session projections: tokenUsage, contextPressure, contextBreakdown; @deepseek-ai/dsh-session-stats (built into the web layer) provides sessionStats.
  2. dsh-host-apiproxy broadcasts every projection change as a session/projection frame; history tails also carry the projection baseline for reopened sessions.
  3. The browser's dsh-client-runtime writes into ProjectionValueStore, exposed to UI components through the useProjection(key) hook of the slot standard kit.
  4. The plugin registers TokenUsageBadge into conversation.session.header.utilities.

Global panel (host-side log scan + client render)

dsh-token-usage (node half, lib/index.js — zero external deps, Node builtins + ./stats.js only)
  GET /api/token-stats ──▶ scans $DSH_HOME/sessions/**/session.jsonl.zstd
                            (concatenated zstd frames, decompressed frame by frame, JSONL events parsed)
                            ├─ assistant/message events → data.usage (provider-reported tokens)
                            ├─ request/header / request/context → current model
                            └─ aggregated by "local day × model" → JSON
                                  │
                                  ▼  (browser fetch, same-origin)
  GlobalStatsPanel (client half) ── summary cards + yearly heatmap + workspace/model/session/per-day panels
  • Log format: dsh-session-persistence-jsonl's multi-frame zstd container (one independent frame per appended batch); this plugin ports the official frame-boundary scanner (magic/descriptor/block/checksum), decompresses each frame with zstdDecompressSync (built into Node 22.22+), and skips torn trailing frames left by a crash.
  • Per-request memoization by file mtime/size: only changed session logs are re-read, so refreshes are near-instant.
  • One log per session: when dsh upgrades the log format it rewrites the file in place as session.v4.jsonl.zstd and leaves the old session.v3.jsonl.zstd beside it; the scan keeps only the highest version per directory (the old one is a subset of it), otherwise that history would be counted twice.
  • /api/token-stats is registered as an exact route on the webserver (it wins over the connection plugin's /api prefix) and applies its own browser-trust fence (loopback / trustedHosts + same-origin checks, mirroring the /api fence in dsh-client-connection), rejecting DNS rebinding and cross-site requests.
  • The host half is deliberately dependency-free: DSH_HOME is resolved from the environment ($DSH_HOME → ~/.dsh) and no @deepseek-ai/* package is imported, so it loads correctly no matter how it is installed (git / registry / file: / link:).

Directory layout

dsh-token-usage/               # repo root = npm package root
├── package.json               # dsh.bundle.patch (config patch layer) + dsh.client (browser declaration)
├── cordis.patch.yml           # composition row: inject webRuntime + trustedHosts config
├── LICENSE                    # MIT
├── screenshot/                # screenshots (panel.png global panel / pill.jpg session pill)
└── lib/
    ├── index.js               # host half: /api/token-stats route + zstd frame scan + aggregation cache
    ├── stats.js               # pure aggregation logic (no deps, independently testable)
    └── client.js              # browser bundle: per-session pill + global panel

Usage

  • Per-session pill: in {input} · out {output} · ctx {occupancy%} (compact 1.2k / 3.4M format); click for the four-section breakdown (provider usage / context composition / context pressure / session stats).
  • Global panel (sidebar bottom → Token stats):
    • Summary cards: total / today / last 7 days / searches / requests / sessions ("searches" = web-search sidecar calls);
    • Yearly activity heatmap (‹ 2026 › pages year by year, always Jan 1 – Dec 31): grey = elapsed day with no usage, four blue levels = that day's usage, ghosted outline = days still to come; hover shows "day · tokens · searches", and clicking a cell expands that day's 24-hour usage below;
    • Four detail panels (by workspace / by model / heaviest sessions / per-day drilldown) laid out in two columns and all expanded by default; click a panel title row to collapse or expand it (▾/▴ on the right):
      • By workspace: workspace | sessions | requests | total | share;
      • By model: model | input | output | cache | total | share;
      • Heaviest sessions: session (with start date) | workspace | requests | total — hover shows models/messages/tools/span;
      • Per-day drilldown: day | total | input | output | searches | requests | model count — click a day row to expand that day's models;
    • All four lists stay height-aligned: the header is sticky, at most 12 rows are shown, and the rest scrolls inside the box (so the panels never grow taller than each other);
    • Fetches once on open, with a manual ↻ refresh in the header; Esc / clicking the backdrop closes it.
  • Instant open: aggregated data is cached locally, so the panel opens instantly and stays fast across repeated opens and dsh restarts.
  • UI language follows the interface: Simplified Chinese / English dictionaries are both built in.

License

MIT