Jovan1666/dsh-commandcode-quota ↗★ 4

dsh-commandcode-quota

Command Code plan quota panel for DeepSeek Harness: monthly / 5-hour / weekly credit windows with reset countdowns, above the sidebar Settings seat. 适合Command Code用户,需要实时查看多窗口信用额度及重置倒计时。

패키지
dsh-commandcode-quota
호환성
미검증
버전
0.1.0
라이선스
MIT
최근 업데이트
2026. 9. 26.

같은 패키지 이름의 다른 저장소

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Jovan1666/dsh-commandcode-quota

Command Code quota for DeepSeek Harness

Your 5-hour, weekly and monthly credit windows, in the sidebar — right above Settings.

No browser tab, no login, no guessing how much of the plan is left.

Check License: MIT DeepSeek Harness dsh PRs welcome

The quota card in the sidebar: light rail, light expanded, dark expanded


What you get

Three windows, one glance5-hour, weekly and monthly, shortest first — so the tightest limit is where your eye lands
Percentage firstThe headline rounds to a whole percent, exactly like the Command Code dashboard, so the card and the website never disagree
Money where it mattersUsed and remaining for the monthly allowance; exact figures for every row on hover
Instant, then liveThe card is on screen about 2 ms after a restart, and live about a second later
Quiet when it should beNo Command Code account? The card does not render at all
BilingualThe card follows your DSH interface language (中文 / English)

Everything is read from your own account's data — window count, caps and percentages come from the API, never assumed. GOAT, Pro, Provider, Max and Teams work; a plan that reports no rolling windows simply renders no rows. (The $1 Go tier is the exception — it has no API access, so the card has nothing to render there.)

Check your dsh version first

This plugin needs dsh ^0.1.5-rc.1. On anything older it crashes at startup:

Error: failed to apply loader entry commandcode-quota:
Cannot read properties of undefined (reading 'register')

The ctx.connection.fetch seam it relies on does not exist in older releases. Check before you install:

dsh --version          # needs 0.1.5-rc.1 or newer
npm i -g @deepseek-ai/dsh@latest

Note that the plugin's 146 offline checks also pass on an older dsh — they never start dsh. So "the checks are green" does not mean it will work once installed.

Install

dsh plugin --profile web add github:Jovan1666/dsh-commandcode-quota

Then restart dsh web and reload the browser page. That is the whole setup — no configuration file, no API key to paste: if Command Code is already a provider in your DSH settings, the plugin finds it.

The package declares a bundle patch (dsh.bundle.patch → its cordis.patch.yml), so dsh plugin add registers the plugin row for you. Do not also append that row to your profile's cordis.patch.yml. Two layers inserting the same loader id make dsh refuse to start: duplicate loader entry id: commandcode-quota. The row belongs to the manual install below, where no bundle layer exists.

Other ways to install, and how to remove it

From a local clone

git clone https://github.com/Jovan1666/dsh-commandcode-quota
dsh plugin --profile web add ./dsh-commandcode-quota

Manually, without pnpm — link the folder into the profile's node_modules, then register the row yourself, since nothing else will:

# $DSH_HOME/profiles/web/cordis.patch.yml
- insert:
    - id: commandcode-quota
      name: "dsh-commandcode-quota"

A freshly created profile ends that file with []. Replace the [] — appending a sequence under it is not valid YAML, and the profile will not load.

# macOS / Linux  ($DSH_HOME defaults to $HOME/.dsh)
ln -s "$PWD/dsh-commandcode-quota" "${DSH_HOME:-$HOME/.dsh}/profiles/web/node_modules/dsh-commandcode-quota"
# Windows  ($env:DSH_HOME defaults to $env:USERPROFILE\.dsh)
$dsh = if ($env:DSH_HOME) { $env:DSH_HOME } else { "$env:USERPROFILE\.dsh" }
New-Item -ItemType Junction -Path "$dsh\profiles\web\node_modules\dsh-commandcode-quota" -Target "$PWD\dsh-commandcode-quota"

To remove it: dsh plugin --profile web remove dsh-commandcode-quota drops the package and the bundle layer that registers it; a manual install instead deletes the cordis.patch.yml row. Restart dsh web either way. To clear the cached snapshot too, delete $DSH_HOME/dsh-commandcode-quota/.

Why it appears before you look

The card used to wait out a full upstream round trip before drawing anything, and a restarted dsh has nothing cached — which is exactly the "it takes a moment to show up" feeling. Measured against the live API with node preview/latency.mjs:

First answer after a restart, snapshot on disk~2 ms
First answer after a restart, no snapshot yet~1.4 s
The four endpoints requested one after another~2.3 s
The four endpoints requested together~1.2 s

Two things make the difference:

  1. All four endpoints are requested at once. whoami used to be awaited on its own — about 590 ms of pure waiting, to learn an org id that personal accounts never report.
  2. The last good report is kept on disk. A cold start answers with it immediately — dimmed, and labelled with how old it is — while a live read runs behind it. The card re-asks 3 seconds later instead of waiting out the usual minute, so the numbers are live by the time you have read them.

How to read the card

WindowWhat it meansOn GOAT
5-hourRolling burst limit — one long session cannot drain the month$14
WeeklyRolling 7-day limit$35
MonthlyThe billing period's credit allowance$70

Each row shows the used percentage (green below 60 %, amber below 85 %, red above), a meter in the same colour, and a reset countdown (59m, 6d9h, 8d1h). Click the card for the monthly allowance in money, the remaining credit, the request count and the token totals. Collapse the sidebar and the card becomes a 36 px badge showing the most constrained window.

Reading the numbers

  • Percentages are used ÷ (used + remaining), read live from the API. preview/e2e-live.mjs asserts that identity against a real account on demand.
  • The headline rounds to a whole percent, the same way the dashboard does. That is why the website can say 100% while the exact share is 99.84% — same data, two roundings. The exact figure and the money are one hover away.
  • The monthly cap is the sum of two figures from two different endpoints. Across a billing-period rollover or a plan change those two can describe different periods, and the sum would look plausible while being wrong by tens of percent. The plan's nominal allowance is the sanity check; when a read fails it, the host reports no percentage at all and the card says why. The next refresh corrects it.

What the card deliberately leaves out

The sidebar is about 200 px of content width, and a laptop screen makes small type smaller still. So the card answers one question well — how deep am I? — instead of laying out everything the API returns:

  • Money only for the monthly allowance. The 5-hour and weekly windows are pass/fail gates, not budgets; their dollar rows told a user nothing they could act on. Hover still shows exact figures.
  • No pace verdict, no burn-rate forecast. "Over pace" cannot be acted on by someone who has work to do, and a projected exhaustion date assumes a constant burn rate that credit usage never has. The host still exposes projection in its JSON for scripts.
  • Nothing silent. A row that disappears because its endpoint failed says so; a failure with nothing to fall back on says what went wrong in one readable line, with the full diagnostic text on hover.

The /quota command

Type /quota in a conversation to print the same report as text:

Command Code · GOAT (active)
5-hour 1.4% used · resets in 3h17m
Weekly 12.8% used · resets in 6d7h
Monthly 99.8% used · $70.11 / $70.23 · $0.11 left · resets in 7d22h
18,087 requests · 100% success · in 3.49B / out 16.77M

It reads the same cached report the card does, so a slash invocation costs no extra upstream requests — and unlike the card, it never answers from a stale snapshot: typing a command means asking for the current numbers. Its text is English; the card is the bilingual surface.

Requirements

  • DeepSeek Harness ^0.1.5-rc.1. The plugin uses framework seams that are not a stable public API yet; see Compatibility.
  • The web profile. The card mounts into the browser sidebar through the connection service, which only the web app composes — a headless or CLI profile has nowhere to put it.
  • A Command Code account with API access. Every plan except the $1 Go tier includes it; see Getting a Command Code plan.
  • Node.js 18+ — only for the optional CLI and the development scripts.

Getting a Command Code plan

The card reads any Command Code plan that has API access. This plugin was built against GOAT: $10/month, which buys $70 of credits, gated at $14 per 5-hour window and $35 per rolling week.

GOAT is the tier that suits an agent harness. Command Code's own estimate for DeepSeek V4 Flash on that allowance is ~154,000 requests a month (~30,800 per 5-hour window, ~76,900 per week), because flash-tier models bill at roughly $0.15 input / $0.60 output per million tokens with cache reads at $0.003. A coding agent spends its budget on exactly those calls: many small turns, most of the context re-read from cache. Tens of thousands of tool-calling turns a month is ordinary work, and at that price the window caps and the monthly allowance are what run out — not the request count.

Two caveats on those numbers, both from the same page: the request counts assume a typical agent turn of ~800 fresh input tokens, ~50,000 cache-read tokens and 125–200 output tokens, so a run that carries a large repo context drains the allowance faster; and DeepSeek is billed by time of day, with peak hours priced higher (01:00–04:00 and 06:00–10:00 UTC, Mon–Fri). Command Code states that allowances can change at any time — the pricing page is authoritative, and the figures above are what it said on 2026-09-19.

Subscribing

  1. Sign in at commandcode.ai and open Pricing, or Studio → Billing.

  2. Choose GOAT and check out. Card payments run through Stripe; Alipay is supported on the USD-denominated plans and sets up automatic renewal, which is worth knowing before the first invoice. UnionPay is not listed.

  3. In Studio, open API keys → Generate. The key looks like user_…, not sk-….

  4. Hand it to dsh. Settings → Models takes a provider interactively; by file, add a route to $DSH_HOME/settings.yaml:

    llm-pi-ai:
      providers:
        command-code-goat:
          apiKeyEnv: COMMAND_CODE_GOAT_API_KEY
          api: openai-completions
          baseURL: https://api.commandcode.ai/provider/v1
          models:
            - id: deepseek/deepseek-v4.1-flash
              contextWindow: 1000000
              input: ["text", "image"]
    

    Keep the key itself out of the file: put it in the environment, or in $DSH_HOME/.credentials.yaml under refs.COMMAND_CODE_GOAT_API_KEY. Nothing else is needed — Credentials is how the card finds this same route, which is why installing the plugin never asks for a key.

Before you subscribe

  • Go ($1) has no API access. All four quota endpoints answer 404, which the plugin reports as "this plan has no API access" rather than as an error it can retry.
  • The 5-hour and weekly windows start at your first request, not at a calendar boundary, and switching plans clears both of them. The card shows the reset times the API reports instead of computing them from a period start.
  • One account per person. The terms forbid sharing, reselling, or rotating keys across accounts, and a violation puts every account involved at risk of a permanent ban.
  • Other tiers, same card. $20 Pro ($80 of credits) is the same shape with more headroom and $100 / $200 Max scale it again. The $15 Provider plan is metered API access with no rolling windows, so the card shows the balance and no window rows.

Credentials

The API key never reaches the browser. The host resolves it in this order and reports which source won:

  1. An explicitly passed key (the CLI's --key).
  2. Discovered from your own $DSH_HOME/settings.yaml — any provider route whose baseURL points at commandcode.ai. The plugin reads that route's literal apiKey or its apiKeyEnv, then resolves the name through the environment and $DSH_HOME/.credentials.yaml. The provider's host is kept (a staging host or proxy works), but only its origin: the quota endpoints live at the host root, not under the provider's /provider/v1 path.
  3. Environment variables: COMMANDCODE_API_KEY, COMMAND_CODE_API_KEY, CMD_API_KEY, then any variable whose name contains commandcode.
  4. Those same names inside $DSH_HOME/.credentials.yaml (refs.).
  5. ~/.commandcode/auth.json, the official command-code CLI's login state.

Step 2 is what makes this work for other people: it follows your provider configuration instead of hardcoding one naming convention.

How it works — endpoints, seams, and the one that bit us

flowchart LR
  A["Sidebar card
(browser half)"] -->|"POST /api/cc-quota/report
same origin, session cookie"| B["Host half
(15 s cache + disk snapshot)"]
  B -->|"four read-only GETs, in parallel"| C["Command Code API
/alpha/*"]
EndpointUsed for
/alpha/whoamiAccount name, org id
/alpha/usage/summaryCredits used this period, requests, success rate, tokens
/alpha/billing/creditsRemaining credits, the 5-hour and weekly windows
/alpha/billing/subscriptionsPlan id, status, billing-period start and end

Each endpoint degrades on its own: one failure is recorded in the report's failures, is shown on the card as a muted line, and the rest still render. All four failing raises one error with the most specific code — including "this plan has no API access" when all four answer 404.

Compatibility

The plugin depends on framework seams that are not a stable public API yet. Each is pinned to what dsh 0.1.5-rc.1 actually exposes:

SeamUsed for
sidebar.footer.action slotThe seat above Settings, in both sidebar widths
ctx.slots.register({ name, id, order, inject }, Component)Contributing the card
ctx.connection.rpc.call(channel, endpoint, payload, signal)The browser side of the request
ctx.connection.fetch.register({ path, methods, requestBody, fetch })The host side of the route
ctx.get('commands') + commands.register({ name, description, handler })The optional /quota command
dsh.client manifest + exports["./client"]Client-bundle discovery, served at /plugins//client.js

Why an exact Fetch route instead of connection.rpc.handle? rpc.handle mounts its channel through owner.webServer, where owner is the Connection service's own context — which never injects webServer. Calling it from any other plugin throws cannot get property "webServer" without inject, whatever the caller injects. connection.fetch.register only writes the route table, works from any plugin fiber, a