dsh-webui-perf
awa-123-cw
DeepSeek Harness WebUI 性能优化开关插件:长代码流式渲染/历史加载/高亮缓存优化,设置面板一键开关(with official-package patches)
PROJECT TOPICS
PROJECT README
English | 中文
dsh-quota-panel is a provider quota / balance status widget for the
DeepSeek Harness (DSH) web surface (dsh web). It sits in the
bottom-right corner of the product UI, watches every AI provider whose API
key you have configured, and tells you at a glance how much balance /
quota is left — DeepSeek, OpenRouter, SiliconFlow, Moonshot, StepFun,
xAI, Zhipu GLM, OpenCode Go, plus one-api / new-api style aggregators,
and the coding plans (智谱 GLM Coding, Z.AI, Kimi Coding, MiniMax
Coding global/CN) with 5-hour / weekly usage windows and search quota.
Since v0.5 it is a dual-face plugin with a built-in provider catalog
and auto discovery: install it, restart dsh web, and every provider
whose key resolves automatically appears on the panel — zero configuration.
It needs no npm dependencies and asks for no allowBuilds authorization.
Collapsed capsule, light theme:

Expanded card, light theme:

Settings panel (⚙), light theme:

Collapsed capsule, dark theme:

Expanded card, dark theme:

Settings panel (⚙), dark theme:

$DSH_HOME/.credentials.yaml / .env / environment variables)
appears on the panel automatically, with zero config. Remove the key
and the row disappears. No credential enumeration API exists in DSH, so
the catalog is probed each refresh cycle.— instead of a fabricated 0%.● ¥58.36 · ● 45%); expanded: a
full card with a row per provider (status dot, name, primary value,
secondary info, progress bar for usage-kind providers).critical <= warn <= healthy), usage rows by percent
(error >= warn); the offending dot/value alone recolors, others stay
calm. Usage percentages use battery-style three-color grading, independent
of the status dots.openai-billing
format adapts aggregator dashboards.--dsw-alias-*, --dsw-static-*, --dsw-shadow-*,
--dsw-font-*) with sensible fallbacks, so it follows the product
theme (light/dark) and ships no palette of its own.arkcli CLI, or
chat-endpoint rate-limit probes (per
CodexBar research).
This plugin only speaks API keys, so those plans cannot be wired in
until an API-key endpoint appears.format value outside the built-in set fails loud at mount.shell.overlay
slot only (bottom-right corner), not in sidebars, headers, or the status
bar.Missing a provider? Open an issue with:
^[a-z0-9-]+$, e.g. together), using a
-cn suffix for the China site of a dual-site provider
(cf. siliconflow / siliconflow-cn);GET https://api.provider.com/v1/user/info, Bearer auth), plus the
response shape if you can paste it.That is all the catalog needs: an id whose standard credential reference resolves, an endpoint, and a format adapter for the response. Providers with only cookie/CLI quota pages (see above) cannot be supported until they expose an API-key endpoint.
┌─────────────── browser (lib/client.js) ───────────────┐
│ shell.overlay slot → capsule / card / settings panel │
│ localStorage: visibility · interval · thresholds · │
│ proxy URLs (frontend settings) │
└──────────────┬─────────────────────────────────────────┘
│ loopback-only Connection RPC: /dsh-quota-panel
│ specs (render hints, no credentials)
│ fetch-all { proxy: {rowId: url} } → normalized views
┌──────────────▼────────────── host (lib/index.js) ──────┐
│ ctx.credentials → API keys (never leave the host) │
│ catalog probe → auto discovery (14 built-in providers) │
│ per-row fetch → proxy engine (CONNECT tunnel / │
│ absolute-URI) → upstream JSON │
│ normalization → {balance | usage | info} view models │
└─────────────────────────────────────────────────────────┘
lib/index.js) registers one loopback-only Connection
RPC channel /dsh-quota-panel with two endpoints:specs — the resolved rows with render hints only (id, label, row
kind, currency, threshold tiers, window labels, configured proxy name).
No credentials, no endpoints.fetch-all — fetches every visible row, normalizes each upstream
response into a generic view model (balance / usage /
info), and returns {rows: [{id, view} | {id, error}], fetchedAt}.
Raw upstream JSON stays host-side like the keys; one failing row never
affects the others.providers).proxiedGetJson:
https targets go through an HTTP CONNECT tunnel (TLS over the
tunnel), http targets via absolute-URI forwarding. 15 s per-row timeout,
1 MB body cap. Proxy selection precedence:
frontend settings panel > profile config > direct.specs hints, so
local threshold overrides apply without refetching; profile thresholds
ship in specs and the frontend settings override them locally.Config schema (vendored
schemastery) declares structure and defaults; cross-field constraints (id
uniqueness, critical <= warn <= healthy, proxy references, catalog
override keys) are validated host-side at mount and fail loud.createElement/textContent; API values never touch innerHTML;
technical errors (401, timeout, missing credential, refused proxy) surface
only in title tooltips or inline row text.Out of the box: nothing. Install, restart, and any provider whose key resolves appears automatically. The table below is only for tuning.
All keys are optional — the structure and defaults live in the exported
Config schema, so profile patches may omit every defaulted field.
| Key | Meaning | Default |
|---|---|---|
auto |
probe the built-in catalog; providers with a resolvable key join the panel | true |
hide |
row ids to drop (catalog and explicit rows alike) | [] |
proxies |
named proxy definitions {<name>: "http://host:port"}, HTTP(S) only |
{} |
catalog |
partial overrides for auto-discovered rows {<catalog-id>: {...}} |
{} |
refreshMs |
auto-refresh interval | 60000 |
providers |
explicit rows; a same-id entry replaces the catalog row wholesale | [] |
Each catalog override may set: label / endpoint / format /
proxy / refs (credential references to probe, UPPER_SNAKE) / currency
(balance rows: symbol like $ or US$) / balanceTiers / warnPercent /
errorPercent / windowLabels.
Explicit providers fields:
| Field | Meaning | Default |
|---|---|---|
id |
row id (RPC rows align by id), ^[a-z0-9-]+$ |
required |
label |
provider name shown on the card | required |
credential |
credential reference ($DSH_HOME/.credentials.yaml or environment) |
required |
endpoint |
quota JSON endpoint; base URL for openai-billing |
required |
format |
row adapter (see table below) | deepseek-balance |
proxy |
a proxy name defined in proxies; absent = direct |
— |
currency |
(balance rows) currency symbol, overrides the format default | format default |
balanceTiers |
(balance rows) {critical, warn, healthy} |
{10, 20, 50} |
lowBalance |
legacy alias for balanceTiers.warn |
— |
windowLabels |
(usage-kind formats) labels for the usage windows | {滚, 周, 月} |
warnPercent / errorPercent |
(usage rows) thresholds | 70 / 90 |
| Provider | Credential refs probed | Endpoint | Row kind |
|---|---|---|---|
| DeepSeek | DEEPSEEK_API_KEY |
api.deepseek.com/user/balance |
¥ balance |
| OpenRouter | OPENROUTER_API_KEY |
openrouter.ai/api/v1/credits |
$ balance (purchased − used) |
| SiliconFlow (global) | SILICONFLOW_API_KEY |
api.siliconflow.com/v1/user/info |
$ balance |
| SiliconFlow (CN) | SILICONFLOW_CN_API_KEY |
api.siliconflow.cn/v1/user/info |
¥ balance |
| Moonshot / Kimi | MOONSHOT_API_KEY |
api.moonshot.cn/v1/users/me/balance |
¥ balance |
| MiniMax Coding (global) | MINIMAX_API_KEY |
www.minimax.io/v1/token_plan/remains |
5h prompt usage % |
| MiniMax Coding (CN) | MINIMAX_CN_API_KEY |
api.minimaxi.com/v1/token_plan/remains |
5h prompt usage % |
| StepFun | STEP_API_KEY / STEPFUN_API_KEY |
api.stepfun.com/v1/accounts |
¥ balance (hover: cash/voucher) |
| xAI | XAI_API_KEY |
api.x.ai/v1/billing/credits |
$ balance |
| Zhipu GLM | ZHIPU_API_KEY / GLM_API_KEY |
open.bigmodel.cn/api/monitor/usage/quota/limit |
text row (quota remaining/total; no public balance API) |
| 智谱 GLM Coding | ZAI_CODING_CN_API_KEY |
open.bigmodel.cn/api/monitor/usage/quota/limit |
coding-plan windows (5h tokens / weekly / searches) |
| Z.AI GLM Coding | ZAI_API_KEY |
api.z.ai/api/monitor/usage/quota/limit |
coding-plan windows (5h tokens / weekly / searches) |
| Kimi Coding | KIMI_API_KEY |
api.kimi.com/coding/v1/usages |
usage % (5h rate limit + weekly request pool) |
| OpenCode Go | OPENCODE_GO_API_KEY |
opencode.ai/zen/go/v1/usage |
three-window usage % |
An additional openai-billing format adapts one-api / new-api style
aggregators: set endpoint to the aggregator base URL and the host half
requests {base}/v1/dashboard/billing/subscription
(hard_limit_usd) plus {base}/v1/dashboard/billing/usage
(total_usage); remaining = limit − used ($). Aggregator domains differ
per deployment, so this format is explicit-config only.
Some providers run separate international and China sites with different
endpoints, credential references and currencies. The catalog models each
site as its own provider id, so configuring the matching key is all it
takes — and an explicit providers: entry reusing one of these ids replaces
the catalog row wholesale (same fields, your endpoint/label/currency):
| provider id | Site | Endpoint | Credential ref | Currency |
|---|---|---|---|---|
siliconflow |
SiliconFlow global | api.siliconflow.com/v1/user/info |
SILICONFLOW_API_KEY |
$ |
siliconflow-cn |
SiliconFlow China | api.siliconflow.cn/v1/user/info |
SILICONFLOW_CN_API_KEY |
¥ |
minimax |
MiniMax Coding global | www.minimax.io/v1/token_plan/remains |
MINIMAX_API_KEY |
— (usage %) |
minimax-cn |
MiniMax Coding China | api.minimaxi.com/v1/token_plan/remains |
MINIMAX_CN_API_KEY |
— (usage %) |
zai |
Z.AI GLM Coding global | api.z.ai/api/monitor/usage/quota/limit |
ZAI_API_KEY |
— (usage %) |
zai-coding-cn |
智谱 GLM Coding China | open.bigmodel.cn/api/monitor/usage/quota/limit |
ZAI_CODING_CN_API_KEY |
— (usage %) |
Both sites of one provider can be on the panel at the same time (configure
both keys); hide: ["siliconflow"] drops either row individually.
The currency symbol for balance-kind rows comes from the format by default
(siliconflow-balance renders ¥) and can be overridden per row: catalog
rows carry currency (the global SiliconFlow row sets $), a catalog:
override may set it, and explicit providers: entries accept a currency
field (e.g. "US$").
| format | Row kind | Upstream response shape |
|---|---|---|
deepseek-balance |
¥ balance | { balance_infos: [{ currency, total_balance, granted_balance, topped_up_balance }] } |
openrouter-credits |
$ balance | { data: { total_credits, total_usage } } |
siliconflow-balance |
balance (¥ by default, per-row currency override) | { data: { balance, chargeBalance, totalUsage } } |
moonshot-balance |
¥ balance | { data: { total_balance } } |
minimax-remains |
usage % | { base_resp, model_remains: [{ current_interval_total_count, current_interval_remaining_percent | …count aliases, end_time }] } (remaining → used %) |
stepfun-accounts |
¥ balance | { balance, total_cash_balance, total_voucher_balance } |
xai-credits |
$ balance | { total: { val } } (cents → dollars) |
openai-billing |
$ balance | aggregator dashboard/billing endpoints |
zhipu-quota |
text | { code: 200, data: { limits: [{ remaining, number }] } } (limits without remaining fall back to percentage) |
opencode-usage |
usage % | { usage: { rolling|weekly|monthly: { percent, resetsAt } } } |
zai-coding-quota |
usage % | { code: 200, data: { limits: [{ type: TOKENS_LIMIT \| TIME_LIMIT, unit, number, percentage, currentValue, usage, nextResetTime }] } } — shortest TOKENS_LIMIT → 5h window, longest → weekly, TIME_LIMIT → search lane |
kimi-coding-usage |
usage % | { usage: { limit, used, resetTime }, limits: [{ window, detail: { limit, used, resetTime } }] } — weekly pool + first 5h window |
Configure per-provider proxies in the frontend settings panel (⚙ →
代理): fill an HTTP(S) proxy URL (e.g. http://127.0.0.1:7890,
user:pass allowed), saved to browser localStorage, effective immediately —
leave it empty to fall back to the profile config or a direct connection.
Requests still run host-side: the browser sends each row's proxy URL in the
fetch-all payload, the host validates it (http/https only, socks
rejected) and fetches through it — keys still never leave the host.
The profile proxies map + row-level proxy /
catalog.<id>.proxy remain available as default proxies (used when
the frontend field is empty). Precedence:
frontend settings > profile config > direct.
# example profile-level default proxy (the ⚙ panel can override per row)
- id: quota-panel
name: 'dsh-quota-panel'
config:
proxies:
home: http://127.0.0.1:7890 # local proxy http port (clash / v2rayN …)
catalog:
openrouter:
proxy: home # OpenRouter via proxy by default
providers:
- id: my-agg
label: My aggregator
credential: AGG_API_KEY
endpoint: https://agg.example # base URL for openai-billing
format: openai-billing
proxy: home
DeepSeek balance (balanceTiers {critical: 10, warn: 20, healthy: 50}):
| Balance | Status | Secondary info |
|---|---|---|
<= 10 |
error (red dot + red value) | 建议充值 |
10 < x <= 20 |
warn (amber) | 余额紧张 |
20 < x <= 50 |
ok | 余额正常 |
> 50 |
ok | 余额充足 |
OpenCode usage (high = max(rolling, weekly, monthly)):
| Usage | Status |
|---|---|
< warnPercent |
ok (green dot, DeepSeek-blue bar) |
>= warnPercent |
warn (amber dot + bar) |
>= errorPercent |
error (red dot + bar) |
Install a released version — not the main branch. main receives
unverified work-in-progress; only tagged releases have passed the CI gates
(check + boot) and — for stable versions — the human approval gate.
Recommended — the latest stable release (or the latest pre-release for the current iteration cycle):
# Pin the latest stable release tag (checked on the Releases page)
dsh plugin --profile web add "github:wenzetan/dsh-quota-panel#v0.8.0"
# Or, once the repo secret NPM_TOKEN is configured (see below), by name —
# npm `latest` always resolves to the last human-approved stable:
dsh plugin --profile web add dsh-quota-panel
# Restart `dsh web` (bundle layer and client module graph apply at boot)
When you want the latest pre-release (e.g. testing the current
0.8.0-rc.N iteration):
# Pin the pre-release tag
dsh plugin --profile web add "github:wenzetan/dsh-quota-panel#v0.8.0-rc.1"
# Or from npm under the `next` dist-tag:
dsh plugin --profile web add dsh-quota-panel@next
Avoid bare
github:wenzetan/dsh-quota-panel(no#tag) — it tracksmainHEAD, which is the testing branch: it may carry unreleased work, fail CI, or break. Only developers iterating on the plugin itself should install frommain.
Refresh the browser page once after installing. Zero npm dependencies (the
schema library — schemastery + cosmokit, both MIT — is vendored under
src/vendor/ with relative-path imports), no allowBuilds authorization
needed.
Versioning policy — the version string picks the channel:
| package.json version | Channel | Gate | GitHub Release | npm dist-tag |
|---|---|---|---|---|
0.8.0-rc.1 (any -suffix) |
pre-release | CI only (check + boot) | flagged pre-release | next |
0.8.0 (plain X.Y.Z) |
stable | CI + human approval | normal release | latest |
Workflow:
0.8.0-rc.1 and push main. CI runs
the full gates, auto-tags v0.8.0-rc.1 and publishes the
pre-release (fast lane, no approval). A pre-release is published under
the npm next dist-tag and can never own latest — a reclaim step
re-claims latest to the newest stable if npm ever pointed it at a
prerelease — so dsh plugin add dsh-quota-panel keeps resolving to the
last verified stable.dsh plugin --profile web add "github:wenzetan/dsh-quota-panel#v0.8.0-rc.1", or
dsh-quota-panel@0.8.0-rc.1 from npm) and test it for real.rc_tag input set to the green pre-release tag (e.g.
v0.8.0-rc.1). The promote job verifies that tag's CI run passed on
exactly that commit, creates the stable twin v0.8.0 on the same
commit and dispatches the release run. The stable release job then
waits in the production environment for a human approval before
creating the GitHub Release and publishing to npm latest.One-time setup:
dsh-quota-panel (name free as of this writing) and add it as
the repository secret NPM_TOKEN (Settings → Secrets and variables →
Actions). Without it, GitHub Releases still ship; npm steps are skipped.production → Required reviewers → add yourself. This is what makes
"no stable release without human confirmation" enforced rather than
conventional. (Without the reviewer configured, the stable channel
publishes without pausing — same as before.)The package declares dsh.bundle.patch (host half auto-activates as a
profile layer) and the dsh.client manifest (browser half auto-joins the
__DSH_BOOT__ module graph, immediately: true prefetched with the shell).
This plugin builds on community work — thanks to:
token_plan/remains response quirks and the
Kimi Code usage endpoint.src/vendor/.next
with a latest reclaim guard; stable versions require the manual
rc_tag promote workflow.cordis.patch.yml no longer
ships explicit example rows (deepseek / opencode-go), so the settings
panel lists exactly the providers whose credential resolves (auto
discovery). The CI boot gate now asserts both directions: the seeded key
appears, and unconfigured providers do not.locale.preference; zh / en) through the
ctx.locale service — all copy (capsule, card, settings panel, errors,
aria labels, usage windows) ships as zh/en dictionaries registered under
the quota-panel namespace; provider labels are proper nouns kept as-is
(GLM, MiniMax, Kimi Coding…) with Chinese brand names romanized
(智谱 → ZhiPu); host catalog labels normalized accordingly
(SiliconFlow CN, MiniMax Coding CN, ZhiPu GLM). Also: usage reset times
now show absolute 24h timestamps (下次重置 2026-08-15 14:00, dictionary
key nextReset); usage rows drop the weekly segment when the plan has no
weekly window and render the search/MCP lane as -% when it is unknown
(no fabricated 0%); the usage caption reads 当前已使用 X%.siliconflow now maps to the
global site (api.siliconflow.com, $), new id siliconflow-cn maps to
the China site (api.siliconflow.cn, ¥, ref SILICONFLOW_CN_API_KEY);
balance rows gained a per-row currency override (catalog rows, catalog:
overrides, and explicit providers: entries); README documents the
dual-site provider id → endpoint/currency mapping.src/*.ts compiled into lib/
by npm run build (tsc + vendored runtime copy), committed artifacts
verified current by CI; new dsh-plugin-check CI gate (any error or warning
fails — currently verdict=pass, 0 error / 0 warning); CI check job now
installs dev dependencies and builds before testing.ZAI_CODING_CN_API_KEY), Z.AI GLM Coding (ZAI_API_KEY), Kimi Coding
(KIMI_API_KEY), MiniMax Coding global/CN (MINIMAX_API_KEY /
MINIMAX_CN_API_KEY); new zai-coding-quota (5h/weekly token windows +
search lane) and kimi-coding-usage (5h + weekly request pool)
adapters; minimax-remains rewritten for the real model_remains
response (now a usage row); zhipu-quota shows percentage when a
limit carries no remaining; usage rows render missing windows as
— (labels from windowLabels, no longer hardcoded rolling/weekly/
monthly).openai-billing); fetch-all
contract switched to host-side normalized views (balance / usage / info),
upstream JSON no longer shipped; per-row HTTP(S) proxy (CONNECT tunnel /
absolute URI, zero-dependency), configured in the ⚙ settings panel
(localStorage, takes precedence over profile proxies / proxy);
new auto / hide / proxies / catalog config keys.specs / fetch-all) + Config schema; browser half
moved into the dsh.client manifest + shell.overlay slot (React);
added the ⚙ settings panel (visibility / refresh interval / thresholds,
localStorage-persisted).ctx.credentials and used only for
host-side requests to providers; the browser talks exclusively over the
loopback RPC channel /dsh-quota-panel, the specs endpoint ships
render hints only (labels/kinds/thresholds) with no credential or
endpoint; since v0.5 fetch-all ships normalized views only — raw
upstream JSON stays host-side too.createElement/textContent;
API values never touch innerHTML; technical errors (401, timeout,
missing credential, refused proxy) surface only in title tooltips or
inline row text, and one failing row never affects the others.# Sources live in src/*.ts (org tool-bundle template): tsc compiles them
# into lib/ (declarations included) and scripts/build.mjs copies the
# vendored schema runtime into lib/vendor/. devDependencies are build-only
# — runtime stays zero-dependency.
npm install
npm run build
# After editing src/, rebuild and COMMIT lib/ — github: installs run from
# the committed artifacts (CI's "Committed artifacts are current" step
# rejects a stale lib/).
# Dual-face check: host RPC contract + catalog discovery/proxy engine
# (exercised against real local servers) + client slot/settings surfaces
node scripts/test-page-script.mjs
# Health check with @deepseek-ai/dsh-plugin-check (same gate as CI; fails
# on any error or warning). One-off deps dir, then the gate script:
mkdir -p /tmp/pc-deps && cd /tmp/pc-deps && npm init -y >/dev/null
npm install --no-audit --no-fund --ignore-scripts \
github:omdsh-dev/dsh-plugin-check \
@deepseek-ai/dsh-tools @deepseek-ai/dsh-invariants @deepseek-ai/cordis
cd /path/to/dsh-quota-panel
PLUGIN_CHECK_DEPS=/tmp/pc-deps node scripts/plugin-check.mjs .
# To upgrade the vendored schema library: replace the two runtime files
# under src/vendor/ and rewrite the cosmokit import on line 1 of
# schemastery.mjs to "./cosmokit.js", then rebuild.
MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。