@slkiser/opencode-quota 5.0.0-beta.1 → 5.0.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 +72 -131
- package/dist/lib/format-utils.d.ts +0 -4
- package/dist/lib/format-utils.d.ts.map +1 -1
- package/dist/lib/format-utils.js +0 -3
- package/dist/lib/format-utils.js.map +1 -1
- package/dist/lib/init-installer.js +2 -2
- package/dist/lib/init-installer.js.map +1 -1
- package/dist/lib/markdown-table.d.ts +36 -0
- package/dist/lib/markdown-table.d.ts.map +1 -1
- package/dist/lib/markdown-table.js +56 -0
- package/dist/lib/markdown-table.js.map +1 -1
- package/dist/lib/opencode-auth.d.ts.map +1 -1
- package/dist/lib/opencode-auth.js +4 -3
- package/dist/lib/opencode-auth.js.map +1 -1
- package/dist/lib/quota-columns.d.ts +38 -0
- package/dist/lib/quota-columns.d.ts.map +1 -0
- package/dist/lib/quota-columns.js +129 -0
- package/dist/lib/quota-columns.js.map +1 -0
- package/dist/lib/quota-command-format.d.ts +11 -0
- package/dist/lib/quota-command-format.d.ts.map +1 -1
- package/dist/lib/quota-command-format.js +80 -27
- package/dist/lib/quota-command-format.js.map +1 -1
- package/dist/lib/quota-dialog-command-specs.d.ts +4 -0
- package/dist/lib/quota-dialog-command-specs.d.ts.map +1 -1
- package/dist/lib/quota-dialog-command-specs.js.map +1 -1
- package/dist/lib/quota-dialog-commands.d.ts +2 -0
- package/dist/lib/quota-dialog-commands.d.ts.map +1 -1
- package/dist/lib/quota-dialog-commands.js +114 -101
- package/dist/lib/quota-dialog-commands.js.map +1 -1
- package/dist/lib/quota-report-message.d.ts +3 -2
- package/dist/lib/quota-report-message.d.ts.map +1 -1
- package/dist/lib/quota-report-message.js +7 -11
- package/dist/lib/quota-report-message.js.map +1 -1
- package/dist/lib/quota-stats-format.d.ts +8 -3
- package/dist/lib/quota-stats-format.d.ts.map +1 -1
- package/dist/lib/quota-stats-format.js +36 -37
- package/dist/lib/quota-stats-format.js.map +1 -1
- package/dist/lib/quota-status.d.ts +5 -2
- package/dist/lib/quota-status.d.ts.map +1 -1
- package/dist/lib/quota-status.js +9 -5
- package/dist/lib/quota-status.js.map +1 -1
- package/dist/lib/report-document.d.ts +56 -2
- package/dist/lib/report-document.d.ts.map +1 -1
- package/dist/lib/report-document.js +105 -24
- package/dist/lib/report-document.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +5 -1
- package/dist/plugin.js.map +1 -1
- package/dist/tui-v2.d.ts.map +1 -1
- package/dist/tui-v2.jsx +149 -23
- package/dist/tui-v2.jsx.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +370 -98
- package/package.json +1 -1
package/dist/tui.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { memo as _$memo } from "@opentui/solid";
|
|
2
|
-
import { effect as _$effect } from "@opentui/solid";
|
|
3
1
|
import { use as _$use } from "@opentui/solid";
|
|
2
|
+
import { memo as _$memo } from "@opentui/solid";
|
|
4
3
|
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
5
4
|
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
5
|
+
import { effect as _$effect } from "@opentui/solid";
|
|
6
6
|
import { createComponent as _$createComponent } from "@opentui/solid";
|
|
7
7
|
import { insert as _$insert } from "@opentui/solid";
|
|
8
8
|
import { setProp as _$setProp } from "@opentui/solid";
|
|
@@ -10,16 +10,18 @@ import { createElement as _$createElement } from "@opentui/solid";
|
|
|
10
10
|
/** @jsxImportSource @opentui/solid */
|
|
11
11
|
|
|
12
12
|
import { Plugin } from "@opencode/plugin/tui";
|
|
13
|
-
import {
|
|
13
|
+
import { TextAttributes } from "@opentui/core";
|
|
14
14
|
import { useTerminalDimensions } from "@opentui/solid";
|
|
15
15
|
import { createSignal, onCleanup, Show } from "solid-js";
|
|
16
16
|
import { loadConfig } from "./lib/config.js";
|
|
17
17
|
import { resolveOpenCodeLocationRoots } from "./lib/config-file-utils.js";
|
|
18
18
|
import { sanitizeDisplayText } from "./lib/display-sanitize.js";
|
|
19
|
+
import { fitTableToWidth } from "./lib/markdown-table.js";
|
|
20
|
+
import { layoutQuotaTables } from "./lib/quota-columns.js";
|
|
19
21
|
import { parseQuotaSlashCommand, QUOTA_DIALOG_COMMANDS } from "./lib/quota-dialog-command-specs.js";
|
|
20
|
-
import {
|
|
22
|
+
import { readQuotaReportMetadata } from "./lib/quota-report-message.js";
|
|
23
|
+
import { renderableSections, renderKvRow } from "./lib/report-document.js";
|
|
21
24
|
import { QuotaRpc } from "./rpc.js";
|
|
22
|
-
const terminalForeground = RGBA.defaultForeground();
|
|
23
25
|
const REFRESH_INTERVAL_MS = 60_000;
|
|
24
26
|
const RPC_TIMEOUT_MS = 60_000;
|
|
25
27
|
function getSessionID(event) {
|
|
@@ -150,8 +152,8 @@ function QuotaFooter(props) {
|
|
|
150
152
|
_$setProp(_el$, "flexDirection", "column");
|
|
151
153
|
_$insert(_el$, () => lines().map(line => (() => {
|
|
152
154
|
var _el$2 = _$createElement("text");
|
|
153
|
-
_$setProp(_el$2, "fg", terminalForeground);
|
|
154
155
|
_$insert(_el$2, line);
|
|
156
|
+
_$effect(_$p => _$setProp(_el$2, "fg", props.context.theme.text.muted, _$p));
|
|
155
157
|
return _el$2;
|
|
156
158
|
})()));
|
|
157
159
|
return _el$;
|
|
@@ -164,6 +166,244 @@ function reportFailure(error) {
|
|
|
164
166
|
console.warn(`[opencode-quota] failed to load quota: ${rpcErrorMessage(error)}${hint}`);
|
|
165
167
|
}
|
|
166
168
|
|
|
169
|
+
/** OpenCode's dialog widths (dialogWidth in its ui/dialog.tsx). */
|
|
170
|
+
const DIALOG_WIDTHS = {
|
|
171
|
+
medium: 60,
|
|
172
|
+
large: 88,
|
|
173
|
+
xlarge: 116
|
|
174
|
+
};
|
|
175
|
+
function sanitizeQuotaRow(row) {
|
|
176
|
+
return {
|
|
177
|
+
...row,
|
|
178
|
+
label: sanitizeDisplayText(row.label),
|
|
179
|
+
value: sanitizeDisplayText(row.value),
|
|
180
|
+
usage: row.usage === undefined ? undefined : sanitizeDisplayText(row.usage),
|
|
181
|
+
reset: row.reset === undefined ? undefined : sanitizeDisplayText(row.reset),
|
|
182
|
+
notes: row.notes.map(sanitizeDisplayText)
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** A report's /quota blocks, sanitized, for layoutQuotaTables. */
|
|
187
|
+
function quotaBlocks(section) {
|
|
188
|
+
return section.blocks.flatMap(block => block.kind === "quota" ? [{
|
|
189
|
+
...block,
|
|
190
|
+
provider: sanitizeDisplayText(block.provider),
|
|
191
|
+
rows: block.rows.map(sanitizeQuotaRow)
|
|
192
|
+
}] : []);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* A /quota table (see layoutQuotaTables): its title bold, like a section title, then its
|
|
197
|
+
* header bold in OpenCode's primary accent, like the token tables, and its providers bold.
|
|
198
|
+
* In the rows, labels, reset times, and notes are muted; bars, percents, and values base.
|
|
199
|
+
*/
|
|
200
|
+
function QuotaTableView(props) {
|
|
201
|
+
return (() => {
|
|
202
|
+
var _el$3 = _$createElement("box"),
|
|
203
|
+
_el$4 = _$createElement("text");
|
|
204
|
+
_$insertNode(_el$3, _el$4);
|
|
205
|
+
_$setProp(_el$3, "flexDirection", "column");
|
|
206
|
+
_$insert(_el$4, () => props.table.title);
|
|
207
|
+
_$insert(_el$3, () => props.table.lines.map(line => line.style === "row" ? (() => {
|
|
208
|
+
var _el$5 = _$createElement("text");
|
|
209
|
+
_$setProp(_el$5, "wrapMode", "none");
|
|
210
|
+
_$insert(_el$5, () => line.segments.map(segment => (() => {
|
|
211
|
+
var _el$6 = _$createElement("span");
|
|
212
|
+
_$insert(_el$6, () => segment.text);
|
|
213
|
+
_$effect(_$p => _$setProp(_el$6, "style", {
|
|
214
|
+
fg: segment.muted ? props.theme.text.muted : props.theme.text.base
|
|
215
|
+
}, _$p));
|
|
216
|
+
return _el$6;
|
|
217
|
+
})()));
|
|
218
|
+
_$effect(_$p => _$setProp(_el$5, "fg", props.theme.text.base, _$p));
|
|
219
|
+
return _el$5;
|
|
220
|
+
})() : (() => {
|
|
221
|
+
var _el$7 = _$createElement("text");
|
|
222
|
+
_$insert(_el$7, () => line.segments.map(segment => segment.text).join(""));
|
|
223
|
+
_$effect(_p$ => {
|
|
224
|
+
var _v$3 = TextAttributes.BOLD,
|
|
225
|
+
_v$4 = line.style === "header" ? props.theme.text.action.primary.selected : props.theme.text.base,
|
|
226
|
+
_v$5 = line.style === "header" ? "none" : undefined;
|
|
227
|
+
_v$3 !== _p$.e && (_p$.e = _$setProp(_el$7, "attributes", _v$3, _p$.e));
|
|
228
|
+
_v$4 !== _p$.t && (_p$.t = _$setProp(_el$7, "fg", _v$4, _p$.t));
|
|
229
|
+
_v$5 !== _p$.a && (_p$.a = _$setProp(_el$7, "wrapMode", _v$5, _p$.a));
|
|
230
|
+
return _p$;
|
|
231
|
+
}, {
|
|
232
|
+
e: undefined,
|
|
233
|
+
t: undefined,
|
|
234
|
+
a: undefined
|
|
235
|
+
});
|
|
236
|
+
return _el$7;
|
|
237
|
+
})()), null);
|
|
238
|
+
_$effect(_p$ => {
|
|
239
|
+
var _v$ = TextAttributes.BOLD,
|
|
240
|
+
_v$2 = props.theme.text.base;
|
|
241
|
+
_v$ !== _p$.e && (_p$.e = _$setProp(_el$4, "attributes", _v$, _p$.e));
|
|
242
|
+
_v$2 !== _p$.t && (_p$.t = _$setProp(_el$4, "fg", _v$2, _p$.t));
|
|
243
|
+
return _p$;
|
|
244
|
+
}, {
|
|
245
|
+
e: undefined,
|
|
246
|
+
t: undefined
|
|
247
|
+
});
|
|
248
|
+
return _el$3;
|
|
249
|
+
})();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* One block of a report. Lines, and the chat lines of /quota rows the dialog's tables do not
|
|
254
|
+
* fit, and key-value rows wrap at words. A table keeps each row on one line and spans `width`
|
|
255
|
+
* columns when it fits (see fitTableToWidth), with the header row bold in OpenCode's primary
|
|
256
|
+
* accent (its text color for a selected tab). Like OpenCode's sidebar, labels are muted and
|
|
257
|
+
* values are base.
|
|
258
|
+
*/
|
|
259
|
+
function ReportBlockView(props) {
|
|
260
|
+
const block = props.block;
|
|
261
|
+
if (block.kind === "lines" || block.kind === "quota") {
|
|
262
|
+
return (() => {
|
|
263
|
+
var _el$8 = _$createElement("text");
|
|
264
|
+
_$insert(_el$8, () => sanitizeDisplayText(block.lines.join("\n")));
|
|
265
|
+
_$effect(_$p => _$setProp(_el$8, "fg", props.theme.text.muted, _$p));
|
|
266
|
+
return _el$8;
|
|
267
|
+
})();
|
|
268
|
+
}
|
|
269
|
+
if (block.kind === "kv") {
|
|
270
|
+
return (() => {
|
|
271
|
+
var _el$9 = _$createElement("box");
|
|
272
|
+
_$setProp(_el$9, "flexDirection", "column");
|
|
273
|
+
_$insert(_el$9, () => block.rows.map(({
|
|
274
|
+
value,
|
|
275
|
+
...key
|
|
276
|
+
}) => value === undefined ? (() => {
|
|
277
|
+
var _el$0 = _$createElement("text");
|
|
278
|
+
_$insert(_el$0, () => sanitizeDisplayText(renderKvRow(key)));
|
|
279
|
+
_$effect(_$p => _$setProp(_el$0, "fg", props.theme.text.muted, _$p));
|
|
280
|
+
return _el$0;
|
|
281
|
+
})() : (() => {
|
|
282
|
+
var _el$1 = _$createElement("text"),
|
|
283
|
+
_el$10 = _$createElement("span"),
|
|
284
|
+
_el$11 = _$createTextNode(` `);
|
|
285
|
+
_$insertNode(_el$1, _el$10);
|
|
286
|
+
_$insert(_el$1, () => sanitizeDisplayText(renderKvRow({
|
|
287
|
+
...key,
|
|
288
|
+
trailingColon: true
|
|
289
|
+
})), _el$10);
|
|
290
|
+
_$insertNode(_el$10, _el$11);
|
|
291
|
+
_$insert(_el$10, () => sanitizeDisplayText(value), null);
|
|
292
|
+
_$effect(_p$ => {
|
|
293
|
+
var _v$6 = props.theme.text.muted,
|
|
294
|
+
_v$7 = {
|
|
295
|
+
fg: props.theme.text.base
|
|
296
|
+
};
|
|
297
|
+
_v$6 !== _p$.e && (_p$.e = _$setProp(_el$1, "fg", _v$6, _p$.e));
|
|
298
|
+
_v$7 !== _p$.t && (_p$.t = _$setProp(_el$10, "style", _v$7, _p$.t));
|
|
299
|
+
return _p$;
|
|
300
|
+
}, {
|
|
301
|
+
e: undefined,
|
|
302
|
+
t: undefined
|
|
303
|
+
});
|
|
304
|
+
return _el$1;
|
|
305
|
+
})()));
|
|
306
|
+
return _el$9;
|
|
307
|
+
})();
|
|
308
|
+
}
|
|
309
|
+
// Read in the JSX, so the table is laid out again when the terminal is resized.
|
|
310
|
+
const table = () => fitTableToWidth({
|
|
311
|
+
headers: block.headers.map(sanitizeDisplayText),
|
|
312
|
+
fullHeaders: block.fullHeaders?.map(sanitizeDisplayText),
|
|
313
|
+
rows: block.rows.map(row => row.map(sanitizeDisplayText)),
|
|
314
|
+
aligns: block.aligns,
|
|
315
|
+
width: props.width
|
|
316
|
+
});
|
|
317
|
+
return (() => {
|
|
318
|
+
var _el$12 = _$createElement("box"),
|
|
319
|
+
_el$13 = _$createElement("text");
|
|
320
|
+
_$insertNode(_el$12, _el$13);
|
|
321
|
+
_$setProp(_el$12, "flexDirection", "column");
|
|
322
|
+
_$setProp(_el$13, "wrapMode", "none");
|
|
323
|
+
_$insert(_el$13, () => table().header);
|
|
324
|
+
_$insert(_el$12, () => table().rows.map(row => (() => {
|
|
325
|
+
var _el$14 = _$createElement("text");
|
|
326
|
+
_$setProp(_el$14, "wrapMode", "none");
|
|
327
|
+
_$insert(_el$14, row);
|
|
328
|
+
_$effect(_$p => _$setProp(_el$14, "fg", props.theme.text.base, _$p));
|
|
329
|
+
return _el$14;
|
|
330
|
+
})()), null);
|
|
331
|
+
_$effect(_p$ => {
|
|
332
|
+
var _v$8 = TextAttributes.BOLD,
|
|
333
|
+
_v$9 = props.theme.text.action.primary.selected;
|
|
334
|
+
_v$8 !== _p$.e && (_p$.e = _$setProp(_el$13, "attributes", _v$8, _p$.e));
|
|
335
|
+
_v$9 !== _p$.t && (_p$.t = _$setProp(_el$13, "fg", _v$9, _p$.t));
|
|
336
|
+
return _p$;
|
|
337
|
+
}, {
|
|
338
|
+
e: undefined,
|
|
339
|
+
t: undefined
|
|
340
|
+
});
|
|
341
|
+
return _el$12;
|
|
342
|
+
})();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Draws a report document's sections with the same spacing as its plain text: one blank row
|
|
347
|
+
* between the sections and between the blocks of a section, and a section title directly
|
|
348
|
+
* above its first block. Section titles are bold. A /quota report's provider sections come
|
|
349
|
+
* first; when their rows fit the dialog's tables (see layoutQuotaTables), the tables take
|
|
350
|
+
* their place. The dialog shows the heading's subtitle under its own title, so the heading
|
|
351
|
+
* line is left out.
|
|
352
|
+
*/
|
|
353
|
+
function ReportDocumentView(props) {
|
|
354
|
+
const sections = renderableSections(props.document);
|
|
355
|
+
const blocks = sections.flatMap(quotaBlocks);
|
|
356
|
+
// Read in the JSX, so the tables are laid out again when the terminal is resized.
|
|
357
|
+
const tables = () => blocks.length > 0 ? layoutQuotaTables(blocks, props.width) : undefined;
|
|
358
|
+
return (() => {
|
|
359
|
+
var _el$15 = _$createElement("box");
|
|
360
|
+
_$setProp(_el$15, "flexDirection", "column");
|
|
361
|
+
_$setProp(_el$15, "gap", 1);
|
|
362
|
+
_$insert(_el$15, () => [...(tables() ?? []).map(table => _$createComponent(QuotaTableView, {
|
|
363
|
+
table: table,
|
|
364
|
+
get theme() {
|
|
365
|
+
return props.theme;
|
|
366
|
+
}
|
|
367
|
+
})), ...sections.filter(section => !tables() || !section.blocks.some(block => block.kind === "quota")).map(section => (() => {
|
|
368
|
+
var _el$16 = _$createElement("box"),
|
|
369
|
+
_el$17 = _$createElement("box");
|
|
370
|
+
_$insertNode(_el$16, _el$17);
|
|
371
|
+
_$setProp(_el$16, "flexDirection", "column");
|
|
372
|
+
_$insert(_el$16, (() => {
|
|
373
|
+
var _c$ = _$memo(() => !!section.title);
|
|
374
|
+
return () => _c$() ? (() => {
|
|
375
|
+
var _el$18 = _$createElement("text");
|
|
376
|
+
_$insert(_el$18, () => sanitizeDisplayText(section.title));
|
|
377
|
+
_$effect(_p$ => {
|
|
378
|
+
var _v$0 = TextAttributes.BOLD,
|
|
379
|
+
_v$1 = props.theme.text.base;
|
|
380
|
+
_v$0 !== _p$.e && (_p$.e = _$setProp(_el$18, "attributes", _v$0, _p$.e));
|
|
381
|
+
_v$1 !== _p$.t && (_p$.t = _$setProp(_el$18, "fg", _v$1, _p$.t));
|
|
382
|
+
return _p$;
|
|
383
|
+
}, {
|
|
384
|
+
e: undefined,
|
|
385
|
+
t: undefined
|
|
386
|
+
});
|
|
387
|
+
return _el$18;
|
|
388
|
+
})() : null;
|
|
389
|
+
})(), _el$17);
|
|
390
|
+
_$setProp(_el$17, "flexDirection", "column");
|
|
391
|
+
_$setProp(_el$17, "gap", 1);
|
|
392
|
+
_$insert(_el$17, () => section.blocks.map(block => _$createComponent(ReportBlockView, {
|
|
393
|
+
block: block,
|
|
394
|
+
get theme() {
|
|
395
|
+
return props.theme;
|
|
396
|
+
},
|
|
397
|
+
get width() {
|
|
398
|
+
return props.width;
|
|
399
|
+
}
|
|
400
|
+
})));
|
|
401
|
+
return _el$16;
|
|
402
|
+
})())]);
|
|
403
|
+
return _el$15;
|
|
404
|
+
})();
|
|
405
|
+
}
|
|
406
|
+
|
|
167
407
|
/**
|
|
168
408
|
* Shows command output like OpenCode's alert dialog, but inside a scrollbox so long
|
|
169
409
|
* reports (/quota_status, /tokens_*) stay reachable. The mouse wheel scrolls the box;
|
|
@@ -173,9 +413,15 @@ function reportFailure(error) {
|
|
|
173
413
|
function QuotaOutputDialog(props) {
|
|
174
414
|
const theme = () => props.context.theme.surface("dialog");
|
|
175
415
|
const dimensions = useTerminalDimensions();
|
|
416
|
+
// OpenCode's dialog is its size's width, at most the terminal width minus 2. Inside it
|
|
417
|
+
// come this box's paddings (2 + 2) and one column for the scrollbox's scrollbar, which
|
|
418
|
+
// shows when the report is taller than the box.
|
|
419
|
+
const tableWidth = () => Math.min(DIALOG_WIDTHS[props.size], dimensions().width - 2) - 4 - 1;
|
|
420
|
+
const subtitle = props.document.heading?.subtitle;
|
|
176
421
|
// The host dialog starts a quarter of the way down the terminal. The remaining
|
|
177
|
-
// 8 rows cover the title, ok button, paddings, gaps, and one spare row
|
|
178
|
-
|
|
422
|
+
// 8 rows cover the title, ok button, paddings, gaps, and one spare row; the subtitle
|
|
423
|
+
// takes one more.
|
|
424
|
+
const maxHeight = () => Math.max(1, Math.floor(dimensions().height * 0.75) - 8 - (subtitle ? 1 : 0));
|
|
179
425
|
let scroll;
|
|
180
426
|
const close = () => props.context.ui.dialog.clear();
|
|
181
427
|
props.context.keymap.layer(() => ({
|
|
@@ -218,60 +464,74 @@ function QuotaOutputDialog(props) {
|
|
|
218
464
|
}]
|
|
219
465
|
}));
|
|
220
466
|
return (() => {
|
|
221
|
-
var _el$
|
|
222
|
-
_el$
|
|
223
|
-
_el$
|
|
224
|
-
_el$
|
|
225
|
-
_el$
|
|
226
|
-
_el$
|
|
227
|
-
_el$
|
|
228
|
-
_el$
|
|
229
|
-
_el$
|
|
230
|
-
_el$
|
|
231
|
-
_$insertNode(_el$
|
|
232
|
-
_$insertNode(_el$
|
|
233
|
-
_$insertNode(_el$
|
|
234
|
-
_$setProp(_el$
|
|
235
|
-
_$setProp(_el$
|
|
236
|
-
_$setProp(_el$
|
|
237
|
-
_$insertNode(_el$
|
|
238
|
-
_$insertNode(_el$
|
|
239
|
-
_$
|
|
240
|
-
_$setProp(_el$
|
|
241
|
-
_$
|
|
242
|
-
_$
|
|
243
|
-
_$
|
|
244
|
-
_$
|
|
245
|
-
_$
|
|
246
|
-
|
|
467
|
+
var _el$19 = _$createElement("box"),
|
|
468
|
+
_el$20 = _$createElement("box"),
|
|
469
|
+
_el$21 = _$createElement("box"),
|
|
470
|
+
_el$22 = _$createElement("text"),
|
|
471
|
+
_el$23 = _$createElement("text"),
|
|
472
|
+
_el$25 = _$createElement("box"),
|
|
473
|
+
_el$26 = _$createElement("scrollbox"),
|
|
474
|
+
_el$27 = _$createElement("box"),
|
|
475
|
+
_el$28 = _$createElement("box"),
|
|
476
|
+
_el$29 = _$createElement("text");
|
|
477
|
+
_$insertNode(_el$19, _el$20);
|
|
478
|
+
_$insertNode(_el$19, _el$25);
|
|
479
|
+
_$insertNode(_el$19, _el$27);
|
|
480
|
+
_$setProp(_el$19, "paddingLeft", 2);
|
|
481
|
+
_$setProp(_el$19, "paddingRight", 2);
|
|
482
|
+
_$setProp(_el$19, "gap", 1);
|
|
483
|
+
_$insertNode(_el$20, _el$21);
|
|
484
|
+
_$insertNode(_el$21, _el$22);
|
|
485
|
+
_$insertNode(_el$21, _el$23);
|
|
486
|
+
_$setProp(_el$21, "flexDirection", "row");
|
|
487
|
+
_$setProp(_el$21, "justifyContent", "space-between");
|
|
488
|
+
_$insert(_el$22, () => props.title);
|
|
489
|
+
_$insertNode(_el$23, _$createTextNode(`esc`));
|
|
490
|
+
_$setProp(_el$23, "onMouseUp", close);
|
|
491
|
+
_$insert(_el$20, subtitle ? (() => {
|
|
492
|
+
var _el$31 = _$createElement("text");
|
|
493
|
+
_$insert(_el$31, () => sanitizeDisplayText(subtitle));
|
|
494
|
+
_$effect(_$p => _$setProp(_el$31, "fg", theme().text.muted, _$p));
|
|
495
|
+
return _el$31;
|
|
496
|
+
})() : null, null);
|
|
497
|
+
_$insertNode(_el$25, _el$26);
|
|
498
|
+
_$setProp(_el$25, "paddingBottom", 1);
|
|
247
499
|
_$use(element => {
|
|
248
500
|
scroll = element;
|
|
249
|
-
}, _el$
|
|
250
|
-
_$insert(_el$
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
501
|
+
}, _el$26);
|
|
502
|
+
_$insert(_el$26, _$createComponent(ReportDocumentView, {
|
|
503
|
+
get document() {
|
|
504
|
+
return props.document;
|
|
505
|
+
},
|
|
506
|
+
get theme() {
|
|
507
|
+
return theme();
|
|
508
|
+
},
|
|
509
|
+
get width() {
|
|
510
|
+
return tableWidth();
|
|
511
|
+
}
|
|
512
|
+
}));
|
|
513
|
+
_$insertNode(_el$27, _el$28);
|
|
514
|
+
_$setProp(_el$27, "flexDirection", "row");
|
|
515
|
+
_$setProp(_el$27, "justifyContent", "flex-end");
|
|
516
|
+
_$setProp(_el$27, "paddingBottom", 1);
|
|
517
|
+
_$insertNode(_el$28, _el$29);
|
|
518
|
+
_$setProp(_el$28, "paddingLeft", 3);
|
|
519
|
+
_$setProp(_el$28, "paddingRight", 3);
|
|
520
|
+
_$setProp(_el$28, "onMouseUp", close);
|
|
521
|
+
_$insertNode(_el$29, _$createTextNode(`ok`));
|
|
260
522
|
_$effect(_p$ => {
|
|
261
|
-
var _v$ = TextAttributes.BOLD,
|
|
262
|
-
_v$
|
|
263
|
-
_v$
|
|
264
|
-
_v$
|
|
265
|
-
_v$
|
|
266
|
-
_v$
|
|
267
|
-
|
|
268
|
-
_v$ !== _p$.
|
|
269
|
-
_v$
|
|
270
|
-
_v$
|
|
271
|
-
_v$
|
|
272
|
-
_v$
|
|
273
|
-
_v$6 !== _p$.n && (_p$.n = _$setProp(_el$10, "backgroundColor", _v$6, _p$.n));
|
|
274
|
-
_v$7 !== _p$.s && (_p$.s = _$setProp(_el$11, "fg", _v$7, _p$.s));
|
|
523
|
+
var _v$10 = TextAttributes.BOLD,
|
|
524
|
+
_v$11 = theme().text.base,
|
|
525
|
+
_v$12 = theme().text.muted,
|
|
526
|
+
_v$13 = maxHeight(),
|
|
527
|
+
_v$14 = theme().background.action.primary.focused,
|
|
528
|
+
_v$15 = theme().text.action.primary.focused;
|
|
529
|
+
_v$10 !== _p$.e && (_p$.e = _$setProp(_el$22, "attributes", _v$10, _p$.e));
|
|
530
|
+
_v$11 !== _p$.t && (_p$.t = _$setProp(_el$22, "fg", _v$11, _p$.t));
|
|
531
|
+
_v$12 !== _p$.a && (_p$.a = _$setProp(_el$23, "fg", _v$12, _p$.a));
|
|
532
|
+
_v$13 !== _p$.o && (_p$.o = _$setProp(_el$26, "maxHeight", _v$13, _p$.o));
|
|
533
|
+
_v$14 !== _p$.i && (_p$.i = _$setProp(_el$28, "backgroundColor", _v$14, _p$.i));
|
|
534
|
+
_v$15 !== _p$.n && (_p$.n = _$setProp(_el$29, "fg", _v$15, _p$.n));
|
|
275
535
|
return _p$;
|
|
276
536
|
}, {
|
|
277
537
|
e: undefined,
|
|
@@ -279,10 +539,9 @@ function QuotaOutputDialog(props) {
|
|
|
279
539
|
a: undefined,
|
|
280
540
|
o: undefined,
|
|
281
541
|
i: undefined,
|
|
282
|
-
n: undefined
|
|
283
|
-
s: undefined
|
|
542
|
+
n: undefined
|
|
284
543
|
});
|
|
285
|
-
return _el$
|
|
544
|
+
return _el$19;
|
|
286
545
|
})();
|
|
287
546
|
}
|
|
288
547
|
function showQuotaOutputDialog(context, output) {
|
|
@@ -292,8 +551,11 @@ function showQuotaOutputDialog(context, output) {
|
|
|
292
551
|
get title() {
|
|
293
552
|
return output.title;
|
|
294
553
|
},
|
|
295
|
-
get
|
|
296
|
-
return output.
|
|
554
|
+
get document() {
|
|
555
|
+
return output.document;
|
|
556
|
+
},
|
|
557
|
+
get size() {
|
|
558
|
+
return output.dialogSize;
|
|
297
559
|
}
|
|
298
560
|
}), resolve);
|
|
299
561
|
context.ui.dialog.set({
|
|
@@ -327,7 +589,7 @@ async function runQuotaCommand(context, command, sessionID, typed) {
|
|
|
327
589
|
if (result.state === "noop") return;
|
|
328
590
|
await showQuotaOutputDialog(context, {
|
|
329
591
|
title: result.title,
|
|
330
|
-
|
|
592
|
+
document: result.document,
|
|
331
593
|
dialogSize: result.dialogSize
|
|
332
594
|
});
|
|
333
595
|
} catch (error) {
|
|
@@ -375,7 +637,7 @@ async function showPostedQuotaReport(context, event) {
|
|
|
375
637
|
});
|
|
376
638
|
void showQuotaOutputDialog(context, {
|
|
377
639
|
title: report.title,
|
|
378
|
-
|
|
640
|
+
document: report.document,
|
|
379
641
|
dialogSize: spec.dialogSize
|
|
380
642
|
});
|
|
381
643
|
}
|
|
@@ -453,46 +715,45 @@ function SidebarQuotaView(props) {
|
|
|
453
715
|
unsubscribe();
|
|
454
716
|
});
|
|
455
717
|
return (() => {
|
|
456
|
-
var _el$
|
|
457
|
-
_el$
|
|
458
|
-
_el$
|
|
459
|
-
_el$
|
|
460
|
-
_$insertNode(_el$
|
|
461
|
-
_$setProp(_el$
|
|
462
|
-
_$insertNode(_el$
|
|
463
|
-
_$setProp(_el$
|
|
464
|
-
_$setProp(_el$
|
|
465
|
-
_$setProp(_el$
|
|
466
|
-
_$insert(_el$
|
|
718
|
+
var _el$32 = _$createElement("box"),
|
|
719
|
+
_el$33 = _$createElement("box"),
|
|
720
|
+
_el$35 = _$createElement("text"),
|
|
721
|
+
_el$36 = _$createElement("b");
|
|
722
|
+
_$insertNode(_el$32, _el$33);
|
|
723
|
+
_$setProp(_el$32, "flexDirection", "column");
|
|
724
|
+
_$insertNode(_el$33, _el$35);
|
|
725
|
+
_$setProp(_el$33, "flexDirection", "row");
|
|
726
|
+
_$setProp(_el$33, "gap", 1);
|
|
727
|
+
_$setProp(_el$33, "onMouseDown", () => expandable() && setOpen(value => !value));
|
|
728
|
+
_$insert(_el$33, _$createComponent(Show, {
|
|
467
729
|
get when() {
|
|
468
730
|
return expandable();
|
|
469
731
|
},
|
|
470
732
|
get children() {
|
|
471
|
-
var _el$
|
|
472
|
-
_$
|
|
473
|
-
_$
|
|
474
|
-
return _el$
|
|
733
|
+
var _el$34 = _$createElement("text");
|
|
734
|
+
_$insert(_el$34, () => open() ? "▼" : "▶");
|
|
735
|
+
_$effect(_$p => _$setProp(_el$34, "fg", props.context.theme.text.base, _$p));
|
|
736
|
+
return _el$34;
|
|
475
737
|
}
|
|
476
|
-
}), _el$
|
|
477
|
-
_$insertNode(_el$
|
|
478
|
-
_$
|
|
479
|
-
_$
|
|
480
|
-
_$insert(_el$16, _$createComponent(Show, {
|
|
738
|
+
}), _el$35);
|
|
739
|
+
_$insertNode(_el$35, _el$36);
|
|
740
|
+
_$insertNode(_el$36, _$createTextNode(`Quota`));
|
|
741
|
+
_$insert(_el$35, _$createComponent(Show, {
|
|
481
742
|
get when() {
|
|
482
743
|
return _$memo(() => !!(expandable() && !open()))() && quota()?.activeProviderCount;
|
|
483
744
|
},
|
|
484
745
|
children: count => ` (${count()} active)`
|
|
485
746
|
}), null);
|
|
486
|
-
_$insert(_el$
|
|
747
|
+
_$insert(_el$32, _$createComponent(Show, {
|
|
487
748
|
get when() {
|
|
488
749
|
return quota();
|
|
489
750
|
},
|
|
490
751
|
get fallback() {
|
|
491
752
|
return (() => {
|
|
492
|
-
var _el$
|
|
493
|
-
_$insertNode(_el$
|
|
494
|
-
_$setProp(_el$
|
|
495
|
-
return _el$
|
|
753
|
+
var _el$38 = _$createElement("text");
|
|
754
|
+
_$insertNode(_el$38, _$createTextNode(`No quota data available`));
|
|
755
|
+
_$effect(_$p => _$setProp(_el$38, "fg", props.context.theme.text.muted, _$p));
|
|
756
|
+
return _el$38;
|
|
496
757
|
})();
|
|
497
758
|
},
|
|
498
759
|
get children() {
|
|
@@ -501,18 +762,29 @@ function SidebarQuotaView(props) {
|
|
|
501
762
|
return !expandable() || open();
|
|
502
763
|
},
|
|
503
764
|
get children() {
|
|
504
|
-
return lines().map(line =>
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
765
|
+
return lines().map(line =>
|
|
766
|
+
// Provider headers such as "[Copilot] (individual)" are bold, like section titles.
|
|
767
|
+
line.startsWith("[") ? (() => {
|
|
768
|
+
var _el$40 = _$createElement("text"),
|
|
769
|
+
_el$41 = _$createElement("b");
|
|
770
|
+
_$insertNode(_el$40, _el$41);
|
|
771
|
+
_$setProp(_el$40, "wrapMode", "none");
|
|
772
|
+
_$insert(_el$41, line);
|
|
773
|
+
_$effect(_$p => _$setProp(_el$40, "fg", props.context.theme.text.base, _$p));
|
|
774
|
+
return _el$40;
|
|
775
|
+
})() : (() => {
|
|
776
|
+
var _el$42 = _$createElement("text");
|
|
777
|
+
_$setProp(_el$42, "wrapMode", "none");
|
|
778
|
+
_$insert(_el$42, line || " ");
|
|
779
|
+
_$effect(_$p => _$setProp(_el$42, "fg", props.context.theme.text.muted, _$p));
|
|
780
|
+
return _el$42;
|
|
510
781
|
})());
|
|
511
782
|
}
|
|
512
783
|
});
|
|
513
784
|
}
|
|
514
785
|
}), null);
|
|
515
|
-
|
|
786
|
+
_$effect(_$p => _$setProp(_el$35, "fg", props.context.theme.text.base, _$p));
|
|
787
|
+
return _el$32;
|
|
516
788
|
})();
|
|
517
789
|
}
|
|
518
790
|
const plugin = Plugin.define({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slkiser/opencode-quota",
|
|
3
|
-
"version": "5.0.0
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "OpenCode quota & tokens usage with zero context window pollution. Supports GitHub Copilot, OpenAI (Plus/Pro), Chutes AI, Synthetic, Google AGY, Z.ai coding plan and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|