@leo000001/opencode-quota-sidebar 1.11.0 → 1.12.0
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 +107 -0
- package/dist/format.js +10 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -164,6 +164,38 @@ Resolution order (low -> high):
|
|
|
164
164
|
|
|
165
165
|
Values are layered; later sources override earlier ones.
|
|
166
166
|
|
|
167
|
+
## Defaults
|
|
168
|
+
|
|
169
|
+
If you do not provide any config file, the plugin uses the built-in defaults below.
|
|
170
|
+
|
|
171
|
+
Sidebar defaults:
|
|
172
|
+
|
|
173
|
+
- `sidebar.enabled`: `true`
|
|
174
|
+
- `sidebar.width`: `36` (clamped to `20`-`60`)
|
|
175
|
+
- `sidebar.multilineTitle`: `true`
|
|
176
|
+
- `sidebar.showCost`: `true`
|
|
177
|
+
- `sidebar.showQuota`: `true`
|
|
178
|
+
- `sidebar.wrapQuotaLines`: `true`
|
|
179
|
+
- `sidebar.includeChildren`: `true`
|
|
180
|
+
- `sidebar.childrenMaxDepth`: `6` (clamped to `1`-`32`)
|
|
181
|
+
- `sidebar.childrenMaxSessions`: `128` (clamped to `0`-`2000`)
|
|
182
|
+
- `sidebar.childrenConcurrency`: `5` (clamped to `1`-`10`)
|
|
183
|
+
|
|
184
|
+
Quota defaults:
|
|
185
|
+
|
|
186
|
+
- `quota.refreshMs`: `300000` (clamped to `>=30000`)
|
|
187
|
+
- `quota.includeOpenAI`: `true`
|
|
188
|
+
- `quota.includeCopilot`: `true`
|
|
189
|
+
- `quota.includeAnthropic`: `true`
|
|
190
|
+
- `quota.providers`: `{}` (per-adapter switches, for example `rightcode.enabled`)
|
|
191
|
+
- `quota.refreshAccessToken`: `false`
|
|
192
|
+
- `quota.requestTimeoutMs`: `8000` (clamped to `>=1000`)
|
|
193
|
+
|
|
194
|
+
Other defaults:
|
|
195
|
+
|
|
196
|
+
- `toast.durationMs`: `12000` (clamped to `>=1000`)
|
|
197
|
+
- `retentionDays`: `730`
|
|
198
|
+
|
|
167
199
|
Example config:
|
|
168
200
|
|
|
169
201
|
```json
|
|
@@ -215,6 +247,81 @@ Notes:
|
|
|
215
247
|
- `quota.providers` is the extensible per-adapter switch map.
|
|
216
248
|
- 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.
|
|
217
249
|
|
|
250
|
+
## Rendering examples
|
|
251
|
+
|
|
252
|
+
These examples show the quota block portion of the sidebar title.
|
|
253
|
+
|
|
254
|
+
### `sidebar.multilineTitle=true`
|
|
255
|
+
|
|
256
|
+
0 providers (no quota data):
|
|
257
|
+
|
|
258
|
+
```text
|
|
259
|
+
(no quota block)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
1 provider, 1 window (fits):
|
|
263
|
+
|
|
264
|
+
```text
|
|
265
|
+
Copilot Monthly 78% Rst 04-01
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
1 provider, multi-window (for example OpenAI 5h + Weekly):
|
|
269
|
+
|
|
270
|
+
```text
|
|
271
|
+
OpenAI
|
|
272
|
+
5h 78% Rst 05:05
|
|
273
|
+
Weekly 73% Rst 03-12
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
2+ providers (even if each provider is single-window):
|
|
277
|
+
|
|
278
|
+
```text
|
|
279
|
+
OpenAI
|
|
280
|
+
5h 78% Rst 05:05
|
|
281
|
+
Copilot
|
|
282
|
+
Monthly 78% Rst 04-01
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
2+ providers mixed (multi-window + single-window):
|
|
286
|
+
|
|
287
|
+
```text
|
|
288
|
+
OpenAI
|
|
289
|
+
5h 78% Rst 05:05
|
|
290
|
+
Weekly 73% Rst 03-12
|
|
291
|
+
Copilot
|
|
292
|
+
Monthly 78% Rst 04-01
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Balance-style quota:
|
|
296
|
+
|
|
297
|
+
```text
|
|
298
|
+
RC Balance $260
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Multi-detail quota (window + balance):
|
|
302
|
+
|
|
303
|
+
```text
|
|
304
|
+
RC
|
|
305
|
+
Daily $88.9/$60 Exp 02-27
|
|
306
|
+
Balance $260
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Provider status (examples):
|
|
310
|
+
|
|
311
|
+
```text
|
|
312
|
+
Anthropic unsupported
|
|
313
|
+
Copilot unavailable
|
|
314
|
+
OpenAI Remaining ?
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### `sidebar.multilineTitle=false`
|
|
318
|
+
|
|
319
|
+
Quota is rendered inline as part of a single-line title:
|
|
320
|
+
|
|
321
|
+
```text
|
|
322
|
+
<base> | Input ... | Output ... | OpenAI 5h 78%+ | Copilot Monthly 78% | ...
|
|
323
|
+
```
|
|
324
|
+
|
|
218
325
|
`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.
|
|
219
326
|
|
|
220
327
|
## Debug logging
|
package/dist/format.js
CHANGED
|
@@ -248,6 +248,9 @@ export function renderSidebarTitle(baseTitle, usage, quotas, config) {
|
|
|
248
248
|
// Quota lines (one provider per line for stable wrapping)
|
|
249
249
|
if (config.sidebar.showQuota) {
|
|
250
250
|
const visibleQuotas = collapseQuotaSnapshots(quotas).filter((q) => ['ok', 'error', 'unsupported', 'unavailable'].includes(q.status));
|
|
251
|
+
// When multiple providers are visible, keep a consistent visual rhythm by
|
|
252
|
+
// always rendering each provider as a header line + indented detail line(s).
|
|
253
|
+
const forceWrappedProviders = visibleQuotas.length > 1;
|
|
251
254
|
const labelWidth = visibleQuotas.reduce((max, item) => {
|
|
252
255
|
const label = sanitizeLine(quotaDisplayLabel(item));
|
|
253
256
|
return Math.max(max, stringCellWidth(label));
|
|
@@ -256,6 +259,7 @@ export function renderSidebarTitle(baseTitle, usage, quotas, config) {
|
|
|
256
259
|
.flatMap((item) => compactQuotaWide(item, labelWidth, {
|
|
257
260
|
width,
|
|
258
261
|
wrapLines: config.sidebar.wrapQuotaLines,
|
|
262
|
+
forceWrapped: forceWrappedProviders,
|
|
259
263
|
}))
|
|
260
264
|
.filter((s) => Boolean(s));
|
|
261
265
|
if (quotaItems.length > 0) {
|
|
@@ -290,19 +294,22 @@ function compactQuotaWide(quota, labelWidth = 0, options) {
|
|
|
290
294
|
const withLabel = (content) => `${labelPadded} ${content}`;
|
|
291
295
|
const wrap = options?.wrapLines === true && (options?.width || 0) > 0;
|
|
292
296
|
const width = options?.width || 0;
|
|
297
|
+
const forceWrapped = options?.forceWrapped === true;
|
|
293
298
|
/** If inline version overflows, break into label-line + indented detail lines. */
|
|
294
299
|
const maybeBreak = (inlineText, detailLines) => {
|
|
295
300
|
const inline = withLabel(inlineText);
|
|
301
|
+
if (forceWrapped)
|
|
302
|
+
return [label, ...detailLines.map((d) => `${detailIndent}${d}`)];
|
|
296
303
|
if (!wrap || stringCellWidth(inline) <= width)
|
|
297
304
|
return [inline];
|
|
298
305
|
return [label, ...detailLines.map((d) => `${detailIndent}${d}`)];
|
|
299
306
|
};
|
|
300
307
|
if (quota.status === 'error')
|
|
301
|
-
return
|
|
308
|
+
return maybeBreak('Remaining ?', ['Remaining ?']);
|
|
302
309
|
if (quota.status === 'unsupported')
|
|
303
|
-
return
|
|
310
|
+
return maybeBreak('unsupported', ['unsupported']);
|
|
304
311
|
if (quota.status === 'unavailable')
|
|
305
|
-
return
|
|
312
|
+
return maybeBreak('unavailable', ['unavailable']);
|
|
306
313
|
if (quota.status !== 'ok')
|
|
307
314
|
return [];
|
|
308
315
|
const balanceText = quota.balance
|