@slkiser/opencode-quota 3.8.7 → 3.9.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 (96) hide show
  1. package/README.md +123 -35
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/lib/alibaba-auth.d.ts.map +1 -1
  5. package/dist/lib/alibaba-auth.js +43 -23
  6. package/dist/lib/alibaba-auth.js.map +1 -1
  7. package/dist/lib/chutes-config.d.ts +1 -0
  8. package/dist/lib/chutes-config.d.ts.map +1 -1
  9. package/dist/lib/chutes-config.js +5 -2
  10. package/dist/lib/chutes-config.js.map +1 -1
  11. package/dist/lib/config.d.ts +1 -1
  12. package/dist/lib/config.d.ts.map +1 -1
  13. package/dist/lib/config.js +32 -0
  14. package/dist/lib/config.js.map +1 -1
  15. package/dist/lib/crof-config.d.ts +2 -1
  16. package/dist/lib/crof-config.d.ts.map +1 -1
  17. package/dist/lib/crof-config.js +9 -1
  18. package/dist/lib/crof-config.js.map +1 -1
  19. package/dist/lib/deepseek-auth.d.ts +15 -0
  20. package/dist/lib/deepseek-auth.d.ts.map +1 -0
  21. package/dist/lib/deepseek-auth.js +32 -0
  22. package/dist/lib/deepseek-auth.js.map +1 -0
  23. package/dist/lib/deepseek.d.ts +40 -0
  24. package/dist/lib/deepseek.d.ts.map +1 -0
  25. package/dist/lib/deepseek.js +109 -0
  26. package/dist/lib/deepseek.js.map +1 -0
  27. package/dist/lib/init-installer.d.ts +1 -0
  28. package/dist/lib/init-installer.d.ts.map +1 -1
  29. package/dist/lib/init-installer.js +39 -0
  30. package/dist/lib/init-installer.js.map +1 -1
  31. package/dist/lib/maintainer-announcements.d.ts +43 -0
  32. package/dist/lib/maintainer-announcements.d.ts.map +1 -0
  33. package/dist/lib/maintainer-announcements.js +131 -0
  34. package/dist/lib/maintainer-announcements.js.map +1 -0
  35. package/dist/lib/minimax-auth.d.ts.map +1 -1
  36. package/dist/lib/minimax-auth.js +2 -4
  37. package/dist/lib/minimax-auth.js.map +1 -1
  38. package/dist/lib/ollama-cloud-config.d.ts +37 -0
  39. package/dist/lib/ollama-cloud-config.d.ts.map +1 -0
  40. package/dist/lib/ollama-cloud-config.js +148 -0
  41. package/dist/lib/ollama-cloud-config.js.map +1 -0
  42. package/dist/lib/ollama-cloud.d.ts +17 -0
  43. package/dist/lib/ollama-cloud.d.ts.map +1 -0
  44. package/dist/lib/ollama-cloud.js +150 -0
  45. package/dist/lib/ollama-cloud.js.map +1 -0
  46. package/dist/lib/opencode-sqlite.d.ts.map +1 -1
  47. package/dist/lib/opencode-sqlite.js +90 -8
  48. package/dist/lib/opencode-sqlite.js.map +1 -1
  49. package/dist/lib/provider-metadata.d.ts +1 -1
  50. package/dist/lib/provider-metadata.d.ts.map +1 -1
  51. package/dist/lib/provider-metadata.js +27 -7
  52. package/dist/lib/provider-metadata.js.map +1 -1
  53. package/dist/lib/quota-render-data.d.ts +7 -0
  54. package/dist/lib/quota-render-data.d.ts.map +1 -1
  55. package/dist/lib/quota-render-data.js +17 -0
  56. package/dist/lib/quota-render-data.js.map +1 -1
  57. package/dist/lib/quota-status.d.ts +6 -1
  58. package/dist/lib/quota-status.d.ts.map +1 -1
  59. package/dist/lib/quota-status.js +34 -4
  60. package/dist/lib/quota-status.js.map +1 -1
  61. package/dist/lib/synthetic-config.d.ts +1 -0
  62. package/dist/lib/synthetic-config.d.ts.map +1 -1
  63. package/dist/lib/synthetic-config.js +5 -2
  64. package/dist/lib/synthetic-config.js.map +1 -1
  65. package/dist/lib/tui-panel-state.d.ts +18 -0
  66. package/dist/lib/tui-panel-state.d.ts.map +1 -1
  67. package/dist/lib/tui-panel-state.js +11 -0
  68. package/dist/lib/tui-panel-state.js.map +1 -1
  69. package/dist/lib/tui-runtime.d.ts +12 -1
  70. package/dist/lib/tui-runtime.d.ts.map +1 -1
  71. package/dist/lib/tui-runtime.js +91 -14
  72. package/dist/lib/tui-runtime.js.map +1 -1
  73. package/dist/lib/types.d.ts +30 -0
  74. package/dist/lib/types.d.ts.map +1 -1
  75. package/dist/lib/types.js +4 -0
  76. package/dist/lib/types.js.map +1 -1
  77. package/dist/lib/zhipu-auth.d.ts.map +1 -1
  78. package/dist/lib/zhipu-auth.js +7 -2
  79. package/dist/lib/zhipu-auth.js.map +1 -1
  80. package/dist/plugin.d.ts.map +1 -1
  81. package/dist/plugin.js +130 -12
  82. package/dist/plugin.js.map +1 -1
  83. package/dist/providers/deepseek.d.ts +9 -0
  84. package/dist/providers/deepseek.d.ts.map +1 -0
  85. package/dist/providers/deepseek.js +61 -0
  86. package/dist/providers/deepseek.js.map +1 -0
  87. package/dist/providers/ollama-cloud.d.ts +9 -0
  88. package/dist/providers/ollama-cloud.d.ts.map +1 -0
  89. package/dist/providers/ollama-cloud.js +77 -0
  90. package/dist/providers/ollama-cloud.js.map +1 -0
  91. package/dist/providers/registry.d.ts.map +1 -1
  92. package/dist/providers/registry.js +4 -0
  93. package/dist/providers/registry.js.map +1 -1
  94. package/dist/tui.d.ts.map +1 -1
  95. package/dist/tui.tsx +76 -34
  96. package/package.json +5 -2
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Ollama Cloud provider wrapper.
3
+ *
4
+ * Scrapes the Ollama Cloud settings page and reports session and weekly
5
+ * usage as percentage-based quota entries.
6
+ */
7
+ import { DEFAULT_OLLAMA_CLOUD_CONFIG_CACHE_MAX_AGE_MS, resolveOllamaCloudConfigCached, } from "../lib/ollama-cloud-config.js";
8
+ import { queryOllamaCloudQuota } from "../lib/ollama-cloud.js";
9
+ import { normalizeQuotaProviderId } from "../lib/provider-metadata.js";
10
+ import { attemptedErrorResult, attemptedResult, notAttemptedResult } from "./result-helpers.js";
11
+ const OLLAMA_CLOUD_PROVIDER_LABEL = "Ollama Cloud";
12
+ function buildOllamaCloudEntries(result) {
13
+ const entries = [];
14
+ if (result.session) {
15
+ entries.push({
16
+ name: `${OLLAMA_CLOUD_PROVIDER_LABEL} Session`,
17
+ group: OLLAMA_CLOUD_PROVIDER_LABEL,
18
+ label: "Session:",
19
+ percentRemaining: result.session.percentRemaining,
20
+ resetTimeIso: result.session.resetTimeIso,
21
+ });
22
+ }
23
+ if (result.weekly) {
24
+ entries.push({
25
+ name: `${OLLAMA_CLOUD_PROVIDER_LABEL} Weekly`,
26
+ group: OLLAMA_CLOUD_PROVIDER_LABEL,
27
+ label: "Weekly:",
28
+ percentRemaining: result.weekly.percentRemaining,
29
+ resetTimeIso: result.weekly.resetTimeIso,
30
+ });
31
+ }
32
+ return entries;
33
+ }
34
+ export const ollamaCloudProvider = {
35
+ id: "ollama-cloud",
36
+ async isAvailable(_ctx) {
37
+ const config = await resolveOllamaCloudConfigCached({
38
+ maxAgeMs: DEFAULT_OLLAMA_CLOUD_CONFIG_CACHE_MAX_AGE_MS,
39
+ });
40
+ return config.state === "configured";
41
+ },
42
+ matchesCurrentModel(model) {
43
+ const [provider] = model.toLowerCase().split("/", 2);
44
+ return normalizeQuotaProviderId(provider) === "ollama-cloud";
45
+ },
46
+ async fetch(ctx) {
47
+ const config = await resolveOllamaCloudConfigCached({
48
+ maxAgeMs: DEFAULT_OLLAMA_CLOUD_CONFIG_CACHE_MAX_AGE_MS,
49
+ });
50
+ if (config.state === "none") {
51
+ return notAttemptedResult();
52
+ }
53
+ if (config.state === "incomplete") {
54
+ return attemptedErrorResult(OLLAMA_CLOUD_PROVIDER_LABEL, `Missing ${config.missing} (source: ${config.source})`);
55
+ }
56
+ if (config.state === "invalid") {
57
+ return attemptedErrorResult(OLLAMA_CLOUD_PROVIDER_LABEL, `Invalid config (${config.source}): ${config.error}`);
58
+ }
59
+ const result = await queryOllamaCloudQuota(config.config.cookie, {
60
+ requestTimeoutMs: ctx.config?.requestTimeoutMsConfigured
61
+ ? ctx.config.requestTimeoutMs
62
+ : undefined,
63
+ });
64
+ if (!result) {
65
+ return attemptedErrorResult(OLLAMA_CLOUD_PROVIDER_LABEL, "No response from Ollama Cloud settings page");
66
+ }
67
+ if (!result.success) {
68
+ return attemptedErrorResult(OLLAMA_CLOUD_PROVIDER_LABEL, result.error);
69
+ }
70
+ const entries = buildOllamaCloudEntries(result);
71
+ if (entries.length === 0) {
72
+ return attemptedErrorResult(OLLAMA_CLOUD_PROVIDER_LABEL, "No usage data found on Ollama Cloud settings page");
73
+ }
74
+ return attemptedResult(entries);
75
+ },
76
+ };
77
+ //# sourceMappingURL=ollama-cloud.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama-cloud.js","sourceRoot":"","sources":["../../src/providers/ollama-cloud.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAsBvD,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAsB9C"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAwBvD,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAwB9C"}
@@ -20,6 +20,8 @@ import { nanoGptProvider } from "./nanogpt.js";
20
20
  import { minimaxChinaCodingPlanProvider, minimaxCodingPlanProvider, } from "./minimax-coding-plan.js";
21
21
  import { opencodeGoProvider } from "./opencode-go.js";
22
22
  import { kimiCodeProvider } from "./kimi-code.js";
23
+ import { deepseekProvider } from "./deepseek.js";
24
+ import { ollamaCloudProvider } from "./ollama-cloud.js";
23
25
  export function getProviders() {
24
26
  // Order here defines display ordering in the toast.
25
27
  return [
@@ -40,7 +42,9 @@ export function getProviders() {
40
42
  minimaxCodingPlanProvider,
41
43
  minimaxChinaCodingPlanProvider,
42
44
  kimiCodeProvider,
45
+ deepseekProvider,
43
46
  opencodeGoProvider,
47
+ ollamaCloudProvider,
44
48
  ];
45
49
  }
46
50
  //# sourceMappingURL=registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACL,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,UAAU,YAAY;IAC1B,oDAAoD;IACpD,OAAO;QACL,iBAAiB;QACjB,eAAe;QACf,cAAc;QACd,cAAc;QACd,gBAAgB;QAChB,yBAAyB;QACzB,iBAAiB;QACjB,cAAc;QACd,YAAY;QACZ,yBAAyB;QACzB,uBAAuB;QACvB,WAAW;QACX,aAAa;QACb,eAAe;QACf,yBAAyB;QACzB,8BAA8B;QAC9B,gBAAgB;QAChB,kBAAkB;KACnB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACL,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,UAAU,YAAY;IAC1B,oDAAoD;IACpD,OAAO;QACL,iBAAiB;QACjB,eAAe;QACf,cAAc;QACd,cAAc;QACd,gBAAgB;QAChB,yBAAyB;QACzB,iBAAiB;QACjB,cAAc;QACd,YAAY;QACZ,yBAAyB;QACzB,uBAAuB;QACvB,WAAW;QACX,aAAa;QACb,eAAe;QACf,yBAAyB;QACzB,8BAA8B;QAC9B,gBAAgB;QAChB,gBAAgB;QAChB,kBAAkB;QAClB,mBAAmB;KACpB,CAAC;AACJ,CAAC"}
package/dist/tui.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AAkdjC,QAAA,MAAM,YAAY,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAGjD,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AA4fjC,QAAA,MAAM,YAAY,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAGjD,CAAC;AAEF,eAAe,YAAY,CAAC"}
package/dist/tui.tsx CHANGED
@@ -8,17 +8,20 @@ import type {
8
8
  } from "@opencode-ai/plugin/tui";
9
9
  import { Show, createEffect, createSignal, onCleanup } from "solid-js";
10
10
 
11
- import type { CompactStatusState, SidebarPanelState } from "./lib/tui-panel-state.js";
11
+ import type { CompactStatusState, HomeBottomState, SidebarPanelState } from "./lib/tui-panel-state.js";
12
12
 
13
13
  import {
14
14
  getCompactStatusText,
15
+ getHomeBottomAnnouncementText,
15
16
  getSidebarPanelLines,
17
+ getSidebarPanelLinesExpanded,
16
18
  shouldRenderCompactStatus,
19
+ shouldRenderHomeBottom,
17
20
  shouldRenderSidebarPanel,
18
21
  } from "./lib/tui-panel-state.js";
19
22
  import { getSidebarBodyLineColor } from "./lib/tui-line-style.js";
20
23
  import {
21
- loadTuiHomeCompactStatus,
24
+ loadTuiHomeBottomStatus,
22
25
  loadTuiSessionQuotaSurfaces,
23
26
  resolveTuiSurfaceRegistration,
24
27
  } from "./lib/tui-runtime.js";
@@ -42,14 +45,14 @@ type SessionQuotaResource = {
42
45
  release: () => void;
43
46
  };
44
47
 
45
- type HomeCompactResource = {
46
- compact: () => CompactStatusState;
47
- retain: () => HomeCompactResource;
48
+ type HomeBottomResource = {
49
+ bottom: () => HomeBottomState;
50
+ retain: () => HomeBottomResource;
48
51
  release: () => void;
49
52
  };
50
53
 
51
54
  const sessionResources = new WeakMap<TuiPluginApi, Map<string, SessionQuotaResource>>();
52
- const homeResources = new WeakMap<TuiPluginApi, HomeCompactResource>();
55
+ const homeResources = new WeakMap<TuiPluginApi, HomeBottomResource>();
53
56
 
54
57
  function getSessionResourceMap(api: TuiPluginApi): Map<string, SessionQuotaResource> {
55
58
  const existing = sessionResources.get(api);
@@ -190,8 +193,11 @@ function acquireSessionQuotaResource(api: TuiPluginApi, sessionID: string): Sess
190
193
  return next;
191
194
  }
192
195
 
193
- function createHomeCompactResource(api: TuiPluginApi): HomeCompactResource {
194
- const [compact, setCompact] = createSignal<CompactStatusState>({ status: "loading" });
196
+ function createHomeBottomResource(api: TuiPluginApi): HomeBottomResource {
197
+ const [bottom, setBottom] = createSignal<HomeBottomState>({
198
+ status: "loading",
199
+ compact: { status: "loading" },
200
+ });
195
201
 
196
202
  let refCount = 0;
197
203
  let disposed = false;
@@ -212,10 +218,10 @@ function createHomeCompactResource(api: TuiPluginApi): HomeCompactResource {
212
218
  inFlight = true;
213
219
  const currentVersion = ++loadVersion;
214
220
 
215
- void loadTuiHomeCompactStatus({ api })
221
+ void loadTuiHomeBottomStatus({ api })
216
222
  .then((next) => {
217
223
  if (disposed || currentVersion !== loadVersion) return;
218
- setCompact(next);
224
+ setBottom(next);
219
225
  })
220
226
  .catch(() => {
221
227
  if (disposed || currentVersion !== loadVersion) return;
@@ -263,8 +269,8 @@ function createHomeCompactResource(api: TuiPluginApi): HomeCompactResource {
263
269
  homeResources.delete(api);
264
270
  };
265
271
 
266
- const resource: HomeCompactResource = {
267
- compact,
272
+ const resource: HomeBottomResource = {
273
+ bottom,
268
274
  retain: () => {
269
275
  refCount += 1;
270
276
  return resource;
@@ -280,16 +286,19 @@ function createHomeCompactResource(api: TuiPluginApi): HomeCompactResource {
280
286
  return resource;
281
287
  }
282
288
 
283
- function acquireHomeCompactResource(api: TuiPluginApi): HomeCompactResource {
289
+ function acquireHomeBottomResource(api: TuiPluginApi): HomeBottomResource {
284
290
  const existing = homeResources.get(api);
285
291
  if (existing) return existing.retain();
286
292
 
287
- const next = createHomeCompactResource(api).retain();
293
+ const next = createHomeBottomResource(api).retain();
288
294
  homeResources.set(api, next);
289
295
  return next;
290
296
  }
291
297
 
292
- function useSessionQuotaResource(api: TuiPluginApi, sessionID: () => string): () => SessionQuotaResource {
298
+ function useSessionQuotaResource(
299
+ api: TuiPluginApi,
300
+ sessionID: () => string,
301
+ ): () => SessionQuotaResource {
293
302
  let current = acquireSessionQuotaResource(api, sessionID());
294
303
  const [resource, setResource] = createSignal(current);
295
304
 
@@ -310,23 +319,46 @@ function useSessionQuotaResource(api: TuiPluginApi, sessionID: () => string): ()
310
319
  return resource;
311
320
  }
312
321
 
313
- function SidebarContentView(props: {
314
- api: TuiPluginApi;
315
- sessionID: string;
316
- }) {
322
+ function SidebarContentView(props: { api: TuiPluginApi; sessionID: string }) {
317
323
  const resource = useSessionQuotaResource(props.api, () => props.sessionID);
318
324
  const panel = () => resource().sidebar();
319
325
 
320
326
  const lines = () => getSidebarPanelLines(panel());
327
+ const hasDetailLines = () => Boolean(panel().linesExpanded?.length);
328
+
329
+ const [collapsed, setCollapsed] = createSignal(
330
+ props.api.kv?.get("quota-sidebar-collapsed", true) ?? true,
331
+ );
332
+
333
+ const toggleCollapsed = () => {
334
+ if (!hasDetailLines()) return;
335
+
336
+ const next = !collapsed();
337
+ setCollapsed(next);
338
+ props.api.kv?.set("quota-sidebar-collapsed", next);
339
+ };
340
+
341
+ const displayLines = () => {
342
+ if (collapsed() || !hasDetailLines()) return lines();
343
+ return getSidebarPanelLinesExpanded(panel());
344
+ };
345
+
346
+ const toggleIcon = () => (collapsed() ? "▶" : "▼");
347
+ const providerCount = () => panel().providerCount ?? 0;
321
348
 
322
349
  return (
323
350
  <Show when={shouldRenderSidebarPanel(panel())}>
324
351
  <box gap={0}>
325
- <text fg={props.api.theme.current.text}>
326
- <b>Quota</b>
327
- </text>
352
+ <box flexDirection="row">
353
+ <text fg={props.api.theme.current.text} onMouseDown={toggleCollapsed}>
354
+ <b>{hasDetailLines() ? `${toggleIcon()} Quota` : "Quota"}</b>
355
+ </text>
356
+ <Show when={collapsed() && providerCount() > 0}>
357
+ <text fg={props.api.theme.current.textMuted}> ({providerCount()} providers)</text>
358
+ </Show>
359
+ </box>
328
360
  <box gap={0}>
329
- {lines().map((line) => (
361
+ {displayLines().map((line) => (
330
362
  <text fg={getSidebarBodyLineColor(line, props.api.theme.current)} wrapMode="none">
331
363
  {line || " "}
332
364
  </text>
@@ -394,17 +426,27 @@ function SessionPromptWithCompactStatus(props: {
394
426
  );
395
427
  }
396
428
 
397
- function HomeCompactStatusView(props: { api: TuiPluginApi }) {
398
- const resource = acquireHomeCompactResource(props.api);
429
+ function HomeBottomView(props: { api: TuiPluginApi }) {
430
+ const resource = acquireHomeBottomResource(props.api);
399
431
  onCleanup(() => resource.release());
400
432
 
433
+ const announcement = () => getHomeBottomAnnouncementText(resource.bottom());
434
+ const compact = () => resource.bottom().compact;
435
+
401
436
  return (
402
- <CompactStatusLine
403
- api={props.api}
404
- panel={resource.compact}
405
- justifyContent="center"
406
- blankLineBefore
407
- />
437
+ <Show when={shouldRenderHomeBottom(resource.bottom())}>
438
+ <box gap={0}>
439
+ <text> </text>
440
+ <Show when={announcement()}>
441
+ <box flexDirection="row" justifyContent="center">
442
+ <text fg={props.api.theme.current.textMuted} wrapMode="none">
443
+ {announcement()}
444
+ </text>
445
+ </box>
446
+ </Show>
447
+ <CompactStatusLine api={props.api} panel={compact} justifyContent="center" />
448
+ </box>
449
+ </Show>
408
450
  );
409
451
  }
410
452
 
@@ -433,7 +475,7 @@ const tui: TuiPlugin = async (api) => {
433
475
  }
434
476
 
435
477
  const compactRegistration = surfaceRegistration.compact;
436
- if (!compactRegistration.enabled) return;
478
+ if (!compactRegistration.enabled && !surfaceRegistration.homeBottom) return;
437
479
 
438
480
  const compactSlots: Record<string, (ctx: any, props: any) => JSX.Element | null> = {};
439
481
 
@@ -459,8 +501,8 @@ const tui: TuiPlugin = async (api) => {
459
501
  );
460
502
  }
461
503
 
462
- if (compactRegistration.homeBottom) {
463
- compactSlots.home_bottom = () => <HomeCompactStatusView api={api} />;
504
+ if (surfaceRegistration.homeBottom) {
505
+ compactSlots.home_bottom = () => <HomeBottomView api={api} />;
464
506
  }
465
507
 
466
508
  if (Object.keys(compactSlots).length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slkiser/opencode-quota",
3
- "version": "3.8.7",
3
+ "version": "3.9.0",
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",
@@ -86,10 +86,13 @@
86
86
  "solid-js": "^1.9.12",
87
87
  "xdg-basedir": "^5.1.0"
88
88
  },
89
+ "optionalDependencies": {
90
+ "better-sqlite3": "^12.10.0"
91
+ },
89
92
  "peerDependencies": {
90
93
  "@opencode-ai/plugin": "^1.4.3"
91
94
  },
92
95
  "engines": {
93
- "node": ">=18.0.0"
96
+ "node": ">=20.0.0"
94
97
  }
95
98
  }