dsh-balance
为 DeepSeek Harness 提供持久化的余额与用量显示插件,让您随时掌握资源消耗情况,无需离开工作区。
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 26, 2026
- Updated
- Aug 26, 2026
Introduction
💳 dsh-balance
A focused multi-provider balance monitor for the DeepSeek Harness Web GUI (dsh web): a persistent dock that shows every configured provider's balance at once, per-provider low-balance alerts, and a trend history sparkline.
dsh-balanceis intentionally narrower than a usage dashboard: it answers one question — "how much credit is left, and is any of it about to run out?" — and does it for every provider in a single glance.
✨ Features
🌐 Multi-provider dock
One row per configured provider, embedded at the bottom of the sidebar (between the session list and the settings foot, full sidebar width). A status dot and colored value tell you the health of each account at a glance; the dock collapses into a small pill when the sidebar folds.
- 🟢 ok — balance healthy
- 🟡 low — below the provider's threshold
- 🔴 bad — out of credit, or the upstream query failed
- ⚪ neutral — unconfigured / no public balance API
⚠️ Low-balance alerts
Set a per-provider threshold (in that provider's currency). When a balance drops below it, the row turns amber and an attention badge on the dock counts how many providers need a top-up.
📈 Trend history
Every successful read appends a compact numeric sample to a bounded, persisted ring buffer. The detail panel draws a small sparkline so you can see whether a balance is draining or stable.
🎛️ Detail panel
The gear opens a panel listing full breakdowns per provider — available / topped-up / granted / used / total credits — plus the trend line, status, and the threshold control. One click on the ↻ refreshes everything.
🛠️ Settings card
Configure every provider from Settings → Plugins → Plugin configuration → Balance: API keys (stored in DSH's credential store), optional base URL overrides, and a show/hide toggle per provider — hide any unwanted auto-discovered provider (e.g. a pi-ai profile without a public balance API). No manual YAML editing.
Installation
The repository is public and installable by anyone. Pick one of two paths:
npx — regular users (recommended)
Run the published @deepseek-ai/dsh CLI through npx, with no global install.
Prerequisites: Node.js 20+ and pnpm (corepack enable or npm i -g pnpm) — DSH manages profile plugins by forwarding to pnpm.
# 1. Add the plugin to the web profile (the profile auto-initializes on first use)
npx @deepseek-ai/dsh plugin --profile web add "github:Anyway-one/dsh-balance"
# 2. Configure keys in Settings → Plugins → Plugin configuration → Balance (see "Configuration" below)
# 3. Boot the web GUI
npx @deepseek-ai/dsh web
Hard-refresh the browser; the dock appears at the bottom-left. Update / remove:
npx @deepseek-ai/dsh plugin --profile web update dsh-balance
npx @deepseek-ai/dsh plugin --profile web remove dsh-balance
pnpm + Harness source — developers (recommended)
Clone the Harness, build it, and run it from source with pnpm; link the plugin from git, or from a local checkout when developing it.
# 1. Clone and build the harness
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
pnpm install
pnpm run build
# 2a. Install the plugin from git
pnpm dsh plugin --profile web add "github:Anyway-one/dsh-balance"
# 2b. ...or link a local checkout while developing dsh-balance itself
pnpm dsh plugin --profile web add "file:/absolute/path/to/dsh-balance"
# 3. Boot the web GUI from source
pnpm dsh web
When developing dsh-balance: server-side changes need a dsh web restart; client-only changes (lib/client.js) apply after a hard refresh.
Configuration
Graphical settings card (recommended)
Open Settings → Plugins → Plugin configuration → Balance. The card lists every configured provider — enter each API Key and optionally override its base URL, then save.
- Keys are written to DSH's credential store (write-only, never echoed back).
- base URL overrides land in the plugin's settings namespace and apply to the next balance read.
Manual credentials (alternative)
Under the hood the plugin reads the same credential references from ~/.dsh/.credentials.yaml:
DEEPSEEK_API_KEY: sk-your-key-here # official DeepSeek route
OPENROUTER_MANAGEMENT_KEY: sk-or-v1-... # OpenRouter account (Management Key, not the inference key)
ZAI_API_KEY: your-zai-key # Z.ai open platform
Moonshot / Kimi profiles under llm-pi-ai are discovered automatically and reuse their apiKeyEnv. Providers without a public balance API show an explicit "no public balance interface" state — never a guess.
Supported providers
| Provider | Upstream endpoint | Default credential ref |
|---|---|---|
| DeepSeek | GET {origin}/user/balance | DEEPSEEK_API_KEY |
| OpenRouter | GET {origin}/api/v1/credits | OPENROUTER_MANAGEMENT_KEY |
| Moonshot / Kimi | GET {origin}/v1/users/me/balance | pi-ai provider apiKeyEnv |
| Z.ai / GLM | GET {origin}/api/paas/v4/balance | ZAI_API_KEY |
API
| Method | Path | Response |
|---|---|---|
GET | /api/balance/providers | provider list, balance scheme, and status summary |
GET | /api/balance | balances for every provider (accounts[], each with a history trend); ?provider=<id> for one, refresh=1 to force an upstream query |
GET | /api/balance/state | provider list (id/displayName/scheme/apiKeyEnv/baseURL) + settings revision/writable for the config card |
POST | /api/balance/mutate | write per-provider base URL overrides ({ops, expectedRevision}) |
Read endpoints reject non-GET with 405; non-loopback callers get 403; every response is JSON with Cache-Control: no-cache.
Troubleshooting: proxy tools (Clash / Surge / Shadowrocket)
If you run a proxy in fake-ip mode, you may see Unsupported endpoint (HTTPS public URL required) and balances stop loading while the proxy is on — but work again as soon as you turn it off.
Why: fake-ip proxies answer every DNS query with a virtual IP from the 198.18.0.0/15 pool (e.g. api.deepseek.com → 198.18.0.13) instead of the real public IP, and the plugin's DNS-pinning safety layer rejects non-public addresses.
Fix (recommended): bypass the provider domains so they resolve to their real public IPs — add a DIRECT rule in your proxy:
DOMAIN-SUFFIX,deepseek.com,DIRECT
DOMAIN-SUFFIX,openrouter.ai,DIRECT
DOMAIN-SUFFIX,z.ai,DIRECT
DOMAIN-SUFFIX,moonshot.cn,DIRECT
Built-in fallback: the plugin already treats the 198.18.0.0/15 pool as public (it is RFC 2544 benchmarking space, not a real LAN), so fake-ip proxies in TUN mode work out of the box. If yours still fails, use the DIRECT rule above — it's faster and keeps the traffic off the proxy.
Universal escape hatch — Proxy mode: for any proxy / gateway / split-DNS setup the above doesn't cover, open Settings → Plugins → Plugin configuration → Balance and enable Proxy mode. It skips the strict DNS pinning + public-IP check and uses the system's normal connection, which works through any proxy. (Trade-off: this disables the DNS-rebinding protection for balance queries, so keep it off when you don't need it.)
Note: server-side code changes (e.g. lib/safe-fetch.js) take effect after restarting dsh web; client-only changes after a hard refresh.
Development & testing
npm run check # syntax checks for every module and script
npm test # 45 offline tests: balance schemes, safe-fetch policy, server boundary, settings/mutate, history
Tests are fully offline — no network, and the real ~/.dsh is never touched (server tests redirect DSH_HOME to a temp dir).
Privacy & security
- API keys never enter browser responses, plugin caches, or logs; they are resolved at request time through Harness's credentials seam.
- Upstream balance queries: HTTPS enforced, DNS pre-resolved and private/loopback ranges rejected, connections pinned to the checked address (DNS-rebinding defense), 1 MiB response cap, 15 s timeout.
- History caches under
~/.dsh/storages/hold only numeric samples (timestamp + balance + currency) — never keys or message text. - Do not expose these endpoints through a reverse proxy to LAN or the public internet.