@cortexkit/opencode-anthropic-auth 2.1.2 → 2.2.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/dist/cli.js +36 -36
- package/dist/{index-x325vp4e.js → index-ccrq4mra.js} +13 -13
- package/dist/{index-53nnxq39.js → index-czyrqpxc.js} +1 -1
- package/dist/index-pden7a7y.js +2 -0
- package/dist/index.js +1 -1
- package/dist/sidebar-state.d.ts +1 -1
- package/dist/sidebar-state.js +1 -1
- package/dist/transform.d.ts +4 -0
- package/dist/tui/claude-sidebar.d.ts +94 -0
- package/dist/v2/menu-contract.d.ts +3 -0
- package/dist/v2/rpc.d.ts +9 -0
- package/dist/v2/server.js +4 -4
- package/dist/v2/sidebar.d.ts +13 -0
- package/dist/v2/source.d.ts +2 -0
- package/dist/v2/tui.d.ts +9 -1
- package/dist/v2/tui.js +2 -2
- package/dist/v2/wire.d.ts +4 -0
- package/package.json +5 -5
- package/src/sidebar-state.ts +8 -3
- package/src/tui/claude-sidebar.tsx +1075 -0
- package/src/tui/entry.mjs +15 -1
- package/src/tui-compiled/sidebar-state.ts +8 -3
- package/src/tui-compiled/tui/claude-sidebar.tsx +1253 -0
- package/src/tui-compiled/tui.tsx +46 -1137
- package/src/tui.tsx +15 -886
- package/dist/index-jexctf5w.js +0 -2
package/src/tui-compiled/tui.tsx
CHANGED
|
@@ -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 {
|
|
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 {
|
|
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,
|
|
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$
|
|
624
|
-
_el$
|
|
625
|
-
_el$
|
|
626
|
-
_el$
|
|
627
|
-
_el$
|
|
628
|
-
_$insertNode(_el
|
|
629
|
-
_$setProp(_el
|
|
630
|
-
_$setProp(_el
|
|
631
|
-
_$setProp(_el
|
|
632
|
-
_$setProp(_el
|
|
633
|
-
_$insertNode(_el$
|
|
634
|
-
_$setProp(_el$
|
|
635
|
-
_$setProp(_el$
|
|
636
|
-
_$insertNode(_el$
|
|
637
|
-
_$setProp(_el$
|
|
638
|
-
_$setProp(_el$
|
|
639
|
-
_$setProp(_el$
|
|
640
|
-
_$insertNode(_el$
|
|
641
|
-
_$insertNode(_el$
|
|
642
|
-
_$insert(_el$
|
|
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$
|
|
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$
|
|
718
|
-
return _el
|
|
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
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
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();
|