dsh-burn
September 3, 2026 · View on GitHub
Token spend, peak/off-peak pricing, and account balance for the DeepSeek Harness web UI.

What it does
- Per-reply cost on hover — every settled assistant message shows
↑in · ↓out ¥costin its action row (copy/like/share), priced at the billing tier in effect at that reply's own timestamp against the live price book. - Cumulative spend + balance in the conversation header —
累计 ¥xx · 余额 ¥xxsits right of the agent-preset label (Standard mode). The cumulative figure is folded live from the session snapshot (updates the moment a reply settles); the balance polls the DeepSeek/user/balanceAPI (host-cached, 60 s). - Settings panel (费用 / Cost) — edit per-model prices, pick the display tier (
auto/peak/offPeak/average), load the official DeepSeek price table, and customize the peak/off-peak schedule. Tier switches re-price instantly.
Pricing follows DeepSeek's billing: each reply is charged at the tier in effect at its own generation time — weekdays peak 09:00–12:00 and 14:00–18:00 Beijing time, everything else off-peak at half price, and weekends off-peak all day (2026-08-23 rule). auto (the default) and average both price that actual per-reply split (the time-weighted figure); peak / offPeak pin an explicit tier for manual inspection. The schedule is customizable. Prices default to the built-in official table, so the plugin works with zero configuration.
Compatibility
Declared in package.json (engines and dsh.compatibility.dshReleases) and rechecked by the DSH STORE source-policy scanner on every pinned commit:
| Target | Declared range | Evidence |
|---|---|---|
| Node.js | ^22.19.0 || >=24.0.0 (engines) | verified on Node 22.22.2 (macOS arm64) |
| DSH releases | 0.1.1-rc.2: compatible (dshReleases) | disposable-profile install + uninstall, live web-profile boot with HTTP 200 on both plugin endpoints (see COMPATIBILITY.md) |
The peer-dependency floor is the DeepSeek Harness 0.1.0-rc.7 contract family; other DSH release lines are declared per version only once verified. The DSH STORE catalog additionally tracks its own independent evidence status (verified / partial / unknown) for install/start/uninstall — this source matrix is a declaration, not a substitute for that runtime evidence.
Install
The plugin is a bundle: dsh plugin add mounts it automatically (the manifest's dsh.bundle.patch is applied for you), no manual patch needed.
From GitHub
dsh plugin --profile web add github:yishan/dsh-burn
dsh web # restart the web service for the profile change to take effect
From npm (once published)
dsh plugin --profile web add dsh-burn
dsh web
From a local directory
dsh plugin --profile web add /path/to/dsh-burn
dsh web
Uninstall
dsh plugin --profile web remove dsh-burn
dsh web
Configuration
Zero-config by default: the built-in official price table (deepseek-v4-flash / deepseek-v4-pro) is back-filled on boot, and everything is editable live in 设置 → 费用 (persisted to a per-profile settings file — <profileDir>/plugins/dsh-burn/settings.json, derived from the Loader's base URL — which overrides the profile config on restart). A legacy global $DSH_HOME/plugins/dsh-burn/settings.json migrates once on first boot; settingsPath in the profile patch overrides the location explicitly.
The balance readout needs a DeepSeek API key resolved from DEEPSEEK_API_KEY.
Advanced: override via profile patch
A profile-level patch targeting id: dsh-burn replaces the bundle row's config (prices, display tier, schedule, balance endpoint):
# $DSH_HOME/profiles/web/cordis.patch.yml
- id: dsh-burn
config:
displayMode: auto # auto | peak | offPeak | average
tierSchedule: default # default | custom
customWindows: [] # [{ start: 540, end: 720, tier: 'peak' }, ...]
defaultTier: offPeak # tier for minutes not covered by customWindows
prices:
deepseek-v4-flash:
peak: { input: 3.0, cacheRead: 0.1, cacheWrite: 3.0, output: 9.0 }
offPeak: { input: 1.5, cacheRead: 0.05, cacheWrite: 1.5, output: 4.5 }
deepseek-v4-pro:
peak: { input: 9.0, cacheRead: 0.3, cacheWrite: 9.0, output: 27.0 }
offPeak: { input: 4.5, cacheRead: 0.15, cacheWrite: 4.5, output: 13.5 }
defaultPrice:
peak: { input: 3.0, cacheRead: 0.1, cacheWrite: 3.0, output: 9.0 }
offPeak: { input: 1.5, cacheRead: 0.05, cacheWrite: 1.5, output: 4.5 }
apiKeyEnv: DEEPSEEK_API_KEY # credential ref for the balance endpoint
balanceRefreshMs: 60000
balanceBaseURL: 'https://api.deepseek.com'
# settingsPath: /abs/path/to/settings.json # optional override of the profile-isolated default
Prices are CNY per 1M tokens. cacheWrite mirrors the cache-miss rate for providers that don't bill cache writes separately.
How it works
- Host (
src/index.ts,src/projection.ts): aCostMeterservice folds the session log into per-model, per-tier token buckets (costsession projection — each message bucketed by the billing tier at its own timestamp), servesGET/POST /api/cost/settings, and proxiesGET /api/cost/balancethrough the credentials seam (401 without a key, 502 on upstream failure, 60 s cache with concurrent-request dedup). The projection'stotalCostis computed live from the buckets against the current price book at the current display tier, so price/tier changes apply to the whole log without a re-fold. - Client (
src/client/): three slot seats —conversation.session.header.actions(cumulative spend + balance, right of the agent-preset label),conversation.chat.assistant-actions(per-reply cost),settings.section(the 费用 page). Token buckets are re-priced at render time against the current price book (per-reply at the reply's own tier), so tier/price changes apply instantly without a restart. The session fold is incremental (append-only O(Δ), O(1) per-message lookups via an index). - Runtime settings persist to the per-profile settings file (see Configuration), which overrides the profile config on boot; models missing from the book are back-filled from the official price table.
POST /api/cost/settingsrejects unknown keys, invalid values, overlapping custom windows (400) and oversized bodies (413), and reports the disk-write result inpersistedso the UI surfaces a failed save.
Development
pnpm install
pnpm run typecheck # tsc --noEmit
pnpm run test # vitest (pricing logic)
pnpm run build # esbuild: lib/index.js (host) + lib/client.js (browser)
The client bundle is a classic-script plugin registered on window.__ModuleLoader__ and may import only the platform module table (see build.mjs).
Permissions, dependencies & failure boundaries
The plugin runs in two places: a host bundle (server side, inside the DSH process) and a web client (browser, inside the DSH web UI). Capabilities are deliberately narrow.
- Files — the host reads/writes only its own settings file (
<profileDir>/plugins/dsh-burn/settings.json, derived from the loader's base URL) and performs a one-time read migration of the legacy$DSH_HOME/plugins/dsh-burn/settings.json. No directory scanning, no other paths (settingsPathconfig can redirect that single file). The client uses no browser storage. - Network — the only absolute outbound URL in the source tree is the balance endpoint (default
https://api.deepseek.com/user/balance, overridable viabalanceBaseURL), called with a Bearer key resolved through the DSH credentials seam. All client traffic is same-origin (/api/cost/settings,/api/cost/balance). No other hosts, no telemetry. - Commands — none. There is no
child_process, shell, or OS command execution anywhere insrc/. - Credentials — resolves exactly one credential reference (
DEEPSEEK_API_KEYby default) through the official credentials service, used only as the Bearer for the balance call; never logged, never persisted by the plugin. - Runtime dependencies — the host service uses only host-provided
@deepseek-ai/*services (peer range^0.1.0-rc.7) plus@deepseek-ai/schemasteryfor config; runtime deps are bundled intolib/at build time. There are no install-time lifecycle scripts (preinstall/install/postinstall/prepare) — the npm scripts arebuild,typecheck,test, andprepublishOnly. - HTTP & projection surface — registers
GET/POST /api/cost/settingsandGET /api/cost/balanceon the profile's web server plus onecostsession projection, mounted only when the matching host children exist. - Failure boundaries — partial assemblies degrade rather than crash: headless (no web server) simply skips the HTTP routes; a missing credential makes the balance endpoint return
401 {no_api_key}; an upstream failure returns502; settings POST rejects unknown keys, invalid values and overlapping time windows with400, rejects oversized bodies with413(1 MiB bound), and reports a failed disk write in thepersistedfield; a missing or corrupt settings file falls back to the profile config and heals on the next successful save. Price/tier changes re-price the whole session log live without a restart.
A high-level security posture and the vulnerability reporting path are in SECURITY.md. Note that store-side capabilities may still require a user-reviewed or blocked status on the DSH STORE; this source-level declaration does not by itself grant automatic approval.
License
MIT