@cortexkit/opencode-anthropic-auth 1.13.0 → 1.15.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.
@@ -27,6 +27,13 @@ export interface SidebarAccountState {
27
27
  needsReauth: boolean
28
28
  }
29
29
 
30
+ export interface FableRecoverySidebarState {
31
+ sessionId: string
32
+ mode: 'opus' | 'fable'
33
+ remaining: number
34
+ changedAt: number
35
+ }
36
+
30
37
  export interface SidebarState {
31
38
  main: {
32
39
  quota: AccountQuota | null
@@ -45,6 +52,7 @@ export interface SidebarState {
45
52
  window?: string
46
53
  trackedSessions?: number
47
54
  }
55
+ fableRecoveries?: FableRecoverySidebarState[]
48
56
  lastUpdated: number
49
57
  }
50
58
 
@@ -121,7 +129,11 @@ function normalizeAccountQuota(value: unknown): AccountQuota | null {
121
129
  }
122
130
  })
123
131
  .filter((entry): entry is ScopedQuotaWindow => entry != null)
124
- if (scoped.length) quota.scoped = scoped
132
+ // Preserve empty `[]` so a sidebar reader can distinguish "scoped owned
133
+ // by anthropic-auth, none visible" from "no quota data at all". The OUTER
134
+ // Array.isArray guard means pre-feature inputs without a `scoped` key are
135
+ // not affected — only inputs that already carried an array reach this line.
136
+ quota.scoped = scoped
125
137
  }
126
138
 
127
139
  return Object.keys(quota).length ? quota : null
@@ -181,6 +193,32 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
181
193
  }
182
194
  }
183
195
 
196
+ const fableRecoveries: FableRecoverySidebarState[] = Array.isArray(
197
+ raw.fableRecoveries,
198
+ )
199
+ ? raw.fableRecoveries
200
+ .filter(isRecord)
201
+ .flatMap((recovery): FableRecoverySidebarState[] => {
202
+ if (
203
+ typeof recovery.sessionId !== 'string' ||
204
+ (recovery.mode !== 'opus' && recovery.mode !== 'fable') ||
205
+ typeof recovery.remaining !== 'number' ||
206
+ !Number.isFinite(recovery.remaining) ||
207
+ typeof recovery.changedAt !== 'number' ||
208
+ !Number.isFinite(recovery.changedAt)
209
+ )
210
+ return []
211
+ return [
212
+ {
213
+ sessionId: recovery.sessionId,
214
+ mode: recovery.mode,
215
+ remaining: Math.max(0, Math.floor(recovery.remaining)),
216
+ changedAt: recovery.changedAt,
217
+ },
218
+ ]
219
+ })
220
+ : []
221
+
184
222
  return {
185
223
  main,
186
224
  fallbacks,
@@ -193,6 +231,7 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
193
231
  ? raw.fastMode
194
232
  : DEFAULT_SIDEBAR_STATE.fastMode,
195
233
  cacheKeep,
234
+ fableRecoveries: fableRecoveries.length > 0 ? fableRecoveries : undefined,
196
235
  lastUpdated: typeof raw.lastUpdated === 'number' ? raw.lastUpdated : 0,
197
236
  }
198
237
  }
@@ -261,6 +300,18 @@ export function formatScopedQuotaLabel(title: string) {
261
300
  return /^fable$/i.test(label) ? 'Fa' : label
262
301
  }
263
302
 
303
+ export function getFableRecoverySummary(
304
+ state: SidebarState,
305
+ sessionId: string,
306
+ ): string | undefined {
307
+ const recovery = state.fableRecoveries?.find(
308
+ (candidate) => candidate.sessionId === sessionId,
309
+ )
310
+ if (!recovery) return undefined
311
+ if (recovery.mode === 'fable') return 'Fable 5 · restored'
312
+ return `Opus 4.8 · ${recovery.remaining} left`
313
+ }
314
+
264
315
  export function getCollapsedQuotaSummary(quota: AccountQuota | null): {
265
316
  fiveHourUsedPercent: number | null
266
317
  sevenDayUsedPercent: number | null
@@ -284,18 +335,23 @@ export function getCollapsedQuotaSummary(quota: AccountQuota | null): {
284
335
  }
285
336
  }
286
337
 
338
+ const scopedSegments = scoped.map(
339
+ (window) =>
340
+ `${formatScopedQuotaLabel(window.title)}: ${Math.round(window.usedPercent)}%`,
341
+ )
342
+ const primarySegments =
343
+ fiveHourUsedPercent == null && sevenDayUsedPercent == null
344
+ ? []
345
+ : [
346
+ `5h: ${fiveHourUsedPercent == null ? '—' : `${Math.round(fiveHourUsedPercent)}%`}`,
347
+ `7d: ${sevenDayUsedPercent == null ? '—' : `${Math.round(sevenDayUsedPercent)}%`}`,
348
+ ]
349
+
287
350
  return {
288
351
  fiveHourUsedPercent,
289
352
  sevenDayUsedPercent,
290
353
  scopedUsedPercents,
291
- text: [
292
- `5h: ${fiveHourUsedPercent == null ? '—' : `${Math.round(fiveHourUsedPercent)}%`}`,
293
- `7d: ${sevenDayUsedPercent == null ? '—' : `${Math.round(sevenDayUsedPercent)}%`}`,
294
- ...scoped.map(
295
- (window) =>
296
- `${formatScopedQuotaLabel(window.title)}: ${Math.round(window.usedPercent)}%`,
297
- ),
298
- ].join(' '),
354
+ text: [...primarySegments, ...scopedSegments].join(' '),
299
355
  }
300
356
  }
301
357
 
package/src/tui.tsx CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  FIVE_HOUR_MS,
26
26
  formatScopedQuotaLabel,
27
27
  getCollapsedQuotaSummary,
28
+ getFableRecoverySummary,
28
29
  getSidebarState,
29
30
  type QuotaPacing,
30
31
  resolveActiveAccount,
@@ -501,6 +502,7 @@ function createSidebarController(
501
502
  function QuotaSidebar(props: {
502
503
  api: TuiPluginApi
503
504
  controller: SidebarController
505
+ sessionId: string
504
506
  }) {
505
507
  const prefs = props.controller.prefs
506
508
  const collapsed = props.controller.collapsed
@@ -604,6 +606,14 @@ function QuotaSidebar(props: {
604
606
  const needsReauth = () => enabledFallbacks().some((f) => f.needsReauth)
605
607
  const degraded = () => quotaBackedOff() || refreshBackedOff() || needsReauth()
606
608
 
609
+ const fableRecoverySummary = () =>
610
+ getFableRecoverySummary(state(), props.sessionId)
611
+ const fableRecoveryTone = (): Tone =>
612
+ state().fableRecoveries?.find(
613
+ (recovery) => recovery.sessionId === props.sessionId,
614
+ )?.mode === 'opus'
615
+ ? 'warn'
616
+ : 'ok'
607
617
  const cacheKeep = () => state().cacheKeep
608
618
  const showCache = () =>
609
619
  prefs().sections.cache && cacheKeep() != null && cacheKeep()?.window != null
@@ -679,6 +689,15 @@ function QuotaSidebar(props: {
679
689
  </text>
680
690
  </CollapsedRow>
681
691
  </Show>
692
+ <Show when={fableRecoverySummary()}>
693
+ {(summary: () => string) => (
694
+ <CollapsedRow theme={theme()} label='Recovery'>
695
+ <text fg={toneColor(theme(), fableRecoveryTone())}>
696
+ <b>{summary()}</b>
697
+ </text>
698
+ </CollapsedRow>
699
+ )}
700
+ </Show>
682
701
  </Show>
683
702
 
684
703
  {/* Expanded: full sections. Also render when there's no data so the
@@ -745,6 +764,17 @@ function QuotaSidebar(props: {
745
764
  />
746
765
  </Show>
747
766
 
767
+ <Show when={fableRecoverySummary()}>
768
+ {(summary: () => string) => (
769
+ <StatRow
770
+ theme={theme()}
771
+ label='Recovery'
772
+ value={summary()}
773
+ tone={fableRecoveryTone()}
774
+ />
775
+ )}
776
+ </Show>
777
+
748
778
  {/* Cache */}
749
779
  <Show when={showCache()}>
750
780
  <SectionHeader theme={theme()} title='Cache' />
@@ -795,8 +825,14 @@ const tui: TuiPlugin = async (api) => {
795
825
  api.slots.register({
796
826
  order: computeEffectiveOrder(root, PLUGIN_KEY, DEFAULT_SLOT_ORDER),
797
827
  slots: {
798
- sidebar_content(_ctx: unknown, _props: { session_id: string }) {
799
- return <QuotaSidebar api={api} controller={controller} />
828
+ sidebar_content(_ctx: unknown, props: { session_id: string }) {
829
+ return (
830
+ <QuotaSidebar
831
+ api={api}
832
+ controller={controller}
833
+ sessionId={props.session_id}
834
+ />
835
+ )
800
836
  },
801
837
  },
802
838
  })