@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.
Files changed (3) hide show
  1. package/README.md +107 -0
  2. package/dist/format.js +10 -3
  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 [withLabel('Remaining ?')];
308
+ return maybeBreak('Remaining ?', ['Remaining ?']);
302
309
  if (quota.status === 'unsupported')
303
- return [withLabel('unsupported')];
310
+ return maybeBreak('unsupported', ['unsupported']);
304
311
  if (quota.status === 'unavailable')
305
- return [withLabel('unavailable')];
312
+ return maybeBreak('unavailable', ['unavailable']);
306
313
  if (quota.status !== 'ok')
307
314
  return [];
308
315
  const balanceText = quota.balance
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leo000001/opencode-quota-sidebar",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "OpenCode plugin that shows quota and token usage in session titles",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",