Plugin directory / UI & Skins / dsh-balance-by-token
dsh-balance-by-token
Verified · install-tested on dsh jsoncode
What it does
DeepSeek Harness(dsh)双面插件(宿主 + 浏览器半边):查看 DeepSeek 账户余额, 按 token 用量估算费用,价格按模型 × 高峰/空闲时段在线配置。所有能力收敛在 统一弹框中(侧边栏底部「余额」入口),另在会话头部提供实时 「当前会话 ≈xx CNY | 余额 xx CNY」按钮。界面中英双语(跟随宿主 UI 语言)。
Works — verified, early-stage project
DeepSeek Harness(dsh)双面插件(宿主 + 浏览器半边):查看 DeepSeek 账户余额, 按 token 用量估算费用,价格按模型 × 高峰/空闲时段在线配置。所有能力收敛在 统一弹框中(侧边栏底部「余额」入口),另在会话头部提供实时 「当前会话 ≈xx CNY | 余额 xx CNY」按钮。界面中英双语(跟随宿主 UI 语言)。 It installs cleanly and boots without issues in our testing. It's early-stage but functional.
“Verified” means our automated CI actually ran dsh plugin add in a clean profile and it booted — nothing more. Feature descriptions and version compatibility are the author’s claims. This is not a security audit and not an endorsement of third-party code.
README
dsh-balance-by-token
A DeepSeek Harness plugin (dual-face: host + browser) for watching your DeepSeek
account balance and estimating token-based costs, with prices configured
per model × peak/off-peak period online. Everything lives in a unified modal
(opened from the sidebar-footer Balance button); a session-header button
shows a live "Session ≈xx CNY". UI copy is bilingual
(Chinese / English, following the host UI language).
Features
Balance tab
- Enumerates every DeepSeek provider:
- entries from the host
llm-pi-aisettings whosebaseURLpoints at DeepSeek, - the official
llm-deepseekroute, - manually attached extra API keys (see below).
- entries from the host
- Each API key row shows "Today spend ≈xx CNY | Balance xx CNY"
(numbers green) — the key's own today cost (matched from the per-key cost
stats by provider route, ≈0.00 when unused) plus its account balance. - For each provider the plugin resolves the configured
apiKeyEnvvia the hostcredentialsservice and calls the officialGET https://api.deepseek.com/user/balance(proxied by the host — keys never
reach the browser). Each row showstotal_balance/granted_balance
(+ topped-out flag) or the failure reason. Results are cached in memory for 60s;
"Refresh" bypasses the cache. - Extra API keys: keys outside any providers config can be attached directly
from the modal (label + key, masked echo), persisted to$DSH_HOME/settings.yaml.
Cost tab — per-API-key breakdown
- Four cards: Last turn / This session / Today · this project / Today · all,
each with the total billed amount + a stacked bar + legend (input / cache read /
cache write / output — pure divs, no chart library). - Per API key rows: inside every card, each configured key (provider route)
gets its own row showing its own four-bucket token counts, a mini bar, an
official/non-official chip and its own cost. - Token usage is counted per key regardless of officialness; cost is only
computed for official keys (API domainapi.deepseek.com) — non-official keys
show a "not billed" chip instead of an amount. Multiple official keys (several
routes pointing at the official API) each get their own row and their own bill. - Official detection: the
providerfield ofrequest/contextevents → that
provider's baseURL in host settings → hostname equalsapi.deepseek.com
(trailing slash / case normalized; lookalike domains such asapi.deepseek.com.xx.comare not official). - Last turn / session: in-memory event folding (same (turn,step)
last-value-wins semantics as the officialtokenUsageprojection). Today
entries: on-demand scan ofdshHomePath('sessions')logs (.jsonland.jsonl.zstd, frame-wise zstd decode, per-file memoized).
Price settings tab — official pricing-table layout
- Mirrors the official price table layout minus the category column:
模型版本(colspan=2) + one column per model; three metric groups (input
cache-hit / cache-miss / output, each rowspan=2) + off-peak/peak rows;
only the price cells are input boxes (peak red, off-peak green). - Each model has peak and off-peak sets of four prices (per million tokens:
input / cache read / cache write / output, CNY). - Periods are configurable: peak windows (cross-midnight supported) + a
timezone-offset slider (UTC-12..+12, shown as 东八区 / 西五区 / 零时区).
Official default: Beijing 9:00–12:00 & 14:00–18:00 are peak; off-peak = peak × 0.5. - Built-in fallback is the official V4 tiers (
deepseek-v4-flash/deepseek-v4-pro/deepseek-v4-flash-vision-exp). Old flat-format
config migrates automatically on first read (legacy built-in defaults upgrade to
the official three tiers).
Session-header live button
- Registered on
conversation.session.header.utilities, showing
Session ≈xx CNY (amount green) — the current session's estimated cost only. - Clicking the button refreshes once; auto-refreshes at the configured interval;
refreshes on session switch.
Entry button (sidebar footer)
sidebar.footer.actionBalance button with horizontal right-side text:
"余额(110.00 CNY) 高峰时段" — the amount in parentheses right after the label,
then the period text. It shows 高峰时段 (red) or 空闲时段 半价 (green)
depending on the current time; the amount comes from the balance API.
Auto refresh
- A 定时更新 button (left of the Refresh button in the modal header) opens a
config dialog: set the interval (seconds) → Start/Stop. While running, the input
and the Start button are disabled; stopping re-enables them. - At each interval, balance & cost refresh automatically (the modal when open, the
header button otherwise). The interval is persisted to$DSH_HOME/settings.yaml(autoRefreshJson) and survives restarts.
Config / packaging
- Schemastery
Config+ a settings namespace (dsh-balance): extra keys,
price config and auto-refresh interval persist to$DSH_HOME/settings.yaml. dsh.bundle+dsh.client(web) manifests; the officialdeepseek-harnessproject is never modified — everything rides existing slots
and the HTTP / command channel.
Layout
├── src/host/*.ts # host half: index.ts, providers.ts (enum + official check),
│ # balance.ts, cost.ts (fold + today scan + period pricing +
│ # official filter), ops.ts, fence.ts, types.ts
├── src/client/* # browser half: plugin.tsx (slots + timer), BalanceModal.tsx,
│ # HeaderButton.tsx, FooterButton.tsx, rpc.ts, store.ts,
│ # i18n.ts, styles.ts, logo.ts
├── lib/index.js # host bundle (tsdown ESM), committed for git installs
├── lib/client.js # browser bundle (__ModuleLoader__ factory), committed
├── lib/types/ # declarations (tsc -b)
├── scripts/ # verify-client.mjs
├── tsdown.config.ts # tsdown config (host + client banner wrap)
├── tsconfig.json # solution: tsconfig.host.json / tsconfig.client.json
├── cordis.patch.yml # bundle patch
├── package.json # dsh.bundle + dsh.client(web) manifests + peerDependencies
├── README.md # this file (English, default)
└── README.zh-CN.md # 中文文档
Install
# local development
dsh plugin --profile web add ./dsh-balance-by-token
# published: npm / tarball / GitHub
dsh plugin --profile web add dsh-balance-by-token
dsh plugin --profile web add ./dsh-balance-by-token-0.1.0.tgz
dsh plugin --profile web add github:you/dsh-balance-by-token#<sha>
dsh --profile web --dump-config # inspect the plugin layer
dsh --profile web # start (host-half changes need a restart)
Local dev deps: the host loads
index.jsas native Node ESM, so@deepseek-ai/schemastery,@deepseek-ai/dsh-tools,@deepseek-ai/dsh-settings,@deepseek-ai/dsh-home-pathsmust resolve from
the plugin directory (runpnpm installthere;node_modulesis gitignored).
No static config required: extra keys, price config and the auto-refresh interval
are edited in the modal and persisted to $DSH_HOME/settings.yaml.
Release
Toolchain: tsc + tsdown (no vite): tsc -b type-checks and emits
declarations; tsdown (Rolldown core) bundles the host half
(lib/index.js, ESM) and the browser half (lib/client.js, single-file CJS__ModuleLoader__ factory). Dependency manager: pnpm 10.
pnpm install # per pnpm-lock.yaml
pnpm run build # clean lib → tsc -b (types + declarations) → tsdown (both halves)
pnpm run verify # simulate the host seed to validate lib/client.js (optional)
pnpm publish # or pnpm pack / git push origin main (lib/ committed → git installs need no build)
Auto publish (GitHub Actions)
Pushing a v* tag (pnpm run release bumps the patch version, rebuilds and
tags) triggers .github/workflows/publish.yml:
- release job: Setup Node →
pnpm install --frozen-lockfile→pnpm run check→pnpm run build→pnpm pack→ create GitHub Release; - publish-npm job: publish to npm — requires the
NPM_TOKENrepo secret.
Development
Requirements: Node ≥ 26 + pnpm 10 (pinned via the packageManager field).
pnpm install # devDependencies: typescript, tsdown, @types/react, @deepseek-ai/* type packages…
pnpm run check # full-tree TypeScript check (tsc -b)
pnpm run build # rebuild both bundles after source changes (tsc -b && tsdown)
pnpm run verify # validate lib/client.js against a simulated host seed
- Host half lives in
src/host/; browser half insrc/client/; - The
window.__ModuleLoader__.loadfactory wrap oflib/client.jsis generated
by tsdown's banner/intro/footer; external deps (reactetc.) resolve through the
host module table (seed) at runtime.
Implementation notes
- Browser ↔ host: HTTP route
/dsh-balance/api(POST JSON, hostwebServer+ trust fence) with actx.remote.commands.executefallback;
errors carry acodethat the client localizes. - Credentials: the
credentialsservice is looked up lazily per request
(not captured at apply time), avoiding a "no credential" state when the host
service starts late; the providers op returnscredentialsPresentand per-entrykeySourcediagnostics. - Pricing:
(uncachedInput × p_input + cacheRead × p_cacheRead + cacheWrite × p_cacheWrite + output × p_output) / 1e6per million tokens, priced
by each event's time (peak/off-peak). - Official filter:
request/contextprovider→ baseURL in host settings →
hostname ==api.deepseek.com; non-official tokens are counted only
(per-provider four buckets), never billed. - Today aggregation:
dshHomePath('sessions')/<projectKey>/<sessionId>/session.jsonl(.zstd),
decoded frame-wise viazstdDecompressSyncfromnode:zlib. - Peer deps (
@deepseek-ai/cordis, dsh-tools, schemastery, dsh-settings,
dsh-commands, dsh-session, dsh-api-remotes, client runtime / ui-slots /
ui-settings / cordis-client-runner,react) are resolved by the host at install. - The official
deepseek-harnessproject is never modified; everything uses
existing slots (sidebar.footer.action,shell.overlay,conversation.session.header.utilities) and the HTTP / command channel.
Install
Install the catalog once, then DeepSeek Harness can find and install any plugin from this site automatically:
dsh plugin add dshbase-catalog Then say "install dsh-balance-by-token for me" — your agent finds it in the directory and installs it. Docs: dshbase-catalog · verified packs.
This plugin is GitHub source (not published to npm) — install it straight from the repo:
Web profile:
dsh plugin --profile web add github:jsoncode/dsh-balance-by-token Headless (CLI) profile:
dsh plugin --profile headless add github:jsoncode/dsh-balance-by-token Test report
Verified: L1 install + L2 load + L3 runtime from GitHub source on dsh 0.1.0-rc.6.