@slkiser/opencode-quota 3.6.2 → 3.8.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 (99) hide show
  1. package/README.md +376 -295
  2. package/dist/lib/config.d.ts +1 -1
  3. package/dist/lib/config.d.ts.map +1 -1
  4. package/dist/lib/config.js +83 -1
  5. package/dist/lib/config.js.map +1 -1
  6. package/dist/lib/entries.d.ts +9 -1
  7. package/dist/lib/entries.d.ts.map +1 -1
  8. package/dist/lib/format.d.ts.map +1 -1
  9. package/dist/lib/format.js +2 -45
  10. package/dist/lib/format.js.map +1 -1
  11. package/dist/lib/google-gemini-cli-companion.d.ts.map +1 -1
  12. package/dist/lib/google-gemini-cli-companion.js +43 -6
  13. package/dist/lib/google-gemini-cli-companion.js.map +1 -1
  14. package/dist/lib/init-installer.d.ts +4 -1
  15. package/dist/lib/init-installer.d.ts.map +1 -1
  16. package/dist/lib/init-installer.js +179 -42
  17. package/dist/lib/init-installer.js.map +1 -1
  18. package/dist/lib/jsonc.d.ts.map +1 -1
  19. package/dist/lib/jsonc.js +2 -1
  20. package/dist/lib/jsonc.js.map +1 -1
  21. package/dist/lib/minimax-auth.d.ts +18 -8
  22. package/dist/lib/minimax-auth.d.ts.map +1 -1
  23. package/dist/lib/minimax-auth.js +124 -45
  24. package/dist/lib/minimax-auth.js.map +1 -1
  25. package/dist/lib/minimax-endpoints.d.ts +10 -0
  26. package/dist/lib/minimax-endpoints.d.ts.map +1 -0
  27. package/dist/lib/minimax-endpoints.js +19 -0
  28. package/dist/lib/minimax-endpoints.js.map +1 -0
  29. package/dist/lib/provider-metadata.d.ts +1 -1
  30. package/dist/lib/provider-metadata.d.ts.map +1 -1
  31. package/dist/lib/provider-metadata.js +29 -0
  32. package/dist/lib/provider-metadata.js.map +1 -1
  33. package/dist/lib/quota-entry-display.d.ts +5 -0
  34. package/dist/lib/quota-entry-display.d.ts.map +1 -0
  35. package/dist/lib/quota-entry-display.js +45 -0
  36. package/dist/lib/quota-entry-display.js.map +1 -0
  37. package/dist/lib/quota-render-data.d.ts +1 -0
  38. package/dist/lib/quota-render-data.d.ts.map +1 -1
  39. package/dist/lib/quota-render-data.js +13 -4
  40. package/dist/lib/quota-render-data.js.map +1 -1
  41. package/dist/lib/quota-runtime-context.d.ts.map +1 -1
  42. package/dist/lib/quota-runtime-context.js +3 -0
  43. package/dist/lib/quota-runtime-context.js.map +1 -1
  44. package/dist/lib/quota-stats.d.ts +4 -0
  45. package/dist/lib/quota-stats.d.ts.map +1 -1
  46. package/dist/lib/quota-stats.js +21 -5
  47. package/dist/lib/quota-stats.js.map +1 -1
  48. package/dist/lib/quota-status.d.ts.map +1 -1
  49. package/dist/lib/quota-status.js +124 -45
  50. package/dist/lib/quota-status.js.map +1 -1
  51. package/dist/lib/session-tokens-format.d.ts.map +1 -1
  52. package/dist/lib/session-tokens-format.js +19 -5
  53. package/dist/lib/session-tokens-format.js.map +1 -1
  54. package/dist/lib/session-tokens.d.ts.map +1 -1
  55. package/dist/lib/session-tokens.js +2 -0
  56. package/dist/lib/session-tokens.js.map +1 -1
  57. package/dist/lib/tui-compact-format.d.ts +8 -0
  58. package/dist/lib/tui-compact-format.d.ts.map +1 -0
  59. package/dist/lib/tui-compact-format.js +180 -0
  60. package/dist/lib/tui-compact-format.js.map +1 -0
  61. package/dist/lib/tui-native-provider-quota.d.ts +7 -0
  62. package/dist/lib/tui-native-provider-quota.d.ts.map +1 -0
  63. package/dist/lib/tui-native-provider-quota.js +25 -0
  64. package/dist/lib/tui-native-provider-quota.js.map +1 -0
  65. package/dist/lib/tui-panel-state.d.ts +15 -1
  66. package/dist/lib/tui-panel-state.d.ts.map +1 -1
  67. package/dist/lib/tui-panel-state.js +13 -0
  68. package/dist/lib/tui-panel-state.js.map +1 -1
  69. package/dist/lib/tui-runtime.d.ts +28 -1
  70. package/dist/lib/tui-runtime.d.ts.map +1 -1
  71. package/dist/lib/tui-runtime.js +140 -29
  72. package/dist/lib/tui-runtime.js.map +1 -1
  73. package/dist/lib/types.d.ts +20 -0
  74. package/dist/lib/types.d.ts.map +1 -1
  75. package/dist/lib/types.js +10 -0
  76. package/dist/lib/types.js.map +1 -1
  77. package/dist/lib/zhipu-auth.d.ts +38 -0
  78. package/dist/lib/zhipu-auth.d.ts.map +1 -0
  79. package/dist/lib/zhipu-auth.js +107 -0
  80. package/dist/lib/zhipu-auth.js.map +1 -0
  81. package/dist/lib/zhipu.d.ts +11 -0
  82. package/dist/lib/zhipu.d.ts.map +1 -0
  83. package/dist/lib/zhipu.js +87 -0
  84. package/dist/lib/zhipu.js.map +1 -0
  85. package/dist/providers/minimax-coding-plan.d.ts +4 -0
  86. package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
  87. package/dist/providers/minimax-coding-plan.js +106 -56
  88. package/dist/providers/minimax-coding-plan.js.map +1 -1
  89. package/dist/providers/registry.d.ts.map +1 -1
  90. package/dist/providers/registry.js +4 -1
  91. package/dist/providers/registry.js.map +1 -1
  92. package/dist/providers/zhipu.d.ts +8 -0
  93. package/dist/providers/zhipu.d.ts.map +1 -0
  94. package/dist/providers/zhipu.js +79 -0
  95. package/dist/providers/zhipu.js.map +1 -0
  96. package/dist/tui.d.ts +0 -1
  97. package/dist/tui.d.ts.map +1 -1
  98. package/dist/tui.tsx +383 -45
  99. package/package.json +1 -1
package/dist/tui.tsx CHANGED
@@ -1,49 +1,113 @@
1
1
  /** @jsxImportSource @opentui/solid */
2
- import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from "@opencode-ai/plugin/tui";
3
- import { createEffect, createSignal, onCleanup } from "solid-js";
2
+ import type { JSX } from "@opentui/solid";
3
+ import type {
4
+ TuiPlugin,
5
+ TuiPluginApi,
6
+ TuiPluginModule,
7
+ TuiPromptRef,
8
+ } from "@opencode-ai/plugin/tui";
9
+ import { Show, createEffect, createSignal, onCleanup } from "solid-js";
4
10
 
5
- import type { SidebarPanelState } from "./lib/tui-panel-state.js";
11
+ import type { CompactStatusState, SidebarPanelState } from "./lib/tui-panel-state.js";
6
12
 
7
- import { getSidebarPanelLines, shouldRenderSidebarPanel } from "./lib/tui-panel-state.js";
13
+ import {
14
+ getCompactStatusText,
15
+ getSidebarPanelLines,
16
+ shouldRenderCompactStatus,
17
+ shouldRenderSidebarPanel,
18
+ } from "./lib/tui-panel-state.js";
8
19
  import { getSidebarBodyLineColor } from "./lib/tui-line-style.js";
9
- import { loadSidebarPanel } from "./lib/tui-runtime.js";
20
+ import {
21
+ loadTuiHomeCompactStatus,
22
+ loadTuiSessionQuotaSurfaces,
23
+ resolveTuiSurfaceRegistration,
24
+ } from "./lib/tui-runtime.js";
10
25
 
11
26
  const id = "@slkiser/opencode-quota";
12
27
  // Place Quota near the top so variable-height built-in sections
13
28
  // (MCP/LSP/Todo/Files) do not push it below the visible fold.
14
29
  const SIDEBAR_ORDER = 150;
30
+ const COMPACT_ORDER = 90;
15
31
  const REFRESH_INTERVAL_MS = 60_000;
32
+ const EVENT_REFRESH_DELAYS_MS = [150, 600] as const;
33
+ const MOUNT_RECOVERY_DELAYS_MS = [500, 1_500, 4_000] as const;
16
34
 
17
- function SidebarContentView(props: {
18
- api: TuiPluginApi;
35
+ type TuiPromptRefCallback = (ref: TuiPromptRef | undefined) => void;
36
+
37
+ type SessionQuotaResource = {
19
38
  sessionID: string;
20
- }) {
21
- const [panel, setPanel] = createSignal<SidebarPanelState>({
39
+ sidebar: () => SidebarPanelState;
40
+ compact: () => CompactStatusState;
41
+ retain: () => SessionQuotaResource;
42
+ release: () => void;
43
+ };
44
+
45
+ type HomeCompactResource = {
46
+ compact: () => CompactStatusState;
47
+ retain: () => HomeCompactResource;
48
+ release: () => void;
49
+ };
50
+
51
+ const sessionResources = new WeakMap<TuiPluginApi, Map<string, SessionQuotaResource>>();
52
+ const homeResources = new WeakMap<TuiPluginApi, HomeCompactResource>();
53
+
54
+ function getSessionResourceMap(api: TuiPluginApi): Map<string, SessionQuotaResource> {
55
+ const existing = sessionResources.get(api);
56
+ if (existing) return existing;
57
+
58
+ const next = new Map<string, SessionQuotaResource>();
59
+ sessionResources.set(api, next);
60
+ return next;
61
+ }
62
+
63
+ function createSessionQuotaResource(api: TuiPluginApi, sessionID: string): SessionQuotaResource {
64
+ const [sidebar, setSidebar] = createSignal<SidebarPanelState>({
22
65
  status: "loading",
23
66
  lines: [],
24
67
  });
68
+ const [compact, setCompact] = createSignal<CompactStatusState>({ status: "loading" });
25
69
 
70
+ let refCount = 0;
26
71
  let disposed = false;
27
72
  let loadVersion = 0;
73
+ let inFlight = false;
74
+ let queued = false;
28
75
  const timers = new Set<ReturnType<typeof setTimeout>>();
29
76
 
30
77
  const reload = () => {
78
+ if (disposed) return;
79
+
80
+ if (inFlight) {
81
+ queued = true;
82
+ loadVersion += 1;
83
+ return;
84
+ }
85
+
86
+ inFlight = true;
31
87
  const currentVersion = ++loadVersion;
32
88
 
33
- void loadSidebarPanel({
34
- api: props.api,
35
- sessionID: props.sessionID,
36
- })
89
+ void loadTuiSessionQuotaSurfaces({ api, sessionID })
37
90
  .then((next) => {
38
91
  if (disposed || currentVersion !== loadVersion) return;
39
- setPanel(next);
92
+ setSidebar(next.sidebar);
93
+ setCompact(next.compact);
40
94
  })
41
95
  .catch(() => {
42
96
  if (disposed || currentVersion !== loadVersion) return;
97
+ })
98
+ .finally(() => {
99
+ if (disposed) return;
100
+ inFlight = false;
101
+ if (queued) {
102
+ queued = false;
103
+ reload();
104
+ }
43
105
  });
44
106
  };
45
107
 
46
108
  const queueRefresh = (delay: number) => {
109
+ if (disposed) return;
110
+
47
111
  const timer = setTimeout(() => {
48
112
  timers.delete(timer);
49
113
  reload();
@@ -52,77 +116,299 @@ function SidebarContentView(props: {
52
116
  };
53
117
 
54
118
  const scheduleRefresh = () => {
55
- queueRefresh(150);
56
- queueRefresh(600);
119
+ for (const delay of EVENT_REFRESH_DELAYS_MS) queueRefresh(delay);
57
120
  };
58
121
 
59
122
  // TUI/session state can hydrate asynchronously after mount or session switch,
60
123
  // so retry a few times to recover from empty first-load reads.
61
124
  const scheduleMountRecovery = () => {
62
- queueRefresh(500);
63
- queueRefresh(1_500);
64
- queueRefresh(4_000);
125
+ for (const delay of MOUNT_RECOVERY_DELAYS_MS) queueRefresh(delay);
65
126
  };
66
127
 
67
- createEffect(() => {
68
- props.sessionID;
69
- reload();
70
- scheduleMountRecovery();
71
- });
72
-
73
128
  const interval = setInterval(reload, REFRESH_INTERVAL_MS);
74
129
  const unsubscribers = [
75
- props.api.event.on("session.updated", (event) => {
76
- if (event.properties?.info?.id === props.sessionID) {
130
+ api.event.on("session.updated", (event) => {
131
+ if (event.properties?.info?.id === sessionID) {
77
132
  scheduleRefresh();
78
133
  }
79
134
  }),
80
- props.api.event.on("message.updated", (event) => {
81
- if (event.properties?.info?.sessionID === props.sessionID) {
135
+ api.event.on("message.updated", (event) => {
136
+ if (event.properties?.info?.sessionID === sessionID) {
82
137
  scheduleRefresh();
83
138
  }
84
139
  }),
85
- props.api.event.on("message.removed", (event) => {
86
- if (event.properties?.sessionID === props.sessionID) {
140
+ api.event.on("message.removed", (event) => {
141
+ if (event.properties?.sessionID === sessionID) {
87
142
  scheduleRefresh();
88
143
  }
89
144
  }),
90
- props.api.event.on("tui.session.select", (event) => {
91
- if (event.properties?.sessionID === props.sessionID) {
145
+ api.event.on("tui.session.select", (event) => {
146
+ if (event.properties?.sessionID === sessionID) {
92
147
  scheduleRefresh();
93
148
  }
94
149
  }),
95
150
  ];
96
151
 
97
- onCleanup(() => {
152
+ const dispose = () => {
153
+ if (disposed) return;
154
+
98
155
  disposed = true;
99
156
  clearInterval(interval);
100
157
  for (const timer of timers) clearTimeout(timer);
101
158
  timers.clear();
102
159
  for (const unsubscribe of unsubscribers) unsubscribe();
160
+ getSessionResourceMap(api).delete(sessionID);
161
+ };
162
+
163
+ const resource: SessionQuotaResource = {
164
+ sessionID,
165
+ sidebar,
166
+ compact,
167
+ retain: () => {
168
+ refCount += 1;
169
+ return resource;
170
+ },
171
+ release: () => {
172
+ refCount -= 1;
173
+ if (refCount <= 0) dispose();
174
+ },
175
+ };
176
+
177
+ reload();
178
+ scheduleMountRecovery();
179
+
180
+ return resource;
181
+ }
182
+
183
+ function acquireSessionQuotaResource(api: TuiPluginApi, sessionID: string): SessionQuotaResource {
184
+ const resources = getSessionResourceMap(api);
185
+ const existing = resources.get(sessionID);
186
+ if (existing) return existing.retain();
187
+
188
+ const next = createSessionQuotaResource(api, sessionID).retain();
189
+ resources.set(sessionID, next);
190
+ return next;
191
+ }
192
+
193
+ function createHomeCompactResource(api: TuiPluginApi): HomeCompactResource {
194
+ const [compact, setCompact] = createSignal<CompactStatusState>({ status: "loading" });
195
+
196
+ let refCount = 0;
197
+ let disposed = false;
198
+ let loadVersion = 0;
199
+ let inFlight = false;
200
+ let queued = false;
201
+ const timers = new Set<ReturnType<typeof setTimeout>>();
202
+
203
+ const reload = () => {
204
+ if (disposed) return;
205
+
206
+ if (inFlight) {
207
+ queued = true;
208
+ loadVersion += 1;
209
+ return;
210
+ }
211
+
212
+ inFlight = true;
213
+ const currentVersion = ++loadVersion;
214
+
215
+ void loadTuiHomeCompactStatus({ api })
216
+ .then((next) => {
217
+ if (disposed || currentVersion !== loadVersion) return;
218
+ setCompact(next);
219
+ })
220
+ .catch(() => {
221
+ if (disposed || currentVersion !== loadVersion) return;
222
+ })
223
+ .finally(() => {
224
+ if (disposed) return;
225
+ inFlight = false;
226
+ if (queued) {
227
+ queued = false;
228
+ reload();
229
+ }
230
+ });
231
+ };
232
+
233
+ const queueRefresh = (delay: number) => {
234
+ if (disposed) return;
235
+
236
+ const timer = setTimeout(() => {
237
+ timers.delete(timer);
238
+ reload();
239
+ }, delay);
240
+ timers.add(timer);
241
+ };
242
+
243
+ const scheduleRefresh = () => {
244
+ for (const delay of EVENT_REFRESH_DELAYS_MS) queueRefresh(delay);
245
+ };
246
+
247
+ const interval = setInterval(reload, REFRESH_INTERVAL_MS);
248
+ const unsubscribers = [
249
+ api.event.on("session.updated", scheduleRefresh),
250
+ api.event.on("message.updated", scheduleRefresh),
251
+ api.event.on("message.removed", scheduleRefresh),
252
+ api.event.on("tui.session.select", scheduleRefresh),
253
+ ];
254
+
255
+ const dispose = () => {
256
+ if (disposed) return;
257
+
258
+ disposed = true;
259
+ clearInterval(interval);
260
+ for (const timer of timers) clearTimeout(timer);
261
+ timers.clear();
262
+ for (const unsubscribe of unsubscribers) unsubscribe();
263
+ homeResources.delete(api);
264
+ };
265
+
266
+ const resource: HomeCompactResource = {
267
+ compact,
268
+ retain: () => {
269
+ refCount += 1;
270
+ return resource;
271
+ },
272
+ release: () => {
273
+ refCount -= 1;
274
+ if (refCount <= 0) dispose();
275
+ },
276
+ };
277
+
278
+ reload();
279
+
280
+ return resource;
281
+ }
282
+
283
+ function acquireHomeCompactResource(api: TuiPluginApi): HomeCompactResource {
284
+ const existing = homeResources.get(api);
285
+ if (existing) return existing.retain();
286
+
287
+ const next = createHomeCompactResource(api).retain();
288
+ homeResources.set(api, next);
289
+ return next;
290
+ }
291
+
292
+ function useSessionQuotaResource(api: TuiPluginApi, sessionID: () => string): () => SessionQuotaResource {
293
+ let current = acquireSessionQuotaResource(api, sessionID());
294
+ const [resource, setResource] = createSignal(current);
295
+
296
+ createEffect(() => {
297
+ const nextSessionID = sessionID();
298
+ if (current.sessionID === nextSessionID) return;
299
+
300
+ const previous = current;
301
+ current = acquireSessionQuotaResource(api, nextSessionID);
302
+ setResource(current);
303
+ previous.release();
103
304
  });
104
305
 
105
- if (!shouldRenderSidebarPanel(panel())) return null;
306
+ onCleanup(() => {
307
+ current.release();
308
+ });
309
+
310
+ return resource;
311
+ }
312
+
313
+ function SidebarContentView(props: {
314
+ api: TuiPluginApi;
315
+ sessionID: string;
316
+ }) {
317
+ const resource = useSessionQuotaResource(props.api, () => props.sessionID);
318
+ const panel = () => resource().sidebar();
106
319
 
107
320
  const lines = () => getSidebarPanelLines(panel());
108
321
 
109
322
  return (
110
- <box gap={0}>
111
- <text fg={props.api.theme.current.text}>
112
- <b>Quota</b>
113
- </text>
323
+ <Show when={shouldRenderSidebarPanel(panel())}>
114
324
  <box gap={0}>
115
- {lines().map((line) => (
116
- <text fg={getSidebarBodyLineColor(line, props.api.theme.current)} wrapMode="none">
117
- {line || " "}
118
- </text>
119
- ))}
325
+ <text fg={props.api.theme.current.text}>
326
+ <b>Quota</b>
327
+ </text>
328
+ <box gap={0}>
329
+ {lines().map((line) => (
330
+ <text fg={getSidebarBodyLineColor(line, props.api.theme.current)} wrapMode="none">
331
+ {line || " "}
332
+ </text>
333
+ ))}
334
+ </box>
120
335
  </box>
336
+ </Show>
337
+ );
338
+ }
339
+
340
+ function CompactStatusLine(props: {
341
+ api: TuiPluginApi;
342
+ panel: () => CompactStatusState;
343
+ justifyContent: "flex-start" | "center" | "flex-end";
344
+ blankLineBefore?: boolean;
345
+ }) {
346
+ const text = () => {
347
+ const panel = props.panel();
348
+ if (!shouldRenderCompactStatus(panel)) return "";
349
+ return getCompactStatusText(panel);
350
+ };
351
+
352
+ const line = () => (
353
+ <box flexDirection="row" justifyContent={props.justifyContent}>
354
+ <text fg={props.api.theme.current.textMuted} wrapMode="none">
355
+ {text()}
356
+ </text>
121
357
  </box>
122
358
  );
359
+
360
+ return (
361
+ <Show when={text()}>
362
+ <Show when={props.blankLineBefore} fallback={line()}>
363
+ <box gap={0}>
364
+ <text> </text>
365
+ {line()}
366
+ </box>
367
+ </Show>
368
+ </Show>
369
+ );
123
370
  }
124
371
 
125
- const tui: TuiPlugin = async (api) => {
372
+ function SessionPromptWithCompactStatus(props: {
373
+ api: TuiPluginApi;
374
+ sessionID: string;
375
+ visible?: boolean;
376
+ disabled?: boolean;
377
+ onSubmit?: () => void;
378
+ promptRef?: TuiPromptRefCallback;
379
+ }) {
380
+ const resource = useSessionQuotaResource(props.api, () => props.sessionID);
381
+ const panel = () => resource().compact();
382
+
383
+ return (
384
+ <box gap={0}>
385
+ <props.api.ui.Prompt
386
+ sessionID={props.sessionID}
387
+ visible={props.visible}
388
+ disabled={props.disabled}
389
+ onSubmit={props.onSubmit}
390
+ ref={props.promptRef}
391
+ />
392
+ <CompactStatusLine api={props.api} panel={panel} justifyContent="flex-end" />
393
+ </box>
394
+ );
395
+ }
396
+
397
+ function HomeCompactStatusView(props: { api: TuiPluginApi }) {
398
+ const resource = acquireHomeCompactResource(props.api);
399
+ onCleanup(() => resource.release());
400
+
401
+ return (
402
+ <CompactStatusLine
403
+ api={props.api}
404
+ panel={resource.compact}
405
+ justifyContent="center"
406
+ blankLineBefore
407
+ />
408
+ );
409
+ }
410
+
411
+ function registerSidebarSlots(api: TuiPluginApi): void {
126
412
  api.slots.register({
127
413
  order: SIDEBAR_ORDER,
128
414
  slots: {
@@ -131,6 +417,58 @@ const tui: TuiPlugin = async (api) => {
131
417
  },
132
418
  },
133
419
  });
420
+ }
421
+
422
+ const tui: TuiPlugin = async (api) => {
423
+ let surfaceRegistration;
424
+ try {
425
+ surfaceRegistration = await resolveTuiSurfaceRegistration(api);
426
+ } catch {
427
+ registerSidebarSlots(api);
428
+ return;
429
+ }
430
+
431
+ if (surfaceRegistration.sidebar.enabled) {
432
+ registerSidebarSlots(api);
433
+ }
434
+
435
+ const compactRegistration = surfaceRegistration.compact;
436
+ if (!compactRegistration.enabled) return;
437
+
438
+ const compactSlots: Record<string, (ctx: any, props: any) => JSX.Element | null> = {};
439
+
440
+ if (compactRegistration.sessionPrompt) {
441
+ compactSlots.session_prompt = (
442
+ _ctx,
443
+ props: {
444
+ session_id: string;
445
+ visible?: boolean;
446
+ disabled?: boolean;
447
+ on_submit?: () => void;
448
+ ref?: TuiPromptRefCallback;
449
+ },
450
+ ) => (
451
+ <SessionPromptWithCompactStatus
452
+ api={api}
453
+ sessionID={props.session_id}
454
+ visible={props.visible}
455
+ disabled={props.disabled}
456
+ onSubmit={props.on_submit}
457
+ promptRef={props.ref}
458
+ />
459
+ );
460
+ }
461
+
462
+ if (compactRegistration.homeBottom) {
463
+ compactSlots.home_bottom = () => <HomeCompactStatusView api={api} />;
464
+ }
465
+
466
+ if (Object.keys(compactSlots).length > 0) {
467
+ api.slots.register({
468
+ order: COMPACT_ORDER,
469
+ slots: compactSlots,
470
+ });
471
+ }
134
472
  };
135
473
 
136
474
  const pluginModule: TuiPluginModule & { id: string } = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slkiser/opencode-quota",
3
- "version": "3.6.2",
3
+ "version": "3.8.0",
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",