VviLliAm-qwq/dsh-peak-balance ↗★ 3
dsh-peak-balance
Peak/off-peak billing clock with a provider-neutral account readout (DeepSeek balance, subscription plan windows, relay credits), per-turn spend measured from the provider's own counter, and a /hist token-history scene split per provider for dsh-tui 适合需要实时监控 DeepSeek 账户余额、峰谷计费状态和单次对话 Token 消耗的用户。
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:VviLliAm-qwq/dsh-peak-balanceREADME
Read the full README ↗dsh-peak-balance
English · 中文
Peak/off-peak billing clock, live DeepSeek account balance, per-turn cost and a
/hist token-history grid — inside
dsh-TUI.
⚡ 峰时 09:00-12:00 · 距谷时 1h23m · 本轮 ¥0.0234 · 余额 ¥42.10
(The order is phase → countdown → turn → balance: a narrow terminal truncates
the tail, and the per-turn cost is the figure that changes while you watch. While
the model is still answering, the turn figure is live — rendered as
本轮·计费中 ¥… and refreshed on every usage report — and it freezes to
本轮 ¥… once the turn closes.)
While the peak window is active you can turn the line into a three-row frame that pulses in one of seven colors:
╭──────────────────────────────────────────────────────────╮
│ ⚡ 峰时 · 距谷时 1h23m · 本轮 ¥0.0234 · 余额 ¥42.10 ▂▃▄▅▆▇ │
╰──────────────────────────────────────────────────────────╯
/hist (also /tokenhistory, alt+h, or /th with a trailing space — see
below) takes over the whole terminal with a GitHub-style contribution grid:
╭─ 🐋 Token history Total tokens 26w subagents counted ───────────────── ✕ ─╮
│ updated 12:04:11 · 341 sessions · 6,706 reports · 9 active days │
│ ───────────────────────────────────────────────────────────────────────────── │
│ 6月 7月 8月 9月 │
│ Mon ▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢ │
│ Wed ▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢ │
│ Fri ▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢▢ │
│ ▲ │
│ Total tokens less ▢▢▢▢▢ more · peak 251,442,584 │
╭─ 2026-09-11 Fri ───────────────────────────────────────────────────────╮
│ tokens input(miss) 2,065,340 · cache read 224.3M · output 1.5M │
│ cost ¥18.8494 │
│ cache hit 99.1% · subagent share 12.4% │
│ model deepseek-flash 227.9M · deepseek-v4-pro 3.2M │
╰───────────────────────────────────────────────────────────────────────────╯
│ Total 1,079,834,040 · Est. cost ¥64.6867 · cache hit 99.0% │
│ subagents 36/341 sessions · 945 reports · busiest 2026-09-11 │
│ ───────────────────────────────────────────────────────────────────────────── │
│ model tokens cost(est) hit rate rates │
│ ───────────────────────────────────────────────────────────────────────────── │
│ deepseek-flash 587.3M ¥33.94 99.3% built-in │
│ deepseek-v4-flash-vision-exp 412.6M ¥24.53 98.8% built-in │
│ deepseek-v4.1-flash-expires… 68.2M — 98.5% unknown │
│ deepseek-v4-pro 8.0M ¥4.28 95.4% built-in │
│ deepseek-v4-flash 457.2k ¥0.0975 90.1% built-in │
│ ←/→ week · ↑/↓ day · t today · m metric · w span · s subagents · r rescan · q/Esc close │
╰───────────────────────────────────────────────────────────────────────────────╯
Features
| Feature | What it shows |
|---|---|
| Peak / off-peak clock | The billing window currently in force and a live countdown to the next price switch (09:00-12:00 / 14:00-18:00 Beijing time, Monday–Friday; weekends are off-peak all day). |
| Account readout (provider-neutral) | The balance or plan quota of the provider the focused conversation actually runs through: an official balance, a subscription's 5-hour/weekly/monthly windows, a relay's credit pool. The provider comes from request/header.config.provider in the session log, and its base URL and credential reference are resolved through the harness seams. A conversation restored at boot names no route until its first request (the host replays its history without re-emitting events), so auto follows the host's persisted /model route — the one the next request will use — until the conversation speaks for itself. A provider with no readable interface is simply left off the line — no figure is ever guessed. |
| Per-turn cost | What the turn that just finished cost. When the provider exposes a spend counter (Command Code credits, OpenRouter key usage, a relay's used quota) this is measured from that counter; otherwise it is estimated from a rate card, and otherwise the line says the model is unrated. The figure follows the conversation you are focused on, not the one that last appended an event. |
Quota diagnostics /quota | One command shows what is being read, which adapter answers, why the last read failed, and every provider route this process could ask about (`/quota check |
| ` probes one on the spot). | |
| Peak-hour warning | Optional. While peak pricing is active the status contribution becomes a rounded frame whose border, phase label and travelling waveform pulse in the chosen color. |
History grid /th | A full-screen scene: one square per day, shaded by that day's usage, with a hover card for the day under the pointer. Keyboard: ←/→ walks days, ↑/↓ walks weeks, m cycles the metric, w the span, s the subagent switch, r rescans, q/Esc returns to the conversation. |
| Totals and per-model stats | Totals: tokens, estimated cost, cache-hit rate, active days, sessions, subagent share, busiest day. Model table: each model's total tokens, estimated cost, cache-hit rate and where its rates came from. The totals row covers all history (it does not follow the grid's span) and says so inline. |
Custom rates /th price | Price a model the embedded card does not list; until you do, it reports tokens with an explicit "unrated" marker instead of a guessed amount. |
| Follows the UI language | Instant hand-off with dsh-TUI's /lang: the status line, the history scene and every command reply switch with it. The host mirrors the choice into its dsh-tui settings namespace and the plugin listens for settings/updated; a 1 s poll of ~/.dsh-tui/lang.json covers hosts that serve no such namespace. The settings card and the command-completion descriptions were already bilingual. |
| Settings subpage | The Peak & Balance card gains a Token history subpage with ten options. |
Install
# from npm
dsh plugin --profile dsh-tui add dsh-peak-balance
# ...or straight from a checkout of this repository (pnpm packs the local
# directory, so the profile keeps a real copy instead of a symlink)
dsh plugin --profile dsh-tui add file:/absolute/path/to/dsh-peak-balance
The command appends the bundle row to the profile's dsh.profile.bundles.
Then restart the TUI (/restart inside dsh-tui) so the profile loads the new
row; the settings card appears under /settings immediately after the restart.
Installing by symlink (
link:or a directory junction) is not recommended: Node resolves a plugin's real path, and@deepseek-ai/*must stay reachable from it.file:and npm installs both leave a real directory inside the profile, which is the layout the host expects.Updating a
file:install: pnpm caches a local directory dependency, soadd/updatealone will not pick up edited sources. Remove and re-add it (after a version bump) to refresh the profile copy:dsh plugin --profile dsh-tui remove dsh-peak-balance dsh plugin --profile dsh-tui add file:/absolute/path/to/dsh-peak-balance
Settings
/settings → the Peak & Balance card. Edits are written live; no restart is
needed.
Main card:
| Field | Type | Default | Meaning |
|---|---|---|---|
| Show balance | boolean | true | Show the account section on the status line (the provider's quota meter, as an amount or a percentage). |
| Show per-turn cost | boolean | true | Show what this turn has cost: a live estimate while the model answers, frozen when the turn closes (measured from the provider's counter when it has one). |
| Peak-hour warning | boolean | false | Turn the line into a pulsing frame while peak pricing is active. |
| Warning color | select | red | Frame color: red orange yellow green cyan blue purple. |
Provider quota subpage:
| Field | Type | Default | Meaning |
|---|---|---|---|
| Quota provider | text | auto | auto follows the focused conversation's provider, falling back to the host's persisted /model route while a restored conversation has not sent its first request; a provider id (commandcode, openrouter, …) pins that one; off hides the account section. |
| Quota metric | select | auto | auto (the tightest window), balance, window5h, windowWeekly, windowDaily, windowMonthly, planRemaining, keyLimit, periodSpend, lifetimeSpend, or rotate (cycle every meter, one every 8 s). |
| Turn spend | select | auto | auto (measured when the provider has a counter), measured, estimate. |
| Unofficial endpoints | boolean | false | Allow quota reads from endpoints no provider documents publicly (mostly reverse-engineered console APIs). |
| Provider spec file | text | empty | JSON file describing providers this build ships no adapter for; empty uses ~/.dsh-tui/dsh-peak-balance-providers.json. |
| Billing mode | select | auto | How the account readout is shaped: auto follows the provider's declaration (a subscription shows percentages, pay-as-you-go shows amounts), or force money / plan. |
| Percentage base | select | meter | What a plan percentage divides by: meter uses the window the line is showing, monthly the whole monthly pool. |
Token history subpage:
| Field | Type | Default | Meaning |
|---|---|---|---|
| Grid metric | select | tokens | What the squares shade: tokens, cost, output, cacheMiss. |
| Time span | select | 26 | Week columns drawn: 13 / 26 / 53. |
| Count subagents | boolean | true | Subagent sessions spend real tokens; off reports only your own conversations. |
| Week starts on | select | mon | Which weekday is the grid's first row (mon / sun). |
| Grid palette | select | github | github (green), blue, or theme (the active accent). |
| Scene layout | select | card | card frames the scene in a rounded box with section separators; plain drops the chrome (2 rows / 4 columns cheaper). Card falls back to plain by itself on a small terminal. |
| Hover: tokens | boolean | true | Show the input / cache-read / output split in the day card. |
| Hover: cost | boolean | true | Show the hovered day's estimated cost. |
| Hover: cache hit rate | boolean | true | Show the hovered day's cache-hit rate. |
| Hover: models | boolean | true | Show which models the hovered day used. |
The settings live in the dsh-peak-balance namespace of the dsh settings
document, so they can also be edited there directly. The scene's m / w / s
keys are settings changes: they write back immediately (and survive a restart);
if the write is refused the change stays for the current session and a warning is
logged.
/hist — token history
/hist # open the grid (recommended: no built-in collision)
/tokenhistory # the long alias
alt+h # same thing without typing
/th # works too, but keep the trailing space (see below)
/hist price # list custom rates and unrated models
/hist price set [peakHit peakMiss peakOut]
/hist price rm
/hist price clear
/quota # quota diagnostics: source, adapter, meter, last failure
/quota check
# probe one provider now (empty = the current target)
/quota meter windowWeekly # switch the status-line meter (same as the setting)
Why a bare /th + Enter switches the theme
A host behaviour the plugin cannot change, stated plainly: while dsh-tui's
slash-completion overlay is open, Enter runs the highlighted suggestion, not
the line you typed (handleEnter in PromptInput.js); the merged list puts
built-ins first and appends plugin commands, and the selection resets to the
first row. Typing /th matches theme, thinking and our th, so the
highlight sits on theme and Enter switches the theme.
| Entry point | Note |
|---|---|
/hist | Recommended. hist is not a prefix of any built-in, so the menu offers only it and Enter runs it. |
/tokenhistory | Same, no collision. |
alt+h | Opens the scene straight from the chat state. |
/th + Enter | Keep the trailing space: the menu closes (no children), and Enter dispatches th. |
A future SKILL whose name starts with
histwould capture/hist's Enter the same way — same host logic; rename then (it is one constant in the code).
Keyboard
| Key | Effect |
|---|---|
← / → | Move to the square to the left/right (same weekday, one week) |
↑ / ↓ | Move to the square above/below (same column, one day) |
t | Jump back to today |
m / w / s | Cycle metric / span / subagents (the matching chip flashes; the change is persisted) |
r | Rescan |
q / Esc | Back to the conversation |
Moves stop at the grid edge and never enter a day that has not happened yet (no
wrapping). The selected square is lightened and a ▲ under the grid points at its
column.
Subagent feedback: the title bar carries a permanent chip (subagent counted
— green — or subagent excluded), pressing s inverts it for 1.2 s, and the
totals row spells out excluded N sessions / M reports instead of just shrinking
the numbers.
The data source is this machine's session logs ($DSH_HOME/sessions/). Every
assistant/message event in those logs carries the usage DeepSeek returned for
that request (inputTokens / cacheReadTokens / outputTokens /
cacheWriteTokens); the plugin files each report into the Beijing calendar day
and the peak/off-peak tier of its own timestamp, then per model. So:
- tokens are the provider's own reported numbers, not a local estimate;
- money is an estimate (the API returns tokens, never money), converted with the embedded rate card or your custom rates, and labelled as such;
- only this machine's dsh usage is covered — web chat or other clients are not;
- the covered range is whatever this machine's logs still hold.
Subagents count by default (they spend real money), stay distinguishable, and can be switched off.
Unrated models (not on the embedded card) show tokens with — for money
until you give them rates through /hist price set. Custom rates are written
immediately to ~/.dsh-tui/dsh-peak-balance-rates.json and feed both the history
view and the status line's per-turn figure. are the
off-peak prices in CNY per million tokens; peak defaults to twice those (the
official rule), and you can pass three more numbers to set the peak tier
explicitly.
Two implementation details that decide the accuracy (both reproducible on real logs):
- The logs are multi-frame zstd (one frame per append).
zlib.zstdDecompressSyncstops after the first frame, and scanning for the magic bytes can hit the magic inside a compressed block — where a truncated decode still "succeeds" with partial content and silently drops events. The plugin parses the zstd frame and block headers to compute each frame's exact length: on this machine's 341 logs the byte-scanning approach lost 282 events, the header walk recovers all of them. - Fork/rewind log