@cortexkit/opencode-anthropic-auth 2.1.2 → 2.2.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.
@@ -1,602 +1,24 @@
1
1
  import { memo as _$memo } from "opentui:runtime-module:%40opentui%2Fsolid";
2
+ import { effect as _$effect } from "opentui:runtime-module:%40opentui%2Fsolid";
3
+ import { insert as _$insert } from "opentui:runtime-module:%40opentui%2Fsolid";
2
4
  import { createComponent as _$createComponent } from "opentui:runtime-module:%40opentui%2Fsolid";
3
5
  import { createTextNode as _$createTextNode } from "opentui:runtime-module:%40opentui%2Fsolid";
4
- import { use as _$use } from "opentui:runtime-module:%40opentui%2Fsolid";
5
- import { effect as _$effect } from "opentui:runtime-module:%40opentui%2Fsolid";
6
6
  import { insertNode as _$insertNode } from "opentui:runtime-module:%40opentui%2Fsolid";
7
- import { insert as _$insert } from "opentui:runtime-module:%40opentui%2Fsolid";
8
7
  import { setProp as _$setProp } from "opentui:runtime-module:%40opentui%2Fsolid";
9
8
  import { createElement as _$createElement } from "opentui:runtime-module:%40opentui%2Fsolid";
10
9
  /** @jsxImportSource @opentui/solid */
11
10
 
12
- import { readFileSync } from "node:fs";
13
- import { dirname, join } from "node:path";
14
- import { fileURLToPath } from "node:url";
15
- import { formatCreditAmounts, quotaDisplayProjection, quotaWindowParts } from "@cortexkit/anthropic-auth-core";
16
- import { TextAttributes } from "opentui:runtime-module:%40opentui%2Fcore";
17
- import { createEffect, createSignal, For, Index, onCleanup, Show } from "opentui:runtime-module:solid-js";
11
+ import { createEffect, createSignal, For, onCleanup, Show } from "opentui:runtime-module:solid-js";
18
12
  import { createRpcClient } from "./rpc/rpc-client.js";
19
13
  import { getRpcDir } from "./rpc/rpc-dir.js";
20
- import { computeQuotaPacing, DEFAULT_SIDEBAR_STATE, FIVE_HOUR_MS, formatPrimeAccountValue, formatQuotaRowLabel, getCollapsedAccounts, getCollapsedQuotaSummary, getFableRecoverySummary, getSidebarState, resolveActiveAccount, SEVEN_DAY_MS } from "./sidebar-state.js";
14
+ import { DEFAULT_SIDEBAR_STATE, getSidebarState } from "./sidebar-state.js";
15
+ import { AccountBlock, ClaudeSidebar, createSidebarController } from "./tui/claude-sidebar.js";
21
16
  import { openCommandDialog, openNativeMenuDialog } from "./tui/command-dialogs.js";
22
- import { computeEffectiveOrder, DEFAULT_SLOT_ORDER, PLUGIN_KEY, queueTuiPreferenceUpdate, readTuiPreferencesFile, resolveAnthropicAuthPrefs, watchTuiPreferences } from "./tui-preferences.js";
17
+ import { computeEffectiveOrder, DEFAULT_SLOT_ORDER, PLUGIN_KEY, readTuiPreferencesFile, resolveAnthropicAuthPrefs } from "./tui-preferences.js";
23
18
  const RPC_POLL_MS = 500;
24
19
  let rpcPollStarted = false;
25
20
  const ID = 'cortexkit.anthropic-auth';
26
21
 
27
- // Read package metadata from either the raw src/ entry or its generated
28
- // src/tui-compiled/ counterpart. Avoid a JSON import because package.json sits
29
- // outside the declaration build's rootDir.
30
- const PLUGIN_VERSION = (() => {
31
- const here = dirname(fileURLToPath(import.meta.url));
32
- for (const packageFile of [join(here, '..', 'package.json'), join(here, '..', '..', 'package.json')]) {
33
- try {
34
- const raw = readFileSync(packageFile, 'utf8');
35
- const version = JSON.parse(raw).version;
36
- if (version) return version;
37
- } catch {
38
- // Try the path for the other TUI entry layout.
39
- }
40
- }
41
- return '';
42
- })();
43
-
44
- // biome-ignore lint/suspicious/noExplicitAny: opentui border prop not typed in plugin tui surface
45
- const SINGLE_BORDER = {
46
- type: 'single'
47
- };
48
- // Tone -> theme token. Theme tokens only — never hardcoded colors. Fallbacks
49
- // resolve to other theme tokens so the sidebar always tracks the active theme.
50
- function toneColor(theme, tone) {
51
- switch (tone) {
52
- case 'ok':
53
- return theme.success ?? theme.accent;
54
- case 'warn':
55
- return theme.warning ?? theme.accent;
56
- case 'err':
57
- return theme.error ?? theme.accent;
58
- case 'muted':
59
- return theme.textMuted ?? theme.text;
60
- case 'accent':
61
- return theme.accent ?? theme.text;
62
- default:
63
- return theme.text;
64
- }
65
- }
66
- function usageTone(usedPct, appearance) {
67
- if (usedPct < appearance.warnThreshold) return 'ok';
68
- if (usedPct < appearance.errorThreshold) return 'warn';
69
- return 'err';
70
- }
71
- const PACE_RESERVE_CHAR = '\u2592';
72
- const PACE_DEFICIT_CHAR = '\u2593';
73
-
74
- // Variant C pacing bar: normal fill up to min(used, pace), then a pace
75
- // segment covering the gap — headroom being banked (reserve, ok tone) or the
76
- // overshoot itself (deficit, err tone) — then empty cells. Without pacing the
77
- // bar renders as a single fill+empty pair, identical to the pre-pacing look.
78
- // Empty text nodes still occupy a phantom cell in the opentui flex row, so
79
- // zero-length segments are dropped from every return path (plain and pacing).
80
- function quotaBarSegments(usedPct, appearance, pacing) {
81
- const width = appearance.barWidth;
82
- const cells = pct => Math.max(0, Math.min(Math.round(pct / 100 * width), width));
83
- const usedCells = cells(usedPct);
84
- const fillTone = usageTone(usedPct, appearance);
85
- const plain = [{
86
- text: appearance.barFilledChar.repeat(usedCells),
87
- tone: fillTone
88
- }, {
89
- text: appearance.barEmptyChar.repeat(width - usedCells),
90
- tone: fillTone
91
- }];
92
- if (!pacing) return plain.filter(segment => segment.text.length > 0);
93
- const paceCells = cells(pacing.pacePercent);
94
- const lo = Math.min(usedCells, paceCells);
95
- const hi = Math.max(usedCells, paceCells);
96
- if (hi === lo) return plain.filter(segment => segment.text.length > 0);
97
- const overspent = usedCells > paceCells;
98
- return [{
99
- text: appearance.barFilledChar.repeat(lo),
100
- tone: fillTone
101
- }, {
102
- text: (overspent ? PACE_DEFICIT_CHAR : PACE_RESERVE_CHAR).repeat(hi - lo),
103
- tone: overspent ? 'err' : 'ok'
104
- }, {
105
- text: appearance.barEmptyChar.repeat(width - hi),
106
- tone: fillTone
107
- }].filter(segment => segment.text.length > 0);
108
- }
109
- function formatResetIn(resetsAt) {
110
- if (!resetsAt) return '';
111
- const ms = new Date(resetsAt).getTime() - Date.now();
112
- if (ms <= 0) return 'now';
113
- const mins = Math.floor(ms / 60_000);
114
- if (mins < 60) return `${mins}m`;
115
- const hrs = Math.floor(mins / 60);
116
- if (hrs < 24) {
117
- const rm = mins % 60;
118
- return rm > 0 ? `${hrs}h${rm}m` : `${hrs}h`;
119
- }
120
- const days = Math.floor(hrs / 24);
121
- const rh = hrs % 24;
122
- return rh > 0 ? `${days}d${rh}h` : `${days}d`;
123
- }
124
- function formatUntil(until) {
125
- if (!until) return '';
126
- const ms = until - Date.now();
127
- if (ms <= 0) return 'now';
128
- const mins = Math.ceil(ms / 60_000);
129
- if (mins < 60) return `${mins}m`;
130
- const hrs = Math.floor(mins / 60);
131
- const rm = mins % 60;
132
- return rm > 0 ? `${hrs}h${rm}m` : `${hrs}h`;
133
- }
134
-
135
- // --- Reusable components (aft-style) ---------------------------------------
136
-
137
- function SectionHeader(props) {
138
- return (() => {
139
- var _el$ = _$createElement("box"),
140
- _el$2 = _$createElement("text"),
141
- _el$3 = _$createElement("b");
142
- _$insertNode(_el$, _el$2);
143
- _$setProp(_el$, "width", '100%');
144
- _$insertNode(_el$2, _el$3);
145
- _$insert(_el$3, () => props.title);
146
- _$effect(_p$ => {
147
- var _v$ = props.marginTop ?? 1,
148
- _v$2 = props.theme.text;
149
- _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "marginTop", _v$, _p$.e));
150
- _v$2 !== _p$.t && (_p$.t = _$setProp(_el$2, "fg", _v$2, _p$.t));
151
- return _p$;
152
- }, {
153
- e: undefined,
154
- t: undefined
155
- });
156
- return _el$;
157
- })();
158
- }
159
- function StatRow(props) {
160
- return (() => {
161
- var _el$4 = _$createElement("box"),
162
- _el$5 = _$createElement("text"),
163
- _el$6 = _$createElement("text"),
164
- _el$7 = _$createElement("b");
165
- _$insertNode(_el$4, _el$5);
166
- _$insertNode(_el$4, _el$6);
167
- _$setProp(_el$4, "width", '100%');
168
- _$setProp(_el$4, "flexDirection", 'row');
169
- _$setProp(_el$4, "justifyContent", 'space-between');
170
- _$insert(_el$5, () => props.label);
171
- _$insertNode(_el$6, _el$7);
172
- _$insert(_el$7, () => props.value);
173
- _$effect(_p$ => {
174
- var _v$3 = props.theme.textMuted,
175
- _v$4 = toneColor(props.theme, props.tone ?? 'text');
176
- _v$3 !== _p$.e && (_p$.e = _$setProp(_el$5, "fg", _v$3, _p$.e));
177
- _v$4 !== _p$.t && (_p$.t = _$setProp(_el$6, "fg", _v$4, _p$.t));
178
- return _p$;
179
- }, {
180
- e: undefined,
181
- t: undefined
182
- });
183
- return _el$4;
184
- })();
185
- }
186
-
187
- // Compact row for the collapsed view: muted label left, caller-provided value
188
- // right. Mirrors StatRow's layout so columns line up.
189
- function CollapsedRow(props) {
190
- return (() => {
191
- var _el$8 = _$createElement("box"),
192
- _el$9 = _$createElement("text");
193
- _$insertNode(_el$8, _el$9);
194
- _$setProp(_el$8, "width", '100%');
195
- _$setProp(_el$8, "flexDirection", 'row');
196
- _$setProp(_el$8, "justifyContent", 'space-between');
197
- _$insert(_el$9, () => props.label);
198
- _$insert(_el$8, () => props.children, null);
199
- _$effect(_$p => _$setProp(_el$9, "fg", props.theme.textMuted, _$p));
200
- return _el$8;
201
- })();
202
- }
203
- function CollapsedAccountRow(props) {
204
- const [width, setWidth] = createSignal(40);
205
- let row;
206
- const summary = () => getCollapsedQuotaSummary(props.account.quota);
207
- const value = () => summary().text ?? '—';
208
- const labelWidth = () => Math.max(0, width() - Bun.stringWidth(value()) - 1);
209
- const dim = () => !props.account.active || props.account.quotaDated || summary().stale;
210
- const attributes = () => dim() ? TextAttributes.DIM : TextAttributes.BOLD;
211
- const color = () => dim() ? props.theme.textMuted : toneColor(props.theme, props.tone);
212
- return (() => {
213
- var _el$0 = _$createElement("box"),
214
- _el$12 = _$createElement("text");
215
- _$insertNode(_el$0, _el$12);
216
- _$use(element => {
217
- row = element;
218
- setWidth(element.width || 40);
219
- }, _el$0);
220
- _$setProp(_el$0, "width", '100%');
221
- _$setProp(_el$0, "height", 1);
222
- _$setProp(_el$0, "flexDirection", 'row');
223
- _$setProp(_el$0, "onSizeChange", () => setWidth(row?.width || 40));
224
- _$insert(_el$0, _$createComponent(Show, {
225
- get when() {
226
- return labelWidth() > 0;
227
- },
228
- get children() {
229
- return [(() => {
230
- var _el$1 = _$createElement("text");
231
- _$setProp(_el$1, "flexShrink", 0);
232
- _$setProp(_el$1, "wrapMode", 'none');
233
- _$insert(_el$1, () => formatQuotaRowLabel(props.account.name, labelWidth()));
234
- _$effect(_p$ => {
235
- var _v$5 = labelWidth(),
236
- _v$6 = color(),
237
- _v$7 = attributes();
238
- _v$5 !== _p$.e && (_p$.e = _$setProp(_el$1, "width", _v$5, _p$.e));
239
- _v$6 !== _p$.t && (_p$.t = _$setProp(_el$1, "fg", _v$6, _p$.t));
240
- _v$7 !== _p$.a && (_p$.a = _$setProp(_el$1, "attributes", _v$7, _p$.a));
241
- return _p$;
242
- }, {
243
- e: undefined,
244
- t: undefined,
245
- a: undefined
246
- });
247
- return _el$1;
248
- })(), (() => {
249
- var _el$10 = _$createElement("text");
250
- _$insertNode(_el$10, _$createTextNode(` `));
251
- _$setProp(_el$10, "width", 1);
252
- _$setProp(_el$10, "flexShrink", 0);
253
- return _el$10;
254
- })()];
255
- }
256
- }), _el$12);
257
- _$setProp(_el$12, "flexShrink", 0);
258
- _$setProp(_el$12, "wrapMode", 'none');
259
- _$insert(_el$12, value);
260
- _$effect(_p$ => {
261
- var _v$8 = Bun.stringWidth(value()),
262
- _v$9 = color(),
263
- _v$0 = attributes();
264
- _v$8 !== _p$.e && (_p$.e = _$setProp(_el$12, "width", _v$8, _p$.e));
265
- _v$9 !== _p$.t && (_p$.t = _$setProp(_el$12, "fg", _v$9, _p$.t));
266
- _v$0 !== _p$.a && (_p$.a = _$setProp(_el$12, "attributes", _v$0, _p$.a));
267
- return _p$;
268
- }, {
269
- e: undefined,
270
- t: undefined,
271
- a: undefined
272
- });
273
- return _el$0;
274
- })();
275
- }
276
-
277
- // Quota window row: muted label left, tone-colored bar + shared figure right,
278
- // with an optional muted reset suffix. When pacing data is present, the bar
279
- // gains a pace segment and an off-pace window adds a muted subline with the
280
- // reserve/deficit delta and the projected runout.
281
- function QuotaRow(props) {
282
- const used = () => props.usedPercent ?? 0;
283
- const reset = () => props.part?.resetIn;
284
- const paceLine = () => {
285
- const pacing = props.pacing;
286
- if (!pacing || pacing.state === 'on-pace') return null;
287
- const pct = Math.round(Math.abs(pacing.deltaPercent));
288
- if (pacing.state === 'reserve') return `reserve ${pct}% \u00b7 lasts`;
289
- return pacing.runsOutAt ? `deficit ${pct}% \u00b7 out in ${formatResetIn(pacing.runsOutAt)}` : `deficit ${pct}% \u00b7 lasts`;
290
- };
291
- return _$createComponent(Show, {
292
- get when() {
293
- return props.part;
294
- },
295
- get fallback() {
296
- return (() => {
297
- var _el$21 = _$createElement("box"),
298
- _el$22 = _$createElement("text"),
299
- _el$23 = _$createElement("text");
300
- _$insertNode(_el$21, _el$22);
301
- _$insertNode(_el$21, _el$23);
302
- _$setProp(_el$21, "width", '100%');
303
- _$setProp(_el$21, "flexDirection", 'row');
304
- _$insert(_el$22, () => `${formatQuotaRowLabel(props.label)} `);
305
- _$insertNode(_el$23, _$createTextNode(`—`));
306
- _$effect(_p$ => {
307
- var _v$13 = props.theme.textMuted,
308
- _v$14 = props.theme.textMuted;
309
- _v$13 !== _p$.e && (_p$.e = _$setProp(_el$22, "fg", _v$13, _p$.e));
310
- _v$14 !== _p$.t && (_p$.t = _$setProp(_el$23, "fg", _v$14, _p$.t));
311
- return _p$;
312
- }, {
313
- e: undefined,
314
- t: undefined
315
- });
316
- return _el$21;
317
- })();
318
- },
319
- get children() {
320
- return [(() => {
321
- var _el$13 = _$createElement("box"),
322
- _el$14 = _$createElement("box"),
323
- _el$15 = _$createElement("text"),
324
- _el$16 = _$createElement("text");
325
- _$insertNode(_el$13, _el$14);
326
- _$setProp(_el$13, "width", '100%');
327
- _$setProp(_el$13, "flexDirection", 'row');
328
- _$setProp(_el$13, "justifyContent", 'space-between');
329
- _$insertNode(_el$14, _el$15);
330
- _$insertNode(_el$14, _el$16);
331
- _$setProp(_el$14, "flexDirection", 'row');
332
- _$insert(_el$15, () => `${formatQuotaRowLabel(props.label)} `);
333
- _$insert(_el$14, _$createComponent(For, {
334
- get each() {
335
- return quotaBarSegments(used(), props.appearance, props.pacing);
336
- },
337
- children: segment => (() => {
338
- var _el$25 = _$createElement("text");
339
- _$insert(_el$25, () => segment.text);
340
- _$effect(_$p => _$setProp(_el$25, "fg", toneColor(props.theme, segment.tone), _$p));
341
- return _el$25;
342
- })()
343
- }), _el$16);
344
- _$insert(_el$16, () => ` ${props.part?.figure}${props.binding ? ' •' : ''}`);
345
- _$insert(_el$13, _$createComponent(Show, {
346
- get when() {
347
- return reset();
348
- },
349
- get children() {
350
- var _el$17 = _$createElement("text");
351
- _$insert(_el$17, reset);
352
- _$effect(_$p => _$setProp(_el$17, "fg", props.theme.textMuted, _$p));
353
- return _el$17;
354
- }
355
- }), null);
356
- _$effect(_p$ => {
357
- var _v$1 = props.theme.textMuted,
358
- _v$10 = toneColor(props.theme, usageTone(used(), props.appearance));
359
- _v$1 !== _p$.e && (_p$.e = _$setProp(_el$15, "fg", _v$1, _p$.e));
360
- _v$10 !== _p$.t && (_p$.t = _$setProp(_el$16, "fg", _v$10, _p$.t));
361
- return _p$;
362
- }, {
363
- e: undefined,
364
- t: undefined
365
- });
366
- return _el$13;
367
- })(), _$createComponent(Show, {
368
- get when() {
369
- return paceLine();
370
- },
371
- get children() {
372
- var _el$18 = _$createElement("box"),
373
- _el$19 = _$createElement("text"),
374
- _el$20 = _$createElement("text");
375
- _$insertNode(_el$18, _el$19);
376
- _$insertNode(_el$18, _el$20);
377
- _$setProp(_el$18, "width", '100%');
378
- _$setProp(_el$18, "flexDirection", 'row');
379
- _$insert(_el$19, () => formatQuotaRowLabel('', 11));
380
- _$insert(_el$20, paceLine);
381
- _$effect(_p$ => {
382
- var _v$11 = props.theme.textMuted,
383
- _v$12 = toneColor(props.theme, props.pacing?.state === 'deficit' ? 'warn' : 'muted');
384
- _v$11 !== _p$.e && (_p$.e = _$setProp(_el$19, "fg", _v$11, _p$.e));
385
- _v$12 !== _p$.t && (_p$.t = _$setProp(_el$20, "fg", _v$12, _p$.t));
386
- return _p$;
387
- }, {
388
- e: undefined,
389
- t: undefined
390
- });
391
- return _el$18;
392
- }
393
- })];
394
- }
395
- });
396
- }
397
-
398
- // The shared credit figure followed by the spent and limit amounts:
399
- // `credits 75% left · $25.00/$100.00`. When that line is wider than the
400
- // measured width, the amounts drop their cents (`$1,250/$5,000`) instead of
401
- // wrapping onto a second line.
402
- function creditLine(figure, extraUsage, width) {
403
- const amounts = formatCreditAmounts(extraUsage);
404
- if (!amounts) return figure;
405
- const line = `${figure} · ${amounts}`;
406
- if (width === undefined || Bun.stringWidth(line) <= width) return line;
407
- return `${figure} · ${formatCreditAmounts(extraUsage, {
408
- wholeUnits: true
409
- })}`;
410
- }
411
-
412
- // Account block: header row (name + status word) then per-window quota rows.
413
- // Pacing is computed here — per window, against the wall clock at render time
414
- // (re-evaluated on every state poll) — and disabled by passing false.
415
- function AccountBlock(props) {
416
- const statusWord = () => props.quotaDated && props.quota ? 'dated' : props.needsReauth ? 're-login' : props.vaultReauth ? 'needs sign-in in the vault' : props.active ? 'active' : 'idle';
417
- const statusTone = () => props.needsReauth || props.vaultReauth || props.stateLine ? 'warn' : props.active ? 'ok' : 'muted';
418
- const pacingFor = (window, windowMs) => props.pacingEnabled && !props.quotaDated && window ? computeQuotaPacing(window, windowMs, Date.now()) : null;
419
- const parts = () => {
420
- const now = Date.now();
421
- return quotaWindowParts(quotaDisplayProjection(props.quota, now), {
422
- now
423
- });
424
- };
425
- const partFor = name => parts().windows.find(part => part.name === name);
426
- return (() => {
427
- var _el$26 = _$createElement("box"),
428
- _el$27 = _$createElement("box"),
429
- _el$28 = _$createElement("text"),
430
- _el$29 = _$createElement("b"),
431
- _el$30 = _$createElement("text"),
432
- _el$31 = _$createElement("b");
433
- _$insertNode(_el$26, _el$27);
434
- _$setProp(_el$26, "width", '100%');
435
- _$setProp(_el$26, "flexDirection", 'column');
436
- _$insertNode(_el$27, _el$28);
437
- _$insertNode(_el$27, _el$30);
438
- _$setProp(_el$27, "width", '100%');
439
- _$setProp(_el$27, "flexDirection", 'row');
440
- _$setProp(_el$27, "justifyContent", 'space-between');
441
- _$insertNode(_el$28, _el$29);
442
- _$insert(_el$29, () => `${props.name}${props.tierLabel ? ` · ${props.tierLabel}` : ''}`);
443
- _$insertNode(_el$30, _el$31);
444
- _$insert(_el$31, statusWord);
445
- _$insert(_el$26, _$createComponent(Show, {
446
- get when() {
447
- return props.stateLine;
448
- },
449
- get children() {
450
- var _el$32 = _$createElement("text");
451
- _$insert(_el$32, () => props.stateLine);
452
- _$effect(_$p => _$setProp(_el$32, "fg", props.theme.textMuted, _$p));
453
- return _el$32;
454
- }
455
- }), null);
456
- _$insert(_el$26, _$createComponent(Show, {
457
- get when() {
458
- return props.quota;
459
- },
460
- get fallback() {
461
- return (() => {
462
- var _el$36 = _$createElement("text");
463
- _$insertNode(_el$36, _$createTextNode(`checking…`));
464
- _$effect(_$p => _$setProp(_el$36, "fg", props.theme.textMuted, _$p));
465
- return _el$36;
466
- })();
467
- },
468
- get children() {
469
- return [_$createComponent(QuotaRow, {
470
- get theme() {
471
- return props.theme;
472
- },
473
- get appearance() {
474
- return props.appearance;
475
- },
476
- label: "5h",
477
- get part() {
478
- return partFor('5h');
479
- },
480
- get usedPercent() {
481
- return props.quota?.five_hour?.usedPercent;
482
- },
483
- get pacing() {
484
- return pacingFor(props.quota?.five_hour, FIVE_HOUR_MS);
485
- },
486
- get binding() {
487
- return props.quota?.bindingWindow === 'five_hour';
488
- }
489
- }), _$createComponent(QuotaRow, {
490
- get theme() {
491
- return props.theme;
492
- },
493
- get appearance() {
494
- return props.appearance;
495
- },
496
- label: "7d",
497
- get part() {
498
- return partFor('7d');
499
- },
500
- get usedPercent() {
501
- return props.quota?.seven_day?.usedPercent;
502
- },
503
- get pacing() {
504
- return pacingFor(props.quota?.seven_day, SEVEN_DAY_MS);
505
- },
506
- get binding() {
507
- return props.quota?.bindingWindow === 'seven_day';
508
- }
509
- }), _$createComponent(For, {
510
- get each() {
511
- return props.quota?.scoped ?? [];
512
- },
513
- children: window => _$createComponent(QuotaRow, {
514
- get theme() {
515
- return props.theme;
516
- },
517
- get appearance() {
518
- return props.appearance;
519
- },
520
- get label() {
521
- return partFor(window.title)?.name ?? window.title;
522
- },
523
- get part() {
524
- return partFor(window.title);
525
- },
526
- get usedPercent() {
527
- return window.usedPercent;
528
- },
529
- get pacing() {
530
- return pacingFor(window, SEVEN_DAY_MS);
531
- },
532
- get binding() {
533
- return props.quota?.bindingWindow === window.id;
534
- }
535
- })
536
- }), _$createComponent(Show, {
537
- get when() {
538
- return partFor('credits');
539
- },
540
- children: budget => {
541
- // The line box's laid-out width, read when it mounts and on each
542
- // resize. It is undefined (amounts keep their cents) until layout.
543
- const [width, setWidth] = createSignal();
544
- let line;
545
- return (() => {
546
- var _el$38 = _$createElement("box"),
547
- _el$39 = _$createElement("text");
548
- _$insertNode(_el$38, _el$39);
549
- _$use(element => {
550
- line = element;
551
- setWidth(element.width || undefined);
552
- }, _el$38);
553
- _$setProp(_el$38, "width", '100%');
554
- _$setProp(_el$38, "onSizeChange", () => setWidth(line?.width || undefined));
555
- _$insert(_el$39, () => creditLine(budget().figure, props.quota?.extraUsage, width()));
556
- _$effect(_$p => _$setProp(_el$39, "fg", toneColor(props.theme, props.quota?.extraUsage?.severity === 'critical' ? 'err' : props.quota?.extraUsage?.severity === 'warning' || props.quota?.extraUsage?.exhausted ? 'warn' : 'muted'), _$p));
557
- return _el$38;
558
- })();
559
- }
560
- }), _$createComponent(Show, {
561
- get when() {
562
- return parts().age;
563
- },
564
- get children() {
565
- var _el$33 = _$createElement("text");
566
- _$insert(_el$33, () => parts().age);
567
- _$effect(_$p => _$setProp(_el$33, "fg", props.theme.textMuted, _$p));
568
- return _el$33;
569
- }
570
- }), _$createComponent(Show, {
571
- get when() {
572
- return props.quota?.fallbackAdvised === true;
573
- },
574
- get children() {
575
- var _el$34 = _$createElement("text");
576
- _$insertNode(_el$34, _$createTextNode(`→ fallback advised`));
577
- _$effect(_$p => _$setProp(_el$34, "fg", props.theme.textMuted, _$p));
578
- return _el$34;
579
- }
580
- })];
581
- }
582
- }), null);
583
- _$effect(_p$ => {
584
- var _v$15 = props.marginTop ?? 0,
585
- _v$16 = props.theme.text,
586
- _v$17 = toneColor(props.theme, statusTone());
587
- _v$15 !== _p$.e && (_p$.e = _$setProp(_el$26, "marginTop", _v$15, _p$.e));
588
- _v$16 !== _p$.t && (_p$.t = _$setProp(_el$28, "fg", _v$16, _p$.t));
589
- _v$17 !== _p$.a && (_p$.a = _$setProp(_el$30, "fg", _v$17, _p$.a));
590
- return _p$;
591
- }, {
592
- e: undefined,
593
- t: undefined,
594
- a: undefined
595
- });
596
- return _el$26;
597
- })();
598
- }
599
-
600
22
  // --- Quota dialog content ---------------------------------------------------
601
23
 
602
24
  // Renders the same rich visualization as the sidebar (account blocks with
@@ -620,26 +42,26 @@ function QuotaDialogContent(props) {
620
42
  const theme = () => props.api.theme.current;
621
43
  const enabledFallbacks = () => (state().fallbacks ?? []).filter(f => f.enabled || f.custodyState && f.custodyState !== 'off');
622
44
  return (() => {
623
- var _el$40 = _$createElement("box"),
624
- _el$41 = _$createElement("box"),
625
- _el$42 = _$createElement("box"),
626
- _el$43 = _$createElement("text"),
627
- _el$44 = _$createElement("b");
628
- _$insertNode(_el$40, _el$41);
629
- _$setProp(_el$40, "flexDirection", 'column');
630
- _$setProp(_el$40, "padding", 2);
631
- _$setProp(_el$40, "width", '100%');
632
- _$setProp(_el$40, "alignItems", 'center');
633
- _$insertNode(_el$41, _el$42);
634
- _$setProp(_el$41, "flexDirection", 'column');
635
- _$setProp(_el$41, "width", 58);
636
- _$insertNode(_el$42, _el$43);
637
- _$setProp(_el$42, "width", '100%');
638
- _$setProp(_el$42, "justifyContent", 'center');
639
- _$setProp(_el$42, "marginBottom", 1);
640
- _$insertNode(_el$43, _el$44);
641
- _$insertNode(_el$44, _$createTextNode(`Quota`));
642
- _$insert(_el$41, _$createComponent(AccountBlock, {
45
+ var _el$ = _$createElement("box"),
46
+ _el$2 = _$createElement("box"),
47
+ _el$3 = _$createElement("box"),
48
+ _el$4 = _$createElement("text"),
49
+ _el$5 = _$createElement("b");
50
+ _$insertNode(_el$, _el$2);
51
+ _$setProp(_el$, "flexDirection", 'column');
52
+ _$setProp(_el$, "padding", 2);
53
+ _$setProp(_el$, "width", '100%');
54
+ _$setProp(_el$, "alignItems", 'center');
55
+ _$insertNode(_el$2, _el$3);
56
+ _$setProp(_el$2, "flexDirection", 'column');
57
+ _$setProp(_el$2, "width", 58);
58
+ _$insertNode(_el$3, _el$4);
59
+ _$setProp(_el$3, "width", '100%');
60
+ _$setProp(_el$3, "justifyContent", 'center');
61
+ _$setProp(_el$3, "marginBottom", 1);
62
+ _$insertNode(_el$4, _el$5);
63
+ _$insertNode(_el$5, _$createTextNode(`Quota`));
64
+ _$insert(_el$2, _$createComponent(AccountBlock, {
643
65
  get theme() {
644
66
  return theme();
645
67
  },
@@ -664,9 +86,12 @@ function QuotaDialogContent(props) {
664
86
  },
665
87
  get quotaDated() {
666
88
  return state().main?.quotaDated;
89
+ },
90
+ get now() {
91
+ return Date.now();
667
92
  }
668
93
  }), null);
669
- _$insert(_el$41, _$createComponent(Show, {
94
+ _$insert(_el$2, _$createComponent(Show, {
670
95
  get when() {
671
96
  return prefs().sections.fallbackAccounts;
672
97
  },
@@ -709,13 +134,16 @@ function QuotaDialogContent(props) {
709
134
  get quotaDated() {
710
135
  return fb.quotaDated;
711
136
  },
712
- marginTop: 1
137
+ marginTop: 1,
138
+ get now() {
139
+ return Date.now();
140
+ }
713
141
  })
714
142
  });
715
143
  }
716
144
  }), null);
717
- _$effect(_$p => _$setProp(_el$43, "fg", theme().text, _$p));
718
- return _el$40;
145
+ _$effect(_$p => _$setProp(_el$4, "fg", theme().text, _$p));
146
+ return _el$;
719
147
  })();
720
148
  }
721
149
 
@@ -724,57 +152,8 @@ function QuotaDialogContent(props) {
724
152
  async function readStateFromFile() {
725
153
  return getSidebarState();
726
154
  }
727
- // The TUI may unmount and remount sidebar_content when the user switches
728
- // views (e.g. main -> subagent -> main). A remount re-runs the component
729
- // body, so any signal created inside the component would reset to its
730
- // seed. The controller lives in the plugin closure (process lifetime)
731
- // and owns the durable prefs/collapse signals plus the single shared
732
- // watcher subscription, so collapse and live pref reloads survive the
733
- // remount. No effects or memos here — those need a Solid owner, so the
734
- // poll-interval createEffect stays inside the component.
735
- function createSidebarController(initialPrefs) {
736
- const [prefs, setPrefs] = createSignal(initialPrefs);
737
- const seedCollapsed = initialPrefs.rememberCollapsed && initialPrefs.collapsed != null ? initialPrefs.collapsed : initialPrefs.startCollapsed;
738
- const [collapsed, setCollapsed] = createSignal(seedCollapsed);
739
- let lastPersistedCollapsed = initialPrefs.collapsed;
740
- let lastApplied = JSON.stringify(initialPrefs);
741
-
742
- // The watcher lives for the plugin/process lifetime — it is intentionally
743
- // never disposed. Collapse guard mirrors the race-fix in toggleCollapsed:
744
- // lastPersistedCollapsed is advanced only once our own write lands, so
745
- // watcher echoes of the previous persisted value are rejected by the
746
- // `!==` check and cannot revert a user click.
747
- watchTuiPreferences(() => {
748
- void (async () => {
749
- const next = resolveAnthropicAuthPrefs(await readTuiPreferencesFile());
750
- const serialized = JSON.stringify(next);
751
- if (serialized === lastApplied) return;
752
- lastApplied = serialized;
753
- setPrefs(next);
754
- if (next.rememberCollapsed && next.collapsed != null && next.collapsed !== lastPersistedCollapsed) {
755
- lastPersistedCollapsed = next.collapsed;
756
- setCollapsed(next.collapsed);
757
- }
758
- })();
759
- });
760
- function toggleCollapsed() {
761
- const next = !collapsed();
762
- setCollapsed(next);
763
- if (prefs().rememberCollapsed) {
764
- void queueTuiPreferenceUpdate(PLUGIN_KEY, ['collapsed'], next).then(() => {
765
- lastPersistedCollapsed = next;
766
- });
767
- }
768
- }
769
- return {
770
- prefs,
771
- collapsed,
772
- toggleCollapsed
773
- };
774
- }
775
155
  function QuotaSidebar(props) {
776
156
  const prefs = props.controller.prefs;
777
- const collapsed = props.controller.collapsed;
778
157
  const [state, setState] = createSignal(DEFAULT_SIDEBAR_STATE);
779
158
  let lastUpdated = 0;
780
159
  let debounce = null;
@@ -806,486 +185,16 @@ function QuotaSidebar(props) {
806
185
  if (debounce) clearTimeout(debounce);
807
186
  for (const u of unsubs) u();
808
187
  });
809
- const theme = () => props.api.theme.current;
810
- const enabledFallbacks = () => (state().fallbacks ?? []).filter(f => f.enabled || f.custodyState && f.custodyState !== 'off');
811
- const hasData = () => state().main?.quota != null || state().main?.stateLine != null || enabledFallbacks().length > 0;
812
- const headerLabel = () => {
813
- const name = prefs().header.label;
814
- return !hasData() ? name : collapsed() ? `\u25b6 ${name}` : `\u25bc ${name}`;
815
- };
816
- const activeAccount = () => resolveActiveAccount(state());
817
- const activeQuotaSummary = () => getCollapsedQuotaSummary(activeAccount().quota);
818
- const activePacingDeficit = () => {
819
- if (!prefs().sections.pacing) return false;
820
- if (activeAccount().quotaDated) return null;
821
- const quota = activeAccount().quota;
822
- if (!quota) return false;
823
- const now = Date.now();
824
- const windows = [[quota.five_hour, FIVE_HOUR_MS], [quota.seven_day, SEVEN_DAY_MS], ...(quota.scoped ?? []).map(window => [window, SEVEN_DAY_MS])];
825
- return windows.some(([w, ms]) => w != null && computeQuotaPacing(w, ms, now)?.state === 'deficit');
826
- };
827
- const activeQuotaTone = () => {
828
- const summary = activeQuotaSummary();
829
- const values = [summary.fiveHourUsedPercent, summary.sevenDayUsedPercent, ...summary.scopedUsedPercents].filter(value => value != null);
830
- // Pacing deficit is an advisory projection, not actual quota exhaustion,
831
- // so it can only BUMP the usage tone up to warn at most — never soften a
832
- // real warn/err usage reading and never paint a true red.
833
- const base = values.length > 0 ? usageTone(Math.max(...values), prefs().appearance) : 'muted';
834
- if (!activePacingDeficit()) return base;
835
- return base === 'ok' || base === 'muted' ? 'warn' : base;
836
- };
837
- const quotaBackedOff = () => state().main?.quotaBackedOff === true;
838
- const refreshBackedOff = () => state().main?.refreshBackedOff === true;
839
- const needsReauth = () => enabledFallbacks().some(f => f.needsReauth);
840
- const vaultReauth = () => enabledFallbacks().some(f => f.vaultReauth);
841
- const degraded = () => quotaBackedOff() || refreshBackedOff() || needsReauth() || vaultReauth();
842
- const fableRecoverySummary = () => getFableRecoverySummary(state(), props.sessionId);
843
- const fableRecoveryTone = () => state().fableRecoveries?.find(recovery => recovery.sessionId === props.sessionId)?.mode === 'fable' ? 'ok' : 'warn';
844
- const cacheKeep = () => state().cacheKeep;
845
- const showCache = () => prefs().sections.cache && cacheKeep() != null && cacheKeep()?.window != null;
846
- const prime = () => state().prime;
847
- const showPrime = () => prime() != null;
848
- const primeHasError = () => prime()?.accounts.some(account => account.lastResult === 'error') ?? false;
849
- const relayValue = () => {
850
- const r = state().relay;
851
- if (!r) return '\u2014';
852
- return `${r.transport} \u00b7 ${r.enabled ? 'on' : 'off'}`;
853
- };
854
- return (() => {
855
- var _el$46 = _$createElement("box"),
856
- _el$47 = _$createElement("box"),
857
- _el$48 = _$createElement("box"),
858
- _el$49 = _$createElement("text"),
859
- _el$50 = _$createElement("b");
860
- _$insertNode(_el$46, _el$47);
861
- _$setProp(_el$46, "width", '100%');
862
- _$setProp(_el$46, "flexDirection", 'column');
863
- _$setProp(_el$46, "border", SINGLE_BORDER);
864
- _$setProp(_el$46, "paddingTop", 1);
865
- _$setProp(_el$46, "paddingBottom", 1);
866
- _$setProp(_el$46, "paddingLeft", 1);
867
- _$setProp(_el$46, "paddingRight", 1);
868
- _$insertNode(_el$47, _el$48);
869
- _$setProp(_el$47, "width", '100%');
870
- _$setProp(_el$47, "flexDirection", 'row');
871
- _$setProp(_el$47, "justifyContent", 'space-between');
872
- _$setProp(_el$47, "alignItems", 'center');
873
- _$setProp(_el$47, "onMouseDown", () => {
874
- if (hasData()) props.controller.toggleCollapsed();
875
- });
876
- _$insertNode(_el$48, _el$49);
877
- _$setProp(_el$48, "paddingLeft", 1);
878
- _$setProp(_el$48, "paddingRight", 1);
879
- _$insertNode(_el$49, _el$50);
880
- _$insert(_el$50, headerLabel);
881
- _$insert(_el$47, _$createComponent(Show, {
882
- get when() {
883
- return degraded();
884
- },
885
- get fallback() {
886
- return _$createComponent(Show, {
887
- get when() {
888
- return prefs().header.showVersion && PLUGIN_VERSION !== '';
889
- },
890
- get children() {
891
- var _el$58 = _$createElement("text");
892
- _$insert(_el$58, `v${PLUGIN_VERSION}`);
893
- _$effect(_$p => _$setProp(_el$58, "fg", theme().textMuted, _$p));
894
- return _el$58;
895
- }
896
- });
897
- },
898
- get children() {
899
- var _el$51 = _$createElement("box"),
900
- _el$52 = _$createElement("text"),
901
- _el$53 = _$createElement("b");
902
- _$insertNode(_el$51, _el$52);
903
- _$setProp(_el$51, "paddingLeft", 1);
904
- _$setProp(_el$51, "paddingRight", 1);
905
- _$insertNode(_el$52, _el$53);
906
- _$insertNode(_el$53, _$createTextNode(`LIMITED`));
907
- _$effect(_p$ => {
908
- var _v$18 = theme().warning,
909
- _v$19 = theme().background;
910
- _v$18 !== _p$.e && (_p$.e = _$setProp(_el$51, "backgroundColor", _v$18, _p$.e));
911
- _v$19 !== _p$.t && (_p$.t = _$setProp(_el$52, "fg", _v$19, _p$.t));
912
- return _p$;
913
- }, {
914
- e: undefined,
915
- t: undefined
916
- });
917
- return _el$51;
918
- }
919
- }), null);
920
- _$insert(_el$46, _$createComponent(Show, {
921
- get when() {
922
- return _$memo(() => !!collapsed())() && hasData();
923
- },
924
- get children() {
925
- return [_$createComponent(Index, {
926
- get each() {
927
- return getCollapsedAccounts(state(), prefs().sections.fallbackAccounts);
928
- },
929
- children: account => _$createComponent(CollapsedAccountRow, {
930
- get theme() {
931
- return theme();
932
- },
933
- get account() {
934
- return account();
935
- },
936
- get tone() {
937
- return activeQuotaTone();
938
- }
939
- })
940
- }), _$createComponent(Show, {
941
- get when() {
942
- return state().fastMode;
943
- },
944
- get children() {
945
- return _$createComponent(CollapsedRow, {
946
- get theme() {
947
- return theme();
948
- },
949
- label: "Mode",
950
- get children() {
951
- var _el$55 = _$createElement("text"),
952
- _el$56 = _$createElement("b");
953
- _$insertNode(_el$55, _el$56);
954
- _$insertNode(_el$56, _$createTextNode(`fast`));
955
- _$effect(_$p => _$setProp(_el$55, "fg", toneColor(theme(), 'accent'), _$p));
956
- return _el$55;
957
- }
958
- });
959
- }
960
- }), _$createComponent(Show, {
961
- get when() {
962
- return fableRecoverySummary();
963
- },
964
- children: summary => _$createComponent(CollapsedRow, {
965
- get theme() {
966
- return theme();
967
- },
968
- label: "Recovery",
969
- get children() {
970
- var _el$59 = _$createElement("text"),
971
- _el$60 = _$createElement("b");
972
- _$insertNode(_el$59, _el$60);
973
- _$insert(_el$60, summary);
974
- _$effect(_$p => _$setProp(_el$59, "fg", toneColor(theme(), fableRecoveryTone()), _$p));
975
- return _el$59;
976
- }
977
- })
978
- })];
979
- }
980
- }), null);
981
- _$insert(_el$46, _$createComponent(Show, {
982
- get when() {
983
- return !collapsed() || !hasData();
984
- },
985
- get children() {
986
- return [_$createComponent(Show, {
987
- get when() {
988
- return hasData();
989
- },
990
- get fallback() {
991
- return (() => {
992
- var _el$61 = _$createElement("box"),
993
- _el$62 = _$createElement("text");
994
- _$insertNode(_el$61, _el$62);
995
- _$setProp(_el$61, "marginTop", 1);
996
- _$setProp(_el$61, "width", '100%');
997
- _$insertNode(_el$62, _$createTextNode(`Waiting for quota…`));
998
- _$effect(_$p => _$setProp(_el$62, "fg", theme().textMuted, _$p));
999
- return _el$61;
1000
- })();
1001
- },
1002
- get children() {
1003
- return _$createComponent(Show, {
1004
- get when() {
1005
- return prefs().sections.quota;
1006
- },
1007
- get children() {
1008
- return [_$createComponent(SectionHeader, {
1009
- get theme() {
1010
- return theme();
1011
- },
1012
- title: "Quota"
1013
- }), _$createComponent(AccountBlock, {
1014
- get theme() {
1015
- return theme();
1016
- },
1017
- get appearance() {
1018
- return prefs().appearance;
1019
- },
1020
- name: "main",
1021
- get quota() {
1022
- return state().main?.quota;
1023
- },
1024
- get active() {
1025
- return state().activeId === 'main';
1026
- },
1027
- get pacingEnabled() {
1028
- return prefs().sections.pacing;
1029
- },
1030
- get tierLabel() {
1031
- return state().main?.tierLabel;
1032
- },
1033
- get stateLine() {
1034
- return state().main?.stateLine;
1035
- },
1036
- get quotaDated() {
1037
- return state().main?.quotaDated;
1038
- }
1039
- }), _$createComponent(Show, {
1040
- get when() {
1041
- return prefs().sections.fallbackAccounts;
1042
- },
1043
- get children() {
1044
- return _$createComponent(For, {
1045
- get each() {
1046
- return enabledFallbacks();
1047
- },
1048
- children: fb => _$createComponent(AccountBlock, {
1049
- get theme() {
1050
- return theme();
1051
- },
1052
- get appearance() {
1053
- return prefs().appearance;
1054
- },
1055
- get name() {
1056
- return fb.label ?? fb.id;
1057
- },
1058
- get quota() {
1059
- return fb.quota;
1060
- },
1061
- get active() {
1062
- return state().activeId === fb.id;
1063
- },
1064
- get pacingEnabled() {
1065
- return prefs().sections.pacing;
1066
- },
1067
- get tierLabel() {
1068
- return fb.tierLabel;
1069
- },
1070
- get needsReauth() {
1071
- return fb.needsReauth;
1072
- },
1073
- get vaultReauth() {
1074
- return fb.vaultReauth;
1075
- },
1076
- get stateLine() {
1077
- return fb.stateLine;
1078
- },
1079
- get quotaDated() {
1080
- return fb.quotaDated;
1081
- },
1082
- marginTop: 1
1083
- })
1084
- });
1085
- }
1086
- })];
1087
- }
1088
- });
1089
- }
1090
- }), _$createComponent(Show, {
1091
- get when() {
1092
- return prefs().sections.routing;
1093
- },
1094
- get children() {
1095
- return [_$createComponent(SectionHeader, {
1096
- get theme() {
1097
- return theme();
1098
- },
1099
- title: "Routing"
1100
- }), _$createComponent(StatRow, {
1101
- get theme() {
1102
- return theme();
1103
- },
1104
- label: "Route",
1105
- get value() {
1106
- return state().route;
1107
- },
1108
- tone: "accent"
1109
- }), _$createComponent(StatRow, {
1110
- get theme() {
1111
- return theme();
1112
- },
1113
- label: "Mode",
1114
- get value() {
1115
- return state().fastMode ? 'fast' : 'std';
1116
- },
1117
- get tone() {
1118
- return state().fastMode ? 'accent' : 'muted';
1119
- }
1120
- }), _$createComponent(StatRow, {
1121
- get theme() {
1122
- return theme();
1123
- },
1124
- label: "Relay",
1125
- get value() {
1126
- return relayValue();
1127
- },
1128
- get tone() {
1129
- return state().relay?.enabled ? 'ok' : 'muted';
1130
- }
1131
- })];
1132
- }
1133
- }), _$createComponent(Show, {
1134
- get when() {
1135
- return fableRecoverySummary();
1136
- },
1137
- children: summary => _$createComponent(StatRow, {
1138
- get theme() {
1139
- return theme();
1140
- },
1141
- label: "Recovery",
1142
- get value() {
1143
- return summary();
1144
- },
1145
- get tone() {
1146
- return fableRecoveryTone();
1147
- }
1148
- })
1149
- }), _$createComponent(Show, {
1150
- get when() {
1151
- return showCache();
1152
- },
1153
- get children() {
1154
- return [_$createComponent(SectionHeader, {
1155
- get theme() {
1156
- return theme();
1157
- },
1158
- title: "Cache"
1159
- }), _$createComponent(StatRow, {
1160
- get theme() {
1161
- return theme();
1162
- },
1163
- label: "1h cache",
1164
- get value() {
1165
- return `${cacheKeep()?.window} \u00b7 ${cacheKeep()?.enabled ? 'on' : 'off'}`;
1166
- },
1167
- get tone() {
1168
- return cacheKeep()?.enabled ? 'ok' : 'muted';
1169
- }
1170
- }), _$createComponent(Show, {
1171
- get when() {
1172
- return (cacheKeep()?.trackedSessions ?? 0) > 0;
1173
- },
1174
- get children() {
1175
- return _$createComponent(StatRow, {
1176
- get theme() {
1177
- return theme();
1178
- },
1179
- label: "Tracked",
1180
- get value() {
1181
- return String(cacheKeep()?.trackedSessions);
1182
- },
1183
- tone: "text"
1184
- });
1185
- }
1186
- })];
1187
- }
1188
- }), _$createComponent(Show, {
1189
- get when() {
1190
- return showPrime();
1191
- },
1192
- get children() {
1193
- return [_$createComponent(StatRow, {
1194
- get theme() {
1195
- return theme();
1196
- },
1197
- label: "Prime",
1198
- get value() {
1199
- return primeHasError() ? 'err' : 'on';
1200
- },
1201
- get tone() {
1202
- return primeHasError() ? 'warn' : 'ok';
1203
- }
1204
- }), _$createComponent(For, {
1205
- get each() {
1206
- return prime()?.accounts ?? [];
1207
- },
1208
- children: account => {
1209
- const value = () => formatPrimeAccountValue(account);
1210
- return _$createComponent(StatRow, {
1211
- get theme() {
1212
- return theme();
1213
- },
1214
- get label() {
1215
- return account.label;
1216
- },
1217
- get value() {
1218
- return value().text;
1219
- },
1220
- get tone() {
1221
- return value().hasError ? 'warn' : 'text';
1222
- }
1223
- });
1224
- }
1225
- })];
1226
- }
1227
- }), _$createComponent(Show, {
1228
- get when() {
1229
- return _$memo(() => !!degraded())() && prefs().sections.health;
1230
- },
1231
- get children() {
1232
- return [_$createComponent(SectionHeader, {
1233
- get theme() {
1234
- return theme();
1235
- },
1236
- title: "Health"
1237
- }), _$createComponent(Show, {
1238
- get when() {
1239
- return quotaBackedOff();
1240
- },
1241
- get children() {
1242
- return _$createComponent(StatRow, {
1243
- get theme() {
1244
- return theme();
1245
- },
1246
- label: "Quota API",
1247
- get value() {
1248
- return `backoff ${formatUntil(state().main?.quotaBackoffUntil)}`;
1249
- },
1250
- tone: "warn"
1251
- });
1252
- }
1253
- }), _$createComponent(Show, {
1254
- get when() {
1255
- return refreshBackedOff();
1256
- },
1257
- get children() {
1258
- return _$createComponent(StatRow, {
1259
- get theme() {
1260
- return theme();
1261
- },
1262
- label: "Token refresh",
1263
- get value() {
1264
- return `backoff ${formatUntil(state().main?.refreshBackoffUntil)}`;
1265
- },
1266
- tone: "warn"
1267
- });
1268
- }
1269
- })];
1270
- }
1271
- })];
1272
- }
1273
- }), null);
1274
- _$effect(_p$ => {
1275
- var _v$20 = theme().borderActive,
1276
- _v$21 = theme().accent,
1277
- _v$22 = theme().background;
1278
- _v$20 !== _p$.e && (_p$.e = _$setProp(_el$46, "borderColor", _v$20, _p$.e));
1279
- _v$21 !== _p$.t && (_p$.t = _$setProp(_el$48, "backgroundColor", _v$21, _p$.t));
1280
- _v$22 !== _p$.a && (_p$.a = _$setProp(_el$49, "fg", _v$22, _p$.a));
1281
- return _p$;
1282
- }, {
1283
- e: undefined,
1284
- t: undefined,
1285
- a: undefined
1286
- });
1287
- return _el$46;
1288
- })();
188
+ return _$createComponent(ClaudeSidebar, {
189
+ state: state,
190
+ theme: () => props.api.theme.current,
191
+ get controller() {
192
+ return props.controller;
193
+ },
194
+ get sessionId() {
195
+ return props.sessionId;
196
+ }
197
+ });
1289
198
  }
1290
199
  const tui = async api => {
1291
200
  const root = await readTuiPreferencesFile();