@leo000001/opencode-quota-sidebar 2.0.9 → 2.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,46 +1,46 @@
1
- # opencode-quota-sidebar
2
-
3
- [![npm version](https://img.shields.io/npm/v/@leo000001/opencode-quota-sidebar.svg)](https://www.npmjs.com/package/@leo000001/opencode-quota-sidebar)
4
- [![license](https://img.shields.io/npm/l/@leo000001/opencode-quota-sidebar.svg)](https://github.com/xihuai18/opencode-quota-sidebar/blob/main/LICENSE)
5
-
6
- OpenCode plugin: show token usage and subscription quota in the session sidebar title.
7
-
8
- ![Example sidebar title with usage and quota](./assets/OpenCode-Quota-Sidebar.png)
9
-
10
- ## Install
11
-
12
- Add the package name to `plugin` in your `opencode.json`. OpenCode uses Bun to install it automatically on startup:
13
-
14
- ```json
1
+ # opencode-quota-sidebar
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@leo000001/opencode-quota-sidebar.svg)](https://www.npmjs.com/package/@leo000001/opencode-quota-sidebar)
4
+ [![license](https://img.shields.io/npm/l/@leo000001/opencode-quota-sidebar.svg)](https://github.com/xihuai18/opencode-quota-sidebar/blob/main/LICENSE)
5
+
6
+ OpenCode plugin: show token usage and subscription quota in the session sidebar title.
7
+
8
+ ![Example sidebar title with usage and quota](./assets/OpenCode-Quota-Sidebar.png)
9
+
10
+ ## Install
11
+
12
+ Add the package name to `plugin` in your `opencode.json`. OpenCode uses Bun to install it automatically on startup:
13
+
14
+ ```json
15
15
  {
16
16
  "plugin": ["@leo000001/opencode-quota-sidebar@2.0.1"]
17
17
  }
18
- ```
19
-
20
- Note for OpenCode `>=1.2.15`: TUI settings (`theme`/`keybinds`/`tui`) moved to `tui.json`, but plugin loading still stays in `opencode.json` (`plugin: []`).
21
- This plugin also accepts both `config.providers` and older `provider.list` runtime shapes when discovering provider options.
22
-
23
- If you prefer automatic upgrades, you can still use `@latest`, but pinning an exact version makes behavior easier to reproduce when debugging.
24
-
25
- ## Development (build from source)
26
-
27
- ```bash
28
- npm install
29
- npm run build
30
- ```
31
-
32
- Add the built file to your `opencode.json`:
33
-
34
- ```json
35
- {
36
- "plugin": ["file:///ABSOLUTE/PATH/opencode-quota-sidebar/dist/index.js"]
37
- }
38
- ```
39
-
40
- On Windows, use forward slashes: `"file:///D:/Lab/opencode-quota-sidebar/dist/index.js"`
41
-
42
- ## Supported quota providers
43
-
18
+ ```
19
+
20
+ Note for OpenCode `>=1.2.15`: TUI settings (`theme`/`keybinds`/`tui`) moved to `tui.json`, but plugin loading still stays in `opencode.json` (`plugin: []`).
21
+ This plugin also accepts both `config.providers` and older `provider.list` runtime shapes when discovering provider options.
22
+
23
+ If you prefer automatic upgrades, you can still use `@latest`, but pinning an exact version makes behavior easier to reproduce when debugging.
24
+
25
+ ## Development (build from source)
26
+
27
+ ```bash
28
+ npm install
29
+ npm run build
30
+ ```
31
+
32
+ Add the built file to your `opencode.json`:
33
+
34
+ ```json
35
+ {
36
+ "plugin": ["file:///ABSOLUTE/PATH/opencode-quota-sidebar/dist/index.js"]
37
+ }
38
+ ```
39
+
40
+ On Windows, use forward slashes: `"file:///D:/Lab/opencode-quota-sidebar/dist/index.js"`
41
+
42
+ ## Supported quota providers
43
+
44
44
  | Provider | Endpoint | Auth | Status |
45
45
  | --------------- | -------------------------------------- | --------------------- | --------------------------------------- |
46
46
  | OpenAI Codex | `chatgpt.com/backend-api/wham/usage` | OAuth (ChatGPT) | Multi-window (short-term + weekly) |
@@ -50,29 +50,33 @@ On Windows, use forward slashes: `"file:///D:/Lab/opencode-quota-sidebar/dist/in
50
50
  | Buzz | `buzzai.cc/v1/dashboard/billing/*` | API key | Balance only (computed from total-used) |
51
51
  | Anthropic | `api.anthropic.com/api/oauth/usage` | OAuth | Multi-window (5h + weekly / plan-based) |
52
52
  | XYAI Vibe | `new.xychatai.com/frontend-api/*` | Login -> session auth | Daily balance quota with reset time |
53
-
54
- Want to add support for another provider (Google Antigravity, Zhipu AI, Firmware AI, etc.)? See [CONTRIBUTING.md](CONTRIBUTING.md).
55
-
56
- ## Features
57
-
58
- - Session title becomes multiline in sidebar:
53
+
54
+ Want to add support for another provider (Google Antigravity, Zhipu AI, Firmware AI, etc.)? See [CONTRIBUTING.md](CONTRIBUTING.md).
55
+
56
+ ## Features
57
+
58
+ - TUI session title becomes multiline in sidebar:
59
59
  - line 1: original session title
60
60
  - line 2: blank separator
61
- - line 3: Input/Output tokens
62
- - line 4: Cache Read tokens (only if non-zero)
63
- - line 5: Cache Write tokens (only if non-zero)
61
+ - line 3: Requests
62
+ - line 4: Input/Output tokens
63
+ - line 5: Cache Read tokens (only if non-zero)
64
+ - line 6: Cache Write tokens (only if non-zero)
64
65
  - next lines: `Cache Coverage` (read/write cache models) and `Cache Read Coverage` (read-only cache models) when enough cache telemetry is available; mixed sessions can show both
65
66
  - next line: `$X.XX as API cost` (equivalent API billing for subscription-auth providers)
66
67
  - quota lines: quota text like `OpenAI 5h 80% Rst 16:20`; short windows (`5h`, `1d`, `Daily`) show `HH:MM` on same-day resets and `MM-DD HH:MM` when crossing days, while longer windows continue to show `MM-DD`
67
68
  - RightCode daily quota shows `$remaining/$dailyTotal` without trailing percent, and shows balance on the next indented line when available
68
69
  - XYAI daily quota follows the same balance-style layout and prefers the real reset time (for example `XYAI Daily $70.2/$90 Rst 22:18`)
69
- - Session-scoped usage/quota can include descendant subagent sessions (enabled by default via `sidebar.includeChildren=true`). Traversal is bounded by `childrenMaxDepth` (default 6), `childrenMaxSessions` (default 128), and `childrenConcurrency` (default 5); truncation is logged when `OPENCODE_QUOTA_DEBUG=1`. Day/week/month ranges never merge children only session scope does.
70
+ - Desktop automatically switches to a compact single-line title. It keeps recently used providers from the last `50` requests or last `60` minutes ahead of `Requests/Input/Output`, and expands all windows/balance for those selected providers in short form such as `OAI 5h80 W70` or `RC D88.9/60 B260`
71
+ - TUI is always rendered as multiline; Desktop is always rendered as compact single-line. This behavior no longer depends on `sidebar.multilineTitle`
72
+ - Web UI currently cannot be reliably detected by the plugin, so it follows the non-desktop multiline path
73
+ - Session-scoped usage/quota can include descendant subagent sessions (enabled by default via `sidebar.includeChildren=true`). Traversal is bounded by `childrenMaxDepth` (default 6), `childrenMaxSessions` (default 128), and `childrenConcurrency` (default 5); truncation is logged when `OPENCODE_QUOTA_DEBUG=1`. Day/week/month ranges never merge children — only session scope does.
70
74
  - Toast message can include four sections: `Token Usage`, `Cost as API` (per provider), `Provider Cache` (when provider-level cache coverage is available), and `Quota`
71
75
  - Expiry reminders are shown in a separate `Expiry Soon` toast section only for providers with real subscription expiry timestamps, and each session shows that auto-reminder at most once
72
76
  - `quota_summary` markdown / toast also include `Cache Coverage` and `Cache Read Coverage` summary lines when available
73
- - Quota snapshots are de-duplicated before rendering to avoid repeated provider lines
74
- - Custom tools:
75
- - `quota_summary` — generate usage report for session/day/week/month (markdown + toast)
77
+ - Quota snapshots are de-duplicated before rendering to avoid repeated provider lines
78
+ - Custom tools:
79
+ - `quota_summary` — generate usage report for session/day/week/month (markdown + toast)
76
80
  - `quota_show` — toggle sidebar title display on/off (state persists across sessions)
77
81
  - After startup, titles are restored immediately when persisted display mode is OFF; when persisted display mode is ON, touched titles refresh on startup and the rest update on the next relevant session/message event or when `quota_show` is toggled
78
82
  - Quota connectors:
@@ -83,8 +87,8 @@ Want to add support for another provider (Google Antigravity, Zhipu AI, Firmware
83
87
  - Buzz API key (`/v1/dashboard/billing/subscription` + `/v1/dashboard/billing/usage`)
84
88
  - Anthropic Claude OAuth (`/api/oauth/usage`, with beta header)
85
89
  - XYAI Vibe account login (`/frontend-api/login` -> cached `share-session` -> `/frontend-api/vibe-code/quota`)
86
- - OpenAI OAuth quota checks auto-refresh expired access token (using refresh token)
87
- - API key providers still show usage aggregation (quota only applies to subscription providers)
90
+ - OpenAI OAuth quota checks auto-refresh expired access token (using refresh token)
91
+ - Generic API key providers without quota endpoints still show usage aggregation only; built-in adapters such as Kimi For Coding, RightCode, Buzz, and XYAI Vibe also show quota or balance details.
88
92
  - Incremental usage aggregation — only processes new messages since last cursor
89
93
  - Sidebar token units are adaptive (`k`/`m` with one decimal where applicable)
90
94
 
@@ -103,15 +107,15 @@ Want to add support for another provider (Google Antigravity, Zhipu AI, Firmware
103
107
  - The adapter logs in via `POST https://new.xychatai.com/frontend-api/login`, caches the returned `share-session`, and retries quota fetches with that session.
104
108
  - Quota data is read from `GET https://new.xychatai.com/frontend-api/vibe-code/quota`.
105
109
  - Compact displays show the daily balance and the true reset time when present; expiry stays as secondary report/toast metadata.
106
-
107
- ## Storage layout
108
-
109
- The plugin stores lightweight global state and date-partitioned session chunks.
110
-
111
- - Global metadata: `<opencode-data>/quota-sidebar.state.json`
112
- - `titleEnabled`
113
- - `sessionDateMap` (sessionID -> `YYYY-MM-DD`)
114
- - `quotaCache`
110
+
111
+ ## Storage layout
112
+
113
+ The plugin stores lightweight global state and date-partitioned session chunks.
114
+
115
+ - Global metadata: `<opencode-data>/quota-sidebar.state.json`
116
+ - `titleEnabled`
117
+ - `sessionDateMap` (sessionID -> `YYYY-MM-DD`)
118
+ - `quotaCache`
115
119
  - Session chunks: `<opencode-data>/quota-sidebar-sessions/YYYY/MM/DD.json`
116
120
  - per-session title state (`baseTitle`, `lastAppliedTitle`)
117
121
  - `createdAt`
@@ -124,360 +128,387 @@ Notes on cache coverage persistence:
124
128
 
125
129
  - Older cached usage written before `cacheBuckets` existed can only be approximated from top-level `cache_read` / `cache_write` totals.
126
130
  - In those legacy cases, mixed read-only + read-write cache traffic may be attributed to a single fallback bucket until the session is recomputed from messages.
127
-
128
- Example tree:
129
-
130
- ```text
131
- ~/.local/share/opencode/
132
- quota-sidebar.state.json
133
- quota-sidebar-sessions/
134
- 2026/
135
- 02/
136
- 23.json
137
- 24.json
138
- ```
139
-
140
- Sessions older than `retentionDays` (default 730 days / 2 years) are evicted from
141
- memory on startup. Chunk files remain on disk for historical range scans.
142
-
143
- ## Compatibility
144
-
145
- - Node.js: >= 18 (for `fetch` + `AbortController`)
146
- - OpenCode: plugin SDK `@opencode-ai/plugin` ^1.2.10
147
- - OpenCode config split: if you are on `>=1.2.15`, keep this plugin in `opencode.json` and keep TUI-only keys in `tui.json`.
148
-
149
- ## Force refresh after npm update
150
-
151
- If `npm view @leo000001/opencode-quota-sidebar version` shows a newer version but OpenCode still behaves like an older release, OpenCode/Bun is usually reusing an older installed copy.
152
-
153
- Recommended recovery steps:
154
-
155
- 1. Pin the target plugin version in `opencode.json`.
156
- 2. Fully exit OpenCode.
157
- 3. Delete any cached installed copies of the plugin.
158
- 4. Start OpenCode again so it reinstalls the package.
159
- 5. Verify the actual installed `package.json` version under the plugin directory.
160
-
161
- Common install/cache locations:
162
-
163
- - `~/.cache/opencode/node_modules/@leo000001/opencode-quota-sidebar`
164
- - `~/node_modules/@leo000001/opencode-quota-sidebar`
165
-
166
- Windows PowerShell example:
167
-
168
- ```powershell
169
- Remove-Item -Recurse -Force "$HOME\.cache\opencode\node_modules\@leo000001\opencode-quota-sidebar" -ErrorAction SilentlyContinue
170
- Remove-Item -Recurse -Force "$HOME\node_modules\@leo000001\opencode-quota-sidebar" -ErrorAction SilentlyContinue
171
- ```
172
-
173
- macOS / Linux example:
174
-
175
- ```bash
176
- rm -rf ~/.cache/opencode/node_modules/@leo000001/opencode-quota-sidebar
177
- rm -rf ~/node_modules/@leo000001/opencode-quota-sidebar
178
- ```
179
-
180
- ## Optional commands
181
-
182
- You can add these command templates in `opencode.json` so you can run `/qday`, `/qweek`, `/qmonth`, `/qtoggle`:
183
-
184
- ```json
185
- {
186
- "command": {
187
- "qday": {
188
- "description": "Show today's usage and quota",
189
- "template": "Call tool quota_summary with period=day and toast=true."
190
- },
191
- "qweek": {
192
- "description": "Show this week's usage and quota",
193
- "template": "Call tool quota_summary with period=week and toast=true."
194
- },
195
- "qmonth": {
196
- "description": "Show this month's usage and quota",
197
- "template": "Call tool quota_summary with period=month and toast=true."
198
- },
199
- "qtoggle": {
200
- "description": "Toggle sidebar usage display on/off",
201
- "template": "Call tool quota_show (no arguments, it toggles)."
202
- }
203
- }
204
- }
205
- ```
206
-
207
- ## Configuration files
208
-
209
- Recommended global config:
210
-
211
- - `~/.config/opencode/quota-sidebar.config.json`
212
-
213
- Optional project overrides:
214
-
215
- - `<worktree>/quota-sidebar.config.json`
216
- - `<directory>/quota-sidebar.config.json` (when different from `worktree`)
217
- - `<worktree>/.opencode/quota-sidebar.config.json`
218
- - `<directory>/.opencode/quota-sidebar.config.json` (when different from `worktree`)
219
-
220
- Optional explicit override:
221
-
222
- - `OPENCODE_QUOTA_CONFIG=/absolute/path/to/config.json`
223
-
224
- Optional config-home override:
225
-
226
- - `OPENCODE_QUOTA_CONFIG_HOME=/absolute/path/to/config-home`
227
-
228
- Resolution order (low -> high):
229
-
230
- 1. Global config (`~/.config/opencode/...`)
231
- 2. `<worktree>/quota-sidebar.config.json`
232
- 3. `<directory>/quota-sidebar.config.json`
233
- 4. `<worktree>/.opencode/quota-sidebar.config.json`
234
- 5. `<directory>/.opencode/quota-sidebar.config.json`
235
- 6. `OPENCODE_QUOTA_CONFIG`
236
-
237
- Values are layered; later sources override earlier ones.
238
-
239
- ## Configuration
240
-
241
- If you do not provide any config file, the plugin uses the built-in defaults below.
242
-
243
- ### Built-in defaults
244
-
245
- Sidebar defaults:
246
-
247
- - `sidebar.enabled`: `true`
248
- - `sidebar.width`: `36` (clamped to `20`-`60`)
249
- - `sidebar.multilineTitle`: `true`
250
- - `sidebar.showCost`: `true`
251
- - `sidebar.showQuota`: `true`
252
- - `sidebar.wrapQuotaLines`: `true`
253
- - `sidebar.includeChildren`: `true`
254
- - `sidebar.childrenMaxDepth`: `6` (clamped to `1`-`32`)
255
- - `sidebar.childrenMaxSessions`: `128` (clamped to `0`-`2000`)
256
- - `sidebar.childrenConcurrency`: `5` (clamped to `1`-`10`)
257
-
258
- Quota defaults:
259
-
260
- - `quota.refreshMs`: `300000` (clamped to `>=30000`)
261
- - `quota.includeOpenAI`: `true`
262
- - `quota.includeCopilot`: `true`
263
- - `quota.includeAnthropic`: `true`
131
+
132
+ Example tree:
133
+
134
+ ```text
135
+ ~/.local/share/opencode/
136
+ quota-sidebar.state.json
137
+ quota-sidebar-sessions/
138
+ 2026/
139
+ 02/
140
+ 23.json
141
+ 24.json
142
+ ```
143
+
144
+ Sessions older than `retentionDays` (default 730 days / 2 years) are evicted from
145
+ memory on startup. Chunk files remain on disk for historical range scans.
146
+
147
+ ## Compatibility
148
+
149
+ - Node.js: >= 18 (for `fetch` + `AbortController`)
150
+ - OpenCode: plugin SDK `@opencode-ai/plugin` ^1.2.10
151
+ - OpenCode config split: if you are on `>=1.2.15`, keep this plugin in `opencode.json` and keep TUI-only keys in `tui.json`.
152
+
153
+ ## Force refresh after npm update
154
+
155
+ If `npm view @leo000001/opencode-quota-sidebar version` shows a newer version but OpenCode still behaves like an older release, OpenCode/Bun is usually reusing an older installed copy.
156
+
157
+ Recommended recovery steps:
158
+
159
+ 1. Pin the target plugin version in `opencode.json`.
160
+ 2. Fully exit OpenCode.
161
+ 3. Delete any cached installed copies of the plugin.
162
+ 4. Start OpenCode again so it reinstalls the package.
163
+ 5. Verify the actual installed `package.json` version under the plugin directory.
164
+
165
+ Common install/cache locations:
166
+
167
+ - `~/.cache/opencode/node_modules/@leo000001/opencode-quota-sidebar`
168
+ - `~/node_modules/@leo000001/opencode-quota-sidebar`
169
+
170
+ Windows PowerShell example:
171
+
172
+ ```powershell
173
+ Remove-Item -Recurse -Force "$HOME\.cache\opencode\node_modules\@leo000001\opencode-quota-sidebar" -ErrorAction SilentlyContinue
174
+ Remove-Item -Recurse -Force "$HOME\node_modules\@leo000001\opencode-quota-sidebar" -ErrorAction SilentlyContinue
175
+ ```
176
+
177
+ macOS / Linux example:
178
+
179
+ ```bash
180
+ rm -rf ~/.cache/opencode/node_modules/@leo000001/opencode-quota-sidebar
181
+ rm -rf ~/node_modules/@leo000001/opencode-quota-sidebar
182
+ ```
183
+
184
+ ## Optional commands
185
+
186
+ You can add these command templates in `opencode.json` so you can run `/qday`, `/qweek`, `/qmonth`, `/qtoggle`:
187
+
188
+ ```json
189
+ {
190
+ "command": {
191
+ "qday": {
192
+ "description": "Show today's usage and quota",
193
+ "template": "Call tool quota_summary with period=day and toast=true."
194
+ },
195
+ "qweek": {
196
+ "description": "Show this week's usage and quota",
197
+ "template": "Call tool quota_summary with period=week and toast=true."
198
+ },
199
+ "qmonth": {
200
+ "description": "Show this month's usage and quota",
201
+ "template": "Call tool quota_summary with period=month and toast=true."
202
+ },
203
+ "qtoggle": {
204
+ "description": "Toggle sidebar usage display on/off",
205
+ "template": "Call tool quota_show (no arguments, it toggles)."
206
+ }
207
+ }
208
+ }
209
+ ```
210
+
211
+ ## Configuration files
212
+
213
+ Recommended global config:
214
+
215
+ - `~/.config/opencode/quota-sidebar.config.json`
216
+
217
+ Optional project overrides:
218
+
219
+ - `<worktree>/quota-sidebar.config.json`
220
+ - `<directory>/quota-sidebar.config.json` (when different from `worktree`)
221
+ - `<worktree>/.opencode/quota-sidebar.config.json`
222
+ - `<directory>/.opencode/quota-sidebar.config.json` (when different from `worktree`)
223
+
224
+ Optional explicit override:
225
+
226
+ - `OPENCODE_QUOTA_CONFIG=/absolute/path/to/config.json`
227
+
228
+ Optional config-home override:
229
+
230
+ - `OPENCODE_QUOTA_CONFIG_HOME=/absolute/path/to/config-home`
231
+
232
+ Resolution order (low -> high):
233
+
234
+ 1. Global config (`~/.config/opencode/...`)
235
+ 2. `<worktree>/quota-sidebar.config.json`
236
+ 3. `<directory>/quota-sidebar.config.json`
237
+ 4. `<worktree>/.opencode/quota-sidebar.config.json`
238
+ 5. `<directory>/.opencode/quota-sidebar.config.json`
239
+ 6. `OPENCODE_QUOTA_CONFIG`
240
+
241
+ Values are layered; later sources override earlier ones.
242
+
243
+ ## Configuration
244
+
245
+ If you do not provide any config file, the plugin uses the built-in defaults below.
246
+
247
+ ### Built-in defaults
248
+
249
+ Sidebar defaults:
250
+
251
+ - `sidebar.enabled`: `true`
252
+ - `sidebar.width`: `36` (clamped to `20`-`60`)
253
+ - `sidebar.multilineTitle`: `true` (legacy compatibility field; TUI/Desktop display mode is now chosen automatically)
254
+ - `sidebar.showCost`: `true`
255
+ - `sidebar.showQuota`: `true`
256
+ - `sidebar.wrapQuotaLines`: `true`
257
+ - `sidebar.includeChildren`: `true`
258
+ - `sidebar.childrenMaxDepth`: `6` (clamped to `1`-`32`)
259
+ - `sidebar.childrenMaxSessions`: `128` (clamped to `0`-`2000`)
260
+ - `sidebar.childrenConcurrency`: `5` (clamped to `1`-`10`)
261
+ - `sidebar.desktopCompact.recentRequests`: `50` (desktop compact only)
262
+ - `sidebar.desktopCompact.recentMinutes`: `60` (desktop compact only)
263
+
264
+ Quota defaults:
265
+
266
+ - `quota.refreshMs`: `300000` (clamped to `>=30000`)
267
+ - `quota.includeOpenAI`: `true`
268
+ - `quota.includeCopilot`: `true`
269
+ - `quota.includeAnthropic`: `true`
264
270
  - `quota.providers`: `{}` (per-adapter switches and adapter-specific config, for example `rightcode.enabled` or `xyai-vibe.login.username/password`)
265
- - `quota.refreshAccessToken`: `false`
266
- - `quota.requestTimeoutMs`: `8000` (clamped to `>=1000`)
267
-
268
- Other defaults:
269
-
270
- - `toast.durationMs`: `12000` (clamped to `>=1000`)
271
- - `retentionDays`: `730`
272
-
273
- ### Full example config
274
-
275
- ```json
276
- {
277
- "sidebar": {
278
- "enabled": true,
279
- "width": 36,
280
- "multilineTitle": true,
281
- "showCost": true,
282
- "showQuota": true,
283
- "wrapQuotaLines": true,
284
- "includeChildren": true,
285
- "childrenMaxDepth": 6,
286
- "childrenMaxSessions": 128,
287
- "childrenConcurrency": 5
288
- },
289
- "quota": {
290
- "refreshMs": 300000,
291
- "includeOpenAI": true,
292
- "includeCopilot": true,
293
- "includeAnthropic": true,
294
- "providers": {
295
- "buzz": {
296
- "enabled": true
297
- },
298
- "rightcode": {
299
- "enabled": true
300
- }
301
- },
302
- "refreshAccessToken": false,
303
- "requestTimeoutMs": 8000
304
- },
305
- "toast": {
306
- "durationMs": 12000
307
- },
308
- "retentionDays": 730
309
- }
310
- ```
311
-
312
- ### Notes
313
-
314
- - `sidebar.showCost` controls API-cost visibility in sidebar title, `quota_summary` markdown report, and toast message.
315
- - `quota_summary` follows the same reset compaction rules for short windows in its subscription section (`5h` / `1d` / `Daily` show time, long windows show date, RightCode `Exp` stays date-only).
316
- - `sidebar.width` is measured in terminal cells. CJK/emoji truncation is best-effort to avoid sidebar overflow.
317
- - `sidebar.multilineTitle` controls multi-line sidebar layout (default: `true`). Set `false` for compact single-line title.
318
- - `sidebar.wrapQuotaLines` controls quota line wrapping and continuation indentation (default: `true`).
319
- - `sidebar.includeChildren` controls whether session-scoped usage/quota includes descendant subagent sessions (default: `true`).
320
- - `sidebar.childrenMaxDepth` limits how many levels of nested subagents are traversed (default: `6`, clamped 1–32).
321
- - `sidebar.childrenMaxSessions` caps the total number of descendant sessions aggregated (default: `128`, clamped 0–2000).
322
- - `sidebar.childrenConcurrency` controls parallel fetches for descendant session messages (default: `5`, clamped 1–10).
323
- - `output` includes reasoning tokens (`output = tokens.output + tokens.reasoning`). Reasoning is not rendered as a separate line.
324
- - API cost bills reasoning tokens at the output rate (same as completion tokens).
325
- - API cost is computed from OpenCode model pricing metadata, not from `message.cost`. This keeps subscription-backed providers such as OpenAI OAuth usable for API-equivalent cost estimation even when OpenCode's measured cost is `0`.
326
- - When OpenCode exposes a long-context tier like `context_over_200k`, the plugin uses that premium rate for the whole request once `input > 200000`, matching OpenCode's current pricing schema.
327
- - `quota.providers` is the extensible per-adapter switch map.
328
- - If API Cost is `$0.00`, it usually means the model/provider has no pricing mapping in OpenCode at the moment, so equivalent API cost cannot be estimated.
271
+ - `quota.refreshAccessToken`: `false`
272
+ - `quota.requestTimeoutMs`: `8000` (clamped to `>=1000`)
273
+
274
+ Other defaults:
275
+
276
+ - `toast.durationMs`: `12000` (clamped to `>=1000`)
277
+ - `retentionDays`: `730`
278
+
279
+ ### Full example config
280
+
281
+ ```json
282
+ {
283
+ "sidebar": {
284
+ "enabled": true,
285
+ "width": 36,
286
+ "multilineTitle": true,
287
+ "showCost": true,
288
+ "showQuota": true,
289
+ "wrapQuotaLines": true,
290
+ "includeChildren": true,
291
+ "childrenMaxDepth": 6,
292
+ "childrenMaxSessions": 128,
293
+ "childrenConcurrency": 5,
294
+ "desktopCompact": {
295
+ "recentRequests": 50,
296
+ "recentMinutes": 60
297
+ }
298
+ },
299
+ "quota": {
300
+ "refreshMs": 300000,
301
+ "includeOpenAI": true,
302
+ "includeCopilot": true,
303
+ "includeAnthropic": true,
304
+ "providers": {
305
+ "buzz": {
306
+ "enabled": true
307
+ },
308
+ "rightcode": {
309
+ "enabled": true
310
+ }
311
+ },
312
+ "refreshAccessToken": false,
313
+ "requestTimeoutMs": 8000
314
+ },
315
+ "toast": {
316
+ "durationMs": 12000
317
+ },
318
+ "retentionDays": 730
319
+ }
320
+ ```
321
+
322
+ ### Notes
323
+
324
+ - `sidebar.showCost` controls API-cost visibility in sidebar title, `quota_summary` markdown report, and toast message.
325
+ - `quota_summary` follows the same reset compaction rules for short windows in its subscription section (`5h` / `1d` / `Daily` show time, long windows show date, RightCode `Exp` stays date-only).
326
+ - `sidebar.width` is measured in terminal cells. CJK/emoji truncation is best-effort to avoid sidebar overflow.
327
+ - `sidebar.multilineTitle` is kept for backward compatibility, but current rendering is fixed by client type: TUI uses multiline titles and Desktop uses compact single-line titles.
328
+ - `sidebar.wrapQuotaLines` controls quota line wrapping and continuation indentation (default: `true`).
329
+ - `sidebar.includeChildren` controls whether session-scoped usage/quota includes descendant subagent sessions (default: `true`).
330
+ - `sidebar.childrenMaxDepth` limits how many levels of nested subagents are traversed (default: `6`, clamped 1–32).
331
+ - `sidebar.childrenMaxSessions` caps the total number of descendant sessions aggregated (default: `128`, clamped 0–2000).
332
+ - `sidebar.childrenConcurrency` controls parallel fetches for descendant session messages (default: `5`, clamped 1–10).
333
+ - `sidebar.desktopCompact.recentRequests` and `sidebar.desktopCompact.recentMinutes` control which recently used providers remain visible in desktop compact titles.
334
+ - `output` includes reasoning tokens (`output = tokens.output + tokens.reasoning`). Reasoning is not rendered as a separate line.
335
+ - API cost bills reasoning tokens at the output rate (same as completion tokens).
336
+ - API cost is computed from OpenCode model pricing metadata, not from `message.cost`. This keeps subscription-backed providers such as OpenAI OAuth usable for API-equivalent cost estimation even when OpenCode's measured cost is `0`.
337
+ - When OpenCode exposes a long-context tier like `context_over_200k`, the plugin uses that premium rate for the whole request once `input > 200000`, matching OpenCode's current pricing schema.
338
+ - `quota.providers` is the extensible per-adapter switch map.
339
+ - If API Cost is `$0.00`, it usually means the model/provider has no pricing mapping in OpenCode at the moment, so equivalent API cost cannot be estimated.
329
340
  - Usage chunks cache both measured `cost` and computed `apiCost`. `quota_summary` (`/qday`, `/qweek`, `/qmonth`) recomputes range totals from session messages so period filtering follows message completion time; refreshed full-session usage may then be persisted back into day chunks when billing-cache refresh is needed.
330
-
331
- ### Buzz provider example
332
-
333
- Buzz matching is based on the provider `baseURL`, similar to RightCode. Any OpenAI-compatible provider that points at `https://buzzai.cc` will be recognized by the Buzz adapter and rendered as a balance-only quota source.
334
-
335
- Provider options example:
336
-
337
- ```json
338
- {
339
- "id": "openai",
340
- "options": {
341
- "baseURL": "https://buzzai.cc",
342
- "apiKey": "sk-..."
343
- }
344
- }
345
- ```
346
-
347
- The adapter also tolerates `https://buzzai.cc/v1`, but `https://buzzai.cc` is the recommended example.
348
-
349
- With that setup, the sidebar/toast quota line will look like:
350
-
351
- ```text
341
+
342
+ ### Buzz provider example
343
+
344
+ Buzz matching is based on the provider `baseURL`, similar to RightCode. Any OpenAI-compatible provider that points at `https://buzzai.cc` will be recognized by the Buzz adapter and rendered as a balance-only quota source.
345
+
346
+ Provider options example:
347
+
348
+ ```json
349
+ {
350
+ "id": "openai",
351
+ "options": {
352
+ "baseURL": "https://buzzai.cc",
353
+ "apiKey": "sk-..."
354
+ }
355
+ }
356
+ ```
357
+
358
+ The adapter also tolerates `https://buzzai.cc/v1`, but `https://buzzai.cc` is the recommended example.
359
+
360
+ With that setup, the sidebar/toast quota line will look like:
361
+
362
+ ```text
352
363
  Buzz Balance ¥10.17
353
- ```
354
-
355
- ## Rendering examples
356
-
357
- These examples show the quota block portion of the sidebar title.
358
-
359
- ### `sidebar.multilineTitle=true`
360
-
361
- 0 providers (no quota data):
362
-
363
- ```text
364
- (no quota block)
365
- ```
366
-
367
- 1 provider, 1 window (fits):
368
-
369
- ```text
370
- Copilot Monthly 78% Rst 04-01
371
- ```
372
-
373
- 1 provider, multi-window (for example OpenAI 5h + Weekly):
374
-
375
- ```text
376
- OpenAI
377
- 5h 78% Rst 05:05
378
- Weekly 73% Rst 03-12
379
- ```
380
-
381
- 1 provider, short window crossing into the next day:
382
-
383
- ```text
384
- Anthropic
385
- 5h 0% Rst 03-10 01:00
386
- Weekly 46% Rst 03-15
387
- ```
388
-
389
- 2+ providers (even if each provider is single-window):
390
-
391
- ```text
392
- OpenAI
393
- 5h 78% Rst 05:05
394
- Copilot
395
- Monthly 78% Rst 04-01
396
- ```
397
-
398
- 2+ providers mixed (multi-window + single-window):
399
-
400
- ```text
401
- OpenAI
402
- 5h 78% Rst 05:05
403
- Weekly 73% Rst 03-12
404
- Copilot
405
- Monthly 78% Rst 04-01
406
- ```
407
-
408
- 2+ providers mixed (window providers + Buzz balance):
409
-
410
- ```text
411
- OpenAI
412
- 5h 78% Rst 05:05
413
- Copilot
414
- Monthly 78% Rst 04-01
364
+ ```
365
+
366
+ ## Rendering examples
367
+
368
+ These examples show the quota block portion of the sidebar title.
369
+
370
+ ### TUI layout
371
+
372
+ This section describes the TUI layout. Desktop uses its own compact single-line format and Web UI currently follows the multiline path.
373
+
374
+ 0 providers (no quota data):
375
+
376
+ ```text
377
+ (no quota block)
378
+ ```
379
+
380
+ 1 provider, 1 window (fits):
381
+
382
+ ```text
383
+ Copilot Monthly 78% Rst 04-01
384
+ ```
385
+
386
+ 1 provider, multi-window (for example OpenAI 5h + Weekly):
387
+
388
+ ```text
389
+ OpenAI
390
+ 5h 78% Rst 05:05
391
+ Weekly 73% Rst 03-12
392
+ ```
393
+
394
+ 1 provider, short window crossing into the next day:
395
+
396
+ ```text
397
+ Anthropic
398
+ 5h 0% Rst 03-10 01:00
399
+ Weekly 46% Rst 03-15
400
+ ```
401
+
402
+ 2+ providers (even if each provider is single-window):
403
+
404
+ ```text
405
+ OpenAI
406
+ 5h 78% Rst 05:05
407
+ Copilot
408
+ Monthly 78% Rst 04-01
409
+ ```
410
+
411
+ 2+ providers mixed (multi-window + single-window):
412
+
413
+ ```text
414
+ OpenAI
415
+ 5h 78% Rst 05:05
416
+ Weekly 73% Rst 03-12
417
+ Copilot
418
+ Monthly 78% Rst 04-01
419
+ ```
420
+
421
+ 2+ providers mixed (window providers + Buzz balance):
422
+
423
+ ```text
424
+ OpenAI
425
+ 5h 78% Rst 05:05
426
+ Copilot
427
+ Monthly 78% Rst 04-01
415
428
  Buzz Balance ¥10.2
416
- ```
417
-
418
- Balance-style quota:
419
-
420
- ```text
421
- RC Balance $260
422
- ```
423
-
424
- Buzz balance quota:
425
-
426
- ```text
429
+ ```
430
+
431
+ Balance-style quota:
432
+
433
+ ```text
434
+ RC Balance $260
435
+ ```
436
+
437
+ Buzz balance quota:
438
+
439
+ ```text
427
440
  Buzz Balance ¥10.17
428
- ```
429
-
430
- Multi-detail quota (window + balance):
431
-
432
- ```text
433
- RC
434
- Daily $88.9/$60 Exp 02-27
435
- Balance $260
436
- ```
437
-
438
- Provider status / quota (examples):
439
-
440
- ```text
441
- Anthropic 5h 80%+
442
- Copilot unavailable
443
- OpenAI Remaining ?
444
- ```
445
-
446
- ### `sidebar.multilineTitle=false`
447
-
448
- Quota is rendered inline as part of a single-line title:
449
-
450
- ```text
451
- <base> | Input ... | Output ... | OpenAI 5h 78%+ | Copilot Monthly 78% | ...
452
- ```
453
-
454
- Mixed with Buzz balance:
455
-
456
- ```text
457
- <base> | Input ... | Output ... | OpenAI 5h 78%+ | Copilot Monthly 78% | Buzz Balance ¥10.2
458
- ```
459
-
460
- `quota_summary` also supports an optional `includeChildren` flag (only effective for `period=session`) to override the config per call. For `day`/`week`/`month` periods, children are never merged — each session is counted independently.
461
-
462
- ## Billing cache behavior
463
-
464
- - Cached per-session usage stores token totals, measured `cost`, computed `apiCost`, provider breakdowns, and the incremental cursor.
465
- - Session-scoped sidebar aggregation can merge descendant subagents when `sidebar.includeChildren=true` (default). Measured `cost` stays aligned with the root session's OpenCode `message.cost`, while API-equivalent cost still includes descendant usage.
466
- - Range tools such as `/qday`, `/qweek`, and `/qmonth` do not merge children. They aggregate each session independently across the selected time window.
467
- - When API-cost logic changes, the plugin bumps an internal billing-cache version so historical range reports are recomputed with the new rules the next time they are queried.
468
-
469
- ## Debug logging
470
-
471
- Set `OPENCODE_QUOTA_DEBUG=1` to enable debug logging to stderr. This logs:
472
-
473
- - Chunk I/O operations
474
- - Auth refresh attempts and failures
475
- - Session eviction counts
476
- - Symlink write refusals
477
-
478
- ## Security & privacy notes
479
-
480
- - The plugin reads OpenCode credentials from `<opencode-data>/auth.json`.
441
+ ```
442
+
443
+ Multi-detail quota (window + balance):
444
+
445
+ ```text
446
+ RC
447
+ Daily $88.9/$60 Exp 02-27
448
+ Balance $260
449
+ ```
450
+
451
+ Provider status / quota (examples):
452
+
453
+ ```text
454
+ Anthropic 5h 80%+
455
+ Copilot unavailable
456
+ OpenAI Remaining ?
457
+ ```
458
+
459
+ ### Legacy compact single-line layout
460
+
461
+ For historical reference, the old non-desktop compact layout looked like this:
462
+
463
+ ```text
464
+ <base> | Req ... | Input ... | Output ... | OpenAI 5h 78%+ | Copilot Monthly 78% | ...
465
+ ```
466
+
467
+ Mixed with Buzz balance:
468
+
469
+ ```text
470
+ <base> | Req ... | Input ... | Output ... | OpenAI 5h 78%+ | Copilot Monthly 78% | Buzz Balance ¥10.2
471
+ ```
472
+
473
+ ### Desktop compact mode
474
+
475
+ Desktop always uses a compact single-line title. Recently used providers are selected from the last `50` assistant requests or last `60` minutes, and each selected provider expands all of its windows and balances in shorthand. To survive upstream Desktop truncation better, quota segments are emitted before usage stats:
476
+
477
+ ```text
478
+ <base> | OAI 5h80 W70 | Cop M78 | RC D88.9/60 B260 | Buzz B¥10.2 | R12 I18.9k O53
479
+ ```
480
+
481
+ Shorthand rules:
482
+
483
+ - `R12` = 12 requests
484
+ - `I18.9k` / `O53` = input / output tokens
485
+ - `5h80` = `5h 80%`
486
+ - `W70` / `M78` / `D46` = weekly / monthly / daily window remaining percent
487
+ - `D88.9/60` = daily remaining / daily total
488
+ - `B260` / `B¥10.2` = balance
489
+ - Order is `base | quota... | usage`, while TUI keeps its multiline usage-first layout.
490
+
491
+ `quota_summary` also supports an optional `includeChildren` flag (only effective for `period=session`) to override the config per call. For `day`/`week`/`month` periods, children are never merged — each session is counted independently.
492
+
493
+ ## Billing cache behavior
494
+
495
+ - Cached per-session usage stores token totals, measured `cost`, computed `apiCost`, provider breakdowns, and the incremental cursor.
496
+ - Session-scoped sidebar aggregation can merge descendant subagents when `sidebar.includeChildren=true` (default). Measured `cost` stays aligned with the root session's OpenCode `message.cost`, while API-equivalent cost still includes descendant usage.
497
+ - Range tools such as `/qday`, `/qweek`, and `/qmonth` do not merge children. They aggregate each session independently across the selected time window.
498
+ - When API-cost logic changes, the plugin bumps an internal billing-cache version so historical range reports are recomputed with the new rules the next time they are queried.
499
+
500
+ ## Debug logging
501
+
502
+ Set `OPENCODE_QUOTA_DEBUG=1` to enable debug logging to stderr. This logs:
503
+
504
+ - Chunk I/O operations
505
+ - Auth refresh attempts and failures
506
+ - Session eviction counts
507
+ - Symlink write refusals
508
+
509
+ ## Security & privacy notes
510
+
511
+ - The plugin reads OpenCode credentials from `<opencode-data>/auth.json`.
481
512
  - If enabled, quota checks call external endpoints:
482
513
  - OpenAI Codex: `https://chatgpt.com/backend-api/wham/usage`
483
514
  - GitHub Copilot: `https://api.github.com/copilot_internal/user`
@@ -485,30 +516,30 @@ Set `OPENCODE_QUOTA_DEBUG=1` to enable debug logging to stderr. This logs:
485
516
  - RightCode: `https://www.right.codes/account/summary`
486
517
  - Buzz: `https://buzzai.cc/v1/dashboard/billing/subscription` and `https://buzzai.cc/v1/dashboard/billing/usage`
487
518
  - Anthropic: `https://api.anthropic.com/api/oauth/usage`
488
- - **Screen-sharing warning**: Session titles and toasts surface usage/quota
489
- information. If you are screen-sharing or recording, consider toggling the
490
- sidebar display off (`/qtoggle` or `quota_show` tool) to avoid leaking
491
- subscription details.
492
- - State is persisted under `<opencode-data>/quota-sidebar.state.json` and
493
- `<opencode-data>/quota-sidebar-sessions/` (see Storage layout).
494
- - OpenAI OAuth token refresh is disabled by default; set
495
- `quota.refreshAccessToken=true` if you want the plugin to refresh access
496
- tokens when expired.
519
+ - **Screen-sharing warning**: Session titles and toasts surface usage/quota
520
+ information. If you are screen-sharing or recording, consider toggling the
521
+ sidebar display off (`/qtoggle` or `quota_show` tool) to avoid leaking
522
+ subscription details.
523
+ - State is persisted under `<opencode-data>/quota-sidebar.state.json` and
524
+ `<opencode-data>/quota-sidebar-sessions/` (see Storage layout).
525
+ - OpenAI OAuth token refresh is disabled by default; set
526
+ `quota.refreshAccessToken=true` if you want the plugin to refresh access
527
+ tokens when expired.
497
528
  - Anthropic quota currently uses a beta/internal-style OAuth usage endpoint and
498
529
  request header; response fields may change without notice.
499
530
  - Kimi For Coding quota uses the current `/usages` response shape exposed by the Kimi coding service; if Kimi changes that payload, window parsing may need to be updated.
500
- - State/chunk file writes refuse to write through symlinked targets (best-effort defense-in-depth).
501
- - The `OPENCODE_QUOTA_DATA_HOME` env var overrides the OpenCode data directory
502
- path (for testing); do not set this in production.
503
- - The `OPENCODE_QUOTA_CONFIG_HOME` env var overrides global config directory
504
- lookup (`<config-home>/opencode`).
505
- - The `OPENCODE_QUOTA_CONFIG` env var points to an explicit config file and
506
- applies as the highest-priority override.
507
-
508
- ## Contributing
509
-
510
- Contributions are welcome — especially new quota provider connectors. See [CONTRIBUTING.md](CONTRIBUTING.md) for a step-by-step guide on adding support for a new provider.
511
-
512
- ## License
513
-
514
- MIT. See `LICENSE`.
531
+ - State/chunk file writes refuse to write through symlinked targets (best-effort defense-in-depth).
532
+ - The `OPENCODE_QUOTA_DATA_HOME` env var overrides the OpenCode data directory
533
+ path (for testing); do not set this in production.
534
+ - The `OPENCODE_QUOTA_CONFIG_HOME` env var overrides global config directory
535
+ lookup (`<config-home>/opencode`).
536
+ - The `OPENCODE_QUOTA_CONFIG` env var points to an explicit config file and
537
+ applies as the highest-priority override.
538
+
539
+ ## Contributing
540
+
541
+ Contributions are welcome — especially new quota provider connectors. See [CONTRIBUTING.md](CONTRIBUTING.md) for a step-by-step guide on adding support for a new provider.
542
+
543
+ ## License
544
+
545
+ MIT. See `LICENSE`.