Skip to content

About

DeepSeek balance and OpenCode Go usage (5-hour / weekly / monthly) merged into one floating pill, with a matching settings page

Topics

Resources

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Repository files navigation

OCG Usage icon

OCG Usage

DeepSeek balance and OpenCode Go usage (5-hour / weekly / monthly) merged into one floating pill, with a matching settings page

English 简体中文

CI CodeQL License: MIT version npm downloads

Listed on dsh-plugin.org dsh.so install · dsh 0.2.2-rc.1 Awesome DSH Plugin

Changelog · Feedback


An unofficial DeepSeek Harness plugin that shows your DeepSeek balance and OpenCode Go usage (Rolling / weekly / monthly) in one floating pill, with click-to-refresh, border-flash feedback, drag-to-snap and a hover popover, plus a full-page settings view of its own.

Contents

Features

The pill and the hover popover

  • OpenCode Go quota amounts + DeepSeek balance display:

    • The balance area on the pill's left can show either the DeepSeek balance or the OCG quota remaining worked out from a reference model;
    • the OCG model list and quota are fetched automatically, falling back to the bundled model table and quota data when the fetch fails.
  • Three rings show each window's usage:

    • OpenCode Go's three windows are drawn as ring progress indicators, and clicking the pill refreshes them;
    • the number in each ring's centre is a percentage (Used by default, switchable to Left in settings): > 20% left normal / ≤ 20% warning / ≤ 5% danger (all three tiers are customisable on the “Colour settings” tab).
  • Hover popover:

    • hovering the pill opens a panel with three separate usage bars showing the percentage and the reset time;
    • it can also show both balances at once (DeepSeek account balance and OpenCode Go quota left — either can be switched off on the “Floating pill” tab), plus this cycle's projected usage chart (also switchable on that tab).
  • Projected usage chart:

    • one chart sits under the three bars on the Usage data tab, and another inside the hover popover: it extrapolates this cycle's used percentage ÷ elapsed fraction at a constant rate to predict where usage will land by the renewal date;
    • the Y axis is fixed at 0–100% with dashed 50% / 100% lines; the real segment is solid and the projection dashed (same colour, following the Normal tier); when usage is on pace to exceed 100% the line stops at the 100% line and the chart labels the exhaustion date above it;
    • the settings-page chart supports per-day hover (projected usage and daily average); the compact popover chart deliberately has no hover so popovers never stack;
    • the renewal date comes straight from the OpenCode Go API's monthly.resetsAt (the same date the official console shows as “Renews …”), so nothing has to be typed in.
  • OCG quota conversion:

    • pick a reference model on the settings page (DeepSeek V4.1 Flash by default; any official OpenCode Go model is available) and the plugin works out the used / remaining amount from “that model's Go-tier monthly quota × this month's used percentage”, shown both in settings and in the hover popover;
    • free models read “Free”, unlimited ones “Unlimited”, and the remaining quota and similar figures all show -- .
  • Amount currency:

    • every amount (the DS balance and the OCG quota) can be priced in ¥ CNY / $ USD / auto (¥ in the Chinese UI, $ in the English UI);
    • the rate is fetched automatically, falls back to a bundled rate, and conversion only affects the display.
  • Minimal mode:

    • Ring data mapping: each of the outer / middle / inner rings can show "5 hours / Weekly / Monthly", with a live preview on the right (minimal mode only);
    • three nested rings (R inner / W middle / M outer) with the balance rounded to whole units shown beside them — a more compact pill (the normal mode is “balance + three separate rings”);
    • turning “show a balance on the pill's left” off as well gives the most compact form: nested rings only, taking up the least space.
  • Other details: The popover is interactive: moving the pointer from the pill onto the popover keeps it open (a 220 ms grace period covers the gap between the two), clicking the popover behaves exactly like clicking the pill (a manual refresh), and its border flashes in sync with the pill; The popover picks its direction: it opens upwards near the bottom of the window and inwards near the left/right edges, so it is never clipped; Drag to snap: on release the position is recorded against the window edges only (so it no longer drifts when the composer card changes size), with 0.1px precision, and the pill keeps its relative position when the window resizes;

    • Fixed size: the pill never changes size in any state (the feedback layer is an absolutely positioned overlay that does not participate in layout).

Optional sidebar entry: a "Sidebar entry" switch in settings (off by default). When enabled the plugin gets a sidebar row that opens its settings page as a full page (the very same UI), with the settings-menu mark as its icon;

General

  • Zero dependencies: plain JavaScript — no build step, no third-party runtime dependencies (only require('react'), provided by the host).
  • Bilingual UI: every interface string goes through the client locale dictionaries and follows the DSH language setting instantly (pill, settings page, menu label and all action messages).

Installation

Requirements: DeepSeek Harness desktop (the app bundles node / pnpm — nothing else to install). This plugin follows the official DSH plugin conventions: you do not hand-edit the profile's package.json / cordis.patch.yml, and you should not run pnpm inside the profile directory.

In DSH, open the plugin manager → “Install plugin” dialog → paste one of the specs below → install (the dialog drives pnpm and installs one spec at a time):

Method Spec to paste
Straight from GitHub (recommended) github:verneuil/dsh-opencode-go-usage
From npm dsh plugin --profile web add @verneuil/dsh-opencode-go-usage
Pin a version github:verneuil/dsh-opencode-go-usage#v3.6.0 (replace with any published tag)
Release tarball https://github.com/verneuil/dsh-opencode-go-usage/releases/download/v3.6.0/dsh-opencode-go-usage-3.5.0.tgz
Release URL (always latest) https://github.com/verneuil/dsh-opencode-go-usage/releases/latest/download/dsh-opencode-go-usage.tgz
Offline tgz file:D:/your/path/dsh-opencode-go-usage-3.5.0.tgz

The equivalent command line (dsh plugin automatically adds dependencies that declare dsh.bundle to the profile's bundles — no hand-written patch needed):

dsh plugin --profile web add github:verneuil/dsh-opencode-go-usage

Follow the on-screen prompt to reload afterwards (replacing an installed JavaScript module generation requires restarting DSH).

  • Bundle-only installs: the plugin manager rejects dependencies without a bundle patch; this package ships its own cordis.patch.yml, so it qualifies.
  • Upgrading = uninstall then reinstall: the plugin manager offers no version picker and no upgrade button. Uninstalling removes the dependency record and reinstalling resolves it afresh, so that is how you get a new version; installing the same spec over the top will not pick up a new commit.
  • Every version's changes are listed in CHANGELOG.md (Chinese and English).

Compatibility

  • Host version gate: the package declares engines.dsh: ">=0.1.7". DSH evaluates it with semver.satisfies(..., { includePrerelease: true }), so every rc / alpha from 0.1.7 on matches — no plugin change is needed for each new host version.

  • Tested: dsh 0.2.1-rc.3 and dsh 0.2.1-rc.5 (isolated profile cold boot plus a headless-browser smoke, both green).

  • If the host refuses to load the plugin (narrowed range or a mismatched ledger): grant an exact exemption in the profile's compatibility.json instead of changing the plugin:

    { "@verneuil/dsh-opencode-go-usage@3.5.0": ["0.2.1-rc.5"] }

    The file lives at ~/.dsh/profiles/<profile>/compatibility.json (desktop: %DSH_HOME%\profiles\<profile>\compatibility.json).

  • After a DSH upgrade, if the pill or settings page misbehaves, check the boot log for plugin tree failed to load first, then compare against CHANGELOG.md.

Usage

  • Click the pill = refresh the balance, the usage, the model list and the exchange rate immediately (or just wait for the automatic refresh).
  • Drag the pill = move it; it snaps on release. The “Reset position” button restores the default position (top-left of the window).
  • The balance line on the pill's left = pick one in settings: DS balance / OCG quota left (see Settings page).
  • Settings page = Settings → Plugins → OCG Usage.

Settings page

The settings page has four tabs: Usage data (default) / Floating pill / Colour settings / General settings.

Next to the page title sit the GitHub icon and the current version (e.g. v3.6.0); clicking the icon opens this repository.

Usage data

  • Quota reference model: a dropdown listing every official OpenCode Go model (default DeepSeek V4.1 Flash); the note beneath shows the model-table update time and the result of this refresh.
  • Amount display currency: a three-way choice — Auto / ¥ CNY / $ USD; the note beneath shows the current rate, when it was fetched and the refresh result.
  • Plan quota: Model: X (total: Z, used: Y, left: W); the amounts come from the reference model's Go-tier monthly quota × this month's used percentage.
  • Usage details: a progress bar, the percentage (basis is selectable), reset countdown and API status for each of the three windows.
  • Projected usage chart: inside the usage card, under the three bars — the projected usage chart (solid real segment / dashed projection, dashed 50% and 100% lines, renewal date; hovering the projected segment shows per-day estimates and the daily average).
  • Progress basis (top-right of the usage card): Used / Left — right next to it sits the OpenCode icon, which opens the OpenCode account page. The pill and the settings rows follow the same basis; defaults to Used.
  • Two rows below the card:
    • manual refresh + last-updated time (after a successful refresh it shows “Updated (time)” and falls back to “Last updated: …” after 3 seconds);
    • the auto-refresh interval (set a number of minutes and save; range 0.5 – 1440).
  • Failures name the source: whenever a fetch fails, the error line appears left of the manual refresh button (and at the very bottom of the hover popover), stating whether OCG usage / DeepSeek balance / the rate / the model table and quota failed.

Floating pill

  • Pill master switch: turning it off greys out the rows below and makes them non-interactive.
  • Pill size: a slider with eight stops where only the “Default 100%” stop carries a label — two stops to the left (−10%, −20%) and five to the right (+15%, +30%, +50%, +75%, +100%), i.e. 80% – 200%; the balance, the rings and the hover popover scale together and anchor-based positioning keeps working.
  • Show a balance on the pill's left (switch): shows one balance line on the pill's left; turning it off also collapses the row below.
  • Pill left-side balance data (two-way): DS balance / OCG quota left — which data that left line uses.
  • Hover popover data control (checkbox dropdown): DS balance / OCG quota left / Projected usage — tick any combination, or none at all (the popover then keeps only the three progress bars); clicking outside the dropdown closes it. Turning the chart off leaves no divider behind.
  • Minimal mode (switch): nested rings (outer / middle / inner) with the rounded balance shown beside them.
  • Ring data mapping (only available in minimal mode): choose which of “5 hours / Weekly / Monthly” each of the outer / middle / inner rings shows, with a live preview on the right (the three segmented controls are labelled Outer / Middle / Inner).
  • Reset the pill position: back to the default position (top-left of the window).

Colour settings

  • Unified colour (switch, on by default): one set of three tiers — normal / warning / danger — paints both the ring progress (the pill's rings, nesting included) and the bar progress (the hover popover, the three bars on the Usage data tab, and the real segment of the projected usage chart); turn it off to get separate Ring progress colour / Bar progress & chart colour rows, each with its own three tiers.
  • Picking a colour: each row shows three dots labelled Normal / Warning / Danger; clicking a dot opens the system colour picker (eyedropper plus RGB / HSL / HEX inputs). Changes apply live and are saved when the picker closes — no save button. Defaults are the theme green / amber / red.
  • Colour actions: Restore default colours resets all three tiers × both places to the theme defaults; Follow host colours switches the normal tier to the host accent (warning / danger keep their defaults) and tracks the theme live — picking a normal colour by hand stops following automatically.
  • Colour preview: shows minimal mode / regular pill / bar progress / projected usage chart with their horizontal centre lines aligned, updating live and without any amounts; each of the four previews shows all three tiers at once (demo data maps 5 hours = danger, weekly = warning, monthly = normal) and the numbers follow the Used / Left basis (used 96 / 88 / 42 ↔ left 4 / 12 / 58). The Ring data mapping preview and the real chart use the same colours as the pill and popover.

General settings

  • API Key section: overrides for both keys (leave empty to use the DSH credential store; clear them at any time to go back to automatic).
  • Settings section:
    • Sidebar entry (switch): when enabled the DSH sidebar shows a row for this plugin that opens its full settings page; off by default and it never affects the settings page itself;
    • Restore defaults: one click writes back “Used basis / 5-minute auto-refresh / Minimal on / no balance on the pill / reference model DeepSeek V4.1 Flash / currency auto / left source DS balance / both popover balances shown / default bottom-left position / default colours”.

Shared behaviour

  • Per-row feedback: each action's message appears in the row it belongs to — red on failure, green on success. Messages live in a slot on the title row, so showing and hiding them does not shift the layout, and they disappear after 3 seconds.
  • Hints wrap first: when a title or hint competes with the control on the right, the hint wraps onto more lines while the control stays on the same row, right-aligned; long titles wrap too instead of being truncated;
  • Animated segmented controls: every two/multi-choice control (the four settings tabs, progress mode, amount currency, pill-balance source and the ring mapping) slides its selected pill to the target position (240 ms); switching settings tabs also fades the panel in with a slight rise (220 ms). All of it is disabled automatically when the system asks for reduced motion.

Because the plugin ships its own settings page, the host side calls the official settings.configure({ auto: false }) to switch off the auto-generated form, avoiding two duplicate configuration UIs.

Screenshots

All twelve are rendered illustrations built from the plugin's real stylesheet and the host theme tokens (not machine screenshots). The four settings groups cover every tab: Usage data (quota reference model, amount currency, plan quota, the usage card and the projected usage chart), Floating pill (master switch, size slider, balance and popover data control, minimal mode, ring data mapping with its live preview, position reset), Colour settings (unified colour, normal / warning / danger dots, restore defaults and follow-host, four-state colour preview) and General settings (both keys, sidebar entry, restore defaults, export / import configuration). The states image includes the latest hover popover (projected usage chart included), and the last one shows the full settings page opened from the sidebar entry.

Pill · light Pill · dark
Pill · light Pill · dark
Settings · Usage data (light) Settings · Usage data (dark)
Settings · Usage data · light Settings · Usage data · dark
Settings · Floating pill (light) Settings · Floating pill (dark)
Settings · Floating pill · light Settings · Floating pill · dark
Settings · Colour settings (light) Settings · Colour settings (dark)
Settings · Colour settings · light Settings · Colour settings · dark
Settings · General settings (light) Settings · General settings (dark)
Settings · General settings · light Settings · General settings · dark
Sidebar entry · full settings page (what the sidebar row opens when the entry is enabled)
Sidebar entry

States and colour grades (refreshing / success / failure / three grade colours / minimal mode / most compact form / narrowed after hiding the balance)

States and colour grades

Design goal: minimal

  • Blend into the existing DeepSeek Harness UI as much as possible: unobtrusive, never shouting, yet still letting you read your usage at a glance — evolved from a long progress bar into the three rings you see today.
  • Only OpenCode Go is supported for now; other coding plans have not been tackled yet.

Data sources

GET https://opencode.ai/zen/go/v1/usage                    # OpenCode Go usage
Authorization: Bearer <OpenCode Go API Key>

GET https://api.deepseek.com/user/balance                  # DeepSeek balance
Authorization: Bearer <DeepSeek API Key>

GET https://opencode.ai/v2/docs/console/go                  # OpenCode Go model list + per-model monthly quota (server-rendered tables)
GET https://open.er-api.com/v6/latest/USD                   # USD/CNY rate (primary, no key)
GET https://api.frankfurter.app/latest?from=USD&to=CNY      # USD/CNY rate (backup, no key)

The usage endpoint returns { usage: { rolling, weekly, monthly } }, where each window carries status / percent (used percentage) / resetsAt; the balance endpoint returns balance_infos[] (the CNY entry is preferred). The UI shows Used by default and can be switched to Left in settings; the internal value always stays “used”. The host half performs the fetching and parsing (neither key ever leaves the host process); the client half only reads the configuration projection the host writes.

The model list and the rate refresh together with everything else: manual refresh (button or pill click) forces a refetch, while auto-refresh reuses the model table for 24 h and the rate for 1 h. If both fail, the plugin falls back to its bundled snapshot (go-data.js, generated 2026-10-31: 30 official models + a rate of 6.669566) and names the failure in the UI. Quota conversion uses the Go-tier monthly quota from that model table.

Key resolution (independent per side, in priority order):

  1. The “manual key” entered on the plugin's settings page (persisted in this row's config; the client-side view masks it);
  • Export / import configuration: export every current setting as a JSON file (you pick where to save it) and import it later to restore everything in one go; the exported file never contains API keys — not even keys you typed into the override fields; a confirmation dialog reminds you to back them up first, and importing never writes keys.
  1. The DSH credential store — OPENCODE_GO_API_KEY (then OPENCODE_API_KEY) for OpenCode Go, and DEEPSEEK_API_KEY for DeepSeek.

Anatomy

Part Location Description
Bundle manifest package.json dsh.bundle.patch + dsh.client (platform web, immediately) + icon + locale/*.json display metadata
Loader patch cordis.patch.yml Inserts one row, id: opencode-go-usage (this row id is also the namespace of the settings form)
Host half index.js export const Config (schemastery when available, falling back to an inline Standard Schema) + apply(ctx, config): fetching, parsing, writing back snapshots, auto-refresh
Client half client.js A window.__ModuleLoader__ lazy factory; only require('react'); registers into shell.overlay (pill) and settings.section (settings page)

Configuration

The settings page covers the common options; the fields below can also be edited directly in this row's patch config.

Field Description
apiKey Manual OpenCode Go API key (secret). Leave empty to use the DSH credential store
deepseekApiKey Manual DeepSeek API key (secret). Leave empty to use the DSH credential store
refreshMinutes Auto-refresh interval in minutes (default 5); one round refreshes both balance and usage
widgetVisible Pill visibility switch
widgetScale Pill scale: 1 default (initial value) / 0.9 −10% / 0.8 −20% / 1.15 +15% / 1.3 +30% / 1.5 +50% / 1.75 +75% / 2 +100%
showBalance Whether the pill shows a balance line on its left (default off)
pillBalanceSource Data for that left line: deepseek DS balance (default) / quota OCG quota left
tipShowBalance, tipShowQuota, tipShowPace Whether each popover module is shown — balance, quota, projected usage chart (all default on; turning all off leaves only the three bars)
sidebarEntry Whether the sidebar shows a row for this plugin (off by default; same as the "Sidebar entry" switch)
ringOuter / ringMiddle / ringInner Which window each of the outer / middle / inner rings shows in minimal mode: rolling (5 hours), weekly, monthly (defaults monthly / weekly / rolling)
colorUnified Unified colour: one three-tier set paints both ring and bar progress (on by default); turn it off for two independent sets
colorFollowHost Follow host colours: the normal tier uses the host accent (--dsw-alias-brand-primary) while warning / danger keep their defaults; picking a normal colour turns it off (off by default)
colorAll / colorAllWarn / colorAllDanger Custom colours for the unified set (CSS values: #RRGGBB, rgb(), hsl(); empty = theme green / amber / red)
colorRing* / colorBar* (with …Warn / …Danger suffixes) When colorUnified is off: the three tiers for ring / bar progress (no suffix = normal, Warn = warning, Danger = danger); the bar normal colour also paints the projected chart's real segment
quotaRefModel Reference model id (default deepseek-v4.1-flash; options come from the official model table)
currencyMode Amount currency: auto (default) / cny / usd
percentMode Usage progress basis: used (default) or left
widgetAnchorX/Y, widgetOffsetX/Y Pill anchoring (written by the client while dragging; defaults to the window's bottom-left, 7 px in and 9.2 px up)
refreshRequest Manual-refresh counter (incremented by the client when the pill is clicked)
refreshTick The “refreshing” signal the host bumps before each round (read-only on the client, used for the border feedback)
minimalMode Minimal mode: nested rings (with the rounded balance beside them; default on)
keyStatus, keyHint, usageError, lastUpdated, usage Derived OCG usage snapshots (written by the host, read by the client)
balanceKeyStatus, balanceKeyHint, balanceError, balance Derived DeepSeek balance snapshots (written by the host, read by the client)
goModels, goModelsAt, goModelsSource, goModelsError Derived model-list and quota snapshots (source = live or snapshot)
fxUsdCny, fxAt, fxRateDate, fxSource, fxError Derived USD/CNY rate, its data date and the moment it was fetched

Robustness

  • Only the seat the official UI reserves for overlays — shell.overlay (replaceRisk: none, a click-through layer whose entries opt into pointer events); registering with its own id means “added next to existing entries”, replacing nothing official.
  • Obscures no official UI: it does not register conversation.composer.dock and does not clone official components.
  • Styling uses theme tokens only (--dsw-alias-*): a token rename can at worst degrade the look, never crash the render; there are no hard-coded colours.
  • No Harness client packages (such as dsh-client-ui-primitives): those packages change often and plain JS plugins get no type checking, so every control in the pill is hand-written.
  • Host API contract self-check: on start-up the contracts this plugin actually uses are verified; a mismatch prints a readable warning and skips safely instead of throwing a TypeError that would silently deactivate the whole entry.
  • Config as the channel: the host writes derived snapshots into this row's volatile Config fields and the client reads them via remote.settings.describe(); writes are committed outside the HMR transaction (avoiding HMR transactions cannot be nested).
  • A failed fetch never clears data: the last known usage is kept (with 3s / 10s anti-jitter retries), so one network hiccup cannot blank the bars to -- or persist empty values.
  • Four independent data paths: usage, balance, model list and exchange rate never block each other — a failure only affects its own field, the UI names which one broke, and a failed model list or rate falls back to the bundled snapshot (labelled as such).
  • Manual refresh means a full refetch: the button (or a pill click) bypasses the TTL and forces the model table and the rate to be re-fetched, so both footnote times follow your manual refresh.
  • While no key is available yet, resolution retries in steps (3/8/20/40/60/120 seconds), and three misses are tolerated once a good snapshot exists — avoiding a false “not configured” reading right after startup.

Security & privacy

  • Release assets carry build provenance: every .tgz is built and signed by GitHub Actions, so the Release page shows Verified; verify it yourself with gh attestation verify <file> --repo verneuil/dsh-opencode-go-usage.
  • Keys never leave your machine except to the official endpoints: the API key is held by DSH settings storage and is only sent as a request header; it is never written into URLs, logs or the usage snapshot, and never projected to the client (the client only sees "configured?" and a masked form).
  • Only four fixed hosts are contacted at runtime: api.deepseek.com (balance), opencode.ai (usage and the official model table), plus open.er-api.com and api.frankfurter.app (exchange rates, only when the currency mode is "auto").
  • No telemetry: no usage data is collected and nothing is reported to a server of our own; the only third-party package involved is the host peer dependency @deepseek-ai/schemastery, which declares the settings schema and its volatile semantics and is installed with the profile so the settings UI behaves identically everywhere.
  • Credential hardening: every request that carries a key disables redirects (redirect: "error") so credentials cannot be forwarded to another host.
  • Reporting: please use GitHub Issues; never paste a key into an issue.

Known limitations & disclaimer

  • Unofficial plugin: this project has no affiliation whatsoever with DeepSeek or OpenCode; neither endpoint is a long-term frozen public contract, so a major upstream change can break it (the parser already tolerates common variants such as “remaining percentage / used amount and quota / seconds to reset”, and on failure the host puts a readable message in usageError).
  • Keys stay on this machine: the host half calls the two endpoints above directly and goes through no third party; a manual key entered in settings is stored in this machine's plugin config, and the UI only ever shows a masked hint (such as sk-****5590).
  • Network hiccups: occasional cross-border HTTPS timeouts are normal. The pill then keeps the last known values and the border turns to a warning colour; the host retries at 3/8/20/40 seconds and recovers automatically.
  • Interface language: the pill and the settings page are bilingual (Chinese / English) and follow the DSH language setting. Error details produced by the API layer (such as 401/403 or an unexpected response shape) are still in Chinese.
  • The quota figure is an estimate: no official endpoint exposes “how much of model X is left right now”, so the plugin estimates it as “that model's Go-tier monthly quota × this month's used percentage” — for reference only. The monthly percentage is the whole plan's progress, not that model's own share. The Go Plus tier is not covered yet (the Go tier is always used).
  • The rate only affects display: the DS balance is originally in CNY and the quota in USD; conversion is purely cosmetic (auto = ¥ in Chinese, $ in English) and never changes a real bill.
  • The model list can lag: the bundled snapshot is the official data of 2026-10-31; it updates with each refresh while online, and while offline (or when fetching fails) the snapshot is shown and labelled in the UI.
  • Use at your own risk: this software is provided “as is” under the MIT licence, without warranty of any kind.

License

MIT © 2026 verneuil

Feedback

Please open an issue for bugs and suggestions; pull requests are welcome. Version history: CHANGELOG.md.

About

DeepSeek balance and OpenCode Go usage (5-hour / weekly / monthly) merged into one floating pill, with a matching settings page

Topics

Resources

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages