> 🤖 **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
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).