@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.
- package/README.md +376 -295
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +83 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/entries.d.ts +9 -1
- package/dist/lib/entries.d.ts.map +1 -1
- package/dist/lib/format.d.ts.map +1 -1
- package/dist/lib/format.js +2 -45
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/google-gemini-cli-companion.d.ts.map +1 -1
- package/dist/lib/google-gemini-cli-companion.js +43 -6
- package/dist/lib/google-gemini-cli-companion.js.map +1 -1
- package/dist/lib/init-installer.d.ts +4 -1
- package/dist/lib/init-installer.d.ts.map +1 -1
- package/dist/lib/init-installer.js +179 -42
- package/dist/lib/init-installer.js.map +1 -1
- package/dist/lib/jsonc.d.ts.map +1 -1
- package/dist/lib/jsonc.js +2 -1
- package/dist/lib/jsonc.js.map +1 -1
- package/dist/lib/minimax-auth.d.ts +18 -8
- package/dist/lib/minimax-auth.d.ts.map +1 -1
- package/dist/lib/minimax-auth.js +124 -45
- package/dist/lib/minimax-auth.js.map +1 -1
- package/dist/lib/minimax-endpoints.d.ts +10 -0
- package/dist/lib/minimax-endpoints.d.ts.map +1 -0
- package/dist/lib/minimax-endpoints.js +19 -0
- package/dist/lib/minimax-endpoints.js.map +1 -0
- package/dist/lib/provider-metadata.d.ts +1 -1
- package/dist/lib/provider-metadata.d.ts.map +1 -1
- package/dist/lib/provider-metadata.js +29 -0
- package/dist/lib/provider-metadata.js.map +1 -1
- package/dist/lib/quota-entry-display.d.ts +5 -0
- package/dist/lib/quota-entry-display.d.ts.map +1 -0
- package/dist/lib/quota-entry-display.js +45 -0
- package/dist/lib/quota-entry-display.js.map +1 -0
- package/dist/lib/quota-render-data.d.ts +1 -0
- package/dist/lib/quota-render-data.d.ts.map +1 -1
- package/dist/lib/quota-render-data.js +13 -4
- package/dist/lib/quota-render-data.js.map +1 -1
- package/dist/lib/quota-runtime-context.d.ts.map +1 -1
- package/dist/lib/quota-runtime-context.js +3 -0
- package/dist/lib/quota-runtime-context.js.map +1 -1
- package/dist/lib/quota-stats.d.ts +4 -0
- package/dist/lib/quota-stats.d.ts.map +1 -1
- package/dist/lib/quota-stats.js +21 -5
- package/dist/lib/quota-stats.js.map +1 -1
- package/dist/lib/quota-status.d.ts.map +1 -1
- package/dist/lib/quota-status.js +124 -45
- package/dist/lib/quota-status.js.map +1 -1
- package/dist/lib/session-tokens-format.d.ts.map +1 -1
- package/dist/lib/session-tokens-format.js +19 -5
- package/dist/lib/session-tokens-format.js.map +1 -1
- package/dist/lib/session-tokens.d.ts.map +1 -1
- package/dist/lib/session-tokens.js +2 -0
- package/dist/lib/session-tokens.js.map +1 -1
- package/dist/lib/tui-compact-format.d.ts +8 -0
- package/dist/lib/tui-compact-format.d.ts.map +1 -0
- package/dist/lib/tui-compact-format.js +180 -0
- package/dist/lib/tui-compact-format.js.map +1 -0
- package/dist/lib/tui-native-provider-quota.d.ts +7 -0
- package/dist/lib/tui-native-provider-quota.d.ts.map +1 -0
- package/dist/lib/tui-native-provider-quota.js +25 -0
- package/dist/lib/tui-native-provider-quota.js.map +1 -0
- package/dist/lib/tui-panel-state.d.ts +15 -1
- package/dist/lib/tui-panel-state.d.ts.map +1 -1
- package/dist/lib/tui-panel-state.js +13 -0
- package/dist/lib/tui-panel-state.js.map +1 -1
- package/dist/lib/tui-runtime.d.ts +28 -1
- package/dist/lib/tui-runtime.d.ts.map +1 -1
- package/dist/lib/tui-runtime.js +140 -29
- package/dist/lib/tui-runtime.js.map +1 -1
- package/dist/lib/types.d.ts +20 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +10 -0
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/zhipu-auth.d.ts +38 -0
- package/dist/lib/zhipu-auth.d.ts.map +1 -0
- package/dist/lib/zhipu-auth.js +107 -0
- package/dist/lib/zhipu-auth.js.map +1 -0
- package/dist/lib/zhipu.d.ts +11 -0
- package/dist/lib/zhipu.d.ts.map +1 -0
- package/dist/lib/zhipu.js +87 -0
- package/dist/lib/zhipu.js.map +1 -0
- package/dist/providers/minimax-coding-plan.d.ts +4 -0
- package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
- package/dist/providers/minimax-coding-plan.js +106 -56
- package/dist/providers/minimax-coding-plan.js.map +1 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +4 -1
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/zhipu.d.ts +8 -0
- package/dist/providers/zhipu.d.ts.map +1 -0
- package/dist/providers/zhipu.js +79 -0
- package/dist/providers/zhipu.js.map +1 -0
- package/dist/tui.d.ts +0 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.tsx +383 -45
- package/package.json +1 -1
package/dist/tui.tsx
CHANGED
|
@@ -1,49 +1,113 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
18
|
-
|
|
35
|
+
type TuiPromptRefCallback = (ref: TuiPromptRef | undefined) => void;
|
|
36
|
+
|
|
37
|
+
type SessionQuotaResource = {
|
|
19
38
|
sessionID: string;
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
76
|
-
if (event.properties?.info?.id ===
|
|
130
|
+
api.event.on("session.updated", (event) => {
|
|
131
|
+
if (event.properties?.info?.id === sessionID) {
|
|
77
132
|
scheduleRefresh();
|
|
78
133
|
}
|
|
79
134
|
}),
|
|
80
|
-
|
|
81
|
-
if (event.properties?.info?.sessionID ===
|
|
135
|
+
api.event.on("message.updated", (event) => {
|
|
136
|
+
if (event.properties?.info?.sessionID === sessionID) {
|
|
82
137
|
scheduleRefresh();
|
|
83
138
|
}
|
|
84
139
|
}),
|
|
85
|
-
|
|
86
|
-
if (event.properties?.sessionID ===
|
|
140
|
+
api.event.on("message.removed", (event) => {
|
|
141
|
+
if (event.properties?.sessionID === sessionID) {
|
|
87
142
|
scheduleRefresh();
|
|
88
143
|
}
|
|
89
144
|
}),
|
|
90
|
-
|
|
91
|
-
if (event.properties?.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
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
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
|
-
{
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
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.
|
|
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",
|