OpenCode v2 TUI sidebar plugin: shows remaining quota of the active coding-plan
provider (GLM, Kimi, DeepSeek, MiniMax). npm package name is
opencode-coding-quota (repo name opencode-usage was taken on npm).
src/tui.tsx— plugin entry (Plugin.define, sidebar slot, panel component). OpenCode loads this source file directly via a symlink created byscripts/install.mjs(npm run setup); hot-reloads on edit, no build needed.src/types.ts—UsageData/UsageRowdata contract between adapters and panel; adapters only produce aUsageData.src/providers/<provider>.ts— one adapter per provider. Each exports:- a pure
parse*()function (unit-testable, takes the JSON payload), - a
query*Usage(apiKey, baseURL, title)function (fetch + error mapping →AuthErrorfor bad key,Errorotherwise). - Header comments document the live payload shape with the date it was verified — keep this updated when endpoints change.
- a pure
src/providers/resolve.ts— classifies the active provider (baseURL host first, provider-id heuristic fallback), resolves the API key (settings.apiKey→~/.local/share/opencode/auth.json→ env vars), routes to the adapter.test/run.mjs— plain-node unit tests on mock payloads (no framework);--livealso reads~/.config/opencode/opencode.jsonand calls real APIs.test/verify-resolve.mjs— end-to-endresolveUsage()against the local opencode config (real network calls).
npm run typecheck # tsc --noEmit (strict, noUncheckedIndexedAccess)
npm test # unit tests on mock payloads
npm run build # tsdown → dist/tui.js (for the npm package only)
node test/verify-resolve.mjs # live e2e — uses real keys from local opencode config- antfu-style TypeScript: single quotes, no semicolons, 2-space indent, comma-first arrays.
- Relative imports use explicit
.tsextensions (./providers/glm.ts) — tests run the TS sources directly via node type-stripping; tsconfig hasallowImportingTsExtensions. - Parse functions tolerate multiple historical response shapes (see Kimi's three shapes); prefer the field that carries absolute numbers, fall back to ratio-only.
- The panel renders
percent != nullrows as bars,text != nullrows as plain values;warn: truecolors a row as danger.
dist/is in.gitignorebutdist/tui.jsis git-tracked (force-added once). After changingsrc/, runnpm run buildandgit add -f dist/tui.js.- tsdown must never bundle
@opencode/*,@opentui/*,solid-js(peer deps,neverBundleintsdown.config.ts) — duplicate Solid instances break reactivity. tui.tsxruns in both the TUI (hascontext.ui) and the server process (nocontext.ui) — setup must return early whencontext.uiis absent.- Provider adapters hit business APIs that can return errors with HTTP 200 (GLM
code/success, MiniMaxbase_resp.status_code) — check body fields, not justresp.ok. - Windows CJK: panel width math uses
visualWidth()(CJK = 2 columns), notString.length.
npm version patch|minor|major(updates package.json + lockfile), commitchore: release vX.Y.Z.- Create a lightweight tag
vX.Y.Zand push it —.github/workflows/publish.ymlpublishes to npm via trusted publishing (OIDC) only onv*tag push or manual dispatch; plain main pushes run no CI. - Project
.npmrcpinsregistry.npmjs.orgso publish never hits a mirror; localnpm viewcan show stale cache — verify against the registry HTTP API if it matters.