@slkiser/opencode-quota 4.0.0 → 4.1.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 (266) hide show
  1. package/README.md +37 -25
  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/index.d.ts +2 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/lib/anthropic.d.ts.map +1 -1
  8. package/dist/lib/anthropic.js +78 -72
  9. package/dist/lib/anthropic.js.map +1 -1
  10. package/dist/lib/api-key-resolver.d.ts.map +1 -1
  11. package/dist/lib/api-key-resolver.js +14 -24
  12. package/dist/lib/api-key-resolver.js.map +1 -1
  13. package/dist/lib/atomic-json.d.ts +3 -1
  14. package/dist/lib/atomic-json.d.ts.map +1 -1
  15. package/dist/lib/atomic-json.js +23 -9
  16. package/dist/lib/atomic-json.js.map +1 -1
  17. package/dist/lib/chutes.d.ts.map +1 -1
  18. package/dist/lib/chutes.js +28 -23
  19. package/dist/lib/chutes.js.map +1 -1
  20. package/dist/lib/cli-show.d.ts +9 -0
  21. package/dist/lib/cli-show.d.ts.map +1 -1
  22. package/dist/lib/cli-show.js +34 -5
  23. package/dist/lib/cli-show.js.map +1 -1
  24. package/dist/lib/cli-status.d.ts +8 -0
  25. package/dist/lib/cli-status.d.ts.map +1 -0
  26. package/dist/lib/cli-status.js +125 -0
  27. package/dist/lib/cli-status.js.map +1 -0
  28. package/dist/lib/config.d.ts +1 -1
  29. package/dist/lib/config.d.ts.map +1 -1
  30. package/dist/lib/config.js +47 -12
  31. package/dist/lib/config.js.map +1 -1
  32. package/dist/lib/copilot.d.ts +11 -5
  33. package/dist/lib/copilot.d.ts.map +1 -1
  34. package/dist/lib/copilot.js +300 -52
  35. package/dist/lib/copilot.js.map +1 -1
  36. package/dist/lib/deepseek.d.ts.map +1 -1
  37. package/dist/lib/deepseek.js +22 -17
  38. package/dist/lib/deepseek.js.map +1 -1
  39. package/dist/lib/display-sanitize.d.ts.map +1 -1
  40. package/dist/lib/display-sanitize.js +8 -0
  41. package/dist/lib/display-sanitize.js.map +1 -1
  42. package/dist/lib/entries.d.ts +14 -1
  43. package/dist/lib/entries.d.ts.map +1 -1
  44. package/dist/lib/entries.js.map +1 -1
  45. package/dist/lib/format-utils.d.ts +7 -0
  46. package/dist/lib/format-utils.d.ts.map +1 -1
  47. package/dist/lib/format-utils.js +18 -0
  48. package/dist/lib/format-utils.js.map +1 -1
  49. package/dist/lib/format.d.ts +1 -0
  50. package/dist/lib/format.d.ts.map +1 -1
  51. package/dist/lib/format.js +22 -7
  52. package/dist/lib/format.js.map +1 -1
  53. package/dist/lib/google-agy.d.ts.map +1 -1
  54. package/dist/lib/google-agy.js +203 -92
  55. package/dist/lib/google-agy.js.map +1 -1
  56. package/dist/lib/google-gemini-cli.d.ts.map +1 -1
  57. package/dist/lib/google-gemini-cli.js +53 -41
  58. package/dist/lib/google-gemini-cli.js.map +1 -1
  59. package/dist/lib/google-token-cache.d.ts.map +1 -1
  60. package/dist/lib/google-token-cache.js +87 -34
  61. package/dist/lib/google-token-cache.js.map +1 -1
  62. package/dist/lib/google.d.ts.map +1 -1
  63. package/dist/lib/google.js +57 -39
  64. package/dist/lib/google.js.map +1 -1
  65. package/dist/lib/grouped-entry-normalization.d.ts.map +1 -1
  66. package/dist/lib/grouped-entry-normalization.js +7 -1
  67. package/dist/lib/grouped-entry-normalization.js.map +1 -1
  68. package/dist/lib/http.d.ts +12 -7
  69. package/dist/lib/http.d.ts.map +1 -1
  70. package/dist/lib/http.js +28 -15
  71. package/dist/lib/http.js.map +1 -1
  72. package/dist/lib/init-installer.d.ts +2 -1
  73. package/dist/lib/init-installer.d.ts.map +1 -1
  74. package/dist/lib/init-installer.js +29 -2
  75. package/dist/lib/init-installer.js.map +1 -1
  76. package/dist/lib/kimi.d.ts.map +1 -1
  77. package/dist/lib/kimi.js +20 -15
  78. package/dist/lib/kimi.js.map +1 -1
  79. package/dist/lib/maintainer-announcements.d.ts.map +1 -1
  80. package/dist/lib/maintainer-announcements.js +10 -13
  81. package/dist/lib/maintainer-announcements.js.map +1 -1
  82. package/dist/lib/mimo-config.d.ts +29 -0
  83. package/dist/lib/mimo-config.d.ts.map +1 -0
  84. package/dist/lib/mimo-config.js +147 -0
  85. package/dist/lib/mimo-config.js.map +1 -0
  86. package/dist/lib/mimo.d.ts +35 -0
  87. package/dist/lib/mimo.d.ts.map +1 -0
  88. package/dist/lib/mimo.js +236 -0
  89. package/dist/lib/mimo.js.map +1 -0
  90. package/dist/lib/modelsdev-pricing.d.ts.map +1 -1
  91. package/dist/lib/modelsdev-pricing.js +39 -27
  92. package/dist/lib/modelsdev-pricing.js.map +1 -1
  93. package/dist/lib/nanogpt.d.ts.map +1 -1
  94. package/dist/lib/nanogpt.js +40 -30
  95. package/dist/lib/nanogpt.js.map +1 -1
  96. package/dist/lib/ollama-cloud.d.ts +1 -1
  97. package/dist/lib/ollama-cloud.d.ts.map +1 -1
  98. package/dist/lib/ollama-cloud.js +73 -68
  99. package/dist/lib/ollama-cloud.js.map +1 -1
  100. package/dist/lib/openai.d.ts.map +1 -1
  101. package/dist/lib/openai.js +65 -45
  102. package/dist/lib/openai.js.map +1 -1
  103. package/dist/lib/opencode-config-editor.d.ts +6 -0
  104. package/dist/lib/opencode-config-editor.d.ts.map +1 -1
  105. package/dist/lib/opencode-config-editor.js +47 -1
  106. package/dist/lib/opencode-config-editor.js.map +1 -1
  107. package/dist/lib/opencode-config-providers.d.ts.map +1 -1
  108. package/dist/lib/opencode-config-providers.js +13 -16
  109. package/dist/lib/opencode-config-providers.js.map +1 -1
  110. package/dist/lib/opencode-config-read.d.ts +23 -0
  111. package/dist/lib/opencode-config-read.d.ts.map +1 -0
  112. package/dist/lib/opencode-config-read.js +30 -0
  113. package/dist/lib/opencode-config-read.js.map +1 -0
  114. package/dist/lib/opencode-go.d.ts.map +1 -1
  115. package/dist/lib/opencode-go.js +44 -39
  116. package/dist/lib/opencode-go.js.map +1 -1
  117. package/dist/lib/opencode-zen-config.d.ts +34 -0
  118. package/dist/lib/opencode-zen-config.d.ts.map +1 -0
  119. package/dist/lib/opencode-zen-config.js +103 -0
  120. package/dist/lib/opencode-zen-config.js.map +1 -0
  121. package/dist/lib/opencode-zen.d.ts +27 -0
  122. package/dist/lib/opencode-zen.d.ts.map +1 -0
  123. package/dist/lib/opencode-zen.js +143 -0
  124. package/dist/lib/opencode-zen.js.map +1 -0
  125. package/dist/lib/provider-add-command.d.ts.map +1 -1
  126. package/dist/lib/provider-add-command.js +21 -2
  127. package/dist/lib/provider-add-command.js.map +1 -1
  128. package/dist/lib/provider-add-json-v1-questionnaire.d.ts +32 -0
  129. package/dist/lib/provider-add-json-v1-questionnaire.d.ts.map +1 -0
  130. package/dist/lib/provider-add-json-v1-questionnaire.js +336 -0
  131. package/dist/lib/provider-add-json-v1-questionnaire.js.map +1 -0
  132. package/dist/lib/provider-add.d.ts.map +1 -1
  133. package/dist/lib/provider-add.js +11 -2
  134. package/dist/lib/provider-add.js.map +1 -1
  135. package/dist/lib/provider-availability.d.ts +2 -2
  136. package/dist/lib/provider-availability.d.ts.map +1 -1
  137. package/dist/lib/provider-availability.js +2 -3
  138. package/dist/lib/provider-availability.js.map +1 -1
  139. package/dist/lib/provider-metadata.d.ts +289 -1
  140. package/dist/lib/provider-metadata.d.ts.map +1 -1
  141. package/dist/lib/provider-metadata.js +321 -227
  142. package/dist/lib/provider-metadata.js.map +1 -1
  143. package/dist/lib/quota-command-format.d.ts.map +1 -1
  144. package/dist/lib/quota-command-format.js +12 -16
  145. package/dist/lib/quota-command-format.js.map +1 -1
  146. package/dist/lib/quota-dialog-commands.d.ts +59 -2
  147. package/dist/lib/quota-dialog-commands.d.ts.map +1 -1
  148. package/dist/lib/quota-dialog-commands.js +71 -30
  149. package/dist/lib/quota-dialog-commands.js.map +1 -1
  150. package/dist/lib/quota-entry-display.d.ts +2 -0
  151. package/dist/lib/quota-entry-display.d.ts.map +1 -1
  152. package/dist/lib/quota-entry-display.js +27 -13
  153. package/dist/lib/quota-entry-display.js.map +1 -1
  154. package/dist/lib/quota-providers-remote.d.ts +6 -1
  155. package/dist/lib/quota-providers-remote.d.ts.map +1 -1
  156. package/dist/lib/quota-providers-remote.js +376 -12
  157. package/dist/lib/quota-providers-remote.js.map +1 -1
  158. package/dist/lib/quota-providers.d.ts +84 -3
  159. package/dist/lib/quota-providers.d.ts.map +1 -1
  160. package/dist/lib/quota-providers.js +561 -24
  161. package/dist/lib/quota-providers.js.map +1 -1
  162. package/dist/lib/quota-render-data.d.ts +4 -0
  163. package/dist/lib/quota-render-data.d.ts.map +1 -1
  164. package/dist/lib/quota-render-data.js +101 -121
  165. package/dist/lib/quota-render-data.js.map +1 -1
  166. package/dist/lib/quota-runtime-context.d.ts +9 -1
  167. package/dist/lib/quota-runtime-context.d.ts.map +1 -1
  168. package/dist/lib/quota-runtime-context.js +5 -0
  169. package/dist/lib/quota-runtime-context.js.map +1 -1
  170. package/dist/lib/quota-state.d.ts.map +1 -1
  171. package/dist/lib/quota-state.js +26 -2
  172. package/dist/lib/quota-state.js.map +1 -1
  173. package/dist/lib/quota-stats.d.ts +1 -0
  174. package/dist/lib/quota-stats.d.ts.map +1 -1
  175. package/dist/lib/quota-stats.js +14 -4
  176. package/dist/lib/quota-stats.js.map +1 -1
  177. package/dist/lib/quota-status.d.ts.map +1 -1
  178. package/dist/lib/quota-status.js +96 -1
  179. package/dist/lib/quota-status.js.map +1 -1
  180. package/dist/lib/runtime-provider-ids.d.ts +4 -0
  181. package/dist/lib/runtime-provider-ids.d.ts.map +1 -0
  182. package/dist/lib/runtime-provider-ids.js +10 -0
  183. package/dist/lib/runtime-provider-ids.js.map +1 -0
  184. package/dist/lib/session-tokens.d.ts +2 -0
  185. package/dist/lib/session-tokens.d.ts.map +1 -1
  186. package/dist/lib/session-tokens.js +4 -2
  187. package/dist/lib/session-tokens.js.map +1 -1
  188. package/dist/lib/synthetic.d.ts.map +1 -1
  189. package/dist/lib/synthetic.js +37 -32
  190. package/dist/lib/synthetic.js.map +1 -1
  191. package/dist/lib/toast-format-grouped.d.ts +1 -0
  192. package/dist/lib/toast-format-grouped.d.ts.map +1 -1
  193. package/dist/lib/toast-format-grouped.js +33 -29
  194. package/dist/lib/toast-format-grouped.js.map +1 -1
  195. package/dist/lib/tui-refresh-lifecycle.d.ts +17 -0
  196. package/dist/lib/tui-refresh-lifecycle.d.ts.map +1 -0
  197. package/dist/lib/tui-refresh-lifecycle.js +83 -0
  198. package/dist/lib/tui-refresh-lifecycle.js.map +1 -0
  199. package/dist/lib/tui-runtime.d.ts +0 -5
  200. package/dist/lib/tui-runtime.d.ts.map +1 -1
  201. package/dist/lib/tui-runtime.js +1 -6
  202. package/dist/lib/tui-runtime.js.map +1 -1
  203. package/dist/lib/tui-sidebar-format.d.ts +1 -1
  204. package/dist/lib/tui-sidebar-format.d.ts.map +1 -1
  205. package/dist/lib/tui-sidebar-format.js +1 -0
  206. package/dist/lib/tui-sidebar-format.js.map +1 -1
  207. package/dist/lib/types.d.ts +61 -7
  208. package/dist/lib/types.d.ts.map +1 -1
  209. package/dist/lib/types.js +2 -0
  210. package/dist/lib/types.js.map +1 -1
  211. package/dist/lib/xai.d.ts +39 -0
  212. package/dist/lib/xai.d.ts.map +1 -0
  213. package/dist/lib/xai.js +153 -0
  214. package/dist/lib/xai.js.map +1 -0
  215. package/dist/lib/zai.d.ts.map +1 -1
  216. package/dist/lib/zai.js +62 -56
  217. package/dist/lib/zai.js.map +1 -1
  218. package/dist/lib/zhipu.d.ts.map +1 -1
  219. package/dist/lib/zhipu.js +55 -50
  220. package/dist/lib/zhipu.js.map +1 -1
  221. package/dist/plugin.d.ts.map +1 -1
  222. package/dist/plugin.js +36 -157
  223. package/dist/plugin.js.map +1 -1
  224. package/dist/providers/copilot.d.ts.map +1 -1
  225. package/dist/providers/copilot.js +24 -3
  226. package/dist/providers/copilot.js.map +1 -1
  227. package/dist/providers/glm-coding-plan-provider.d.ts +35 -0
  228. package/dist/providers/glm-coding-plan-provider.d.ts.map +1 -0
  229. package/dist/providers/glm-coding-plan-provider.js +40 -0
  230. package/dist/providers/glm-coding-plan-provider.js.map +1 -0
  231. package/dist/providers/google-agy.d.ts.map +1 -1
  232. package/dist/providers/google-agy.js +60 -36
  233. package/dist/providers/google-agy.js.map +1 -1
  234. package/dist/providers/mimo.d.ts +3 -0
  235. package/dist/providers/mimo.d.ts.map +1 -0
  236. package/dist/providers/mimo.js +120 -0
  237. package/dist/providers/mimo.js.map +1 -0
  238. package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
  239. package/dist/providers/minimax-coding-plan.js +60 -37
  240. package/dist/providers/minimax-coding-plan.js.map +1 -1
  241. package/dist/providers/opencode-zen.d.ts +3 -0
  242. package/dist/providers/opencode-zen.d.ts.map +1 -0
  243. package/dist/providers/opencode-zen.js +94 -0
  244. package/dist/providers/opencode-zen.js.map +1 -0
  245. package/dist/providers/quota-providers.d.ts.map +1 -1
  246. package/dist/providers/quota-providers.js +5 -3
  247. package/dist/providers/quota-providers.js.map +1 -1
  248. package/dist/providers/registry.d.ts.map +1 -1
  249. package/dist/providers/registry.js +6 -0
  250. package/dist/providers/registry.js.map +1 -1
  251. package/dist/providers/xai.d.ts +6 -0
  252. package/dist/providers/xai.d.ts.map +1 -0
  253. package/dist/providers/xai.js +51 -0
  254. package/dist/providers/xai.js.map +1 -0
  255. package/dist/providers/zai.d.ts +1 -7
  256. package/dist/providers/zai.d.ts.map +1 -1
  257. package/dist/providers/zai.js +9 -45
  258. package/dist/providers/zai.js.map +1 -1
  259. package/dist/providers/zhipu.d.ts +1 -7
  260. package/dist/providers/zhipu.d.ts.map +1 -1
  261. package/dist/providers/zhipu.js +9 -45
  262. package/dist/providers/zhipu.js.map +1 -1
  263. package/dist/tui.d.ts.map +1 -1
  264. package/dist/tui.js +47 -136
  265. package/dist/tui.tsx +62 -179
  266. package/package.json +1 -1
package/dist/tui.tsx CHANGED
@@ -9,6 +9,7 @@ import type {
9
9
  import { Show, createEffect, createSignal, onCleanup } from "solid-js";
10
10
 
11
11
  import type { SessionTokenError } from "./lib/quota-status.js";
12
+ import { createTuiRefreshLifecycle } from "./lib/tui-refresh-lifecycle.js";
12
13
  import type { TuiCommandDisplay } from "./lib/types.js";
13
14
  import type {
14
15
  CompactStatusState,
@@ -91,116 +92,55 @@ function createSessionQuotaResource(api: TuiPluginApi, sessionID: string): Sessi
91
92
  });
92
93
  const [compact, setCompact] = createSignal<CompactStatusState>({ status: "loading" });
93
94
 
94
- let refCount = 0;
95
- let disposed = false;
96
- let loadVersion = 0;
97
- let inFlight = false;
98
- let queued = false;
99
- const timers = new Set<ReturnType<typeof setTimeout>>();
100
-
101
- const reload = () => {
102
- if (disposed) return;
103
-
104
- if (inFlight) {
105
- queued = true;
106
- loadVersion += 1;
107
- return;
108
- }
109
-
110
- inFlight = true;
111
- const currentVersion = ++loadVersion;
112
-
113
- void loadTuiSessionQuotaSurfaces({ api, sessionID })
114
- .then((next) => {
115
- if (disposed || currentVersion !== loadVersion) return;
116
- setSidebar(next.sidebar);
117
- setCompact(next.compact);
118
- })
119
- .catch(() => {
120
- if (disposed || currentVersion !== loadVersion) return;
121
- })
122
- .finally(() => {
123
- if (disposed) return;
124
- inFlight = false;
125
- if (queued) {
126
- queued = false;
127
- reload();
95
+ const lifecycle = createTuiRefreshLifecycle({
96
+ load: () => loadTuiSessionQuotaSurfaces({ api, sessionID }),
97
+ apply: (next) => {
98
+ setSidebar(next.sidebar);
99
+ setCompact(next.compact);
100
+ },
101
+ intervalMs: REFRESH_INTERVAL_MS,
102
+ eventRefreshDelaysMs: EVENT_REFRESH_DELAYS_MS,
103
+ // TUI/session state can hydrate asynchronously after mount or session switch,
104
+ // so retry a few times to recover from empty first-load reads.
105
+ recoveryDelaysMs: MOUNT_RECOVERY_DELAYS_MS,
106
+ subscribe: (scheduleRefresh) => [
107
+ api.event.on("session.updated", (event) => {
108
+ if (event.properties?.info?.id === sessionID) {
109
+ scheduleRefresh();
128
110
  }
129
- });
130
- };
131
-
132
- const queueRefresh = (delay: number) => {
133
- if (disposed) return;
134
-
135
- const timer = setTimeout(() => {
136
- timers.delete(timer);
137
- reload();
138
- }, delay);
139
- timers.add(timer);
140
- };
141
-
142
- const scheduleRefresh = () => {
143
- for (const delay of EVENT_REFRESH_DELAYS_MS) queueRefresh(delay);
144
- };
145
-
146
- // TUI/session state can hydrate asynchronously after mount or session switch,
147
- // so retry a few times to recover from empty first-load reads.
148
- const scheduleMountRecovery = () => {
149
- for (const delay of MOUNT_RECOVERY_DELAYS_MS) queueRefresh(delay);
150
- };
151
-
152
- const interval = setInterval(reload, REFRESH_INTERVAL_MS);
153
- const unsubscribers = [
154
- api.event.on("session.updated", (event) => {
155
- if (event.properties?.info?.id === sessionID) {
156
- scheduleRefresh();
157
- }
158
- }),
159
- api.event.on("message.updated", (event) => {
160
- if (event.properties?.info?.sessionID === sessionID) {
161
- scheduleRefresh();
162
- }
163
- }),
164
- api.event.on("message.removed", (event) => {
165
- if (event.properties?.sessionID === sessionID) {
166
- scheduleRefresh();
167
- }
168
- }),
169
- api.event.on("tui.session.select", (event) => {
170
- if (event.properties?.sessionID === sessionID) {
171
- scheduleRefresh();
172
- }
173
- }),
174
- ];
175
-
176
- const dispose = () => {
177
- if (disposed) return;
178
-
179
- disposed = true;
180
- clearInterval(interval);
181
- for (const timer of timers) clearTimeout(timer);
182
- timers.clear();
183
- for (const unsubscribe of unsubscribers) unsubscribe();
184
- getSessionResourceMap(api).delete(sessionID);
185
- };
111
+ }),
112
+ api.event.on("message.updated", (event) => {
113
+ if (event.properties?.info?.sessionID === sessionID) {
114
+ scheduleRefresh();
115
+ }
116
+ }),
117
+ api.event.on("message.removed", (event) => {
118
+ if (event.properties?.sessionID === sessionID) {
119
+ scheduleRefresh();
120
+ }
121
+ }),
122
+ api.event.on("tui.session.select", (event) => {
123
+ if (event.properties?.sessionID === sessionID) {
124
+ scheduleRefresh();
125
+ }
126
+ }),
127
+ ],
128
+ onDispose: () => {
129
+ getSessionResourceMap(api).delete(sessionID);
130
+ },
131
+ });
186
132
 
187
133
  const resource: SessionQuotaResource = {
188
134
  sessionID,
189
135
  sidebar,
190
136
  compact,
191
137
  retain: () => {
192
- refCount += 1;
138
+ lifecycle.retain();
193
139
  return resource;
194
140
  },
195
- release: () => {
196
- refCount -= 1;
197
- if (refCount <= 0) dispose();
198
- },
141
+ release: lifecycle.release,
199
142
  };
200
143
 
201
- reload();
202
- scheduleMountRecovery();
203
-
204
144
  return resource;
205
145
  }
206
146
 
@@ -223,95 +163,38 @@ function createHomeBottomResource(
223
163
  compact: compactHomeBottomEnabled ? { status: "loading" } : { status: "disabled" },
224
164
  });
225
165
 
226
- let refCount = 0;
227
- let disposed = false;
228
- let loadVersion = 0;
229
- let inFlight = false;
230
- let queued = false;
231
- const timers = new Set<ReturnType<typeof setTimeout>>();
232
-
233
- const reload = () => {
234
- if (disposed) return;
235
-
236
- if (inFlight) {
237
- queued = true;
238
- loadVersion += 1;
239
- return;
240
- }
241
-
242
- inFlight = true;
243
- const currentVersion = ++loadVersion;
244
-
245
- void loadTuiHomeBottomStatus({ api })
246
- .then((next) => {
247
- if (disposed || currentVersion !== loadVersion) return;
248
- setBottom(next);
249
- // Fire-and-forget: write export file if enabled. A failed write must
250
- // never affect TUI rendering, so log a warning and continue.
251
- void writeTuiQuotaExportIfEnabled({ api }).catch((err) => {
252
- console.warn(`[opencode-quota] quota export write failed: ${String(err)}`);
253
- });
254
- })
255
- .catch(() => {
256
- if (disposed || currentVersion !== loadVersion) return;
257
- })
258
- .finally(() => {
259
- if (disposed) return;
260
- inFlight = false;
261
- if (queued) {
262
- queued = false;
263
- reload();
264
- }
166
+ const lifecycle = createTuiRefreshLifecycle({
167
+ load: () => loadTuiHomeBottomStatus({ api }),
168
+ apply: setBottom,
169
+ afterApply: () => {
170
+ // Fire-and-forget: write export file if enabled. A failed write must
171
+ // never affect TUI rendering, so log a warning and continue.
172
+ void writeTuiQuotaExportIfEnabled({ api }).catch((err) => {
173
+ console.warn(`[opencode-quota] quota export write failed: ${String(err)}`);
265
174
  });
266
- };
267
-
268
- const queueRefresh = (delay: number) => {
269
- if (disposed) return;
270
-
271
- const timer = setTimeout(() => {
272
- timers.delete(timer);
273
- reload();
274
- }, delay);
275
- timers.add(timer);
276
- };
277
-
278
- const scheduleRefresh = () => {
279
- for (const delay of EVENT_REFRESH_DELAYS_MS) queueRefresh(delay);
280
- };
281
-
282
- const interval = setInterval(reload, REFRESH_INTERVAL_MS);
283
- const unsubscribers = [
284
- api.event.on("session.updated", scheduleRefresh),
285
- api.event.on("message.updated", scheduleRefresh),
286
- api.event.on("message.removed", scheduleRefresh),
287
- api.event.on("tui.session.select", scheduleRefresh),
288
- ];
289
-
290
- const dispose = () => {
291
- if (disposed) return;
292
-
293
- disposed = true;
294
- clearInterval(interval);
295
- for (const timer of timers) clearTimeout(timer);
296
- timers.clear();
297
- for (const unsubscribe of unsubscribers) unsubscribe();
298
- homeResources.delete(api);
299
- };
175
+ },
176
+ intervalMs: REFRESH_INTERVAL_MS,
177
+ eventRefreshDelaysMs: EVENT_REFRESH_DELAYS_MS,
178
+ subscribe: (scheduleRefresh) => [
179
+ api.event.on("session.updated", scheduleRefresh),
180
+ api.event.on("message.updated", scheduleRefresh),
181
+ api.event.on("message.removed", scheduleRefresh),
182
+ api.event.on("tui.session.select", scheduleRefresh),
183
+ ],
184
+ onDispose: () => {
185
+ homeResources.delete(api);
186
+ },
187
+ });
300
188
 
301
189
  const resource: HomeBottomResource = {
302
190
  bottom,
303
191
  retain: () => {
304
- refCount += 1;
192
+ lifecycle.retain();
305
193
  return resource;
306
194
  },
307
- release: () => {
308
- refCount -= 1;
309
- if (refCount <= 0) dispose();
310
- },
195
+ release: lifecycle.release,
311
196
  };
312
197
 
313
- reload();
314
-
315
198
  return resource;
316
199
  }
317
200
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slkiser/opencode-quota",
3
- "version": "4.0.0",
3
+ "version": "4.1.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",