@leo000001/opencode-quota-sidebar 4.0.5 → 4.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/dist/format.js CHANGED
@@ -1,10 +1,10 @@
1
- import { getCacheCoverageMetrics, getProviderCacheCoverageMetrics, } from './usage.js';
2
- import { canonicalProviderID, collapseQuotaSnapshots, displayShortLabel, quotaDisplayLabel, } from './quota_render.js';
3
- import { stripAnsi } from './title.js';
1
+ import { getCacheCoverageMetrics, getProviderCacheCoverageMetrics, } from "./usage.js";
2
+ import { canonicalProviderID, collapseQuotaSnapshots, displayShortLabel, quotaDisplayLabel, } from "./quota_render.js";
3
+ import { stripAnsi } from "./title.js";
4
4
  /** M6 fix: handle negative, NaN, Infinity gracefully. */
5
5
  function shortNumber(value, decimals = 1) {
6
6
  if (!Number.isFinite(value) || value < 0)
7
- return '0';
7
+ return "0";
8
8
  if (value >= 1_000_000)
9
9
  return `${(value / 1_000_000).toFixed(decimals)}m`;
10
10
  if (value >= 1000) {
@@ -23,9 +23,9 @@ function sidebarNumber(value) {
23
23
  function sanitizeLine(value) {
24
24
  // Sidebars/titles must be plain text: no ANSI and no embedded newlines.
25
25
  return (stripAnsi(value)
26
- .replace(/\r?\n/g, ' ')
26
+ .replace(/\r?\n/g, " ")
27
27
  // Remove control characters that can corrupt TUI rendering.
28
- .replace(/[\x00-\x1F\x7F-\x9F]/g, ' '));
28
+ .replace(/[\x00-\x1F\x7F-\x9F]/g, " "));
29
29
  }
30
30
  function isCombiningCodePoint(codePoint) {
31
31
  return ((codePoint >= 0x0300 && codePoint <= 0x036f) ||
@@ -93,13 +93,13 @@ function padEndCells(value, targetWidth) {
93
93
  const current = stringCellWidth(value);
94
94
  if (current >= targetWidth)
95
95
  return value;
96
- return `${value}${' '.repeat(targetWidth - current)}`;
96
+ return `${value}${" ".repeat(targetWidth - current)}`;
97
97
  }
98
98
  function truncateToCellWidth(value, width) {
99
99
  if (width <= 0)
100
- return '';
100
+ return "";
101
101
  let used = 0;
102
- let out = '';
102
+ let out = "";
103
103
  for (const char of value) {
104
104
  const w = cellWidthOfCodePoint(char.codePointAt(0) || 0);
105
105
  if (used + w > width)
@@ -115,7 +115,7 @@ function truncateToCellWidth(value, width) {
115
115
  */
116
116
  export function fitLine(value, width) {
117
117
  if (width <= 0)
118
- return '';
118
+ return "";
119
119
  const safe = sanitizeLine(value);
120
120
  if (stringCellWidth(safe) <= width)
121
121
  return safe;
@@ -130,7 +130,7 @@ export function fitLine(value, width) {
130
130
  }
131
131
  function formatCurrency(value, currency) {
132
132
  const safe = Number.isFinite(value) ? value : 0;
133
- const prefix = typeof currency === 'string' && currency ? currency : '$';
133
+ const prefix = typeof currency === "string" && currency ? currency : "$";
134
134
  if (safe === 0)
135
135
  return `${prefix}0.00`;
136
136
  if (safe < 0) {
@@ -138,28 +138,28 @@ function formatCurrency(value, currency) {
138
138
  if (abs < 10)
139
139
  return `-${prefix}${abs.toFixed(2)}`;
140
140
  const one = abs.toFixed(1);
141
- const trimmed = one.endsWith('.0') ? one.slice(0, -2) : one;
141
+ const trimmed = one.endsWith(".0") ? one.slice(0, -2) : one;
142
142
  return `-${prefix}${trimmed}`;
143
143
  }
144
144
  if (safe < 10)
145
145
  return `${prefix}${safe.toFixed(2)}`;
146
146
  const one = safe.toFixed(1);
147
- const trimmed = one.endsWith('.0') ? one.slice(0, -2) : one;
147
+ const trimmed = one.endsWith(".0") ? one.slice(0, -2) : one;
148
148
  return `${prefix}${trimmed}`;
149
149
  }
150
150
  function formatUsd(value) {
151
- return formatCurrency(value, '$');
151
+ return formatCurrency(value, "$");
152
152
  }
153
153
  function formatApiCostValue(value) {
154
154
  return formatUsd(value);
155
155
  }
156
156
  function formatApiCostLine(value) {
157
- return `${formatApiCostValue(value)} as API cost`;
157
+ return `API ${formatApiCostValue(value)}`;
158
158
  }
159
159
  function trimTrailingZeroUnit(value) {
160
160
  return value
161
- .replace(/(\d+)\.0(?=[km]\b)/i, '$1')
162
- .replace(/(\d+)\.0(?=$)/, '$1');
161
+ .replace(/(\d+)\.0(?=[km]\b)/i, "$1")
162
+ .replace(/(\d+)\.0(?=$)/, "$1");
163
163
  }
164
164
  function panelNumber(value) {
165
165
  return trimTrailingZeroUnit(shortNumber(value, 1));
@@ -170,11 +170,11 @@ function formatRequestsLabel(value, short = false) {
170
170
  }
171
171
  export function resolveTitleView(opts) {
172
172
  void opts;
173
- if (opts.config.sidebar.titleMode === 'compact')
174
- return 'compact';
175
- if (opts.config.sidebar.titleMode === 'multiline')
176
- return 'multiline';
177
- return 'compact';
173
+ if (opts.config.sidebar.titleMode === "compact")
174
+ return "compact";
175
+ if (opts.config.sidebar.titleMode === "multiline")
176
+ return "multiline";
177
+ return "compact";
178
178
  }
179
179
  function desktopCompactSettings(config) {
180
180
  return {
@@ -209,67 +209,67 @@ export function selectDesktopCompactProviderIDs(usage, config, now = Date.now())
209
209
  }
210
210
  function compactProviderLabel(quota) {
211
211
  const canonical = canonicalProviderID(quota.adapterID || quota.providerID);
212
- if (canonical === 'openai')
213
- return 'OAI';
214
- if (canonical === 'github-copilot')
215
- return 'Cop';
216
- if (canonical === 'anthropic')
217
- return 'Ant';
218
- if (canonical === 'kimi-for-coding')
219
- return 'Kimi';
220
- if (canonical === 'zhipuai-coding-plan')
221
- return 'Zhipu';
222
- if (canonical === 'minimax-cn-coding-plan')
223
- return 'MiniMax';
224
- if (canonical === 'rightcode')
225
- return 'RC';
212
+ if (canonical === "openai")
213
+ return "OAI";
214
+ if (canonical === "github-copilot")
215
+ return "Cop";
216
+ if (canonical === "anthropic")
217
+ return "Ant";
218
+ if (canonical === "kimi-for-coding")
219
+ return "Kimi";
220
+ if (canonical === "zhipuai-coding-plan")
221
+ return "Zhipu";
222
+ if (canonical === "minimax-cn-coding-plan")
223
+ return "MiniMax";
224
+ if (canonical === "rightcode")
225
+ return "RC";
226
226
  return sanitizeLine(quotaDisplayLabel(quota));
227
227
  }
228
228
  function compactWindowToken(label) {
229
- const safe = sanitizeLine(label || '');
229
+ const safe = sanitizeLine(label || "");
230
230
  if (!safe)
231
- return '';
231
+ return "";
232
232
  if (/^daily$/i.test(safe))
233
- return 'D';
233
+ return "D";
234
234
  if (/^weekly$/i.test(safe))
235
- return 'W';
235
+ return "W";
236
236
  if (/^monthly$/i.test(safe))
237
- return 'M';
237
+ return "M";
238
238
  if (/^1d$/i.test(safe))
239
- return 'D';
239
+ return "D";
240
240
  return safe;
241
241
  }
242
242
  function compactQuotaResetToken(resetLabel) {
243
- const safe = sanitizeLine(resetLabel || '');
243
+ const safe = sanitizeLine(resetLabel || "");
244
244
  if (!safe || /^rst$/i.test(safe))
245
- return 'R';
245
+ return "R";
246
246
  if (/^exp\+$/i.test(safe))
247
- return 'E+';
247
+ return "E+";
248
248
  if (/^exp$/i.test(safe))
249
- return 'E';
249
+ return "E";
250
250
  return safe;
251
251
  }
252
252
  function compactQuotaPercentToken(label, percent) {
253
253
  const rounded = percent !== undefined && Number.isFinite(percent)
254
254
  ? `${Math.round(percent)}`
255
- : '';
256
- const safe = sanitizeLine(label || '');
255
+ : "";
256
+ const safe = sanitizeLine(label || "");
257
257
  if (!safe)
258
- return rounded ? `R${rounded}` : '';
258
+ return rounded ? `R${rounded}` : "";
259
259
  if (/^sonnet\s+7d$/i.test(safe))
260
- return rounded ? `S7d${rounded}` : 'S7d';
260
+ return rounded ? `S7d${rounded}` : "S7d";
261
261
  if (/^opus\s+7d$/i.test(safe))
262
- return rounded ? `O7d${rounded}` : 'O7d';
262
+ return rounded ? `O7d${rounded}` : "O7d";
263
263
  if (/^oauth\s+apps\s+7d$/i.test(safe)) {
264
- return rounded ? `OA7d${rounded}` : 'OA7d';
264
+ return rounded ? `OA7d${rounded}` : "OA7d";
265
265
  }
266
266
  if (/^cowork\s+7d$/i.test(safe))
267
- return rounded ? `Co7d${rounded}` : 'Co7d';
267
+ return rounded ? `Co7d${rounded}` : "Co7d";
268
268
  if (/^spark\s+5h$/i.test(safe))
269
- return rounded ? `Sk5h${rounded}` : 'Sk5h';
269
+ return rounded ? `Sk5h${rounded}` : "Sk5h";
270
270
  if (/^spark\s+weekly$/i.test(safe))
271
- return rounded ? `SkW${rounded}` : 'SkW';
272
- const token = compactWindowToken(safe).replace(/\s+/g, '');
271
+ return rounded ? `SkW${rounded}` : "SkW";
272
+ const token = compactWindowToken(safe).replace(/\s+/g, "");
273
273
  if (!rounded)
274
274
  return token;
275
275
  if (/^(?:D|W|M|\d+[hdw])$/i.test(token))
@@ -281,24 +281,24 @@ function compactQuotaWindowText(win) {
281
281
  const resetToken = reset
282
282
  ? `${compactQuotaResetToken(win.resetLabel)}${reset}`
283
283
  : undefined;
284
- const note = sanitizeLine(win.note || '');
284
+ const note = sanitizeLine(win.note || "");
285
285
  if (win.showPercent === false) {
286
- const safe = sanitizeLine(win.label || '');
287
- const daily = safe ? safe.replace(/^Daily\s+/i, 'D') : '';
288
- return [daily, resetToken, note].filter(Boolean).join(' ');
286
+ const safe = sanitizeLine(win.label || "");
287
+ const daily = safe ? safe.replace(/^Daily\s+/i, "D") : "";
288
+ return [daily, resetToken, note].filter(Boolean).join(" ");
289
289
  }
290
290
  const percentToken = compactQuotaPercentToken(win.label, win.remainingPercent);
291
- return [percentToken, resetToken, note].filter(Boolean).join(' ');
291
+ return [percentToken, resetToken, note].filter(Boolean).join(" ");
292
292
  }
293
293
  function compactQuotaWindowTokens(win) {
294
294
  const reset = compactReset(win.resetAt, win.resetLabel, win.label);
295
295
  const resetToken = reset
296
296
  ? `${compactQuotaResetToken(win.resetLabel)}${reset}`
297
297
  : undefined;
298
- const note = sanitizeLine(win.note || '');
298
+ const note = sanitizeLine(win.note || "");
299
299
  if (win.showPercent === false) {
300
- const safe = sanitizeLine(win.label || '');
301
- const daily = safe ? safe.replace(/^Daily\s+/i, 'D') : '';
300
+ const safe = sanitizeLine(win.label || "");
301
+ const daily = safe ? safe.replace(/^Daily\s+/i, "D") : "";
302
302
  return [daily, resetToken, note].filter((value) => Boolean(value));
303
303
  }
304
304
  const percentToken = compactQuotaPercentToken(win.label, win.remainingPercent);
@@ -307,7 +307,7 @@ function compactQuotaWindowTokens(win) {
307
307
  function compactQuotaBalanceText(balance) {
308
308
  return `B${compactDesktopCurrencyValue(balance.amount, balance.currency)}`;
309
309
  }
310
- function packInlineTokens(label, tokens, width, indent = ' ') {
310
+ function packInlineTokens(label, tokens, width, indent = " ") {
311
311
  if (tokens.length === 0)
312
312
  return [label];
313
313
  const lines = [];
@@ -326,20 +326,20 @@ function packInlineTokens(label, tokens, width, indent = ' ') {
326
326
  }
327
327
  function compactDesktopCurrencyValue(value, currency) {
328
328
  const rendered = formatCurrency(value, currency);
329
- if (currency === '$')
330
- return rendered.replace(/^\$/, '');
329
+ if (currency === "$")
330
+ return rendered.replace(/^\$/, "");
331
331
  return rendered;
332
332
  }
333
333
  function compactQuotaStaleToken(quota) {
334
- return quota.stale ? 'St' : undefined;
334
+ return quota.stale ? "St" : undefined;
335
335
  }
336
336
  function verboseQuotaStaleText(quota) {
337
- return quota.stale ? 'stale' : undefined;
337
+ return quota.stale ? "stale" : undefined;
338
338
  }
339
339
  function compactDesktopQuotaSegment(quota) {
340
340
  const label = compactProviderLabel(quota);
341
- if (quota.status !== 'ok') {
342
- if (quota.status === 'error')
341
+ if (quota.status !== "ok") {
342
+ if (quota.status === "error")
343
343
  return `${label} ?`;
344
344
  return `${label} ${sanitizeLine(quota.status)}`;
345
345
  }
@@ -365,11 +365,11 @@ function compactDesktopQuotaSegment(quota) {
365
365
  const staleToken = compactQuotaStaleToken(quota);
366
366
  if (staleToken)
367
367
  parts.push(staleToken);
368
- return [label, ...parts].filter(Boolean).join(' ');
368
+ return [label, ...parts].filter(Boolean).join(" ");
369
369
  }
370
370
  function renderDesktopCompactTitle(baseTitle, usage, quotas, config, _width) {
371
371
  const visibleQuotas = config.sidebar.showQuota
372
- ? collapseQuotaSnapshots(quotas).filter((q) => ['ok', 'error', 'unsupported', 'unavailable'].includes(q.status))
372
+ ? collapseQuotaSnapshots(quotas).filter((q) => ["ok", "error", "unsupported", "unavailable"].includes(q.status))
373
373
  : [];
374
374
  const selectedProviderIDs = new Set(selectDesktopCompactProviderIDs(usage, config));
375
375
  const quotaSegments = visibleQuotas
@@ -382,11 +382,11 @@ function renderDesktopCompactTitle(baseTitle, usage, quotas, config, _width) {
382
382
  usageSegments.push(`Cd${formatPercent(cacheMetrics.cachedRatio, 0)}`);
383
383
  }
384
384
  if (config.sidebar.showCost && usage.apiCost > 0) {
385
- usageSegments.push(`Est${formatApiCostValue(usage.apiCost)}`);
385
+ usageSegments.push(`API${formatApiCostValue(usage.apiCost)}`);
386
386
  }
387
387
  const segments = [...quotaSegments, ...usageSegments];
388
- const detail = segments.join(' | ');
389
- const safeBase = sanitizeLine(baseTitle) || 'Session';
388
+ const detail = segments.join(" | ");
389
+ const safeBase = sanitizeLine(baseTitle) || "Session";
390
390
  if (!detail)
391
391
  return safeBase;
392
392
  return `${safeBase} | ${detail}`;
@@ -394,7 +394,7 @@ function renderDesktopCompactTitle(baseTitle, usage, quotas, config, _width) {
394
394
  function formatPercent(value, decimals = 1) {
395
395
  const safe = Number.isFinite(value) && value >= 0 ? value : 0;
396
396
  const pct = (safe * 100).toFixed(decimals);
397
- return `${pct.replace(/\.0+$/, '').replace(/(\.\d*[1-9])0+$/, '$1')}%`;
397
+ return `${pct.replace(/\.0+$/, "").replace(/(\.\d*[1-9])0+$/, "$1")}%`;
398
398
  }
399
399
  function fitsLine(value, width) {
400
400
  return stringCellWidth(sanitizeLine(value)) <= width;
@@ -402,7 +402,7 @@ function fitsLine(value, width) {
402
402
  function usageDetailLines(usage, cacheMetrics, options) {
403
403
  const width = options.width;
404
404
  const numberToken = options.numberToken || sidebarNumber;
405
- const costToken = options.costToken || ((value) => `Est${formatApiCostValue(value)}`);
405
+ const costToken = options.costToken || ((value) => `API${formatApiCostValue(value)}`);
406
406
  const groups = [];
407
407
  groups.push([
408
408
  `R${shortNumber(usage.assistantMessages, 1)}`,
@@ -437,7 +437,7 @@ function usageDetailLines(usage, cacheMetrics, options) {
437
437
  }
438
438
  if (cacheTokens.length > 0) {
439
439
  if (coverageTokens.length > 0) {
440
- const combined = [...coverageTokens, ...cacheTokens].join(' ');
440
+ const combined = [...coverageTokens, ...cacheTokens].join(" ");
441
441
  if (fitsLine(combined, width)) {
442
442
  secondaryGroups.length = 0;
443
443
  secondaryGroups.push([...coverageTokens, ...cacheTokens]);
@@ -456,7 +456,7 @@ function usageDetailLines(usage, cacheMetrics, options) {
456
456
  }
457
457
  const packed = [];
458
458
  for (const group of groups) {
459
- let current = '';
459
+ let current = "";
460
460
  for (const token of group) {
461
461
  const candidate = current ? `${current} ${token}` : token;
462
462
  if (!current || fitsLine(candidate, width)) {
@@ -474,7 +474,7 @@ function usageDetailLines(usage, cacheMetrics, options) {
474
474
  function packUsageGroups(groups, width) {
475
475
  const packed = [];
476
476
  for (const group of groups) {
477
- let current = '';
477
+ let current = "";
478
478
  for (const token of group) {
479
479
  const candidate = current ? `${current} ${token}` : token;
480
480
  if (!current || fitsLine(candidate, width)) {
@@ -518,7 +518,7 @@ function readableSidebarUsageLines(usage, cacheMetrics, width, showCost) {
518
518
  }
519
519
  const summaryTokens = [];
520
520
  if (showCost && usage.apiCost > 0) {
521
- summaryTokens.push(`Est ${formatApiCostValue(usage.apiCost)}`);
521
+ summaryTokens.push(`API ${formatApiCostValue(usage.apiCost)}`);
522
522
  }
523
523
  if (summaryTokens.length > 0)
524
524
  groups.push(summaryTokens);
@@ -531,7 +531,7 @@ function readableSidebarUsageLines(usage, cacheMetrics, width, showCost) {
531
531
  return packed;
532
532
  }
533
533
  function formatQuotaPercent(value, options) {
534
- const missing = options?.missing ?? '-';
534
+ const missing = options?.missing ?? "-";
535
535
  if (value === undefined)
536
536
  return missing;
537
537
  if (!Number.isFinite(value) || value < 0)
@@ -540,17 +540,17 @@ function formatQuotaPercent(value, options) {
540
540
  return `${Math.round(value)}%`;
541
541
  return `${value.toFixed(options?.decimals ?? 1)}%`;
542
542
  }
543
- function alignPairs(pairs, indent = ' ') {
543
+ function alignPairs(pairs, indent = " ") {
544
544
  if (pairs.length === 0)
545
545
  return [];
546
546
  const safePairs = pairs.map((pair) => ({
547
- label: sanitizeLine(pair.label || ''),
548
- value: sanitizeLine(pair.value || ''),
547
+ label: sanitizeLine(pair.label || ""),
548
+ value: sanitizeLine(pair.value || ""),
549
549
  }));
550
550
  const labelWidth = Math.max(...safePairs.map((pair) => stringCellWidth(pair.label)), 0);
551
551
  return safePairs.map((pair) => {
552
552
  if (!pair.label) {
553
- return `${indent}${' '.repeat(labelWidth)} ${pair.value}`;
553
+ return `${indent}${" ".repeat(labelWidth)} ${pair.value}`;
554
554
  }
555
555
  return `${indent}${padEndCells(pair.label, labelWidth)} ${pair.value}`;
556
556
  });
@@ -558,37 +558,37 @@ function alignPairs(pairs, indent = ' ') {
558
558
  function compactQuotaInline(quota) {
559
559
  const label = sanitizeLine(quotaDisplayLabel(quota));
560
560
  const staleToken = compactQuotaStaleToken(quota);
561
- if (quota.status !== 'ok') {
562
- if (quota.status === 'error')
561
+ if (quota.status !== "ok") {
562
+ if (quota.status === "error")
563
563
  return `${label} Remaining ?`;
564
564
  return `${label} ${sanitizeLine(quota.status)}`;
565
565
  }
566
566
  if (quota.windows && quota.windows.length > 0) {
567
567
  const first = quota.windows[0];
568
568
  const showPercent = first.showPercent !== false;
569
- const firstLabel = sanitizeLine(first.label || '');
569
+ const firstLabel = sanitizeLine(first.label || "");
570
570
  const pct = formatQuotaPercent(first.remainingPercent, {
571
571
  rounded: true,
572
- missing: '',
572
+ missing: "",
573
573
  });
574
574
  const summary = showPercent
575
- ? [firstLabel, pct].filter(Boolean).join(' ')
576
- : firstLabel.replace(/^Daily\s+/i, '') || firstLabel;
575
+ ? [firstLabel, pct].filter(Boolean).join(" ")
576
+ : firstLabel.replace(/^Daily\s+/i, "") || firstLabel;
577
577
  const hasMore = quota.windows.length > 1 ||
578
- (quota.balance !== undefined && !summary.includes('Balance '));
579
- return `${label}${summary ? ` ${summary}` : ''}${hasMore ? '+' : ''}${staleToken ? ` ${staleToken}` : ''}`;
578
+ (quota.balance !== undefined && !summary.includes("Balance "));
579
+ return `${label}${summary ? ` ${summary}` : ""}${hasMore ? "+" : ""}${staleToken ? ` ${staleToken}` : ""}`;
580
580
  }
581
581
  if (quota.balance) {
582
- return `${label} Balance ${formatCurrency(quota.balance.amount, quota.balance.currency)}${staleToken ? ` ${staleToken}` : ''}`;
582
+ return `${label} Balance ${formatCurrency(quota.balance.amount, quota.balance.currency)}${staleToken ? ` ${staleToken}` : ""}`;
583
583
  }
584
584
  const singlePercent = formatQuotaPercent(quota.remainingPercent, {
585
585
  rounded: true,
586
- missing: '',
586
+ missing: "",
587
587
  });
588
588
  if (singlePercent) {
589
- return `${label} ${singlePercent}${staleToken ? ` ${staleToken}` : ''}`;
589
+ return `${label} ${singlePercent}${staleToken ? ` ${staleToken}` : ""}`;
590
590
  }
591
- return `${label}${staleToken ? ` ${staleToken}` : ''}`;
591
+ return `${label}${staleToken ? ` ${staleToken}` : ""}`;
592
592
  }
593
593
  function renderSingleLineTitle(baseTitle, usage, quotas, config, width) {
594
594
  const baseBudget = Math.min(16, Math.max(8, Math.floor(width * 0.35)));
@@ -611,10 +611,10 @@ function renderSingleLineTitle(baseTitle, usage, quotas, config, width) {
611
611
  segments.push(formatApiCostLine(usage.apiCost));
612
612
  }
613
613
  if (config.sidebar.showQuota) {
614
- const visibleQuotas = collapseQuotaSnapshots(quotas).filter((q) => ['ok', 'error', 'unsupported', 'unavailable'].includes(q.status));
614
+ const visibleQuotas = collapseQuotaSnapshots(quotas).filter((q) => ["ok", "error", "unsupported", "unavailable"].includes(q.status));
615
615
  segments.push(...visibleQuotas.map(compactQuotaInline));
616
616
  }
617
- const detail = segments.filter(Boolean).join(' | ');
617
+ const detail = segments.filter(Boolean).join(" | ");
618
618
  if (!detail)
619
619
  return fitLine(baseTitle, width);
620
620
  return fitLine(`${base} | ${detail}`, width);
@@ -627,23 +627,23 @@ function renderSingleLineTitle(baseTitle, usage, quotas, config, width) {
627
627
  * Input 18.9k Output 53
628
628
  * Cache Read 1.5k (only if read > 0)
629
629
  * Cache Write 200 (only if write > 0)
630
- * $3.81 as API cost (only if showCost=true)
630
+ * API $3.81 (only if showCost=true)
631
631
  * OpenAI Remaining 78% (only if quota available)
632
632
  */
633
633
  export function renderSidebarTitle(baseTitle, usage, quotas, config, view) {
634
634
  const width = Math.max(8, Math.floor(config.sidebar.width || 36));
635
- const safeBaseTitle = stripAnsi(baseTitle || 'Session') || 'Session';
635
+ const safeBaseTitle = stripAnsi(baseTitle || "Session") || "Session";
636
636
  const mode = view || resolveTitleView({ config });
637
- if (mode === 'compact') {
638
- const singleLineBase = safeBaseTitle.split(/\r?\n/, 1)[0] || 'Session';
637
+ if (mode === "compact") {
638
+ const singleLineBase = safeBaseTitle.split(/\r?\n/, 1)[0] || "Session";
639
639
  return renderDesktopCompactTitle(singleLineBase, usage, quotas, config, width);
640
640
  }
641
641
  const cacheMetrics = getCacheCoverageMetrics(usage);
642
642
  const lines = [];
643
643
  for (const line of safeBaseTitle.split(/\r?\n/)) {
644
- lines.push(fitLine(line || 'Session', width));
644
+ lines.push(fitLine(line || "Session", width));
645
645
  }
646
- lines.push('');
646
+ lines.push("");
647
647
  for (const detailLine of usageDetailLines(usage, cacheMetrics, {
648
648
  width,
649
649
  showCost: config.sidebar.showCost,
@@ -652,7 +652,7 @@ export function renderSidebarTitle(baseTitle, usage, quotas, config, view) {
652
652
  }
653
653
  // Quota lines (one provider per line for stable wrapping)
654
654
  if (config.sidebar.showQuota) {
655
- const visibleQuotas = collapseQuotaSnapshots(quotas).filter((q) => ['ok', 'error', 'unsupported', 'unavailable'].includes(q.status));
655
+ const visibleQuotas = collapseQuotaSnapshots(quotas).filter((q) => ["ok", "error", "unsupported", "unavailable"].includes(q.status));
656
656
  const compactQuotaDetails = true;
657
657
  const forceWrappedProviders = false;
658
658
  const labelWidth = visibleQuotas.reduce((max, item) => {
@@ -670,20 +670,20 @@ export function renderSidebarTitle(baseTitle, usage, quotas, config, view) {
670
670
  }))
671
671
  .filter((s) => Boolean(s));
672
672
  if (quotaItems.length > 0) {
673
- lines.push('');
673
+ lines.push("");
674
674
  }
675
675
  for (const line of quotaItems) {
676
676
  lines.push(fitLine(line, width));
677
677
  }
678
678
  }
679
- return lines.join('\n');
679
+ return lines.join("\n");
680
680
  }
681
681
  export function renderSidebarContextLine(tokens, percent, width) {
682
682
  const parts = [`${panelNumber(tokens)} tok`];
683
683
  if (percent !== undefined && Number.isFinite(percent) && percent >= 0) {
684
684
  parts.push(`${Math.round(percent)}% ctx`);
685
685
  }
686
- return fitLine(parts.join(' '), width);
686
+ return fitLine(parts.join(" "), width);
687
687
  }
688
688
  export function renderSidebarUsageLines(usage, config, options) {
689
689
  const width = Math.max(8, Math.floor(config.sidebar.width || 36));
@@ -696,7 +696,7 @@ export function renderSidebarUsageLines(usage, config, options) {
696
696
  width,
697
697
  showCost,
698
698
  numberToken: panelNumber,
699
- costToken: (value) => `Est ${formatApiCostValue(value)}`,
699
+ costToken: (value) => `API ${formatApiCostValue(value)}`,
700
700
  cacheReadFirst: true,
701
701
  }).map((line) => fitLine(line, width));
702
702
  }
@@ -705,7 +705,7 @@ export function renderSidebarQuotaLines(quotas, config) {
705
705
  }
706
706
  export function renderSidebarQuotaLineGroups(quotas, config) {
707
707
  const width = Math.max(8, Math.floor(config.sidebar.width || 36));
708
- const visibleQuotas = collapseQuotaSnapshots(quotas).filter((q) => ['ok', 'error', 'unsupported', 'unavailable'].includes(q.status));
708
+ const visibleQuotas = collapseQuotaSnapshots(quotas).filter((q) => ["ok", "error", "unsupported", "unavailable"].includes(q.status));
709
709
  const labelWidth = visibleQuotas.reduce((max, item) => {
710
710
  const label = compactProviderLabel(item);
711
711
  return Math.max(max, stringCellWidth(label));
@@ -746,7 +746,7 @@ function compactQuotaWide(quota, labelWidth = 0, options) {
746
746
  ? compactProviderLabel(quota)
747
747
  : sanitizeLine(quotaDisplayLabel(quota));
748
748
  const labelPadded = padEndCells(label, labelWidth);
749
- const detailIndent = ' ';
749
+ const detailIndent = " ";
750
750
  const withLabel = (content) => `${labelPadded} ${content}`;
751
751
  const wrap = options?.wrapLines === true && (options?.width || 0) > 0;
752
752
  const width = options?.width || 0;
@@ -760,13 +760,13 @@ function compactQuotaWide(quota, labelWidth = 0, options) {
760
760
  return [inline];
761
761
  return [label, ...detailLines.map((d) => `${detailIndent}${d}`)];
762
762
  };
763
- if (quota.status === 'error')
764
- return maybeBreak('Remaining ?', ['Remaining ?']);
765
- if (quota.status === 'unsupported')
766
- return maybeBreak('unsupported', ['unsupported']);
767
- if (quota.status === 'unavailable')
768
- return maybeBreak('unavailable', ['unavailable']);
769
- if (quota.status !== 'ok')
763
+ if (quota.status === "error")
764
+ return maybeBreak("Remaining ?", ["Remaining ?"]);
765
+ if (quota.status === "unsupported")
766
+ return maybeBreak("unsupported", ["unsupported"]);
767
+ if (quota.status === "unavailable")
768
+ return maybeBreak("unavailable", ["unavailable"]);
769
+ if (quota.status !== "ok")
770
770
  return [];
771
771
  const balanceText = quota.balance
772
772
  ? compactDetails
@@ -785,11 +785,11 @@ function compactQuotaWide(quota, labelWidth = 0, options) {
785
785
  : [pct];
786
786
  const reset = compactReset(win.resetAt, win.resetLabel, win.label);
787
787
  if (reset) {
788
- parts.push(`${sanitizeLine(win.resetLabel || 'Rst')} ${reset}`);
788
+ parts.push(`${sanitizeLine(win.resetLabel || "Rst")} ${reset}`);
789
789
  }
790
790
  if (win.note)
791
791
  parts.push(sanitizeLine(win.note));
792
- return parts.join(' ');
792
+ return parts.join(" ");
793
793
  };
794
794
  // Multi-window rendering
795
795
  if (quota.windows && quota.windows.length > 0) {
@@ -799,7 +799,7 @@ function compactQuotaWide(quota, labelWidth = 0, options) {
799
799
  : [];
800
800
  // Build the detail lines (window texts + optional balance)
801
801
  const details = [...parts];
802
- if (balanceText && !parts.some((p) => p.includes('Balance '))) {
802
+ if (balanceText && !parts.some((p) => p.includes("Balance "))) {
803
803
  details.push(balanceText);
804
804
  }
805
805
  if (compactDetails) {
@@ -809,7 +809,7 @@ function compactQuotaWide(quota, labelWidth = 0, options) {
809
809
  const staleToken = compactQuotaStaleToken(quota);
810
810
  if (staleToken)
811
811
  tokens.push(staleToken);
812
- return packInlineTokens(label, tokens, width, ' '.repeat(stringCellWidth(label) + 1));
812
+ return packInlineTokens(label, tokens, width, " ".repeat(stringCellWidth(label) + 1));
813
813
  }
814
814
  // Keep a unified wrapped layout for providers that have multiple detail
815
815
  // lines so OpenAI/Copilot/others match the RightCode multi-line style,
@@ -828,23 +828,23 @@ function compactQuotaWide(quota, labelWidth = 0, options) {
828
828
  }
829
829
  // Fallback: single value from top-level remainingPercent
830
830
  const percent = formatQuotaPercent(quota.remainingPercent, { rounded: true });
831
- const reset = compactReset(quota.resetAt, 'Rst');
831
+ const reset = compactReset(quota.resetAt, "Rst");
832
832
  const fallbackText = compactDetails
833
833
  ? [
834
- `R${percent.replace(/%$/, '')}`,
834
+ `R${percent.replace(/%$/, "")}`,
835
835
  reset ? `R${reset}` : undefined,
836
836
  compactQuotaStaleToken(quota),
837
837
  ]
838
838
  .filter(Boolean)
839
- .join(' ')
840
- : `Remaining ${percent}${reset ? ` Rst ${reset}` : ''}${verboseQuotaStaleText(quota) ? ` ${verboseQuotaStaleText(quota)}` : ''}`;
839
+ .join(" ")
840
+ : `Remaining ${percent}${reset ? ` Rst ${reset}` : ""}${verboseQuotaStaleText(quota) ? ` ${verboseQuotaStaleText(quota)}` : ""}`;
841
841
  return maybeBreak(fallbackText, [fallbackText]);
842
842
  }
843
843
  function compactCountdown(remainingMs) {
844
844
  if (!Number.isFinite(remainingMs))
845
845
  return undefined;
846
846
  if (remainingMs <= 0)
847
- return '0m';
847
+ return "0m";
848
848
  const minuteMs = 60_000;
849
849
  const hourMinutes = 60;
850
850
  const dayMinutes = 24 * hourMinutes;
@@ -855,11 +855,11 @@ function compactCountdown(remainingMs) {
855
855
  if (totalMinutes < dayMinutes) {
856
856
  const hours = Math.floor(totalMinutes / hourMinutes);
857
857
  const minutes = totalMinutes % hourMinutes;
858
- return `${hours}h${`${minutes}`.padStart(2, '0')}m`;
858
+ return `${hours}h${`${minutes}`.padStart(2, "0")}m`;
859
859
  }
860
860
  const days = Math.floor(totalMinutes / dayMinutes);
861
861
  const hours = Math.floor((totalMinutes % dayMinutes) / hourMinutes);
862
- return `${days}D${`${hours}`.padStart(2, '0')}h`;
862
+ return `${days}D${`${hours}`.padStart(2, "0")}h`;
863
863
  }
864
864
  function compactReset(iso, resetLabel, windowLabel) {
865
865
  void resetLabel;
@@ -873,7 +873,7 @@ function compactReset(iso, resetLabel, windowLabel) {
873
873
  }
874
874
  function dateLine(iso) {
875
875
  if (!iso)
876
- return '-';
876
+ return "-";
877
877
  const time = Date.parse(iso);
878
878
  if (Number.isNaN(time))
879
879
  return iso;
@@ -896,7 +896,7 @@ function expiryAlertLine(iso, nowMs = Date.now()) {
896
896
  }
897
897
  function quotaExpiryPairs(quotas, nowMs = Date.now()) {
898
898
  return collapseQuotaSnapshots(quotas)
899
- .filter((item) => item.status === 'ok')
899
+ .filter((item) => item.status === "ok")
900
900
  .map((item) => ({
901
901
  label: quotaDisplayLabel(item),
902
902
  value: expiryAlertLine(item.expiresAt, nowMs),
@@ -904,7 +904,7 @@ function quotaExpiryPairs(quotas, nowMs = Date.now()) {
904
904
  .filter((item) => Boolean(item.value));
905
905
  }
906
906
  function toolVisibleQuotaSnapshots(quotas) {
907
- return collapseQuotaSnapshots(quotas).filter((item) => item.status === 'ok' || item.status === 'error');
907
+ return collapseQuotaSnapshots(quotas).filter((item) => item.status === "ok" || item.status === "error");
908
908
  }
909
909
  function reportResetLine(iso, resetLabel, windowLabel) {
910
910
  const compact = compactReset(iso, resetLabel, windowLabel);
@@ -913,47 +913,47 @@ function reportResetLine(iso, resetLabel, windowLabel) {
913
913
  return dateLine(iso);
914
914
  }
915
915
  function periodLabel(period) {
916
- if (period === 'day')
917
- return 'Today';
918
- if (period === 'week')
919
- return 'This Week';
920
- if (period === 'month')
921
- return 'This Month';
922
- return 'Current Session';
916
+ if (period === "day")
917
+ return "Today";
918
+ if (period === "week")
919
+ return "This Week";
920
+ if (period === "month")
921
+ return "This Month";
922
+ return "Current Session";
923
923
  }
924
924
  function historyPeriodLabel(period) {
925
- if (period === 'day')
926
- return 'Daily';
927
- if (period === 'week')
928
- return 'Weekly';
929
- if (period === 'month')
930
- return 'Monthly';
931
- return 'Session';
925
+ if (period === "day")
926
+ return "Daily";
927
+ if (period === "week")
928
+ return "Weekly";
929
+ if (period === "month")
930
+ return "Monthly";
931
+ return "Session";
932
932
  }
933
933
  function historyProviderLabel(providerID) {
934
934
  return quotaDisplayLabel({
935
935
  providerID,
936
936
  label: providerID,
937
- status: 'ok',
937
+ status: "ok",
938
938
  checkedAt: 0,
939
939
  });
940
940
  }
941
941
  function historyMdCell(value) {
942
- return sanitizeLine(value).replace(/\|/g, '\\|');
942
+ return sanitizeLine(value).replace(/\|/g, "\\|");
943
943
  }
944
944
  function formatDelta(current, previous) {
945
945
  if (previous === undefined)
946
- return 'n/a';
946
+ return "n/a";
947
947
  if (!Number.isFinite(previous) || previous < 0)
948
- return 'n/a';
948
+ return "n/a";
949
949
  if (previous === 0)
950
- return current === 0 ? 'flat' : 'new';
950
+ return current === 0 ? "flat" : "new";
951
951
  const delta = ((current - previous) / previous) * 100;
952
952
  if (!Number.isFinite(delta))
953
- return 'n/a';
953
+ return "n/a";
954
954
  const abs = Math.abs(delta);
955
- const rounded = (abs >= 10 ? delta.toFixed(0) : delta.toFixed(1)).replace(/\.0$/, '');
956
- return `${delta > 0 ? '+' : ''}${rounded}%`;
955
+ const rounded = (abs >= 10 ? delta.toFixed(0) : delta.toFixed(1)).replace(/\.0$/, "");
956
+ return `${delta > 0 ? "+" : ""}${rounded}%`;
957
957
  }
958
958
  function currentHistoryRow(result) {
959
959
  return ([...result.rows].reverse().find((row) => row.range.isCurrent) ||
@@ -991,46 +991,46 @@ function renderHistoryTotalsTable(result, options) {
991
991
  : undefined;
992
992
  const metricRows = [
993
993
  {
994
- label: 'Requests',
994
+ label: "Requests",
995
995
  total: shortNumber(result.total.assistantMessages),
996
996
  average: rows.length
997
997
  ? shortNumber(result.total.assistantMessages / rows.length)
998
- : '-',
998
+ : "-",
999
999
  },
1000
1000
  {
1001
- label: 'Total Tokens',
1001
+ label: "Total Tokens",
1002
1002
  total: shortNumber(result.total.total),
1003
1003
  average: rows.length
1004
1004
  ? shortNumber(result.total.total / rows.length)
1005
- : '-',
1005
+ : "-",
1006
1006
  },
1007
1007
  {
1008
- label: 'Cache Hit',
1009
- total: cacheTotal !== undefined ? formatPercent(cacheTotal, 1) : '-',
1010
- average: cacheAverage !== undefined ? formatPercent(cacheAverage, 1) : '-',
1008
+ label: "Cache Hit",
1009
+ total: cacheTotal !== undefined ? formatPercent(cacheTotal, 1) : "-",
1010
+ average: cacheAverage !== undefined ? formatPercent(cacheAverage, 1) : "-",
1011
1011
  },
1012
1012
  ...(options?.showCost !== false
1013
1013
  ? [
1014
1014
  {
1015
- label: 'API Cost',
1015
+ label: "API Cost",
1016
1016
  total: formatApiCostValue(result.total.apiCost),
1017
1017
  average: rows.length
1018
1018
  ? formatApiCostValue(result.total.apiCost / rows.length)
1019
- : '-',
1019
+ : "-",
1020
1020
  },
1021
1021
  ]
1022
1022
  : []),
1023
1023
  ];
1024
1024
  return [
1025
- '| Metric | Total | Avg/Period |',
1026
- '| --- | ---: | ---: |',
1025
+ "| Metric | Total | Avg/Period |",
1026
+ "| --- | ---: | ---: |",
1027
1027
  ...metricRows.map((metric) => `| ${metric.label} | ${metric.total} | ${metric.average} |`),
1028
1028
  ];
1029
1029
  }
1030
1030
  function renderHistoryProviderBreakdown(result, options) {
1031
1031
  const providers = Object.values(result.total.providers);
1032
1032
  if (providers.length === 0)
1033
- return ['- no provider activity in selected range'];
1033
+ return ["- no provider activity in selected range"];
1034
1034
  const sorted = [...providers].sort((a, b) => {
1035
1035
  if (b.total !== a.total)
1036
1036
  return b.total - a.total;
@@ -1038,16 +1038,16 @@ function renderHistoryProviderBreakdown(result, options) {
1038
1038
  });
1039
1039
  return [
1040
1040
  options?.showCost !== false
1041
- ? '| Provider | Req | Input | Output | Total | Share | Cache Hit | API Cost |'
1042
- : '| Provider | Req | Input | Output | Total | Share | Cache Hit |',
1041
+ ? "| Provider | Req | Input | Output | Total | Share | Cache Hit | API Cost |"
1042
+ : "| Provider | Req | Input | Output | Total | Share | Cache Hit |",
1043
1043
  options?.showCost !== false
1044
- ? '| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |'
1045
- : '| --- | ---: | ---: | ---: | ---: | ---: | ---: |',
1044
+ ? "| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |"
1045
+ : "| --- | ---: | ---: | ---: | ---: | ---: | ---: |",
1046
1046
  ...sorted.map((provider) => {
1047
1047
  const cache = getProviderCacheCoverageMetrics(provider).cachedRatio;
1048
1048
  const share = result.total.total > 0
1049
1049
  ? formatPercent(provider.total / result.total.total, 1)
1050
- : '-';
1050
+ : "-";
1051
1051
  const cells = [
1052
1052
  historyMdCell(historyProviderLabel(provider.providerID)),
1053
1053
  shortNumber(provider.assistantMessages),
@@ -1055,23 +1055,23 @@ function renderHistoryProviderBreakdown(result, options) {
1055
1055
  shortNumber(provider.output),
1056
1056
  shortNumber(provider.total),
1057
1057
  share,
1058
- cache !== undefined ? formatPercent(cache, 1) : '-',
1058
+ cache !== undefined ? formatPercent(cache, 1) : "-",
1059
1059
  ];
1060
1060
  if (options?.showCost !== false) {
1061
- cells.push(provider.apiCost > 0 ? formatApiCostValue(provider.apiCost) : '-');
1061
+ cells.push(provider.apiCost > 0 ? formatApiCostValue(provider.apiCost) : "-");
1062
1062
  }
1063
- return `| ${cells.join(' | ')} |`;
1063
+ return `| ${cells.join(" | ")} |`;
1064
1064
  }),
1065
1065
  ];
1066
1066
  }
1067
1067
  function renderHistoryQuotaSnapshot(quotas) {
1068
1068
  const visible = toolVisibleQuotaSnapshots(quotas).slice(0, 5);
1069
1069
  if (visible.length === 0)
1070
- return ['- no provider quota data available'];
1070
+ return ["- no provider quota data available"];
1071
1071
  return visible.map((quota) => {
1072
1072
  const label = quotaDisplayLabel(quota);
1073
- if (quota.status === 'error') {
1074
- return `- ${label}: error${quota.note ? ` | ${quota.note}` : ''}`;
1073
+ if (quota.status === "error") {
1074
+ return `- ${label}: error${quota.note ? ` | ${quota.note}` : ""}`;
1075
1075
  }
1076
1076
  if (quota.windows && quota.windows.length > 0) {
1077
1077
  const summary = quota.windows
@@ -1081,11 +1081,11 @@ function renderHistoryQuotaSnapshot(quotas) {
1081
1081
  ? undefined
1082
1082
  : formatQuotaPercent(window.remainingPercent);
1083
1083
  const reset = reportResetLine(window.resetAt, window.resetLabel, window.label);
1084
- return [window.label || 'Quota', remaining, `reset ${reset}`]
1084
+ return [window.label || "Quota", remaining, `reset ${reset}`]
1085
1085
  .filter(Boolean)
1086
- .join(' | ');
1086
+ .join(" | ");
1087
1087
  })
1088
- .join('; ');
1088
+ .join("; ");
1089
1089
  return `- ${label}: ${summary}`;
1090
1090
  }
1091
1091
  if (quota.balance) {
@@ -1100,22 +1100,22 @@ function renderHistoryPeriodDetailRows(result, options) {
1100
1100
  ? result.rows.map((row) => {
1101
1101
  const cache = getCacheCoverageMetrics(row.usage).cachedRatio;
1102
1102
  const cells = [
1103
- `${row.range.label}${row.range.isCurrent ? '*' : ''}`,
1103
+ `${row.range.label}${row.range.isCurrent ? "*" : ""}`,
1104
1104
  shortNumber(row.usage.assistantMessages),
1105
1105
  shortNumber(row.usage.input),
1106
1106
  shortNumber(row.usage.output),
1107
1107
  shortNumber(row.usage.cacheRead + row.usage.cacheWrite),
1108
- cache !== undefined ? formatPercent(cache, 1) : '-',
1108
+ cache !== undefined ? formatPercent(cache, 1) : "-",
1109
1109
  shortNumber(row.usage.total),
1110
1110
  ];
1111
1111
  if (showCost)
1112
1112
  cells.push(formatApiCostValue(row.usage.apiCost));
1113
- return `| ${cells.join(' | ')} |`;
1113
+ return `| ${cells.join(" | ")} |`;
1114
1114
  })
1115
1115
  : [
1116
1116
  showCost
1117
- ? '| - | - | - | - | - | - | - | - |'
1118
- : '| - | - | - | - | - | - | - |',
1117
+ ? "| - | - | - | - | - | - | - | - |"
1118
+ : "| - | - | - | - | - | - | - |",
1119
1119
  ];
1120
1120
  }
1121
1121
  export function renderHistoryMarkdownReport(result, quotas, options) {
@@ -1124,66 +1124,66 @@ export function renderHistoryMarkdownReport(result, quotas, options) {
1124
1124
  return [
1125
1125
  `## Quota History - ${historyPeriodLabel(result.period)} since ${result.since.raw}`,
1126
1126
  ...(result.warning
1127
- ? ['', `> Warning: ${sanitizeLine(result.warning)}`]
1127
+ ? ["", `> Warning: ${sanitizeLine(result.warning)}`]
1128
1128
  : []),
1129
- '',
1130
- '### Quota Status',
1131
- '',
1129
+ "",
1130
+ "### Quota Status",
1131
+ "",
1132
1132
  ...renderHistoryQuotaSnapshot(quotas),
1133
- '',
1134
- '### Totals',
1135
- '',
1133
+ "",
1134
+ "### Totals",
1135
+ "",
1136
1136
  ...renderHistoryTotalsTable(result, { showCost }),
1137
- '',
1138
- '### Provider Breakdown',
1139
- '',
1137
+ "",
1138
+ "### Provider Breakdown",
1139
+ "",
1140
1140
  ...renderHistoryProviderBreakdown(result, { showCost }),
1141
- '',
1142
- '### Period Detail',
1143
- '',
1141
+ "",
1142
+ "### Period Detail",
1143
+ "",
1144
1144
  showCost
1145
- ? '| Period | Requests | Input | Output | Cache | Cache Hit | Total | API Cost |'
1146
- : '| Period | Requests | Input | Output | Cache | Cache Hit | Total |',
1145
+ ? "| Period | Requests | Input | Output | Cache | Cache Hit | Total | API Cost |"
1146
+ : "| Period | Requests | Input | Output | Cache | Cache Hit | Total |",
1147
1147
  showCost
1148
- ? '| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |'
1149
- : '| --- | ---: | ---: | ---: | ---: | ---: | ---: |',
1148
+ ? "| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |"
1149
+ : "| --- | ---: | ---: | ---: | ---: | ---: | ---: |",
1150
1150
  ...detailRows,
1151
1151
  ...(result.rows.some((row) => row.range.isCurrent)
1152
- ? ['', '* `*` marks the current partial period.']
1152
+ ? ["", "* `*` marks the current partial period."]
1153
1153
  : []),
1154
- ].join('\n');
1154
+ ].join("\n");
1155
1155
  }
1156
1156
  export function renderMarkdownReport(period, usage, quotas, options) {
1157
1157
  const showCost = options?.showCost !== false;
1158
1158
  const cacheMetrics = getCacheCoverageMetrics(usage);
1159
- const mdCell = (value) => sanitizeLine(value).replace(/\|/g, '\\|');
1159
+ const mdCell = (value) => sanitizeLine(value).replace(/\|/g, "\\|");
1160
1160
  const rightCodeSubscriptionProviderIDs = new Set(collapseQuotaSnapshots(quotas)
1161
- .filter((quota) => quota.adapterID === 'rightcode')
1162
- .filter((quota) => quota.status === 'ok')
1161
+ .filter((quota) => quota.adapterID === "rightcode")
1162
+ .filter((quota) => quota.status === "ok")
1163
1163
  .filter((quota) => Array.isArray(quota.windows) && quota.windows.length)
1164
- .filter((quota) => quota.windows[0].label.startsWith('Daily $'))
1164
+ .filter((quota) => quota.windows[0].label.startsWith("Daily $"))
1165
1165
  .map((quota) => quota.providerID));
1166
1166
  const measuredCostCell = (providerID, cost) => {
1167
1167
  const canonical = canonicalProviderID(providerID);
1168
- const isSubscription = canonical === 'openai' ||
1169
- canonical === 'anthropic' ||
1170
- canonical === 'github-copilot' ||
1168
+ const isSubscription = canonical === "openai" ||
1169
+ canonical === "anthropic" ||
1170
+ canonical === "github-copilot" ||
1171
1171
  rightCodeSubscriptionProviderIDs.has(providerID);
1172
1172
  if (isSubscription)
1173
- return '-';
1173
+ return "-";
1174
1174
  return formatUsd(cost);
1175
1175
  };
1176
1176
  const isSubscriptionMeasuredProvider = (providerID) => {
1177
1177
  const canonical = canonicalProviderID(providerID);
1178
- return (canonical === 'openai' ||
1179
- canonical === 'anthropic' ||
1180
- canonical === 'github-copilot' ||
1178
+ return (canonical === "openai" ||
1179
+ canonical === "anthropic" ||
1180
+ canonical === "github-copilot" ||
1181
1181
  rightCodeSubscriptionProviderIDs.has(providerID));
1182
1182
  };
1183
1183
  const apiCostCell = (providerID, apiCost) => {
1184
1184
  const canonical = canonicalProviderID(providerID);
1185
- if (canonical === 'github-copilot')
1186
- return '-';
1185
+ if (canonical === "github-copilot")
1186
+ return "-";
1187
1187
  return formatUsd(apiCost);
1188
1188
  };
1189
1189
  const measuredCostSummaryValue = () => {
@@ -1192,23 +1192,23 @@ export function renderMarkdownReport(period, usage, quotas, options) {
1192
1192
  return formatUsd(usage.cost);
1193
1193
  const hasNonSubscription = providers.some((provider) => !isSubscriptionMeasuredProvider(provider.providerID));
1194
1194
  if (!hasNonSubscription)
1195
- return '-';
1195
+ return "-";
1196
1196
  return formatUsd(usage.cost);
1197
1197
  };
1198
1198
  const apiCostSummaryValue = () => {
1199
1199
  const providers = Object.values(usage.providers);
1200
1200
  if (providers.length === 0)
1201
1201
  return formatApiCostValue(usage.apiCost);
1202
- const hasNonCopilot = providers.some((provider) => canonicalProviderID(provider.providerID) !== 'github-copilot');
1202
+ const hasNonCopilot = providers.some((provider) => canonicalProviderID(provider.providerID) !== "github-copilot");
1203
1203
  if (!hasNonCopilot)
1204
- return '-';
1204
+ return "-";
1205
1205
  return formatApiCostValue(usage.apiCost);
1206
1206
  };
1207
1207
  const cachedCell = (provider) => {
1208
1208
  const metrics = getProviderCacheCoverageMetrics(provider);
1209
1209
  return metrics.cachedRatio !== undefined
1210
1210
  ? formatPercent(metrics.cachedRatio, 1)
1211
- : '-';
1211
+ : "-";
1212
1212
  };
1213
1213
  const providerEntries = Object.values(usage.providers).sort((a, b) => b.total - a.total);
1214
1214
  const highlightLines = () => {
@@ -1216,7 +1216,7 @@ export function renderMarkdownReport(period, usage, quotas, options) {
1216
1216
  const providerLabel = (providerID) => quotaDisplayLabel({
1217
1217
  providerID,
1218
1218
  label: providerID,
1219
- status: 'ok',
1219
+ status: "ok",
1220
1220
  checkedAt: 0,
1221
1221
  });
1222
1222
  const topApiCost = providerEntries
@@ -1226,7 +1226,7 @@ export function renderMarkdownReport(period, usage, quotas, options) {
1226
1226
  lines.push(`- Top API cost: ${quotaDisplayLabel({
1227
1227
  providerID: topApiCost.providerID,
1228
1228
  label: topApiCost.providerID,
1229
- status: 'ok',
1229
+ status: "ok",
1230
1230
  checkedAt: 0,
1231
1231
  })} (${formatUsd(topApiCost.apiCost)})`);
1232
1232
  }
@@ -1241,7 +1241,7 @@ export function renderMarkdownReport(period, usage, quotas, options) {
1241
1241
  lines.push(`- Best Cached Ratio: ${providerLabel(bestCachedRatio.provider.providerID)} (${formatPercent(bestCachedRatio.value, 1)})`);
1242
1242
  }
1243
1243
  const highestMeasured = providerEntries
1244
- .filter((provider) => measuredCostCell(provider.providerID, provider.cost) !== '-')
1244
+ .filter((provider) => measuredCostCell(provider.providerID, provider.cost) !== "-")
1245
1245
  .sort((a, b) => b.cost - a.cost)[0];
1246
1246
  if (highestMeasured && highestMeasured.cost > 0) {
1247
1247
  lines.push(`- Highest measured cost: ${providerLabel(highestMeasured.providerID)} (${formatUsd(highestMeasured.cost)})`);
@@ -1255,27 +1255,27 @@ export function renderMarkdownReport(period, usage, quotas, options) {
1255
1255
  : `| ${providerID} | ${shortNumber(provider.assistantMessages)} | ${shortNumber(provider.input)} | ${shortNumber(provider.output)} | ${shortNumber(provider.cacheRead + provider.cacheWrite)} | ${shortNumber(provider.total)} |`;
1256
1256
  });
1257
1257
  const providerHeader = showCost
1258
- ? '| Provider | Requests | Input | Output | Cache | Total | Cached | Measured Cost | API Cost |'
1259
- : '| Provider | Requests | Input | Output | Cache | Total |';
1258
+ ? "| Provider | Requests | Input | Output | Cache | Total | Cached | Measured Cost | API Cost |"
1259
+ : "| Provider | Requests | Input | Output | Cache | Total |";
1260
1260
  const providerDivider = showCost
1261
- ? '| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |'
1262
- : '| --- | ---: | ---: | ---: | ---: | ---: |';
1261
+ ? "| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |"
1262
+ : "| --- | ---: | ---: | ---: | ---: | ---: |";
1263
1263
  const quotaLines = toolVisibleQuotaSnapshots(quotas).flatMap((quota) => {
1264
1264
  const displayLabel = quotaDisplayLabel(quota);
1265
- const staleSuffix = quota.stale ? ' | stale' : '';
1265
+ const staleSuffix = quota.stale ? " | stale" : "";
1266
1266
  // Multi-window detail
1267
- if (quota.windows && quota.windows.length > 0 && quota.status === 'ok') {
1267
+ if (quota.windows && quota.windows.length > 0 && quota.status === "ok") {
1268
1268
  const windowLines = quota.windows.map((win) => {
1269
1269
  const extraNote = win.note || (win === quota.windows?.[0] && quota.note)
1270
1270
  ? ` | ${win.note || quota.note}`
1271
- : '';
1272
- const staleNote = quota.stale && win === quota.windows?.[0] ? staleSuffix : '';
1271
+ : "";
1272
+ const staleNote = quota.stale && win === quota.windows?.[0] ? staleSuffix : "";
1273
1273
  if (win.showPercent === false) {
1274
- const winLabel = win.label ? ` (${win.label})` : '';
1274
+ const winLabel = win.label ? ` (${win.label})` : "";
1275
1275
  return mdCell(`- ${displayLabel}${winLabel}: ${quota.status} | reset ${reportResetLine(win.resetAt, win.resetLabel, win.label)}${extraNote}${staleNote}`);
1276
1276
  }
1277
1277
  const remaining = formatQuotaPercent(win.remainingPercent);
1278
- const winLabel = win.label ? ` (${win.label})` : '';
1278
+ const winLabel = win.label ? ` (${win.label})` : "";
1279
1279
  return mdCell(`- ${displayLabel}${winLabel}: ${quota.status} | remaining ${remaining} | reset ${reportResetLine(win.resetAt, win.resetLabel, win.label)}${extraNote}${staleNote}`);
1280
1280
  });
1281
1281
  if (quota.balance) {
@@ -1283,32 +1283,32 @@ export function renderMarkdownReport(period, usage, quotas, options) {
1283
1283
  }
1284
1284
  return windowLines;
1285
1285
  }
1286
- if (quota.status === 'ok' && quota.balance) {
1286
+ if (quota.status === "ok" && quota.balance) {
1287
1287
  return [
1288
1288
  mdCell(`- ${displayLabel}: ${quota.status} | balance ${formatCurrency(quota.balance.amount, quota.balance.currency)}${staleSuffix}`),
1289
1289
  ];
1290
1290
  }
1291
- if (quota.status === 'error') {
1291
+ if (quota.status === "error") {
1292
1292
  return [
1293
- mdCell(`- ${displayLabel}: ${quota.status}${quota.note ? ` | ${quota.note}` : ''}`),
1293
+ mdCell(`- ${displayLabel}: ${quota.status}${quota.note ? ` | ${quota.note}` : ""}`),
1294
1294
  ];
1295
1295
  }
1296
1296
  const remaining = formatQuotaPercent(quota.remainingPercent);
1297
1297
  return [
1298
- mdCell(`- ${displayLabel}: ${quota.status} | remaining ${remaining} | reset ${reportResetLine(quota.resetAt)}${quota.note ? ` | ${quota.note}` : ''}${staleSuffix}`),
1298
+ mdCell(`- ${displayLabel}: ${quota.status} | remaining ${remaining} | reset ${reportResetLine(quota.resetAt)}${quota.note ? ` | ${quota.note}` : ""}${staleSuffix}`),
1299
1299
  ];
1300
1300
  });
1301
1301
  return [
1302
1302
  `## Quota Report - ${periodLabel(period)}`,
1303
- '',
1304
- '### Quota Status',
1305
- '',
1303
+ "",
1304
+ "### Quota Status",
1305
+ "",
1306
1306
  ...(quotaLines.length
1307
1307
  ? quotaLines
1308
- : ['- no provider quota data available']),
1309
- '',
1310
- '### Usage Summary',
1311
- '',
1308
+ : ["- no provider quota data available"]),
1309
+ "",
1310
+ "### Usage Summary",
1311
+ "",
1312
1312
  `- Sessions: ${usage.sessionCount}`,
1313
1313
  `- Requests: ${usage.assistantMessages}`,
1314
1314
  `- Tokens: input ${usage.input}, output ${usage.output}, cache_read ${usage.cacheRead}, cache_write ${usage.cacheWrite}, total ${usage.total}`,
@@ -1319,24 +1319,25 @@ export function renderMarkdownReport(period, usage, quotas, options) {
1319
1319
  ? [
1320
1320
  `- Measured cost: ${measuredCostSummaryValue()}`,
1321
1321
  `- API cost: ${apiCostSummaryValue()}`,
1322
+ "- API cost is an API-equivalent estimate based on model pricing.",
1322
1323
  ]
1323
1324
  : []),
1324
- '',
1325
- '### Usage by Provider',
1326
- '',
1325
+ "",
1326
+ "### Usage by Provider",
1327
+ "",
1327
1328
  providerHeader,
1328
1329
  providerDivider,
1329
1330
  ...(providerRows.length
1330
1331
  ? providerRows
1331
1332
  : [
1332
1333
  showCost
1333
- ? '| - | - | - | - | - | - | - | - | - |'
1334
- : '| - | - | - | - | - | - |',
1334
+ ? "| - | - | - | - | - | - | - | - | - |"
1335
+ : "| - | - | - | - | - | - |",
1335
1336
  ]),
1336
1337
  ...(highlightLines().length > 0
1337
- ? ['', '### Highlights', ...highlightLines()]
1338
+ ? ["", "### Highlights", ...highlightLines()]
1338
1339
  : []),
1339
- ].join('\n');
1340
+ ].join("\n");
1340
1341
  }
1341
1342
  export function renderToastMessage(period, usage, quotas, options) {
1342
1343
  const width = Math.max(24, Math.floor(options?.width || 56));
@@ -1344,28 +1345,28 @@ export function renderToastMessage(period, usage, quotas, options) {
1344
1345
  const cacheMetrics = getCacheCoverageMetrics(usage);
1345
1346
  const lines = [];
1346
1347
  lines.push(fitLine(`${periodLabel(period)} - Total ${shortNumber(usage.total)}`, width));
1347
- lines.push('');
1348
- lines.push(fitLine('Token Usage', width));
1348
+ lines.push("");
1349
+ lines.push(fitLine("Token Usage", width));
1349
1350
  const tokenPairs = [
1350
- { label: 'Requests', value: shortNumber(usage.assistantMessages) },
1351
- { label: 'Input', value: shortNumber(usage.input) },
1352
- { label: 'Output', value: shortNumber(usage.output) },
1351
+ { label: "Requests", value: shortNumber(usage.assistantMessages) },
1352
+ { label: "Input", value: shortNumber(usage.input) },
1353
+ { label: "Output", value: shortNumber(usage.output) },
1353
1354
  ];
1354
1355
  if (usage.cacheWrite > 0) {
1355
1356
  tokenPairs.push({
1356
- label: 'Cache Write',
1357
+ label: "Cache Write",
1357
1358
  value: shortNumber(usage.cacheWrite),
1358
1359
  });
1359
1360
  }
1360
1361
  if (usage.cacheRead > 0) {
1361
1362
  tokenPairs.push({
1362
- label: 'Cache Read',
1363
+ label: "Cache Read",
1363
1364
  value: shortNumber(usage.cacheRead),
1364
1365
  });
1365
1366
  }
1366
1367
  if (cacheMetrics.cachedRatio !== undefined) {
1367
1368
  tokenPairs.push({
1368
- label: 'Cached',
1369
+ label: "Cached",
1369
1370
  value: formatPercent(cacheMetrics.cachedRatio, 1),
1370
1371
  });
1371
1372
  }
@@ -1382,37 +1383,37 @@ export function renderToastMessage(period, usage, quotas, options) {
1382
1383
  })
1383
1384
  .filter((item) => Boolean(item));
1384
1385
  if (providerCachePairs.length > 0) {
1385
- lines.push('');
1386
- lines.push(fitLine('Provider Cache', width));
1386
+ lines.push("");
1387
+ lines.push(fitLine("Provider Cache", width));
1387
1388
  lines.push(...alignPairs(providerCachePairs).map((line) => fitLine(line, width)));
1388
1389
  }
1389
1390
  if (showCost) {
1390
1391
  const costPairs = Object.values(usage.providers)
1391
- .filter((provider) => canonicalProviderID(provider.providerID) !== 'github-copilot')
1392
+ .filter((provider) => canonicalProviderID(provider.providerID) !== "github-copilot")
1392
1393
  .filter((provider) => provider.apiCost > 0)
1393
1394
  .sort((left, right) => right.apiCost - left.apiCost)
1394
1395
  .map((provider) => ({
1395
1396
  label: displayShortLabel(provider.providerID),
1396
1397
  value: formatUsd(provider.apiCost),
1397
1398
  }));
1398
- lines.push('');
1399
- lines.push(fitLine('Cost as API', width));
1399
+ lines.push("");
1400
+ lines.push(fitLine("Cost as API", width));
1400
1401
  if (costPairs.length > 0) {
1401
1402
  lines.push(...alignPairs(costPairs).map((line) => fitLine(line, width)));
1402
1403
  }
1403
1404
  else {
1404
1405
  const hasAnyUsage = Object.keys(usage.providers).length > 0;
1405
1406
  const hasOnlyCopilotUsage = hasAnyUsage &&
1406
- Object.values(usage.providers).every((provider) => canonicalProviderID(provider.providerID) === 'github-copilot');
1407
+ Object.values(usage.providers).every((provider) => canonicalProviderID(provider.providerID) === "github-copilot");
1407
1408
  lines.push(fitLine(hasOnlyCopilotUsage
1408
- ? ' N/A (Copilot)'
1409
+ ? " N/A (Copilot)"
1409
1410
  : hasAnyUsage
1410
- ? ' N/A'
1411
- : ' -', width));
1411
+ ? " N/A"
1412
+ : " -", width));
1412
1413
  }
1413
1414
  }
1414
1415
  const quotaPairs = toolVisibleQuotaSnapshots(quotas).flatMap((item) => {
1415
- if (item.status === 'ok') {
1416
+ if (item.status === "ok") {
1416
1417
  if (item.windows && item.windows.length > 0) {
1417
1418
  const pairs = item.windows.map((win, idx) => {
1418
1419
  const showPercent = win.showPercent !== false;
@@ -1422,19 +1423,19 @@ export function renderToastMessage(period, usage, quotas, options) {
1422
1423
  if (showPercent)
1423
1424
  parts.push(pct);
1424
1425
  if (reset)
1425
- parts.push(`${win.resetLabel || 'Rst'} ${reset}`);
1426
+ parts.push(`${win.resetLabel || "Rst"} ${reset}`);
1426
1427
  if (win.note)
1427
1428
  parts.push(win.note);
1428
1429
  if (item.stale && idx === 0)
1429
- parts.push('stale');
1430
+ parts.push("stale");
1430
1431
  return {
1431
- label: idx === 0 ? quotaDisplayLabel(item) : '',
1432
- value: parts.filter(Boolean).join(' '),
1432
+ label: idx === 0 ? quotaDisplayLabel(item) : "",
1433
+ value: parts.filter(Boolean).join(" "),
1433
1434
  };
1434
1435
  });
1435
1436
  if (item.balance) {
1436
1437
  pairs.push({
1437
- label: '',
1438
+ label: "",
1438
1439
  value: `Balance ${formatCurrency(item.balance.amount, item.balance.currency)}`,
1439
1440
  });
1440
1441
  }
@@ -1444,31 +1445,31 @@ export function renderToastMessage(period, usage, quotas, options) {
1444
1445
  return [
1445
1446
  {
1446
1447
  label: quotaDisplayLabel(item),
1447
- value: `Balance ${formatCurrency(item.balance.amount, item.balance.currency)}${item.stale ? ' stale' : ''}`,
1448
+ value: `Balance ${formatCurrency(item.balance.amount, item.balance.currency)}${item.stale ? " stale" : ""}`,
1448
1449
  },
1449
1450
  ];
1450
1451
  }
1451
1452
  const percent = formatQuotaPercent(item.remainingPercent);
1452
- const reset = compactReset(item.resetAt, 'Rst');
1453
+ const reset = compactReset(item.resetAt, "Rst");
1453
1454
  return [
1454
1455
  {
1455
1456
  label: quotaDisplayLabel(item),
1456
- value: `Remaining ${percent}${reset ? ` Rst ${reset}` : ''}${item.stale ? ' stale' : ''}`,
1457
+ value: `Remaining ${percent}${reset ? ` Rst ${reset}` : ""}${item.stale ? " stale" : ""}`,
1457
1458
  },
1458
1459
  ];
1459
1460
  }
1460
- return [{ label: quotaDisplayLabel(item), value: 'Remaining ?' }];
1461
+ return [{ label: quotaDisplayLabel(item), value: "Remaining ?" }];
1461
1462
  });
1462
1463
  if (quotaPairs.length > 0) {
1463
- lines.push('');
1464
- lines.push(fitLine('Quota', width));
1464
+ lines.push("");
1465
+ lines.push(fitLine("Quota", width));
1465
1466
  lines.push(...alignPairs(quotaPairs).map((line) => fitLine(line, width)));
1466
1467
  }
1467
1468
  const expiryPairs = quotaExpiryPairs(quotas);
1468
1469
  if (expiryPairs.length > 0) {
1469
- lines.push('');
1470
- lines.push(fitLine('Expiry Soon', width));
1470
+ lines.push("");
1471
+ lines.push(fitLine("Expiry Soon", width));
1471
1472
  lines.push(...alignPairs(expiryPairs).map((line) => fitLine(line, width)));
1472
1473
  }
1473
- return lines.join('\n');
1474
+ return lines.join("\n");
1474
1475
  }