@slkiser/opencode-quota 3.11.0 → 3.11.2

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 (38) hide show
  1. package/README.md +61 -43
  2. package/dist/bin/opencode-quota.d.ts.map +1 -1
  3. package/dist/bin/opencode-quota.js +8 -0
  4. package/dist/bin/opencode-quota.js.map +1 -1
  5. package/dist/lib/anthropic.d.ts.map +1 -1
  6. package/dist/lib/anthropic.js +106 -3
  7. package/dist/lib/anthropic.js.map +1 -1
  8. package/dist/lib/atomic-json.d.ts +1 -0
  9. package/dist/lib/atomic-json.d.ts.map +1 -1
  10. package/dist/lib/atomic-json.js +5 -2
  11. package/dist/lib/atomic-json.js.map +1 -1
  12. package/dist/lib/init-installer.d.ts.map +1 -1
  13. package/dist/lib/init-installer.js +40 -18
  14. package/dist/lib/init-installer.js.map +1 -1
  15. package/dist/lib/openai.d.ts +9 -12
  16. package/dist/lib/openai.d.ts.map +1 -1
  17. package/dist/lib/openai.js +69 -40
  18. package/dist/lib/openai.js.map +1 -1
  19. package/dist/lib/quota-state.js +1 -1
  20. package/dist/lib/quota-state.js.map +1 -1
  21. package/dist/lib/scoped-update.d.ts +63 -0
  22. package/dist/lib/scoped-update.d.ts.map +1 -0
  23. package/dist/lib/scoped-update.js +301 -0
  24. package/dist/lib/scoped-update.js.map +1 -0
  25. package/dist/lib/tui-runtime.d.ts.map +1 -1
  26. package/dist/lib/tui-runtime.js +7 -5
  27. package/dist/lib/tui-runtime.js.map +1 -1
  28. package/dist/providers/minimax-coding-plan.d.ts +1 -1
  29. package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
  30. package/dist/providers/minimax-coding-plan.js +7 -4
  31. package/dist/providers/minimax-coding-plan.js.map +1 -1
  32. package/dist/providers/openai.d.ts.map +1 -1
  33. package/dist/providers/openai.js +1 -0
  34. package/dist/providers/openai.js.map +1 -1
  35. package/dist/tui.d.ts.map +1 -1
  36. package/dist/tui.js +504 -0
  37. package/dist/tui.tsx +5 -246
  38. package/package.json +8 -4
package/dist/tui.tsx CHANGED
@@ -8,8 +8,11 @@ import type {
8
8
  } from "@opencode-ai/plugin/tui";
9
9
  import { Show, createEffect, createSignal, onCleanup } from "solid-js";
10
10
 
11
- import type { SessionTokenError } from "./lib/quota-status.js";
12
- import type { CompactStatusState, HomeBottomState, SidebarPanelState } from "./lib/tui-panel-state.js";
11
+ import type {
12
+ CompactStatusState,
13
+ HomeBottomState,
14
+ SidebarPanelState,
15
+ } from "./lib/tui-panel-state.js";
13
16
 
14
17
  import {
15
18
  getCompactStatusText,
@@ -22,20 +25,11 @@ import {
22
25
  } from "./lib/tui-panel-state.js";
23
26
  import { getSidebarBodyLineColor } from "./lib/tui-line-style.js";
24
27
  import {
25
- createTuiQuotaClient,
26
- getTuiRuntimeRootHints,
27
- getTuiSessionModelMeta,
28
28
  loadTuiHomeBottomStatus,
29
- normalizeTuiSessionID,
30
29
  loadTuiSessionQuotaSurfaces,
31
30
  resolveTuiSurfaceRegistration,
32
31
  writeTuiQuotaExportIfEnabled,
33
32
  } from "./lib/tui-runtime.js";
34
- import {
35
- QUOTA_DIALOG_COMMANDS,
36
- buildQuotaDialogCommandOutput,
37
- type QuotaDialogCommandId,
38
- } from "./lib/quota-dialog-commands.js";
39
33
 
40
34
  const id = "@slkiser/opencode-quota";
41
35
  // Place Quota near the top so variable-height built-in sections
@@ -47,12 +41,6 @@ const EVENT_REFRESH_DELAYS_MS = [150, 600] as const;
47
41
  const MOUNT_RECOVERY_DELAYS_MS = [500, 1_500, 4_000] as const;
48
42
 
49
43
  type TuiPromptRefCallback = (ref: TuiPromptRef | undefined) => void;
50
- type DialogSize = "medium" | "large" | "xlarge";
51
-
52
- type QuotaDialogCommandState = {
53
- lastSessionTokenError?: SessionTokenError;
54
- };
55
-
56
44
  type SessionQuotaResource = {
57
45
  sessionID: string;
58
46
  sidebar: () => SidebarPanelState;
@@ -471,233 +459,6 @@ function HomeBottomView(props: { api: TuiPluginApi }) {
471
459
  );
472
460
  }
473
461
 
474
- function getActiveTuiSessionID(api: TuiPluginApi): string | undefined {
475
- const route = (api as any).route?.current;
476
- if (route?.name !== "session" && route?.type !== "session") return undefined;
477
-
478
- return normalizeTuiSessionID(
479
- route.params?.sessionID ?? route.params?.session_id ?? route.params?.id ?? route.sessionID,
480
- );
481
- }
482
-
483
- function getTuiCommandArguments(input: unknown): string | undefined {
484
- if (!input || typeof input !== "object") return undefined;
485
- const record = input as Record<string, unknown>;
486
- for (const key of ["arguments", "args", "query"] as const) {
487
- const value = record[key];
488
- if (typeof value === "string" && value.trim()) return value.trim();
489
- }
490
- return undefined;
491
- }
492
-
493
- function CommandLoadingDialog(props: { api: TuiPluginApi; title: string }) {
494
- return (
495
- <box gap={1}>
496
- <text fg={props.api.theme.current.text}>
497
- <b>{props.title}</b>
498
- </text>
499
- <text fg={props.api.theme.current.textMuted}>Loading deterministic local output…</text>
500
- </box>
501
- );
502
- }
503
-
504
- function CommandOutputDialog(props: { api: TuiPluginApi; title: string; output: string }) {
505
- const lines = () => props.output.split("\n");
506
- const bodyHeight = () => Math.min(28, Math.max(6, lines().length));
507
- return (
508
- <box gap={1} width="100%" flexGrow={1} paddingLeft={2} paddingRight={2} paddingBottom={1}>
509
- <text fg={props.api.theme.current.text}>
510
- <b>{props.title}</b>
511
- </text>
512
- <scrollbox width="100%" flexGrow={1} minHeight={bodyHeight()} maxHeight={28}>
513
- <box gap={0} width="100%" minWidth={0}>
514
- {lines().map((line) => (
515
- <text fg={props.api.theme.current.text} wrapMode="word" width="100%">
516
- {line || " "}
517
- </text>
518
- ))}
519
- </box>
520
- </scrollbox>
521
- <text fg={props.api.theme.current.textMuted}>esc closes</text>
522
- </box>
523
- );
524
- }
525
-
526
- function CommandErrorDialog(props: { api: TuiPluginApi; title: string; error: unknown }) {
527
- const message = props.error instanceof Error ? props.error.message : String(props.error);
528
- return (
529
- <box gap={1}>
530
- <text fg={props.api.theme.current.text}>
531
- <b>{props.title}</b>
532
- </text>
533
- <text fg={props.api.theme.current.text}>OpenCode Quota command failed.</text>
534
- <text fg={props.api.theme.current.textMuted} wrapMode="none">
535
- {message || "Unknown error"}
536
- </text>
537
- <text fg={props.api.theme.current.textMuted}>esc closes</text>
538
- </box>
539
- );
540
- }
541
-
542
- function TokensBetweenPromptDialog(props: {
543
- api: TuiPluginApi;
544
- onConfirm: (value: string) => void;
545
- onCancel: () => void;
546
- }) {
547
- const DialogPrompt = (props.api as any).ui?.DialogPrompt;
548
- if (DialogPrompt) {
549
- return (
550
- <DialogPrompt
551
- title="OpenCode Quota Token Range"
552
- placeholder="YYYY-MM-DD YYYY-MM-DD"
553
- description={() => (
554
- <text fg={props.api.theme.current.textMuted} wrapMode="none">
555
- Enter start and end dates, for example: 2026-01-01 2026-01-15
556
- </text>
557
- )}
558
- onConfirm={props.onConfirm}
559
- onCancel={props.onCancel}
560
- />
561
- );
562
- }
563
-
564
- return (
565
- <CommandOutputDialog
566
- api={props.api}
567
- title="OpenCode Quota Token Range"
568
- output={
569
- "Missing arguments for /tokens_between\n\nExpected: /tokens_between YYYY-MM-DD YYYY-MM-DD\nExample: /tokens_between 2026-01-01 2026-01-15"
570
- }
571
- />
572
- );
573
- }
574
-
575
- function replaceDialog(api: TuiPluginApi, size: DialogSize, render: () => JSX.Element) {
576
- const dialog = (api as any).ui?.dialog;
577
- dialog?.replace?.(render);
578
- // OpenCode's dialog.replace() resets size to medium; xlarge is the widest supported dialog.
579
- dialog?.setSize?.(size);
580
- }
581
-
582
- function clearDialog(api: TuiPluginApi): void {
583
- (api as any).ui?.dialog?.clear?.();
584
- }
585
-
586
- async function runQuotaDialogCommandAsync(
587
- api: TuiPluginApi,
588
- command: QuotaDialogCommandId,
589
- rawInput?: unknown,
590
- state?: QuotaDialogCommandState,
591
- ): Promise<void> {
592
- const spec = QUOTA_DIALOG_COMMANDS.find((item) => item.id === command)!;
593
- const args = getTuiCommandArguments(rawInput);
594
- const sessionID = getActiveTuiSessionID(api);
595
-
596
- if (command === "tokens_between" && !args) {
597
- replaceDialog(api, "medium", () => (
598
- <TokensBetweenPromptDialog
599
- api={api}
600
- onCancel={() => clearDialog(api)}
601
- onConfirm={(value) => {
602
- const nextArgs = value.trim();
603
- if (!nextArgs) {
604
- replaceDialog(api, "large", () => (
605
- <CommandOutputDialog
606
- api={api}
607
- title={spec.title}
608
- output={
609
- "Missing arguments for /tokens_between\n\nExpected: /tokens_between YYYY-MM-DD YYYY-MM-DD\nExample: /tokens_between 2026-01-01 2026-01-15"
610
- }
611
- />
612
- ));
613
- return;
614
- }
615
-
616
- runQuotaDialogCommand(api, command, { arguments: nextArgs }, state);
617
- }}
618
- />
619
- ));
620
- return;
621
- }
622
-
623
- replaceDialog(api, spec.dialogSize, () => <CommandLoadingDialog api={api} title={spec.title} />);
624
-
625
- try {
626
- const result = await buildQuotaDialogCommandOutput({
627
- command,
628
- arguments: args,
629
- client: createTuiQuotaClient(api),
630
- roots: getTuiRuntimeRootHints(api),
631
- sessionID,
632
- resolveSessionMeta: (id) => getTuiSessionModelMeta(api, id),
633
- lastSessionTokenError: state?.lastSessionTokenError,
634
- setLastSessionTokenError: state
635
- ? (error) => {
636
- state.lastSessionTokenError = error;
637
- }
638
- : undefined,
639
- log: async (message, extra) => {
640
- await (api as any).client?.app?.log?.({
641
- body: {
642
- service: "quota-toast",
643
- level: "debug",
644
- message,
645
- extra,
646
- },
647
- });
648
- },
649
- });
650
-
651
- if (result.state === "noop") {
652
- clearDialog(api);
653
- return;
654
- }
655
-
656
- replaceDialog(api, result.dialogSize, () => (
657
- <CommandOutputDialog api={api} title={result.title} output={result.output} />
658
- ));
659
- } catch (error) {
660
- replaceDialog(api, "large", () => <CommandErrorDialog api={api} title={spec.title} error={error} />);
661
- (api as any).ui?.toast?.({
662
- variant: "error",
663
- message: "OpenCode Quota command failed",
664
- });
665
- }
666
- }
667
-
668
- function runQuotaDialogCommand(
669
- api: TuiPluginApi,
670
- command: QuotaDialogCommandId,
671
- rawInput?: unknown,
672
- state?: QuotaDialogCommandState,
673
- ): void {
674
- void runQuotaDialogCommandAsync(api, command, rawInput, state);
675
- }
676
-
677
- function registerQuotaDialogCommands(api: TuiPluginApi): void {
678
- const keymap = (api as any).keymap;
679
- if (!keymap?.registerLayer) return;
680
-
681
- const commandState: QuotaDialogCommandState = {};
682
- const dispose = keymap.registerLayer({
683
- commands: QUOTA_DIALOG_COMMANDS.map((spec) => ({
684
- namespace: "palette",
685
- name: `opencode-quota.${spec.id}`,
686
- title: spec.title,
687
- desc: spec.description,
688
- category: "OpenCode Quota",
689
- slashName: spec.slashName,
690
- run(input?: unknown) {
691
- runQuotaDialogCommand(api, spec.id, input, commandState);
692
- },
693
- })),
694
- });
695
-
696
- if (typeof dispose === "function") {
697
- api.lifecycle.onDispose(dispose);
698
- }
699
- }
700
-
701
462
  function registerSidebarSlots(api: TuiPluginApi): void {
702
463
  api.slots.register({
703
464
  order: SIDEBAR_ORDER,
@@ -710,8 +471,6 @@ function registerSidebarSlots(api: TuiPluginApi): void {
710
471
  }
711
472
 
712
473
  const tui: TuiPlugin = async (api) => {
713
- registerQuotaDialogCommands(api);
714
-
715
474
  let surfaceRegistration;
716
475
  try {
717
476
  surfaceRegistration = await resolveTuiSurfaceRegistration(api);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slkiser/opencode-quota",
3
- "version": "3.11.0",
3
+ "version": "3.11.2",
4
4
  "packageManager": "pnpm@11.0.0",
5
5
  "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.",
6
6
  "type": "module",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "./tui": {
22
22
  "types": "./dist/tui.d.ts",
23
- "default": "./dist/tui.tsx"
23
+ "default": "./dist/tui.js"
24
24
  }
25
25
  },
26
26
  "oc-plugin": [
@@ -70,8 +70,11 @@
70
70
  },
71
71
  "homepage": "https://github.com/slkiser/opencode-quota#readme",
72
72
  "devDependencies": {
73
+ "@babel/core": "^7.28.0",
74
+ "@babel/preset-typescript": "^7.27.1",
73
75
  "@opencode-ai/plugin": "^1.4.3",
74
76
  "@types/node": "^22.0.0",
77
+ "babel-preset-solid": "^1.9.12",
75
78
  "husky": "^9.1.7",
76
79
  "lint-staged": "^16.2.7",
77
80
  "prettier": "^3.8.0",
@@ -80,9 +83,10 @@
80
83
  },
81
84
  "dependencies": {
82
85
  "@clack/prompts": "^1.2.0",
83
- "@opentui/core": "^0.2.7",
84
- "@opentui/solid": "^0.2.7",
86
+ "@opentui/core": "^0.4.3",
87
+ "@opentui/solid": "^0.4.3",
85
88
  "comment-json": "^5.0.0",
89
+ "jsonc-parser": "^3.3.1",
86
90
  "solid-js": "^1.9.12",
87
91
  "xdg-basedir": "^5.1.0"
88
92
  },