@cortexkit/opencode-anthropic-auth 2.4.6 → 2.4.8
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 +43 -43
- package/dist/{index-zxyjjr82.js → index-61yvrgwy.js} +25 -25
- package/dist/index.js +1 -1
- package/dist/tui/claude-sidebar.d.ts +1 -1
- package/dist/v2/server.js +7 -7
- package/package.json +2 -2
- package/src/tui/claude-sidebar.tsx +349 -298
- package/src/tui/quota-sidebar.d.ts +11 -0
- package/src/tui/quota-sidebar.js +879 -0
- package/src/tui-compiled/quota-sidebar.js +879 -0
- package/src/tui-compiled/tui/claude-sidebar.tsx +499 -593
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
quotaDisplayProjection,
|
|
14
14
|
quotaWindowParts,
|
|
15
15
|
} from '@cortexkit/anthropic-auth-core'
|
|
16
|
-
import {
|
|
16
|
+
import type { BoxRenderable, RGBA } from '@opentui/core'
|
|
17
17
|
import {
|
|
18
18
|
createEffect,
|
|
19
19
|
createMemo,
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
onCleanup,
|
|
25
25
|
Show,
|
|
26
26
|
} from 'solid-js'
|
|
27
|
+
import { createStore, reconcile } from 'solid-js/store'
|
|
27
28
|
import {
|
|
28
29
|
type AccountQuota,
|
|
29
30
|
computeQuotaPacing,
|
|
@@ -32,7 +33,6 @@ import {
|
|
|
32
33
|
fitPaceLine,
|
|
33
34
|
fitQuotaRow,
|
|
34
35
|
formatPrimeAccountValue,
|
|
35
|
-
formatQuotaRowLabel,
|
|
36
36
|
getCollapsedAccounts,
|
|
37
37
|
getCollapsedQuotaSummary,
|
|
38
38
|
getFableRecoverySummary,
|
|
@@ -52,6 +52,13 @@ import {
|
|
|
52
52
|
resolveAnthropicAuthPrefs,
|
|
53
53
|
watchTuiPreferences,
|
|
54
54
|
} from '../tui-preferences.js'
|
|
55
|
+
import {
|
|
56
|
+
type AccountView,
|
|
57
|
+
type PaceView,
|
|
58
|
+
type Tone as SharedTone,
|
|
59
|
+
SidebarFrame,
|
|
60
|
+
SidebarTextRow,
|
|
61
|
+
} from './quota-sidebar.js'
|
|
55
62
|
|
|
56
63
|
// Read package metadata from either the raw src/ entry or its generated
|
|
57
64
|
// src/tui-compiled/tui/ counterpart. Avoid a JSON import because package.json sits
|
|
@@ -114,6 +121,18 @@ function usageTone(usedPct: number, appearance: AppearancePrefs): Tone {
|
|
|
114
121
|
return 'err'
|
|
115
122
|
}
|
|
116
123
|
|
|
124
|
+
function sharedTone(tone: Tone): SharedTone {
|
|
125
|
+
return tone === 'ok'
|
|
126
|
+
? 'success'
|
|
127
|
+
: tone === 'warn'
|
|
128
|
+
? 'warning'
|
|
129
|
+
: tone === 'err'
|
|
130
|
+
? 'error'
|
|
131
|
+
: tone === 'muted'
|
|
132
|
+
? 'textMuted'
|
|
133
|
+
: tone
|
|
134
|
+
}
|
|
135
|
+
|
|
117
136
|
interface BarSegment {
|
|
118
137
|
text: string
|
|
119
138
|
tone: Tone
|
|
@@ -242,77 +261,6 @@ function CollapsedRow(props: {
|
|
|
242
261
|
)
|
|
243
262
|
}
|
|
244
263
|
|
|
245
|
-
function CollapsedAccountRow(props: {
|
|
246
|
-
theme: SidebarTheme
|
|
247
|
-
account: ReturnType<typeof getCollapsedAccounts>[number]
|
|
248
|
-
tone: Tone
|
|
249
|
-
now: number
|
|
250
|
-
}) {
|
|
251
|
-
const [width, setWidth] = createSignal(40)
|
|
252
|
-
let row: BoxRenderable | undefined
|
|
253
|
-
const summary = () => getCollapsedQuotaSummary(props.account.quota, props.now)
|
|
254
|
-
const value = () => summary().text ?? '—'
|
|
255
|
-
// Keep the quota and its two-cell status suffix intact; only the label shrinks.
|
|
256
|
-
const labelWidth = () =>
|
|
257
|
-
Math.max(0, width() - 1 - Bun.stringWidth(value()) - 2)
|
|
258
|
-
const dim = () =>
|
|
259
|
-
!props.account.active || props.account.quotaDated || summary().stale
|
|
260
|
-
const attributes = () => (dim() ? TextAttributes.DIM : TextAttributes.BOLD)
|
|
261
|
-
const color = () =>
|
|
262
|
-
dim() ? props.theme.textMuted : toneColor(props.theme, props.tone)
|
|
263
|
-
return (
|
|
264
|
-
<box
|
|
265
|
-
width='100%'
|
|
266
|
-
height={1}
|
|
267
|
-
flexDirection='row'
|
|
268
|
-
ref={(element: BoxRenderable) => {
|
|
269
|
-
row = element
|
|
270
|
-
setWidth(element.width || 40)
|
|
271
|
-
}}
|
|
272
|
-
onSizeChange={() => setWidth(row?.width || 40)}
|
|
273
|
-
>
|
|
274
|
-
<Show when={labelWidth() > 0}>
|
|
275
|
-
<text
|
|
276
|
-
width={labelWidth()}
|
|
277
|
-
flexShrink={0}
|
|
278
|
-
wrapMode='none'
|
|
279
|
-
fg={color()}
|
|
280
|
-
attributes={attributes()}
|
|
281
|
-
>
|
|
282
|
-
{formatQuotaRowLabel(props.account.name, labelWidth())}
|
|
283
|
-
</text>
|
|
284
|
-
<text width={1} flexShrink={0}>
|
|
285
|
-
{' '}
|
|
286
|
-
</text>
|
|
287
|
-
</Show>
|
|
288
|
-
<text
|
|
289
|
-
width={Bun.stringWidth(value())}
|
|
290
|
-
flexShrink={0}
|
|
291
|
-
wrapMode='none'
|
|
292
|
-
fg={color()}
|
|
293
|
-
attributes={attributes()}
|
|
294
|
-
>
|
|
295
|
-
{value()}
|
|
296
|
-
</text>
|
|
297
|
-
<text
|
|
298
|
-
width={2}
|
|
299
|
-
flexShrink={0}
|
|
300
|
-
fg={toneColor(
|
|
301
|
-
props.theme,
|
|
302
|
-
props.account.blocked
|
|
303
|
-
? 'warn'
|
|
304
|
-
: props.account.active
|
|
305
|
-
? 'ok'
|
|
306
|
-
: 'muted',
|
|
307
|
-
)}
|
|
308
|
-
attributes={attributes()}
|
|
309
|
-
>
|
|
310
|
-
{props.account.blocked ? ' ⊘' : ' ●'}
|
|
311
|
-
</text>
|
|
312
|
-
</box>
|
|
313
|
-
)
|
|
314
|
-
}
|
|
315
|
-
|
|
316
264
|
// One cell run of a single-line row: drawn at its own width, never shrunk and
|
|
317
265
|
// never wrapped, so the row's layout is exactly what `fitQuotaRow` measured.
|
|
318
266
|
function Cell(props: { fg: SidebarColor; text: string }) {
|
|
@@ -541,30 +489,34 @@ export function AccountBlock(props: {
|
|
|
541
489
|
when={props.quota}
|
|
542
490
|
fallback={<text fg={props.theme.textMuted}>{'checking\u2026'}</text>}
|
|
543
491
|
>
|
|
544
|
-
<
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
492
|
+
<Show when={props.quota?.five_hour}>
|
|
493
|
+
<QuotaRow
|
|
494
|
+
theme={props.theme}
|
|
495
|
+
appearance={props.appearance}
|
|
496
|
+
label='5h'
|
|
497
|
+
labelWidth={labelWidth()}
|
|
498
|
+
width={width()}
|
|
499
|
+
part={partFor('5h')}
|
|
500
|
+
usedPercent={props.quota?.five_hour?.usedPercent}
|
|
501
|
+
pacing={pacingFor(props.quota?.five_hour, FIVE_HOUR_MS)}
|
|
502
|
+
binding={props.quota?.bindingWindow === 'five_hour'}
|
|
503
|
+
now={props.now}
|
|
504
|
+
/>
|
|
505
|
+
</Show>
|
|
506
|
+
<Show when={props.quota?.seven_day}>
|
|
507
|
+
<QuotaRow
|
|
508
|
+
theme={props.theme}
|
|
509
|
+
appearance={props.appearance}
|
|
510
|
+
label='7d'
|
|
511
|
+
labelWidth={labelWidth()}
|
|
512
|
+
width={width()}
|
|
513
|
+
part={partFor('7d')}
|
|
514
|
+
usedPercent={props.quota?.seven_day?.usedPercent}
|
|
515
|
+
pacing={pacingFor(props.quota?.seven_day, SEVEN_DAY_MS)}
|
|
516
|
+
binding={props.quota?.bindingWindow === 'seven_day'}
|
|
517
|
+
now={props.now}
|
|
518
|
+
/>
|
|
519
|
+
</Show>
|
|
568
520
|
<For each={props.quota?.scoped ?? []}>
|
|
569
521
|
{(window, index) => (
|
|
570
522
|
<QuotaRow
|
|
@@ -614,6 +566,54 @@ export function AccountBlock(props: {
|
|
|
614
566
|
)
|
|
615
567
|
}
|
|
616
568
|
|
|
569
|
+
function AccountExtras(props: {
|
|
570
|
+
quota: AccountQuota | null
|
|
571
|
+
now: number
|
|
572
|
+
theme: SidebarTheme
|
|
573
|
+
}) {
|
|
574
|
+
const [width, setWidth] = createSignal<number>()
|
|
575
|
+
let block: BoxRenderable | undefined
|
|
576
|
+
const budget = () =>
|
|
577
|
+
quotaWindowParts(quotaDisplayProjection(props.quota, props.now), {
|
|
578
|
+
now: props.now,
|
|
579
|
+
}).windows.find((part) => part.kind === 'budget')
|
|
580
|
+
return (
|
|
581
|
+
<box
|
|
582
|
+
width='100%'
|
|
583
|
+
flexDirection='column'
|
|
584
|
+
ref={(element: BoxRenderable) => {
|
|
585
|
+
block = element
|
|
586
|
+
setWidth(element.width || undefined)
|
|
587
|
+
}}
|
|
588
|
+
onSizeChange={() => setWidth(block?.width || undefined)}
|
|
589
|
+
>
|
|
590
|
+
<Show when={budget()}>
|
|
591
|
+
{(part: () => QuotaWindowPart) => (
|
|
592
|
+
<box width='100%' height={1} flexDirection='row'>
|
|
593
|
+
<text
|
|
594
|
+
wrapMode='none'
|
|
595
|
+
fg={toneColor(
|
|
596
|
+
props.theme,
|
|
597
|
+
props.quota?.extraUsage?.severity === 'critical'
|
|
598
|
+
? 'err'
|
|
599
|
+
: props.quota?.extraUsage?.severity === 'warning' ||
|
|
600
|
+
props.quota?.extraUsage?.exhausted
|
|
601
|
+
? 'warn'
|
|
602
|
+
: 'muted',
|
|
603
|
+
)}
|
|
604
|
+
>
|
|
605
|
+
{creditLine(part().figure, props.quota?.extraUsage, width())}
|
|
606
|
+
</text>
|
|
607
|
+
</box>
|
|
608
|
+
)}
|
|
609
|
+
</Show>
|
|
610
|
+
<Show when={props.quota?.fallbackAdvised === true}>
|
|
611
|
+
<SidebarTextRow text='→ fallback advised' />
|
|
612
|
+
</Show>
|
|
613
|
+
</box>
|
|
614
|
+
)
|
|
615
|
+
}
|
|
616
|
+
|
|
617
617
|
export interface SidebarController {
|
|
618
618
|
prefs: () => AnthropicAuthTuiPrefs
|
|
619
619
|
collapsed: () => boolean
|
|
@@ -717,22 +717,6 @@ export function ClaudeSidebar(props: {
|
|
|
717
717
|
state().main?.quota != null ||
|
|
718
718
|
state().main?.stateLine != null ||
|
|
719
719
|
enabledFallbacks().length > 0
|
|
720
|
-
// One label column for every expanded account, so all their bars line up.
|
|
721
|
-
const quotaLabelWidth = () =>
|
|
722
|
-
quotaLabelColumnWidth(
|
|
723
|
-
[
|
|
724
|
-
state().main?.quota,
|
|
725
|
-
...(prefs().sections.fallbackAccounts
|
|
726
|
-
? enabledFallbacks().map((fallback) => fallback.quota)
|
|
727
|
-
: []),
|
|
728
|
-
],
|
|
729
|
-
now(),
|
|
730
|
-
)
|
|
731
|
-
|
|
732
|
-
const headerLabel = () => {
|
|
733
|
-
const name = prefs().header.label
|
|
734
|
-
return !hasData() ? name : collapsed() ? `\u25b6 ${name}` : `\u25bc ${name}`
|
|
735
|
-
}
|
|
736
720
|
const activeAccount = () => resolveActiveAccount(state())
|
|
737
721
|
const activeQuotaSummary = () =>
|
|
738
722
|
getCollapsedQuotaSummary(activeAccount().quota, now())
|
|
@@ -808,217 +792,284 @@ export function ClaudeSidebar(props: {
|
|
|
808
792
|
return `${r.transport} \u00b7 ${r.enabled ? 'on' : 'off'}`
|
|
809
793
|
}
|
|
810
794
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
795
|
+
const accountDetail = (id: string) =>
|
|
796
|
+
id === 'main'
|
|
797
|
+
? state().main
|
|
798
|
+
: state().fallbacks?.find((account) => account.id === id)
|
|
799
|
+
const accountViews = createMemo((): AccountView[] => {
|
|
800
|
+
if (!hasData()) return []
|
|
801
|
+
return getCollapsedAccounts(state(), prefs().sections.fallbackAccounts).map(
|
|
802
|
+
(account): AccountView => {
|
|
803
|
+
const detail = accountDetail(account.id)
|
|
804
|
+
const quota = quotaDisplayProjection(account.quota, now())
|
|
805
|
+
const needsReauth =
|
|
806
|
+
detail && 'needsReauth' in detail && detail.needsReauth
|
|
807
|
+
const vaultReauth =
|
|
808
|
+
detail && 'vaultReauth' in detail && detail.vaultReauth
|
|
809
|
+
const active = state().activeId === account.id
|
|
810
|
+
const status =
|
|
811
|
+
account.quotaDated && account.quota
|
|
812
|
+
? 'dated'
|
|
813
|
+
: needsReauth
|
|
814
|
+
? 're-login'
|
|
815
|
+
: vaultReauth
|
|
816
|
+
? 'needs sign-in in the vault'
|
|
817
|
+
: active
|
|
818
|
+
? 'active'
|
|
819
|
+
: 'idle'
|
|
820
|
+
const groups = [
|
|
821
|
+
{
|
|
822
|
+
rows: quotaWindowParts(quota, { now: now() })
|
|
823
|
+
.windows.filter((part) => part.kind === 'window')
|
|
824
|
+
.map((part) => {
|
|
825
|
+
const scoped = account.quota?.scoped?.find(
|
|
826
|
+
(window) => window.title === part.name,
|
|
827
|
+
)
|
|
828
|
+
const window =
|
|
829
|
+
part.name === '5h'
|
|
830
|
+
? account.quota?.five_hour
|
|
831
|
+
: part.name === '7d'
|
|
832
|
+
? account.quota?.seven_day
|
|
833
|
+
: scoped
|
|
834
|
+
const pacing =
|
|
835
|
+
prefs().sections.pacing && !account.quotaDated && window
|
|
836
|
+
? computeQuotaPacing(
|
|
837
|
+
window,
|
|
838
|
+
part.name === '5h' ? FIVE_HOUR_MS : SEVEN_DAY_MS,
|
|
839
|
+
now(),
|
|
840
|
+
)
|
|
841
|
+
: null
|
|
842
|
+
const text = fitPaceLine(
|
|
843
|
+
pacing,
|
|
844
|
+
undefined,
|
|
845
|
+
pacing?.runsOutAt
|
|
846
|
+
? formatResetIn(pacing.runsOutAt, now())
|
|
847
|
+
: undefined,
|
|
848
|
+
part.resetIn,
|
|
849
|
+
part.remainingPercent,
|
|
850
|
+
)
|
|
851
|
+
const pace: PaceView | undefined = pacing
|
|
852
|
+
? {
|
|
853
|
+
text: text ?? '',
|
|
854
|
+
tone:
|
|
855
|
+
pacing.state === 'deficit' ? 'warning' : 'textMuted',
|
|
856
|
+
overlay: {
|
|
857
|
+
kind: pacing.deltaPercent > 0 ? 'deficit' : 'reserve',
|
|
858
|
+
percent: pacing.pacePercent,
|
|
859
|
+
},
|
|
860
|
+
}
|
|
861
|
+
: undefined
|
|
862
|
+
const binding =
|
|
863
|
+
account.quota?.bindingWindow ===
|
|
864
|
+
(part.name === '5h'
|
|
865
|
+
? 'five_hour'
|
|
866
|
+
: part.name === '7d'
|
|
867
|
+
? 'seven_day'
|
|
868
|
+
: scoped?.id)
|
|
869
|
+
return {
|
|
870
|
+
part: {
|
|
871
|
+
...part,
|
|
872
|
+
name: part.short,
|
|
873
|
+
figure: `${part.figure}${binding ? ' •' : ''}`,
|
|
874
|
+
},
|
|
875
|
+
pace,
|
|
876
|
+
}
|
|
877
|
+
}),
|
|
878
|
+
},
|
|
879
|
+
]
|
|
880
|
+
return {
|
|
881
|
+
id: account.id,
|
|
882
|
+
label: account.name,
|
|
883
|
+
titleSuffix: detail?.tierLabel,
|
|
884
|
+
quota,
|
|
885
|
+
groups,
|
|
886
|
+
status: {
|
|
887
|
+
text: status,
|
|
888
|
+
tone:
|
|
889
|
+
needsReauth || vaultReauth || detail?.stateLine
|
|
890
|
+
? 'warning'
|
|
891
|
+
: active
|
|
892
|
+
? 'success'
|
|
893
|
+
: 'textMuted',
|
|
894
|
+
},
|
|
895
|
+
blocked: Boolean(account.blocked),
|
|
896
|
+
indicatorTone: account.blocked
|
|
897
|
+
? 'warning'
|
|
898
|
+
: account.active
|
|
899
|
+
? 'success'
|
|
900
|
+
: 'textMuted',
|
|
901
|
+
collapsed: {
|
|
902
|
+
muted: Boolean(
|
|
903
|
+
!account.active ||
|
|
904
|
+
account.quotaDated ||
|
|
905
|
+
getCollapsedQuotaSummary(account.quota, now()).stale,
|
|
906
|
+
),
|
|
907
|
+
quotaTone: sharedTone(activeQuotaTone()),
|
|
908
|
+
},
|
|
909
|
+
emptyQuotaText: { expanded: 'checking…', collapsed: '—' },
|
|
910
|
+
}
|
|
911
|
+
},
|
|
912
|
+
)
|
|
913
|
+
})
|
|
914
|
+
// Polls rebuild snapshots, but account ids keep the shared frame's rows mounted.
|
|
915
|
+
const [accounts, setAccounts] = createStore<AccountView[]>([])
|
|
916
|
+
createEffect(() => setAccounts(reconcile(accountViews(), { key: 'id' })))
|
|
833
917
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
)}
|
|
853
|
-
</Index>
|
|
854
|
-
<Show when={state().fastMode}>
|
|
855
|
-
<CollapsedRow theme={theme()} label='Mode'>
|
|
856
|
-
<text fg={toneColor(theme(), 'accent')}>
|
|
857
|
-
<b>{'fast'}</b>
|
|
858
|
-
</text>
|
|
859
|
-
</CollapsedRow>
|
|
918
|
+
return (
|
|
919
|
+
<SidebarFrame
|
|
920
|
+
header={{
|
|
921
|
+
badge: prefs().header.label,
|
|
922
|
+
version:
|
|
923
|
+
prefs().header.showVersion && PLUGIN_VERSION !== ''
|
|
924
|
+
? `v${PLUGIN_VERSION}`
|
|
925
|
+
: undefined,
|
|
926
|
+
}}
|
|
927
|
+
accounts={accounts}
|
|
928
|
+
theme={theme()}
|
|
929
|
+
appearance={prefs().appearance}
|
|
930
|
+
showQuota={prefs().sections.quota}
|
|
931
|
+
now={now()}
|
|
932
|
+
collapsed={collapsed()}
|
|
933
|
+
onToggle={props.controller.toggleCollapsed}
|
|
934
|
+
beforeQuota={(account) => (
|
|
935
|
+
<Show when={accountDetail(account.id)?.stateLine}>
|
|
936
|
+
{(text: () => string) => <SidebarTextRow text={text()} />}
|
|
860
937
|
</Show>
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
938
|
+
)}
|
|
939
|
+
afterQuota={(account) => (
|
|
940
|
+
<AccountExtras
|
|
941
|
+
quota={accountDetail(account.id)?.quota ?? null}
|
|
942
|
+
now={now()}
|
|
943
|
+
theme={theme()}
|
|
944
|
+
/>
|
|
945
|
+
)}
|
|
946
|
+
collapsedSections={() => (
|
|
947
|
+
<>
|
|
948
|
+
<Show when={state().fastMode}>
|
|
949
|
+
<CollapsedRow theme={theme()} label='Mode'>
|
|
950
|
+
<text fg={toneColor(theme(), 'accent')}>
|
|
951
|
+
<b>{'fast'}</b>
|
|
866
952
|
</text>
|
|
867
953
|
</CollapsedRow>
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
954
|
+
</Show>
|
|
955
|
+
<Show when={fableRecoverySummary()}>
|
|
956
|
+
{(summary: () => string) => (
|
|
957
|
+
<CollapsedRow theme={theme()} label='Recovery'>
|
|
958
|
+
<text fg={toneColor(theme(), fableRecoveryTone())}>
|
|
959
|
+
<b>{summary()}</b>
|
|
960
|
+
</text>
|
|
961
|
+
</CollapsedRow>
|
|
962
|
+
)}
|
|
963
|
+
</Show>
|
|
964
|
+
</>
|
|
965
|
+
)}
|
|
966
|
+
sections={() => (
|
|
967
|
+
<>
|
|
968
|
+
<Show when={!hasData()}>
|
|
878
969
|
<box marginTop={1} width='100%'>
|
|
879
970
|
<text fg={theme().textMuted}>{'Waiting for quota\u2026'}</text>
|
|
880
971
|
</box>
|
|
881
|
-
}
|
|
882
|
-
>
|
|
883
|
-
{/* Quota */}
|
|
884
|
-
<Show when={prefs().sections.quota}>
|
|
885
|
-
<SectionHeader theme={theme()} title='Quota' />
|
|
886
|
-
<AccountBlock
|
|
887
|
-
theme={theme()}
|
|
888
|
-
appearance={prefs().appearance}
|
|
889
|
-
name='main'
|
|
890
|
-
quota={state().main?.quota}
|
|
891
|
-
active={state().activeId === 'main'}
|
|
892
|
-
pacingEnabled={prefs().sections.pacing}
|
|
893
|
-
tierLabel={state().main?.tierLabel}
|
|
894
|
-
labelWidth={quotaLabelWidth()}
|
|
895
|
-
stateLine={state().main?.stateLine}
|
|
896
|
-
quotaDated={state().main?.quotaDated}
|
|
897
|
-
now={now()}
|
|
898
|
-
/>
|
|
899
|
-
<Show when={prefs().sections.fallbackAccounts}>
|
|
900
|
-
<For each={enabledFallbacks()}>
|
|
901
|
-
{(fb) => (
|
|
902
|
-
<AccountBlock
|
|
903
|
-
theme={theme()}
|
|
904
|
-
appearance={prefs().appearance}
|
|
905
|
-
name={fb.label ?? fb.id}
|
|
906
|
-
quota={fb.quota}
|
|
907
|
-
active={state().activeId === fb.id}
|
|
908
|
-
pacingEnabled={prefs().sections.pacing}
|
|
909
|
-
tierLabel={fb.tierLabel}
|
|
910
|
-
labelWidth={quotaLabelWidth()}
|
|
911
|
-
needsReauth={fb.needsReauth}
|
|
912
|
-
vaultReauth={fb.vaultReauth}
|
|
913
|
-
stateLine={fb.stateLine}
|
|
914
|
-
quotaDated={fb.quotaDated}
|
|
915
|
-
marginTop={1}
|
|
916
|
-
now={now()}
|
|
917
|
-
/>
|
|
918
|
-
)}
|
|
919
|
-
</For>
|
|
920
|
-
</Show>
|
|
921
972
|
</Show>
|
|
922
|
-
</Show>
|
|
923
|
-
|
|
924
|
-
{/* Routing */}
|
|
925
|
-
<Show when={prefs().sections.routing}>
|
|
926
|
-
<SectionHeader theme={theme()} title='Routing' />
|
|
927
|
-
<StatRow
|
|
928
|
-
theme={theme()}
|
|
929
|
-
label='Route'
|
|
930
|
-
value={state().route}
|
|
931
|
-
tone='accent'
|
|
932
|
-
/>
|
|
933
|
-
<StatRow
|
|
934
|
-
theme={theme()}
|
|
935
|
-
label='Mode'
|
|
936
|
-
value={state().fastMode ? 'fast' : 'std'}
|
|
937
|
-
tone={state().fastMode ? 'accent' : 'muted'}
|
|
938
|
-
/>
|
|
939
|
-
<StatRow
|
|
940
|
-
theme={theme()}
|
|
941
|
-
label='Relay'
|
|
942
|
-
value={relayValue()}
|
|
943
|
-
tone={state().relay?.enabled ? 'ok' : 'muted'}
|
|
944
|
-
/>
|
|
945
|
-
</Show>
|
|
946
973
|
|
|
947
|
-
|
|
948
|
-
{(
|
|
974
|
+
{/* Routing */}
|
|
975
|
+
<Show when={prefs().sections.routing}>
|
|
976
|
+
<SectionHeader theme={theme()} title='Routing' />
|
|
949
977
|
<StatRow
|
|
950
978
|
theme={theme()}
|
|
951
|
-
label='
|
|
952
|
-
value={
|
|
953
|
-
tone=
|
|
979
|
+
label='Route'
|
|
980
|
+
value={state().route}
|
|
981
|
+
tone='accent'
|
|
982
|
+
/>
|
|
983
|
+
<StatRow
|
|
984
|
+
theme={theme()}
|
|
985
|
+
label='Mode'
|
|
986
|
+
value={state().fastMode ? 'fast' : 'std'}
|
|
987
|
+
tone={state().fastMode ? 'accent' : 'muted'}
|
|
954
988
|
/>
|
|
955
|
-
)}
|
|
956
|
-
</Show>
|
|
957
|
-
|
|
958
|
-
{/* Cache */}
|
|
959
|
-
<Show when={showCache()}>
|
|
960
|
-
<SectionHeader theme={theme()} title='Cache' />
|
|
961
|
-
<StatRow
|
|
962
|
-
theme={theme()}
|
|
963
|
-
label='1h cache'
|
|
964
|
-
value={`${cacheKeep()?.window} \u00b7 ${cacheKeep()?.enabled ? 'on' : 'off'}`}
|
|
965
|
-
tone={cacheKeep()?.enabled ? 'ok' : 'muted'}
|
|
966
|
-
/>
|
|
967
|
-
<Show when={(cacheKeep()?.trackedSessions ?? 0) > 0}>
|
|
968
989
|
<StatRow
|
|
969
990
|
theme={theme()}
|
|
970
|
-
label='
|
|
971
|
-
value={
|
|
972
|
-
tone='
|
|
991
|
+
label='Relay'
|
|
992
|
+
value={relayValue()}
|
|
993
|
+
tone={state().relay?.enabled ? 'ok' : 'muted'}
|
|
973
994
|
/>
|
|
974
995
|
</Show>
|
|
975
|
-
</Show>
|
|
976
996
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
const value = () => formatPrimeAccountValue(account, now())
|
|
988
|
-
return (
|
|
989
|
-
<StatRow
|
|
990
|
-
theme={theme()}
|
|
991
|
-
label={account.label}
|
|
992
|
-
value={value().text}
|
|
993
|
-
tone={value().hasError ? 'warn' : 'text'}
|
|
994
|
-
/>
|
|
995
|
-
)
|
|
996
|
-
}}
|
|
997
|
-
</For>
|
|
998
|
-
</Show>
|
|
997
|
+
<Show when={fableRecoverySummary()}>
|
|
998
|
+
{(summary: () => string) => (
|
|
999
|
+
<StatRow
|
|
1000
|
+
theme={theme()}
|
|
1001
|
+
label='Recovery'
|
|
1002
|
+
value={summary()}
|
|
1003
|
+
tone={fableRecoveryTone()}
|
|
1004
|
+
/>
|
|
1005
|
+
)}
|
|
1006
|
+
</Show>
|
|
999
1007
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
<Show when={quotaBackedOff()}>
|
|
1008
|
+
{/* Cache */}
|
|
1009
|
+
<Show when={showCache()}>
|
|
1010
|
+
<SectionHeader theme={theme()} title='Cache' />
|
|
1004
1011
|
<StatRow
|
|
1005
1012
|
theme={theme()}
|
|
1006
|
-
label='
|
|
1007
|
-
value={
|
|
1008
|
-
tone='
|
|
1013
|
+
label='1h cache'
|
|
1014
|
+
value={`${cacheKeep()?.window} \u00b7 ${cacheKeep()?.enabled ? 'on' : 'off'}`}
|
|
1015
|
+
tone={cacheKeep()?.enabled ? 'ok' : 'muted'}
|
|
1009
1016
|
/>
|
|
1017
|
+
<Show when={(cacheKeep()?.trackedSessions ?? 0) > 0}>
|
|
1018
|
+
<StatRow
|
|
1019
|
+
theme={theme()}
|
|
1020
|
+
label='Tracked'
|
|
1021
|
+
value={String(cacheKeep()?.trackedSessions)}
|
|
1022
|
+
tone='text'
|
|
1023
|
+
/>
|
|
1024
|
+
</Show>
|
|
1010
1025
|
</Show>
|
|
1011
|
-
|
|
1026
|
+
|
|
1027
|
+
{/* Prime — only when enabled. Expanded view only (no collapsed surface). */}
|
|
1028
|
+
<Show when={showPrime()}>
|
|
1012
1029
|
<StatRow
|
|
1013
1030
|
theme={theme()}
|
|
1014
|
-
label='
|
|
1015
|
-
value={
|
|
1016
|
-
tone='warn'
|
|
1031
|
+
label='Prime'
|
|
1032
|
+
value={primeHasError() ? 'err' : 'on'}
|
|
1033
|
+
tone={primeHasError() ? 'warn' : 'ok'}
|
|
1017
1034
|
/>
|
|
1035
|
+
<For each={prime()?.accounts ?? []}>
|
|
1036
|
+
{(account) => {
|
|
1037
|
+
const value = () => formatPrimeAccountValue(account, now())
|
|
1038
|
+
return (
|
|
1039
|
+
<StatRow
|
|
1040
|
+
theme={theme()}
|
|
1041
|
+
label={account.label}
|
|
1042
|
+
value={value().text}
|
|
1043
|
+
tone={value().hasError ? 'warn' : 'text'}
|
|
1044
|
+
/>
|
|
1045
|
+
)
|
|
1046
|
+
}}
|
|
1047
|
+
</For>
|
|
1018
1048
|
</Show>
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1049
|
+
|
|
1050
|
+
{/* Health — only when something is wrong */}
|
|
1051
|
+
<Show when={degraded() && prefs().sections.health}>
|
|
1052
|
+
<SectionHeader theme={theme()} title='Health' />
|
|
1053
|
+
<Show when={quotaBackedOff()}>
|
|
1054
|
+
<StatRow
|
|
1055
|
+
theme={theme()}
|
|
1056
|
+
label='Quota API'
|
|
1057
|
+
value={`backoff ${formatUntil(state().main?.quotaBackoffUntil, now())}`}
|
|
1058
|
+
tone='warn'
|
|
1059
|
+
/>
|
|
1060
|
+
</Show>
|
|
1061
|
+
<Show when={refreshBackedOff()}>
|
|
1062
|
+
<StatRow
|
|
1063
|
+
theme={theme()}
|
|
1064
|
+
label='Token refresh'
|
|
1065
|
+
value={`backoff ${formatUntil(state().main?.refreshBackoffUntil, now())}`}
|
|
1066
|
+
tone='warn'
|
|
1067
|
+
/>
|
|
1068
|
+
</Show>
|
|
1069
|
+
</Show>
|
|
1070
|
+
</>
|
|
1071
|
+
)}
|
|
1072
|
+
/>
|
|
1022
1073
|
)
|
|
1023
1074
|
}
|
|
1024
1075
|
|