@slkiser/opencode-quota 4.9.0 → 4.10.1

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 (190) hide show
  1. package/README.md +18 -16
  2. package/dist/lib/alibaba-token-plan.d.ts +88 -0
  3. package/dist/lib/alibaba-token-plan.d.ts.map +1 -0
  4. package/dist/lib/alibaba-token-plan.js +505 -0
  5. package/dist/lib/alibaba-token-plan.js.map +1 -0
  6. package/dist/lib/anthropic.d.ts +19 -2
  7. package/dist/lib/anthropic.d.ts.map +1 -1
  8. package/dist/lib/anthropic.js +62 -3
  9. package/dist/lib/anthropic.js.map +1 -1
  10. package/dist/lib/atomic-json.d.ts +3 -0
  11. package/dist/lib/atomic-json.d.ts.map +1 -1
  12. package/dist/lib/atomic-json.js +16 -4
  13. package/dist/lib/atomic-json.js.map +1 -1
  14. package/dist/lib/cli-show.d.ts.map +1 -1
  15. package/dist/lib/cli-show.js +6 -1
  16. package/dist/lib/cli-show.js.map +1 -1
  17. package/dist/lib/config-write-target.d.ts +28 -0
  18. package/dist/lib/config-write-target.d.ts.map +1 -0
  19. package/dist/lib/config-write-target.js +159 -0
  20. package/dist/lib/config-write-target.js.map +1 -0
  21. package/dist/lib/config.d.ts +1 -1
  22. package/dist/lib/config.d.ts.map +1 -1
  23. package/dist/lib/config.js +34 -0
  24. package/dist/lib/config.js.map +1 -1
  25. package/dist/lib/cursor-usage.d.ts +1 -0
  26. package/dist/lib/cursor-usage.d.ts.map +1 -1
  27. package/dist/lib/cursor-usage.js +1 -0
  28. package/dist/lib/cursor-usage.js.map +1 -1
  29. package/dist/lib/entries.d.ts +17 -0
  30. package/dist/lib/entries.d.ts.map +1 -1
  31. package/dist/lib/entries.js +4 -0
  32. package/dist/lib/entries.js.map +1 -1
  33. package/dist/lib/format-utils.d.ts +11 -8
  34. package/dist/lib/format-utils.d.ts.map +1 -1
  35. package/dist/lib/format-utils.js +47 -6
  36. package/dist/lib/format-utils.js.map +1 -1
  37. package/dist/lib/format.d.ts +3 -0
  38. package/dist/lib/format.d.ts.map +1 -1
  39. package/dist/lib/format.js +66 -29
  40. package/dist/lib/format.js.map +1 -1
  41. package/dist/lib/glm-coding-plan.d.ts.map +1 -1
  42. package/dist/lib/glm-coding-plan.js +12 -3
  43. package/dist/lib/glm-coding-plan.js.map +1 -1
  44. package/dist/lib/init-installer.d.ts.map +1 -1
  45. package/dist/lib/init-installer.js +2 -2
  46. package/dist/lib/init-installer.js.map +1 -1
  47. package/dist/lib/ollama-cloud.d.ts +2 -2
  48. package/dist/lib/ollama-cloud.d.ts.map +1 -1
  49. package/dist/lib/ollama-cloud.js +3 -45
  50. package/dist/lib/ollama-cloud.js.map +1 -1
  51. package/dist/lib/openai.d.ts +2 -0
  52. package/dist/lib/openai.d.ts.map +1 -1
  53. package/dist/lib/openai.js +29 -13
  54. package/dist/lib/openai.js.map +1 -1
  55. package/dist/lib/opencode-config-editor.d.ts +3 -0
  56. package/dist/lib/opencode-config-editor.d.ts.map +1 -1
  57. package/dist/lib/opencode-config-editor.js +71 -10
  58. package/dist/lib/opencode-config-editor.js.map +1 -1
  59. package/dist/lib/opencode-go.d.ts.map +1 -1
  60. package/dist/lib/opencode-go.js +25 -4
  61. package/dist/lib/opencode-go.js.map +1 -1
  62. package/dist/lib/openrouter.d.ts +2 -1
  63. package/dist/lib/openrouter.d.ts.map +1 -1
  64. package/dist/lib/openrouter.js +3 -4
  65. package/dist/lib/openrouter.js.map +1 -1
  66. package/dist/lib/provider-registration.d.ts +12 -1
  67. package/dist/lib/provider-registration.d.ts.map +1 -1
  68. package/dist/lib/provider-registration.js +13 -1
  69. package/dist/lib/provider-registration.js.map +1 -1
  70. package/dist/lib/quota-accounting-projection.d.ts +2 -0
  71. package/dist/lib/quota-accounting-projection.d.ts.map +1 -1
  72. package/dist/lib/quota-accounting-projection.js +16 -1
  73. package/dist/lib/quota-accounting-projection.js.map +1 -1
  74. package/dist/lib/quota-command-format.d.ts +2 -0
  75. package/dist/lib/quota-command-format.d.ts.map +1 -1
  76. package/dist/lib/quota-command-format.js +32 -36
  77. package/dist/lib/quota-command-format.js.map +1 -1
  78. package/dist/lib/quota-dialog-commands.d.ts.map +1 -1
  79. package/dist/lib/quota-dialog-commands.js +2 -0
  80. package/dist/lib/quota-dialog-commands.js.map +1 -1
  81. package/dist/lib/quota-exhaustion-projection.d.ts +11 -0
  82. package/dist/lib/quota-exhaustion-projection.d.ts.map +1 -0
  83. package/dist/lib/quota-exhaustion-projection.js +105 -0
  84. package/dist/lib/quota-exhaustion-projection.js.map +1 -0
  85. package/dist/lib/quota-providers-local.d.ts.map +1 -1
  86. package/dist/lib/quota-providers-local.js +14 -0
  87. package/dist/lib/quota-providers-local.js.map +1 -1
  88. package/dist/lib/quota-providers-remote.d.ts.map +1 -1
  89. package/dist/lib/quota-providers-remote.js +6 -2
  90. package/dist/lib/quota-providers-remote.js.map +1 -1
  91. package/dist/lib/quota-render-data.d.ts.map +1 -1
  92. package/dist/lib/quota-render-data.js +7 -3
  93. package/dist/lib/quota-render-data.js.map +1 -1
  94. package/dist/lib/quota-state-codec.d.ts +1 -1
  95. package/dist/lib/quota-state-codec.d.ts.map +1 -1
  96. package/dist/lib/quota-state-codec.js +6 -3
  97. package/dist/lib/quota-state-codec.js.map +1 -1
  98. package/dist/lib/quota-status.d.ts.map +1 -1
  99. package/dist/lib/quota-status.js +19 -0
  100. package/dist/lib/quota-status.js.map +1 -1
  101. package/dist/lib/quota-toast-runtime.d.ts.map +1 -1
  102. package/dist/lib/quota-toast-runtime.js +9 -0
  103. package/dist/lib/quota-toast-runtime.js.map +1 -1
  104. package/dist/lib/qwen-local-quota.d.ts +2 -0
  105. package/dist/lib/qwen-local-quota.d.ts.map +1 -1
  106. package/dist/lib/qwen-local-quota.js +17 -1
  107. package/dist/lib/qwen-local-quota.js.map +1 -1
  108. package/dist/lib/scoped-update.d.ts +2 -0
  109. package/dist/lib/scoped-update.d.ts.map +1 -1
  110. package/dist/lib/scoped-update.js +43 -7
  111. package/dist/lib/scoped-update.js.map +1 -1
  112. package/dist/lib/synthetic.d.ts.map +1 -1
  113. package/dist/lib/synthetic.js +9 -0
  114. package/dist/lib/synthetic.js.map +1 -1
  115. package/dist/lib/toast-format-grouped.d.ts +3 -0
  116. package/dist/lib/toast-format-grouped.d.ts.map +1 -1
  117. package/dist/lib/toast-format-grouped.js +34 -20
  118. package/dist/lib/toast-format-grouped.js.map +1 -1
  119. package/dist/lib/tui-compact-format.d.ts +1 -0
  120. package/dist/lib/tui-compact-format.d.ts.map +1 -1
  121. package/dist/lib/tui-compact-format.js +176 -20
  122. package/dist/lib/tui-compact-format.js.map +1 -1
  123. package/dist/lib/tui-panel-state.d.ts +8 -0
  124. package/dist/lib/tui-panel-state.d.ts.map +1 -1
  125. package/dist/lib/tui-panel-state.js.map +1 -1
  126. package/dist/lib/tui-prompt-bar-format.d.ts +25 -0
  127. package/dist/lib/tui-prompt-bar-format.d.ts.map +1 -0
  128. package/dist/lib/tui-prompt-bar-format.js +206 -0
  129. package/dist/lib/tui-prompt-bar-format.js.map +1 -0
  130. package/dist/lib/tui-runtime.d.ts.map +1 -1
  131. package/dist/lib/tui-runtime.js +18 -81
  132. package/dist/lib/tui-runtime.js.map +1 -1
  133. package/dist/lib/tui-sidebar-content.d.ts +32 -0
  134. package/dist/lib/tui-sidebar-content.d.ts.map +1 -0
  135. package/dist/lib/tui-sidebar-content.js +52 -0
  136. package/dist/lib/tui-sidebar-content.js.map +1 -0
  137. package/dist/lib/tui-sidebar-format.d.ts +1 -1
  138. package/dist/lib/tui-sidebar-format.d.ts.map +1 -1
  139. package/dist/lib/tui-sidebar-format.js +3 -0
  140. package/dist/lib/tui-sidebar-format.js.map +1 -1
  141. package/dist/lib/types.d.ts +14 -12
  142. package/dist/lib/types.d.ts.map +1 -1
  143. package/dist/lib/types.js +1 -0
  144. package/dist/lib/types.js.map +1 -1
  145. package/dist/lib/xai.d.ts +2 -0
  146. package/dist/lib/xai.d.ts.map +1 -1
  147. package/dist/lib/xai.js +19 -3
  148. package/dist/lib/xai.js.map +1 -1
  149. package/dist/providers/alibaba-token-plan.d.ts +3 -0
  150. package/dist/providers/alibaba-token-plan.d.ts.map +1 -0
  151. package/dist/providers/alibaba-token-plan.js +89 -0
  152. package/dist/providers/alibaba-token-plan.js.map +1 -0
  153. package/dist/providers/anthropic.d.ts.map +1 -1
  154. package/dist/providers/anthropic.js +36 -0
  155. package/dist/providers/anthropic.js.map +1 -1
  156. package/dist/providers/cache-policies.d.ts +3 -0
  157. package/dist/providers/cache-policies.d.ts.map +1 -1
  158. package/dist/providers/cache-policies.js +1 -0
  159. package/dist/providers/cache-policies.js.map +1 -1
  160. package/dist/providers/cursor.d.ts.map +1 -1
  161. package/dist/providers/cursor.js +12 -0
  162. package/dist/providers/cursor.js.map +1 -1
  163. package/dist/providers/ollama-cloud.d.ts +1 -2
  164. package/dist/providers/ollama-cloud.d.ts.map +1 -1
  165. package/dist/providers/ollama-cloud.js +1 -20
  166. package/dist/providers/ollama-cloud.js.map +1 -1
  167. package/dist/providers/opencode-go.d.ts +1 -0
  168. package/dist/providers/opencode-go.d.ts.map +1 -1
  169. package/dist/providers/opencode-go.js +29 -1
  170. package/dist/providers/opencode-go.js.map +1 -1
  171. package/dist/providers/openrouter.d.ts.map +1 -1
  172. package/dist/providers/openrouter.js +11 -4
  173. package/dist/providers/openrouter.js.map +1 -1
  174. package/dist/providers/qwen-code.d.ts.map +1 -1
  175. package/dist/providers/qwen-code.js +1 -0
  176. package/dist/providers/qwen-code.js.map +1 -1
  177. package/dist/providers/registry.d.ts.map +1 -1
  178. package/dist/providers/registry.js +2 -0
  179. package/dist/providers/registry.js.map +1 -1
  180. package/dist/providers/result-helpers.d.ts +2 -1
  181. package/dist/providers/result-helpers.d.ts.map +1 -1
  182. package/dist/providers/result-helpers.js +1 -0
  183. package/dist/providers/result-helpers.js.map +1 -1
  184. package/dist/providers/xai.d.ts.map +1 -1
  185. package/dist/providers/xai.js +3 -0
  186. package/dist/providers/xai.js.map +1 -1
  187. package/dist/tui.d.ts.map +1 -1
  188. package/dist/tui.js +229 -217
  189. package/dist/tui.tsx +70 -42
  190. package/package.json +5 -1
package/dist/tui.tsx CHANGED
@@ -7,15 +7,19 @@ import type {
7
7
  TuiPromptRef,
8
8
  } from "@opencode-ai/plugin/tui";
9
9
  import type { JSX } from "@opentui/solid";
10
- import { createEffect, createSignal, onCleanup, Show } from "solid-js";
11
- import { formatDisplayedPercentLabel, formatResetCountdown } from "./lib/format-utils.js";
10
+ import { createEffect, createSignal, Index, onCleanup, Show } from "solid-js";
11
+ import {
12
+ formatQuotaModeHeading,
13
+ formatResetCountdown,
14
+ isResetTimeDecimals,
15
+ resolveDisplayedPercent,
16
+ } from "./lib/format-utils.js";
12
17
  import {
13
18
  buildQuotaDialogCommandOutput,
14
19
  QUOTA_DIALOG_COMMANDS,
15
20
  type QuotaDialogCommandId,
16
21
  type QuotaDialogCommandSpec,
17
22
  } from "./lib/quota-dialog-commands.js";
18
- import { extractSingleWindowWindowLabel } from "./lib/quota-entry-display.js";
19
23
  import type { SessionTokenError } from "./lib/quota-status.js";
20
24
  import { disposeQuotaTelemetryOwner } from "./lib/quota-telemetry.js";
21
25
  import { getSidebarBodyLineColor } from "./lib/tui-line-style.js";
@@ -34,6 +38,11 @@ import {
34
38
  shouldRenderHomeBottom,
35
39
  shouldRenderSidebarPanel,
36
40
  } from "./lib/tui-panel-state.js";
41
+ import {
42
+ formatPromptBarPercentMeta,
43
+ PROMPT_BAR_WIDTH,
44
+ resolvePromptBarLabel,
45
+ } from "./lib/tui-prompt-bar-format.js";
37
46
  import { createTuiRefreshLifecycle } from "./lib/tui-refresh-lifecycle.js";
38
47
  import {
39
48
  createTuiQuotaClient,
@@ -47,6 +56,7 @@ import {
47
56
  type TuiSurfaceRegistration,
48
57
  writeTuiQuotaExportIfEnabled,
49
58
  } from "./lib/tui-runtime.js";
59
+ import { buildSidebarContentRows, type SidebarContentRow } from "./lib/tui-sidebar-content.js";
50
60
  import type { TuiCommandDisplay } from "./lib/types.js";
51
61
 
52
62
  const id = "@slkiser/opencode-quota";
@@ -371,27 +381,46 @@ function SidebarContentView(props: {
371
381
  return collapsed() ? lines() : getSidebarPanelLinesExpanded(panel());
372
382
  };
373
383
 
374
- const toggleIcon = () => (collapsed() ? "▶" : "▼");
375
- const providerCount = () => panel().providerCount ?? 0;
384
+ const contentRows = (): SidebarContentRow[] => {
385
+ const heading = panel().headerPercentMode
386
+ ? formatQuotaModeHeading(panel().headerPercentMode)
387
+ : "Quota";
388
+ return buildSidebarContentRows({
389
+ collapsed: collapsed(),
390
+ heading,
391
+ hasDetailLines: hasDetailLines(),
392
+ providerCount: panel().providerCount ?? 0,
393
+ lines: displayLines(),
394
+ });
395
+ };
376
396
 
377
397
  return (
378
398
  <Show when={shouldRenderSidebarPanel(panel())}>
379
- <box gap={0}>
380
- <box flexDirection="row">
381
- <text fg={props.api.theme.current.text} onMouseDown={toggleCollapsed}>
382
- <b>{hasDetailLines() ? `${toggleIcon()} Quota` : "Quota"}</b>
383
- </text>
384
- <Show when={collapsed() && providerCount() > 0}>
385
- <text fg={props.api.theme.current.textMuted}> ({providerCount()} providers)</text>
386
- </Show>
387
- </box>
388
- <box gap={0}>
389
- {displayLines().map((line) => (
390
- <text fg={getSidebarBodyLineColor(line, props.api.theme.current)} wrapMode="none">
391
- {line || " "}
399
+ <box gap={0} width="100%">
400
+ <Index each={contentRows()}>
401
+ {(row: () => SidebarContentRow) => (
402
+ <text
403
+ fg={
404
+ row().kind === "header"
405
+ ? props.api.theme.current.text
406
+ : getSidebarBodyLineColor(row().text, props.api.theme.current)
407
+ }
408
+ wrapMode="none"
409
+ width="100%"
410
+ onMouseDown={row().kind === "header" ? toggleCollapsed : undefined}
411
+ >
412
+ {row().kind === "header"
413
+ ? row().segments.map((segment) =>
414
+ segment.style === "muted" ? (
415
+ <span fg={props.api.theme.current.textMuted}>{segment.text}</span>
416
+ ) : (
417
+ <b>{segment.text}</b>
418
+ ),
419
+ )
420
+ : row().text || " "}
392
421
  </text>
393
- ))}
394
- </box>
422
+ )}
423
+ </Index>
395
424
  </box>
396
425
  </Show>
397
426
  );
@@ -455,8 +484,6 @@ function SessionPromptWithCompactStatus(props: {
455
484
  );
456
485
  }
457
486
 
458
- const PROMPT_BAR_WIDTH = 12;
459
-
460
487
  function shouldRenderPromptBar(
461
488
  bar: PromptBarState,
462
489
  ): bar is Extract<PromptBarState, { status: "ready" }> {
@@ -515,28 +542,24 @@ function buildPromptBarParts(params: {
515
542
  if (!shouldRenderPromptBar(bar)) return undefined;
516
543
  const entry = bar.entry;
517
544
  if (!entry) return undefined;
518
- const reset = entry.resetTimeIso
519
- ? formatResetCountdown(entry.resetTimeIso, {
520
- compactRounded: true,
521
- decimals: bar.resetTimeDecimals,
522
- })
523
- : "";
524
545
 
525
546
  const hasPercent = Number.isFinite(entry.percentRemaining);
526
547
  if (entry.semanticSegment && !hasPercent) {
527
- return { label: entry.semanticSegment, barText: "", meta: reset };
548
+ const reset = entry.resetTimeIso
549
+ ? formatResetCountdown(
550
+ entry.resetTimeIso,
551
+ isResetTimeDecimals(bar.resetTimeDecimals)
552
+ ? { compactRounded: true, decimals: bar.resetTimeDecimals }
553
+ : { spaced: bar.resetTimeSpaced },
554
+ )
555
+ : "";
556
+ return { label: resolvePromptBarLabel(entry), barText: "", meta: reset };
528
557
  }
529
558
 
530
- const windowLabel =
531
- entry.semanticSegment ??
532
- extractSingleWindowWindowLabel(entry.label ?? "") ??
533
- extractSingleWindowWindowLabel(entry.name ?? "") ??
534
- "Quota";
535
- const percent = formatDisplayedPercentLabel(
536
- entry.percentRemaining ?? 0,
537
- bar.percentDisplayMode ?? "remaining",
559
+ const p = Math.min(
560
+ 100,
561
+ resolveDisplayedPercent(entry.percentRemaining ?? 0, bar.percentDisplayMode ?? "remaining"),
538
562
  );
539
- const p = Math.max(0, Math.min(100, Math.round(entry.percentRemaining ?? 0)));
540
563
  const filled = Math.round((p / 100) * PROMPT_BAR_WIDTH);
541
564
  const empty = PROMPT_BAR_WIDTH - filled;
542
565
  let barText = "█".repeat(filled) + "░".repeat(empty);
@@ -551,11 +574,16 @@ function buildPromptBarParts(params: {
551
574
  barText = cells.join("") + "░".repeat(empty);
552
575
  }
553
576
  return {
554
- label: windowLabel,
577
+ label: resolvePromptBarLabel(entry),
555
578
  barText,
556
- meta: entry.semanticSegment
557
- ? reset
558
- : [percent.replace(/\s+left$/u, ""), reset].filter(Boolean).join(" | "),
579
+ meta: formatPromptBarPercentMeta({
580
+ percentRemaining: entry.percentRemaining ?? 0,
581
+ percentDisplayMode: bar.percentDisplayMode,
582
+ resetTimeIso: entry.resetTimeIso,
583
+ resetTimeDecimals: bar.resetTimeDecimals,
584
+ resetTimeSpaced: bar.resetTimeSpaced,
585
+ runway: entry.runway,
586
+ }),
559
587
  };
560
588
  }
561
589
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slkiser/opencode-quota",
3
- "version": "4.9.0",
3
+ "version": "4.10.1",
4
4
  "description": "OpenCode quota & tokens usage with zero context window pollution. Supports GitHub Copilot, OpenAI (Plus/Pro), Qwen Code, Chutes AI, Synthetic, Google Antigravity, Z.ai coding plan and more.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -109,6 +109,10 @@
109
109
  "typecheck": "tsc --noEmit",
110
110
  "test": "vitest run",
111
111
  "test:watch": "vitest",
112
+ "test:stabilization:tui": "node scripts/test-stabilization-connected.mjs --tui",
113
+ "test:stabilization:tui:prompt-bar": "node scripts/test-stabilization-connected.mjs --tui --prompt-bar",
114
+ "test:stabilization:web": "node scripts/test-stabilization-connected.mjs --web",
115
+ "test:stabilization:fixtures": "node scripts/test-stabilization-fixtures.mjs",
112
116
  "verify": "pnpm run check && pnpm run verify:typescript-version && pnpm run verify:v4-history && pnpm run typecheck && pnpm run build && pnpm test && pnpm run test:four-surfaces && pnpm run verify:package-contents"
113
117
  }
114
118
  }