> 🤖 **This was generated by an AI coding agent, not written by a human.** > **本内容由 AI 编码代理生成,非人类手写。** > > - Agent: blancatora (DeepSeek Harness coding agent) > - Model: deepseek-v4.1-flash > - Contact: blancatora@agent.qq.com > > **Disclaimer / 免责声明**: This content was produced by the AI agent named above. It may > contain errors, omissions, or unverified conclusions. **The account owner did not write, > review, or decide on this content** and is not responsible for it or its consequences. > It does not represent the maintainers of any repository or any third party. > Please verify before relying on it. > 本内容由上述 AI 代理生成,可能存在错误、不完整或未经充分验证的结论。**账号所有者未参与 > 本内容的编写与决策**,不对其内容与后果负责;也不代表任何第三方的立场。使用前请自行核实。

dsh-opendesign-usage

See your Open Design plan quota and this session's token usage right in the DSH composer.

中文 · Install · Features · Configuration · How it works · Credits & disclosure · Changelog

MIT license DSH bundle plugin Node version

A standalone [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bundle plugin. It adds a **read-only readout** to the composer's tool row: the remaining percentage of your Open Design plan's two rolling windows (5-hour / 7-day). The wallet balance and this session's token usage live in the detail panel, **not in the always-visible readout**. The readout **only appears when the session's model belongs to the `opendesign` provider** — switch to another provider and it disappears cleanly without holding a slot. Every feature can be toggled in the plugin's own detail page. ``` OD · 90% · 97% │ └────── 7-day window remaining └───────────── 5-hour window remaining ``` The readout keeps only the two quota windows: the tool row is narrow, and adding tokens plus the wallet makes it visibly too long. **The wallet balance, this session's tokens, and each window's reset countdown are all in the click-through panel.** ## Features ### 1. Plan quota Reads the Open Design console's `coding-plan-usage` endpoint and shows the remaining quota for both rolling windows. Click the readout for the breakdown: | Window | Remaining | Resets | |---|---|---| | 5-hour quota | 50% (24,960 / 50,000 credits) | in 1 h 38 m | | 7-day quota | 87% (130,918 / 150,000 credits) | in 6 days | - Countdowns use the upstream's **server-side relative** value (`resetsInMs`) rather than subtracting `resetsAt` from the local clock — a skewed machine clock cannot make it wrong. - A window that could not be read shows `—` rather than being omitted: both positions stay fixed, so a 7-day figure can never be mistaken for the 5-hour one. ### 2. Wallet balance The fallback balance (subscription credits + top-up credits) once the plan is exhausted, shown in the panel detail. > The wallet follows the "plan quota" toggle: it is the *fallback balance after the plan runs > out*, and a bare dollar amount with no plan context leaves users unsure what the money is. ### 3. This session's token usage Reads the host's `tokenUsage` projection and shows the total plus a breakdown (input / output / cache read / cache write) in the panel detail. **Pure host data — no credentials needed.** ### 4. Toggle everything in the plugin detail page | Toggle | Default | Effect | |---|---|---| | `enableComposerUsage` | on | Whether the readout appears in the composer | | `enablePlanQuota` | on | Whether plan quota **and wallet** are shown (both need credentials) | | `enableTokenUsage` | on | Whether session token usage is shown | Turning off `enableComposerUsage` means no control is registered and no request is ever made. Turning off `enablePlanQuota` means the host never calls upstream at all — nothing keeps polling in the background. ## Install ### Requirements - A working DSH installation (developed and verified on **0.2.1-alpha.2**); - An Open Design account (a free tier is enough) if you want the quota readout. ### Add the plugin DSH ships a plugin manager. In the GUI: 1. Click **Plugins** in the sidebar; 2. Click **Add plugin** (or the arrow → **Install third-party plugin**); 3. Paste one of the values below and press Enter: | Method | Value | |---|---| | npm (**recommended**, once published) | `dsh-opendesign-usage` | | Git repository | `https://github.com//dsh-opendesign-usage` | | Local directory | `/absolute/path/to/dsh-opendesign-usage` | The manager runs pnpm to add the package to the current profile and offers **Enable now**.
Manual install (without the GUI plugin manager) ```sh # 1) Add the package to the profile's dependencies cd ~/.dsh/profiles/ pnpm add /absolute/path/to/dsh-opendesign-usage # 2) Add it to the profile's bundle list # Edit ~/.dsh/profiles//package.json and append to dsh.profile.bundles: # "dsh-opendesign-usage" # 3) Restart DSH ```
### Enable After installing, **restart DSH** (a new bundle requires the profile to be recomposed). Then switch the session's model to any `opendesign` model — the readout appears in the bottom-left of the composer. > A missing readout is expected: it only renders when the session's provider is `opendesign`. > With any other provider it takes no slot and makes no request. ## Configuration Configuration lives in the **plugin detail page**, not in the general Settings page: > Sidebar → **Plugins** → find **Open Design Usage** → configure it on its own page. This is DSH's intended split. The plugin manager's own documentation says: *"Plugins that register a configuration page are edited here, on their own page; Settings keeps only a read-only plugin list."* Changes take effect when you press **Save** (the three toggles and the input fields are staged together and submitted once). The three feature toggles, `workspaceId`, `sessionCookie` and the refresh interval all live on this page. The **Test connection** button lets you verify credentials with the draft values **before** saving. ### Getting your workspaceId Log in to the [Open Design console](https://open-design.ai). The `workspaceId` parameter in the address bar is the value you need: ``` https://open-design.ai/cloud/dashboard?workspaceId= ^^^^^^^^^^^^^^^^^^ copy this part ``` ### Getting your sessionCookie 1. Log in to the Open Design console in your browser; 2. Open DevTools (`F12`) → **Network** tab → reload the page; 3. Filter for `coding-plan-usage`; 4. Open that request → **Request Headers** → find the `Cookie` line; 5. Copy the value **after** `__Secure-better-auth.session_token=` (up to the `;`). > Pasting the whole `Cookie` header also works — the plugin extracts the token for you. > The field is **never echoed in plaintext** (it uses primitives' `SettingsSecretField`: always > blank, reporting only whether a value is configured). ⚠️ **This is a login credential.** It is equivalent to your console session: - The plugin stores it in DSH's local settings and uses it **only** to read your own quota from `amr-api.open-design.ai`; - It is never collected, uploaded, or forwarded to any third party; - It expires (better-auth sessions are time-limited). Once expired the readout shows `—`; just repeat the steps above; - On a shared machine, turn off `enablePlanQuota` and use the credential-free token usage instead. ### Refresh interval 5 minutes by default, adjustable from 1 to 60 minutes. Requests are made **only while the readout is visible and the quota toggle is on**, so it never polls upstream in the background. ## How it works ``` Composer readout (browser) │ GET /plugins/dsh-opendesign-usage/plan-usage ← same-origin route, host side ▼ DSH host (src/index.js) │ GET https://amr-api.open-design.ai/api/v1/workspaces/{id}/billing/coding-plan-usage │ GET https://amr-api.open-design.ai/api/v1/billing/summary ▼ Open Design console API ``` Three design decisions worth spelling out: **① Credentials stay on the host side; the browser never sees them.** The client never calls upstream directly. It calls the host's same-origin route `/plugins/dsh-opendesign-usage/plan-usage`; the host attaches the cookie, calls upstream, and returns normalized data. Credentials never enter the page context. **② Both routes enforce a loopback origin check.** `plan-usage` and `test-connection` only accept requests from loopback or DSH's own protocols (`dsh-app:` / `dsh:`). An endpoint that carries credentials should not be callable by an arbitrary web page. **③ The two upstream endpoints succeed or fail independently.** Quota and wallet are separate endpoints; one failing never clears the other's figure — the panel can show "quota available, wallet temporarily unreadable" at the same time. ### Why `conversation.input.left` The composer tool row is **per-session and provider-owned**: the readout appears only in sessions whose model belongs to `opendesign`, so exactly one plugin cares about that slot. The sidebar footer, by contrast, is a **single root-level shared row** where connector plugins crowd each other out. ### Why the gate uses the `modelSelection` projection Whether the readout should appear is decided by the session's currently selected model — a projection the host has already computed. Registration is unconditional and the component itself returns `null`. Conditional registration leaves a gap during provider switches (the registry tracks slots by id, and unregister-then-register races), whereas unconditional registration plus `return null` costs nothing. ## Compatibility - **DSH**: 0.2.1-alpha.2 (the version this was developed and verified against). Every slot and official component the plugin uses is declared in `dsh.client.inject`; - **Node**: `^22.19.0 || >=24.0.0`; - **Platform**: `web` (DSH's Web GUI). ### Permissions and data | Item | Detail | |---|---| | Network | Host side reaches only `amr-api.open-design.ai`; the client reaches only the host's same-origin route | | Credentials read | `workspaceId` + session token, stored in DSH local settings; **never echoed in plaintext** | | Uploads | None. Nothing is collected or sent to a third party | | Files | No workspace files are read or written | ## Development ```sh node src/build-client.mjs # generate lib/client.js from src/ node --test test/*.test.mjs # unit tests ``` ⚠️ `lib/client.js` is a **build artifact** — do not edit it by hand; rebuild after changing `src/`. The build script enforces a **bundle guard** (`assertBundleShape()` in `src/build-client.mjs`): the artifact must parse, and its `require` calls may only reference the nine modules in the seed table. A broken artifact **fails at build time** and never reaches disk — a broken DSH client bundle shows up as a blank application with no stack trace in the crash log, so this has to be caught during the build. ### Reference documentation - **[docs/plugin-development.md](docs/plugin-development.md)** (Chinese) — DSH client plugin development rules: the two different `inject`s, why `apply` must never throw, the `require` seed-table allowlist, how to read `import failed` (it is a fallback message, not a real import error), the build-time guard, testing against the real bundle, pnpm hardlink snapshots, and a pre-release checklist. - **[docs/design-guidelines.md](docs/design-guidelines.md)** (Chinese) — DSH plugin UI design rules: use the official `primitives` components instead of hand-rolling, rely only on theme tokens, keep the always-visible readout short, and match the host's interaction patterns. - **[CREDITS.md](CREDITS.md)** — attribution, AI collaboration disclosure, and third-party sources. - **[CHANGELOG.md](CHANGELOG.md)** — release history. ## License [MIT](LICENSE). Attribution and AI collaboration disclosure: [CREDITS.md](CREDITS.md). This is an **unofficial** third-party plugin. It is not affiliated with or endorsed by Open Design (AMR).