@slkiser/opencode-quota 4.5.1 → 4.6.1

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 (46) hide show
  1. package/README.md +2 -0
  2. package/dist/data/modelsdev-pricing.min.json +5 -0
  3. package/dist/lib/config.d.ts +1 -1
  4. package/dist/lib/config.d.ts.map +1 -1
  5. package/dist/lib/config.js +75 -0
  6. package/dist/lib/config.js.map +1 -1
  7. package/dist/lib/maintainer-announcements.d.ts +3 -0
  8. package/dist/lib/maintainer-announcements.d.ts.map +1 -1
  9. package/dist/lib/maintainer-announcements.js +13 -0
  10. package/dist/lib/maintainer-announcements.js.map +1 -1
  11. package/dist/lib/quota-export.d.ts +1 -0
  12. package/dist/lib/quota-export.d.ts.map +1 -1
  13. package/dist/lib/quota-export.js +4 -0
  14. package/dist/lib/quota-export.js.map +1 -1
  15. package/dist/lib/quota-render-data.d.ts +2 -0
  16. package/dist/lib/quota-render-data.d.ts.map +1 -1
  17. package/dist/lib/quota-render-data.js +7 -0
  18. package/dist/lib/quota-render-data.js.map +1 -1
  19. package/dist/lib/quota-reset-notifications.d.ts +20 -0
  20. package/dist/lib/quota-reset-notifications.d.ts.map +1 -0
  21. package/dist/lib/quota-reset-notifications.js +328 -0
  22. package/dist/lib/quota-reset-notifications.js.map +1 -0
  23. package/dist/lib/quota-stats.d.ts.map +1 -1
  24. package/dist/lib/quota-stats.js +4 -0
  25. package/dist/lib/quota-stats.js.map +1 -1
  26. package/dist/lib/tui-panel-state.d.ts +15 -0
  27. package/dist/lib/tui-panel-state.d.ts.map +1 -1
  28. package/dist/lib/tui-panel-state.js.map +1 -1
  29. package/dist/lib/tui-refresh-lifecycle.d.ts.map +1 -1
  30. package/dist/lib/tui-refresh-lifecycle.js +0 -1
  31. package/dist/lib/tui-refresh-lifecycle.js.map +1 -1
  32. package/dist/lib/tui-runtime.d.ts +14 -2
  33. package/dist/lib/tui-runtime.d.ts.map +1 -1
  34. package/dist/lib/tui-runtime.js +87 -6
  35. package/dist/lib/tui-runtime.js.map +1 -1
  36. package/dist/lib/types.d.ts +14 -0
  37. package/dist/lib/types.d.ts.map +1 -1
  38. package/dist/lib/types.js +7 -0
  39. package/dist/lib/types.js.map +1 -1
  40. package/dist/plugin.d.ts.map +1 -1
  41. package/dist/plugin.js +38 -1
  42. package/dist/plugin.js.map +1 -1
  43. package/dist/tui.d.ts.map +1 -1
  44. package/dist/tui.js +472 -181
  45. package/dist/tui.tsx +395 -73
  46. package/package.json +1 -1
package/dist/tui.js CHANGED
@@ -9,7 +9,9 @@ import { createElement as _$createElement } from "@opentui/solid";
9
9
  /** @jsxImportSource @opentui/solid */
10
10
 
11
11
  import { createEffect, createSignal, onCleanup, Show } from "solid-js";
12
+ import { formatDisplayedPercentLabel, formatResetCountdown } from "./lib/format-utils.js";
12
13
  import { buildQuotaDialogCommandOutput, QUOTA_DIALOG_COMMANDS } from "./lib/quota-dialog-commands.js";
14
+ import { extractSingleWindowWindowLabel } from "./lib/quota-entry-display.js";
13
15
  import { disposeQuotaTelemetryOwner } from "./lib/quota-telemetry.js";
14
16
  import { getSidebarBodyLineColor } from "./lib/tui-line-style.js";
15
17
  import { getCompactStatusText, getHomeBottomAnnouncementText, getSidebarPanelLines, getSidebarPanelLinesExpanded, shouldRenderCompactStatus, shouldRenderHomeBottom, shouldRenderSidebarPanel } from "./lib/tui-panel-state.js";
@@ -23,6 +25,64 @@ const COMPACT_ORDER = 90;
23
25
  const REFRESH_INTERVAL_MS = 60_000;
24
26
  const EVENT_REFRESH_DELAYS_MS = [150, 600];
25
27
  const MOUNT_RECOVERY_DELAYS_MS = [500, 1_500, 4_000];
28
+ const FALLBACK_SURFACE_REGISTRATION = {
29
+ commandDisplay: "inline",
30
+ sidebar: {
31
+ enabled: true
32
+ },
33
+ compact: {
34
+ enabled: false,
35
+ homeBottom: false,
36
+ sessionPrompt: false,
37
+ hasNativeProviderQuota: false,
38
+ suppressedByNativeProviderQuota: false
39
+ },
40
+ promptBar: {
41
+ enabled: false
42
+ },
43
+ announcements: {
44
+ homeBottom: false
45
+ },
46
+ homeBottom: false
47
+ };
48
+ function createTuiInitialLoadCoordinator(seed) {
49
+ let sessionAvailable = true;
50
+ let homeAvailable = true;
51
+ return {
52
+ takeInitialSession() {
53
+ if (!sessionAvailable) return undefined;
54
+ sessionAvailable = false;
55
+ return seed;
56
+ },
57
+ takeInitialHome() {
58
+ if (!homeAvailable) return undefined;
59
+ homeAvailable = false;
60
+ return seed;
61
+ }
62
+ };
63
+ }
64
+ function createTuiRegistrationGate() {
65
+ const [current, setCurrent] = createSignal({
66
+ status: "pending"
67
+ });
68
+ return {
69
+ current,
70
+ activate(registration, initialLoads) {
71
+ if (current().status !== "pending") return;
72
+ setCurrent({
73
+ status: "active",
74
+ registration,
75
+ initialLoads
76
+ });
77
+ },
78
+ dispose() {
79
+ if (current().status === "disposed") return;
80
+ setCurrent({
81
+ status: "disposed"
82
+ });
83
+ }
84
+ };
85
+ }
26
86
  const sessionResources = new WeakMap();
27
87
  const homeResources = new WeakMap();
28
88
  function getSessionResourceMap(api) {
@@ -32,7 +92,7 @@ function getSessionResourceMap(api) {
32
92
  sessionResources.set(api, next);
33
93
  return next;
34
94
  }
35
- function createSessionQuotaResource(api, sessionID) {
95
+ function createSessionQuotaResource(api, sessionID, initialLoads) {
36
96
  const [sidebar, setSidebar] = createSignal({
37
97
  status: "loading",
38
98
  lines: []
@@ -40,14 +100,28 @@ function createSessionQuotaResource(api, sessionID) {
40
100
  const [compact, setCompact] = createSignal({
41
101
  status: "loading"
42
102
  });
103
+ const [promptBar, setPromptBar] = createSignal({
104
+ status: "loading"
105
+ });
106
+ let loadOrdinal = 0;
43
107
  const lifecycle = createTuiRefreshLifecycle({
44
- load: () => loadTuiSessionQuotaSurfaces({
45
- api,
46
- sessionID
47
- }),
108
+ load: () => {
109
+ const initialRuntimeSeed = loadOrdinal === 0 ? initialLoads?.takeInitialSession() : undefined;
110
+ loadOrdinal += 1;
111
+ return loadTuiSessionQuotaSurfaces({
112
+ api,
113
+ sessionID,
114
+ ...(initialRuntimeSeed ? {
115
+ initialRuntimeSeed
116
+ } : {})
117
+ });
118
+ },
48
119
  apply: next => {
49
120
  setSidebar(next.sidebar);
50
121
  setCompact(next.compact);
122
+ setPromptBar(next.promptBar ?? {
123
+ status: "loading"
124
+ });
51
125
  },
52
126
  intervalMs: REFRESH_INTERVAL_MS,
53
127
  eventRefreshDelaysMs: EVENT_REFRESH_DELAYS_MS,
@@ -79,6 +153,7 @@ function createSessionQuotaResource(api, sessionID) {
79
153
  sessionID,
80
154
  sidebar,
81
155
  compact,
156
+ promptBar,
82
157
  retain: () => {
83
158
  lifecycle.retain();
84
159
  return resource;
@@ -87,15 +162,15 @@ function createSessionQuotaResource(api, sessionID) {
87
162
  };
88
163
  return resource;
89
164
  }
90
- function acquireSessionQuotaResource(api, sessionID) {
165
+ function acquireSessionQuotaResource(api, sessionID, initialLoads) {
91
166
  const resources = getSessionResourceMap(api);
92
167
  const existing = resources.get(sessionID);
93
168
  if (existing) return existing.retain();
94
- const next = createSessionQuotaResource(api, sessionID).retain();
169
+ const next = createSessionQuotaResource(api, sessionID, initialLoads).retain();
95
170
  resources.set(sessionID, next);
96
171
  return next;
97
172
  }
98
- function createHomeBottomResource(api, compactHomeBottomEnabled) {
173
+ function createHomeBottomResource(api, compactHomeBottomEnabled, initialLoads) {
99
174
  const [bottom, setBottom] = createSignal({
100
175
  status: "loading",
101
176
  compact: compactHomeBottomEnabled ? {
@@ -104,10 +179,18 @@ function createHomeBottomResource(api, compactHomeBottomEnabled) {
104
179
  status: "disabled"
105
180
  }
106
181
  });
182
+ let loadOrdinal = 0;
107
183
  const lifecycle = createTuiRefreshLifecycle({
108
- load: () => loadTuiHomeBottomStatus({
109
- api
110
- }),
184
+ load: () => {
185
+ const initialRuntimeSeed = loadOrdinal === 0 ? initialLoads?.takeInitialHome() : undefined;
186
+ loadOrdinal += 1;
187
+ return loadTuiHomeBottomStatus({
188
+ api,
189
+ ...(initialRuntimeSeed ? {
190
+ initialRuntimeSeed
191
+ } : {})
192
+ });
193
+ },
111
194
  apply: setBottom,
112
195
  afterApply: () => {
113
196
  // Fire-and-forget: write export file if enabled. A failed write must
@@ -135,21 +218,21 @@ function createHomeBottomResource(api, compactHomeBottomEnabled) {
135
218
  };
136
219
  return resource;
137
220
  }
138
- function acquireHomeBottomResource(api, compactHomeBottomEnabled) {
221
+ function acquireHomeBottomResource(api, compactHomeBottomEnabled, initialLoads) {
139
222
  const existing = homeResources.get(api);
140
223
  if (existing) return existing.retain();
141
- const next = createHomeBottomResource(api, compactHomeBottomEnabled).retain();
224
+ const next = createHomeBottomResource(api, compactHomeBottomEnabled, initialLoads).retain();
142
225
  homeResources.set(api, next);
143
226
  return next;
144
227
  }
145
- function useSessionQuotaResource(api, sessionID) {
146
- let current = acquireSessionQuotaResource(api, sessionID());
228
+ function useSessionQuotaResource(api, sessionID, initialLoads) {
229
+ let current = acquireSessionQuotaResource(api, sessionID(), initialLoads);
147
230
  const [resource, setResource] = createSignal(current);
148
231
  createEffect(() => {
149
232
  const nextSessionID = sessionID();
150
233
  if (current.sessionID === nextSessionID) return;
151
234
  const previous = current;
152
- current = acquireSessionQuotaResource(api, nextSessionID);
235
+ current = acquireSessionQuotaResource(api, nextSessionID, initialLoads);
153
236
  setResource(current);
154
237
  previous.release();
155
238
  });
@@ -159,7 +242,7 @@ function useSessionQuotaResource(api, sessionID) {
159
242
  return resource;
160
243
  }
161
244
  function SidebarContentView(props) {
162
- const resource = useSessionQuotaResource(props.api, () => props.sessionID);
245
+ const resource = useSessionQuotaResource(props.api, () => props.sessionID, props.initialLoads);
163
246
  const panel = () => resource().sidebar();
164
247
  const lines = () => getSidebarPanelLines(panel());
165
248
  const hasDetailLines = () => Boolean(panel().linesExpanded?.length);
@@ -276,7 +359,7 @@ function CompactStatusLine(props) {
276
359
  });
277
360
  }
278
361
  function SessionPromptWithCompactStatus(props) {
279
- const resource = useSessionQuotaResource(props.api, () => props.sessionID);
362
+ const resource = useSessionQuotaResource(props.api, () => props.sessionID, props.initialLoads);
280
363
  const panel = () => resource().compact();
281
364
  return (() => {
282
365
  var _el$13 = _$createElement("box");
@@ -309,42 +392,203 @@ function SessionPromptWithCompactStatus(props) {
309
392
  return _el$13;
310
393
  })();
311
394
  }
395
+ const PROMPT_BAR_WIDTH = 12;
396
+ function shouldRenderPromptBar(bar) {
397
+ return bar.status === "ready" && Boolean(bar.entry);
398
+ }
399
+ function useSessionRunning(api, sessionID) {
400
+ const [running, setRunning] = createSignal(false);
401
+ createEffect(() => {
402
+ const id = sessionID();
403
+ if (!id) {
404
+ setRunning(false);
405
+ return;
406
+ }
407
+ const update = () => {
408
+ try {
409
+ const sessionState = api.state.session;
410
+ const status = sessionState.status?.(id);
411
+ setRunning(status?.type === "busy" || status?.type === "retry");
412
+ } catch {
413
+ setRunning(false);
414
+ }
415
+ };
416
+ update();
417
+ const disposers = [api.event.on("session.status", event => {
418
+ if (event.properties?.sessionID === id) {
419
+ update();
420
+ }
421
+ }), api.event.on("session.updated", event => {
422
+ if (event.properties?.info?.id === id) {
423
+ update();
424
+ }
425
+ })];
426
+ onCleanup(() => {
427
+ for (const dispose of disposers) {
428
+ if (typeof dispose === "function") {
429
+ dispose();
430
+ }
431
+ }
432
+ });
433
+ });
434
+ return running;
435
+ }
436
+ function buildPromptBarParts(params) {
437
+ const bar = params.bar();
438
+ if (!shouldRenderPromptBar(bar)) return undefined;
439
+ const entry = bar.entry;
440
+ if (!entry) return undefined;
441
+ const windowLabel = extractSingleWindowWindowLabel(entry.label ?? "") ?? extractSingleWindowWindowLabel(entry.name ?? "") ?? "Quota";
442
+ const percent = formatDisplayedPercentLabel(entry.percentRemaining ?? 0, bar.percentDisplayMode ?? "remaining");
443
+ const reset = entry.resetTimeIso ? formatResetCountdown(entry.resetTimeIso, {
444
+ compactRounded: true,
445
+ decimals: bar.resetTimeDecimals
446
+ }) : "";
447
+ const p = Math.max(0, Math.min(100, Math.round(entry.percentRemaining ?? 0)));
448
+ const filled = Math.round(p / 100 * PROMPT_BAR_WIDTH);
449
+ const empty = PROMPT_BAR_WIDTH - filled;
450
+ let barText = "█".repeat(filled) + "░".repeat(empty);
451
+ if (params.running() && filled > 0) {
452
+ const cells = Array(filled).fill("▓");
453
+ const center = params.phase() % filled;
454
+ const gradient = ["▒", "▓", "█", "▓", "▒"];
455
+ for (let offset = -2; offset <= 2; offset++) {
456
+ const position = (center + offset + filled) % filled;
457
+ cells[position] = gradient[offset + 2];
458
+ }
459
+ barText = cells.join("") + "░".repeat(empty);
460
+ }
461
+ return {
462
+ label: windowLabel,
463
+ barText,
464
+ meta: [percent.replace(/\s+left$/u, ""), reset].filter(Boolean).join(" | ")
465
+ };
466
+ }
467
+ function PromptQuotaHint(props) {
468
+ const parts = () => buildPromptBarParts(props);
469
+ const barColor = () => props.api.theme.current.textMuted;
470
+ const label = () => parts()?.label ?? "";
471
+ const bar = () => parts()?.barText ?? "";
472
+ const meta = () => parts()?.meta ?? "";
473
+ return _$createComponent(Show, {
474
+ get when() {
475
+ return parts();
476
+ },
477
+ get children() {
478
+ var _el$14 = _$createElement("box"),
479
+ _el$15 = _$createElement("text"),
480
+ _el$16 = _$createElement("text"),
481
+ _el$17 = _$createElement("text");
482
+ _$insertNode(_el$14, _el$15);
483
+ _$insertNode(_el$14, _el$16);
484
+ _$insertNode(_el$14, _el$17);
485
+ _$setProp(_el$14, "flexDirection", "row");
486
+ _$setProp(_el$14, "justifyContent", "flex-end");
487
+ _$setProp(_el$14, "gap", 1);
488
+ _$setProp(_el$15, "wrapMode", "none");
489
+ _$insert(_el$15, label);
490
+ _$setProp(_el$16, "wrapMode", "none");
491
+ _$insert(_el$16, bar);
492
+ _$setProp(_el$17, "wrapMode", "none");
493
+ _$insert(_el$17, meta);
494
+ _$effect(_p$ => {
495
+ var _v$3 = props.api.theme.current.textMuted,
496
+ _v$4 = barColor(),
497
+ _v$5 = props.api.theme.current.textMuted;
498
+ _v$3 !== _p$.e && (_p$.e = _$setProp(_el$15, "fg", _v$3, _p$.e));
499
+ _v$4 !== _p$.t && (_p$.t = _$setProp(_el$16, "fg", _v$4, _p$.t));
500
+ _v$5 !== _p$.a && (_p$.a = _$setProp(_el$17, "fg", _v$5, _p$.a));
501
+ return _p$;
502
+ }, {
503
+ e: undefined,
504
+ t: undefined,
505
+ a: undefined
506
+ });
507
+ return _el$14;
508
+ }
509
+ });
510
+ }
511
+ function SessionQuotaPromptBar(props) {
512
+ const resource = useSessionQuotaResource(props.api, () => props.sessionID, props.initialLoads);
513
+ const promptBar = () => resource().promptBar();
514
+ const running = useSessionRunning(props.api, () => props.sessionID);
515
+ const [phase, setPhase] = createSignal(0);
516
+ createEffect(() => {
517
+ if (!running() || !shouldRenderPromptBar(promptBar())) {
518
+ setPhase(0);
519
+ return;
520
+ }
521
+ const interval = setInterval(() => setPhase(p => p + 1), 160);
522
+ onCleanup(() => clearInterval(interval));
523
+ });
524
+ return (() => {
525
+ var _el$18 = _$createElement("box");
526
+ _$setProp(_el$18, "gap", 0);
527
+ _$insert(_el$18, _$createComponent(props.api.ui.Prompt, {
528
+ get sessionID() {
529
+ return props.sessionID;
530
+ },
531
+ get visible() {
532
+ return props.visible;
533
+ },
534
+ get disabled() {
535
+ return props.disabled;
536
+ },
537
+ get onSubmit() {
538
+ return props.onSubmit;
539
+ },
540
+ ref(r$) {
541
+ var _ref$2 = props.promptRef;
542
+ typeof _ref$2 === "function" ? _ref$2(r$) : props.promptRef = r$;
543
+ }
544
+ }), null);
545
+ _$insert(_el$18, _$createComponent(PromptQuotaHint, {
546
+ get api() {
547
+ return props.api;
548
+ },
549
+ bar: promptBar,
550
+ running: running,
551
+ phase: phase
552
+ }), null);
553
+ return _el$18;
554
+ })();
555
+ }
312
556
  function HomeBottomView(props) {
313
- const resource = acquireHomeBottomResource(props.api, props.compactHomeBottomEnabled);
557
+ const resource = acquireHomeBottomResource(props.api, props.compactHomeBottomEnabled, props.initialLoads);
314
558
  onCleanup(() => resource.release());
315
559
  const announcement = () => getHomeBottomAnnouncementText(resource.bottom());
316
560
  const compact = () => resource.bottom().compact;
317
561
  const visible = () => shouldRenderHomeBottom(resource.bottom());
318
562
  return (() => {
319
- var _el$14 = _$createElement("box");
320
- _$setProp(_el$14, "gap", 0);
321
- _$insert(_el$14, _$createComponent(Show, {
563
+ var _el$19 = _$createElement("box");
564
+ _$setProp(_el$19, "gap", 0);
565
+ _$insert(_el$19, _$createComponent(Show, {
322
566
  get when() {
323
567
  return visible();
324
568
  },
325
569
  get children() {
326
- var _el$15 = _$createElement("text");
327
- _$insertNode(_el$15, _$createTextNode(` `));
328
- return _el$15;
570
+ var _el$20 = _$createElement("text");
571
+ _$insertNode(_el$20, _$createTextNode(` `));
572
+ return _el$20;
329
573
  }
330
574
  }), null);
331
- _$insert(_el$14, _$createComponent(Show, {
575
+ _$insert(_el$19, _$createComponent(Show, {
332
576
  get when() {
333
577
  return _$memo(() => !!visible())() && announcement();
334
578
  },
335
579
  get children() {
336
- var _el$17 = _$createElement("box"),
337
- _el$18 = _$createElement("text");
338
- _$insertNode(_el$17, _el$18);
339
- _$setProp(_el$17, "flexDirection", "row");
340
- _$setProp(_el$17, "justifyContent", "center");
341
- _$setProp(_el$18, "wrapMode", "none");
342
- _$insert(_el$18, announcement);
343
- _$effect(_$p => _$setProp(_el$18, "fg", props.api.theme.current.textMuted, _$p));
344
- return _el$17;
580
+ var _el$22 = _$createElement("box"),
581
+ _el$23 = _$createElement("text");
582
+ _$insertNode(_el$22, _el$23);
583
+ _$setProp(_el$22, "flexDirection", "row");
584
+ _$setProp(_el$22, "justifyContent", "center");
585
+ _$setProp(_el$23, "wrapMode", "none");
586
+ _$insert(_el$23, announcement);
587
+ _$effect(_$p => _$setProp(_el$23, "fg", props.api.theme.current.textMuted, _$p));
588
+ return _el$22;
345
589
  }
346
590
  }), null);
347
- _$insert(_el$14, _$createComponent(Show, {
591
+ _$insert(_el$19, _$createComponent(Show, {
348
592
  get when() {
349
593
  return visible();
350
594
  },
@@ -358,7 +602,7 @@ function HomeBottomView(props) {
358
602
  });
359
603
  }
360
604
  }), null);
361
- return _el$14;
605
+ return _el$19;
362
606
  })();
363
607
  }
364
608
  function getActiveTuiSessionID(api) {
@@ -376,117 +620,117 @@ function getTuiCommandArguments(input) {
376
620
  }
377
621
  function CommandLoadingDialog(props) {
378
622
  return (() => {
379
- var _el$19 = _$createElement("box"),
380
- _el$20 = _$createElement("text"),
381
- _el$21 = _$createElement("b"),
382
- _el$22 = _$createElement("text");
383
- _$insertNode(_el$19, _el$20);
384
- _$insertNode(_el$19, _el$22);
385
- _$setProp(_el$19, "gap", 1);
386
- _$setProp(_el$19, "paddingLeft", 2);
387
- _$setProp(_el$19, "paddingRight", 2);
388
- _$setProp(_el$19, "paddingBottom", 1);
389
- _$insertNode(_el$20, _el$21);
390
- _$insert(_el$21, () => props.title);
391
- _$insertNode(_el$22, _$createTextNode(`Loading deterministic local output…`));
623
+ var _el$24 = _$createElement("box"),
624
+ _el$25 = _$createElement("text"),
625
+ _el$26 = _$createElement("b"),
626
+ _el$27 = _$createElement("text");
627
+ _$insertNode(_el$24, _el$25);
628
+ _$insertNode(_el$24, _el$27);
629
+ _$setProp(_el$24, "gap", 1);
630
+ _$setProp(_el$24, "paddingLeft", 2);
631
+ _$setProp(_el$24, "paddingRight", 2);
632
+ _$setProp(_el$24, "paddingBottom", 1);
633
+ _$insertNode(_el$25, _el$26);
634
+ _$insert(_el$26, () => props.title);
635
+ _$insertNode(_el$27, _$createTextNode(`Loading deterministic local output…`));
392
636
  _$effect(_p$ => {
393
- var _v$3 = props.api.theme.current.text,
394
- _v$4 = props.api.theme.current.textMuted;
395
- _v$3 !== _p$.e && (_p$.e = _$setProp(_el$20, "fg", _v$3, _p$.e));
396
- _v$4 !== _p$.t && (_p$.t = _$setProp(_el$22, "fg", _v$4, _p$.t));
637
+ var _v$6 = props.api.theme.current.text,
638
+ _v$7 = props.api.theme.current.textMuted;
639
+ _v$6 !== _p$.e && (_p$.e = _$setProp(_el$25, "fg", _v$6, _p$.e));
640
+ _v$7 !== _p$.t && (_p$.t = _$setProp(_el$27, "fg", _v$7, _p$.t));
397
641
  return _p$;
398
642
  }, {
399
643
  e: undefined,
400
644
  t: undefined
401
645
  });
402
- return _el$19;
646
+ return _el$24;
403
647
  })();
404
648
  }
405
649
  function CommandOutputDialog(props) {
406
650
  const lines = () => props.output.split("\n");
407
651
  const bodyHeight = () => Math.min(28, Math.max(6, lines().length));
408
652
  return (() => {
409
- var _el$24 = _$createElement("box"),
410
- _el$25 = _$createElement("text"),
411
- _el$26 = _$createElement("b"),
412
- _el$27 = _$createElement("scrollbox"),
413
- _el$28 = _$createElement("box"),
414
- _el$29 = _$createElement("text");
415
- _$insertNode(_el$24, _el$25);
416
- _$insertNode(_el$24, _el$27);
417
- _$insertNode(_el$24, _el$29);
418
- _$setProp(_el$24, "gap", 1);
419
- _$setProp(_el$24, "width", "100%");
420
- _$setProp(_el$24, "flexGrow", 1);
421
- _$setProp(_el$24, "paddingLeft", 2);
422
- _$setProp(_el$24, "paddingRight", 2);
423
- _$setProp(_el$24, "paddingBottom", 1);
424
- _$insertNode(_el$25, _el$26);
425
- _$insert(_el$26, () => props.title);
426
- _$insertNode(_el$27, _el$28);
427
- _$setProp(_el$27, "width", "100%");
428
- _$setProp(_el$27, "flexGrow", 1);
429
- _$setProp(_el$27, "maxHeight", 28);
430
- _$setProp(_el$28, "gap", 0);
431
- _$setProp(_el$28, "width", "100%");
432
- _$setProp(_el$28, "minWidth", 0);
433
- _$insert(_el$28, () => lines().map(line => (() => {
434
- var _el$31 = _$createElement("text");
435
- _$setProp(_el$31, "wrapMode", "word");
436
- _$setProp(_el$31, "width", "100%");
437
- _$insert(_el$31, line || " ");
438
- _$effect(_$p => _$setProp(_el$31, "fg", props.api.theme.current.text, _$p));
439
- return _el$31;
653
+ var _el$29 = _$createElement("box"),
654
+ _el$30 = _$createElement("text"),
655
+ _el$31 = _$createElement("b"),
656
+ _el$32 = _$createElement("scrollbox"),
657
+ _el$33 = _$createElement("box"),
658
+ _el$34 = _$createElement("text");
659
+ _$insertNode(_el$29, _el$30);
660
+ _$insertNode(_el$29, _el$32);
661
+ _$insertNode(_el$29, _el$34);
662
+ _$setProp(_el$29, "gap", 1);
663
+ _$setProp(_el$29, "width", "100%");
664
+ _$setProp(_el$29, "flexGrow", 1);
665
+ _$setProp(_el$29, "paddingLeft", 2);
666
+ _$setProp(_el$29, "paddingRight", 2);
667
+ _$setProp(_el$29, "paddingBottom", 1);
668
+ _$insertNode(_el$30, _el$31);
669
+ _$insert(_el$31, () => props.title);
670
+ _$insertNode(_el$32, _el$33);
671
+ _$setProp(_el$32, "width", "100%");
672
+ _$setProp(_el$32, "flexGrow", 1);
673
+ _$setProp(_el$32, "maxHeight", 28);
674
+ _$setProp(_el$33, "gap", 0);
675
+ _$setProp(_el$33, "width", "100%");
676
+ _$setProp(_el$33, "minWidth", 0);
677
+ _$insert(_el$33, () => lines().map(line => (() => {
678
+ var _el$36 = _$createElement("text");
679
+ _$setProp(_el$36, "wrapMode", "word");
680
+ _$setProp(_el$36, "width", "100%");
681
+ _$insert(_el$36, line || " ");
682
+ _$effect(_$p => _$setProp(_el$36, "fg", props.api.theme.current.text, _$p));
683
+ return _el$36;
440
684
  })()));
441
- _$insertNode(_el$29, _$createTextNode(`esc closes`));
685
+ _$insertNode(_el$34, _$createTextNode(`esc closes`));
442
686
  _$effect(_p$ => {
443
- var _v$5 = props.api.theme.current.text,
444
- _v$6 = bodyHeight(),
445
- _v$7 = props.api.theme.current.textMuted;
446
- _v$5 !== _p$.e && (_p$.e = _$setProp(_el$25, "fg", _v$5, _p$.e));
447
- _v$6 !== _p$.t && (_p$.t = _$setProp(_el$27, "minHeight", _v$6, _p$.t));
448
- _v$7 !== _p$.a && (_p$.a = _$setProp(_el$29, "fg", _v$7, _p$.a));
687
+ var _v$8 = props.api.theme.current.text,
688
+ _v$9 = bodyHeight(),
689
+ _v$0 = props.api.theme.current.textMuted;
690
+ _v$8 !== _p$.e && (_p$.e = _$setProp(_el$30, "fg", _v$8, _p$.e));
691
+ _v$9 !== _p$.t && (_p$.t = _$setProp(_el$32, "minHeight", _v$9, _p$.t));
692
+ _v$0 !== _p$.a && (_p$.a = _$setProp(_el$34, "fg", _v$0, _p$.a));
449
693
  return _p$;
450
694
  }, {
451
695
  e: undefined,
452
696
  t: undefined,
453
697
  a: undefined
454
698
  });
455
- return _el$24;
699
+ return _el$29;
456
700
  })();
457
701
  }
458
702
  function CommandErrorDialog(props) {
459
703
  const message = props.error instanceof Error ? props.error.message : String(props.error);
460
704
  return (() => {
461
- var _el$32 = _$createElement("box"),
462
- _el$33 = _$createElement("text"),
463
- _el$34 = _$createElement("b"),
464
- _el$35 = _$createElement("text"),
465
- _el$37 = _$createElement("text"),
466
- _el$38 = _$createElement("text");
467
- _$insertNode(_el$32, _el$33);
468
- _$insertNode(_el$32, _el$35);
469
- _$insertNode(_el$32, _el$37);
470
- _$insertNode(_el$32, _el$38);
471
- _$setProp(_el$32, "gap", 1);
472
- _$setProp(_el$32, "paddingLeft", 2);
473
- _$setProp(_el$32, "paddingRight", 2);
474
- _$setProp(_el$32, "paddingBottom", 1);
475
- _$insertNode(_el$33, _el$34);
476
- _$insert(_el$34, () => props.title);
477
- _$insertNode(_el$35, _$createTextNode(`OpenCode Quota command failed.`));
478
- _$setProp(_el$37, "wrapMode", "none");
479
- _$insert(_el$37, message || "Unknown error");
480
- _$insertNode(_el$38, _$createTextNode(`esc closes`));
705
+ var _el$37 = _$createElement("box"),
706
+ _el$38 = _$createElement("text"),
707
+ _el$39 = _$createElement("b"),
708
+ _el$40 = _$createElement("text"),
709
+ _el$42 = _$createElement("text"),
710
+ _el$43 = _$createElement("text");
711
+ _$insertNode(_el$37, _el$38);
712
+ _$insertNode(_el$37, _el$40);
713
+ _$insertNode(_el$37, _el$42);
714
+ _$insertNode(_el$37, _el$43);
715
+ _$setProp(_el$37, "gap", 1);
716
+ _$setProp(_el$37, "paddingLeft", 2);
717
+ _$setProp(_el$37, "paddingRight", 2);
718
+ _$setProp(_el$37, "paddingBottom", 1);
719
+ _$insertNode(_el$38, _el$39);
720
+ _$insert(_el$39, () => props.title);
721
+ _$insertNode(_el$40, _$createTextNode(`OpenCode Quota command failed.`));
722
+ _$setProp(_el$42, "wrapMode", "none");
723
+ _$insert(_el$42, message || "Unknown error");
724
+ _$insertNode(_el$43, _$createTextNode(`esc closes`));
481
725
  _$effect(_p$ => {
482
- var _v$8 = props.api.theme.current.text,
483
- _v$9 = props.api.theme.current.text,
484
- _v$0 = props.api.theme.current.textMuted,
485
- _v$1 = props.api.theme.current.textMuted;
486
- _v$8 !== _p$.e && (_p$.e = _$setProp(_el$33, "fg", _v$8, _p$.e));
487
- _v$9 !== _p$.t && (_p$.t = _$setProp(_el$35, "fg", _v$9, _p$.t));
488
- _v$0 !== _p$.a && (_p$.a = _$setProp(_el$37, "fg", _v$0, _p$.a));
489
- _v$1 !== _p$.o && (_p$.o = _$setProp(_el$38, "fg", _v$1, _p$.o));
726
+ var _v$1 = props.api.theme.current.text,
727
+ _v$10 = props.api.theme.current.text,
728
+ _v$11 = props.api.theme.current.textMuted,
729
+ _v$12 = props.api.theme.current.textMuted;
730
+ _v$1 !== _p$.e && (_p$.e = _$setProp(_el$38, "fg", _v$1, _p$.e));
731
+ _v$10 !== _p$.t && (_p$.t = _$setProp(_el$40, "fg", _v$10, _p$.t));
732
+ _v$11 !== _p$.a && (_p$.a = _$setProp(_el$42, "fg", _v$11, _p$.a));
733
+ _v$12 !== _p$.o && (_p$.o = _$setProp(_el$43, "fg", _v$12, _p$.o));
490
734
  return _p$;
491
735
  }, {
492
736
  e: undefined,
@@ -494,7 +738,7 @@ function CommandErrorDialog(props) {
494
738
  a: undefined,
495
739
  o: undefined
496
740
  });
497
- return _el$32;
741
+ return _el$37;
498
742
  })();
499
743
  }
500
744
  function getCommandPromptCopy(spec) {
@@ -538,11 +782,11 @@ async function runQuotaDialogCommandAsync(api, command, commandDisplay, rawInput
538
782
  return prompt.placeholder;
539
783
  },
540
784
  description: () => (() => {
541
- var _el$40 = _$createElement("text");
542
- _$setProp(_el$40, "wrapMode", "word");
543
- _$insert(_el$40, () => prompt.description);
544
- _$effect(_$p => _$setProp(_el$40, "fg", api.theme.current.textMuted, _$p));
545
- return _el$40;
785
+ var _el$45 = _$createElement("text");
786
+ _$setProp(_el$45, "wrapMode", "word");
787
+ _$insert(_el$45, () => prompt.description);
788
+ _$effect(_$p => _$setProp(_el$45, "fg", api.theme.current.textMuted, _$p));
789
+ return _el$45;
546
790
  })(),
547
791
  onCancel: () => api.ui.dialog.clear(),
548
792
  onConfirm: value => {
@@ -629,7 +873,7 @@ async function runQuotaDialogCommandAsync(api, command, commandDisplay, rawInput
629
873
  });
630
874
  }
631
875
  }
632
- function registerQuotaDialogCommands(api, commandDisplay) {
876
+ function registerQuotaDialogCommands(api, gate) {
633
877
  const commandState = {};
634
878
  const dispose = api.keymap.registerLayer({
635
879
  commands: QUOTA_DIALOG_COMMANDS.map(spec => ({
@@ -640,88 +884,135 @@ function registerQuotaDialogCommands(api, commandDisplay) {
640
884
  category: "OpenCode Quota",
641
885
  slashName: spec.slashName,
642
886
  run(input) {
643
- void runQuotaDialogCommandAsync(api, spec.id, commandDisplay, input, commandState);
887
+ const state = gate.current();
888
+ if (state.status !== "active") return;
889
+ void runQuotaDialogCommandAsync(api, spec.id, state.registration.commandDisplay, input, commandState);
644
890
  }
645
891
  })),
646
892
  bindings: []
647
893
  });
648
894
  api.lifecycle.onDispose(dispose);
649
895
  }
650
- function registerSidebarSlots(api) {
896
+ function registerStableTuiSlots(api, current) {
651
897
  api.slots.register({
652
898
  order: SIDEBAR_ORDER,
653
899
  slots: {
654
900
  sidebar_content(_ctx, props) {
901
+ const state = current();
902
+ if (state.status !== "active" || !state.registration.sidebar.enabled) return null;
655
903
  return _$createComponent(SidebarContentView, {
656
904
  api: api,
657
905
  get sessionID() {
658
906
  return props.session_id;
907
+ },
908
+ get initialLoads() {
909
+ return state.initialLoads;
910
+ }
911
+ });
912
+ }
913
+ }
914
+ });
915
+ api.slots.register({
916
+ order: COMPACT_ORDER,
917
+ slots: {
918
+ session_prompt(_ctx, props) {
919
+ const state = current();
920
+ if (state.status !== "active") return null;
921
+ if (state.registration.promptBar.enabled) {
922
+ return _$createComponent(SessionQuotaPromptBar, {
923
+ api: api,
924
+ get sessionID() {
925
+ return props.session_id;
926
+ },
927
+ get initialLoads() {
928
+ return state.initialLoads;
929
+ },
930
+ get visible() {
931
+ return props.visible;
932
+ },
933
+ get disabled() {
934
+ return props.disabled;
935
+ },
936
+ get onSubmit() {
937
+ return props.on_submit;
938
+ },
939
+ get promptRef() {
940
+ return props.ref;
941
+ }
942
+ });
943
+ }
944
+ if (!state.registration.compact.sessionPrompt) return null;
945
+ return _$createComponent(SessionPromptWithCompactStatus, {
946
+ api: api,
947
+ get sessionID() {
948
+ return props.session_id;
949
+ },
950
+ get initialLoads() {
951
+ return state.initialLoads;
952
+ },
953
+ get visible() {
954
+ return props.visible;
955
+ },
956
+ get disabled() {
957
+ return props.disabled;
958
+ },
959
+ get onSubmit() {
960
+ return props.on_submit;
961
+ },
962
+ get promptRef() {
963
+ return props.ref;
964
+ }
965
+ });
966
+ },
967
+ home_bottom() {
968
+ const state = current();
969
+ if (state.status !== "active" || !state.registration.homeBottom) return null;
970
+ return _$createComponent(HomeBottomView, {
971
+ api: api,
972
+ get compactHomeBottomEnabled() {
973
+ return state.registration.compact.homeBottom;
974
+ },
975
+ get initialLoads() {
976
+ return state.initialLoads;
659
977
  }
660
978
  });
661
979
  }
662
980
  }
663
981
  });
664
982
  }
665
- async function initializeTuiRegistration(api, isDisposed) {
983
+ async function initializeTuiRegistration(api, gate) {
984
+ let initialRuntimeSeed;
666
985
  let surfaceRegistration;
667
986
  try {
668
- surfaceRegistration = await resolveTuiSurfaceRegistration(api);
669
- } catch {
670
- if (isDisposed()) return;
671
- registerQuotaDialogCommands(api, "inline");
672
- registerSidebarSlots(api);
673
- return;
674
- }
675
- if (isDisposed()) return;
676
- registerQuotaDialogCommands(api, surfaceRegistration.commandDisplay);
677
- if (surfaceRegistration.sidebar.enabled) {
678
- registerSidebarSlots(api);
679
- }
680
- const compactRegistration = surfaceRegistration.compact;
681
- if (!compactRegistration.enabled && !surfaceRegistration.homeBottom) return;
682
- const compactSlots = {};
683
- if (compactRegistration.sessionPrompt) {
684
- compactSlots.session_prompt = (_ctx, props) => _$createComponent(SessionPromptWithCompactStatus, {
685
- api: api,
686
- get sessionID() {
687
- return props.session_id;
688
- },
689
- get visible() {
690
- return props.visible;
691
- },
692
- get disabled() {
693
- return props.disabled;
694
- },
695
- get onSubmit() {
696
- return props.on_submit;
697
- },
698
- get promptRef() {
699
- return props.ref;
700
- }
701
- });
702
- }
703
- if (surfaceRegistration.homeBottom) {
704
- compactSlots.home_bottom = () => _$createComponent(HomeBottomView, {
705
- api: api,
706
- get compactHomeBottomEnabled() {
707
- return surfaceRegistration.compact.homeBottom;
987
+ surfaceRegistration = resolveTuiSurfaceRegistration(api, {
988
+ captureInitialRuntime(seed) {
989
+ initialRuntimeSeed = seed;
708
990
  }
991
+ }).then(registration => ({
992
+ registration,
993
+ initialRuntimeSeed
994
+ })).catch(() => ({
995
+ registration: FALLBACK_SURFACE_REGISTRATION
996
+ }));
997
+ } catch {
998
+ surfaceRegistration = Promise.resolve({
999
+ registration: FALLBACK_SURFACE_REGISTRATION
709
1000
  });
710
1001
  }
711
- if (Object.keys(compactSlots).length > 0) {
712
- api.slots.register({
713
- order: COMPACT_ORDER,
714
- slots: compactSlots
715
- });
716
- }
1002
+ registerQuotaDialogCommands(api, gate);
1003
+ void surfaceRegistration.then(({
1004
+ registration,
1005
+ initialRuntimeSeed
1006
+ }) => gate.activate(registration, initialRuntimeSeed ? createTuiInitialLoadCoordinator(initialRuntimeSeed) : undefined));
1007
+ registerStableTuiSlots(api, gate.current);
717
1008
  }
718
1009
  const tui = async api => {
719
- let disposed = false;
1010
+ const registrationGate = createTuiRegistrationGate();
720
1011
  api.lifecycle.onDispose(() => {
721
- disposed = true;
1012
+ registrationGate.dispose();
722
1013
  disposeQuotaTelemetryOwner(createTuiQuotaClient(api));
723
1014
  });
724
- void initializeTuiRegistration(api, () => disposed).catch(() => {});
1015
+ void initializeTuiRegistration(api, registrationGate).catch(() => {});
725
1016
  };
726
1017
  const pluginModule = {
727
1018
  id,