@cortexkit/opencode-anthropic-auth 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +35 -845
  2. package/dist/cli-failure.d.ts +6 -5
  3. package/dist/cli.js +57 -103
  4. package/dist/custody-mode.d.ts +1 -0
  5. package/dist/{index-52r2e1h9.js → index-5hyennzm.js} +1 -1
  6. package/dist/{index-p4wvcwhh.js → index-fncp6r0j.js} +1 -1
  7. package/dist/index-jmjevtm1.js +2 -0
  8. package/dist/index-kd89hcr3.js +2 -0
  9. package/dist/index-mdpyfkv3.js +464 -0
  10. package/dist/index-nfcp0m1t.js +42 -0
  11. package/dist/index-qttfa42y.js +2 -0
  12. package/dist/{index-3xqv3rw3.js → index-rftced5v.js} +1 -1
  13. package/dist/{index-zdgceztz.js → index-vjehtqnb.js} +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/quota-preflight.d.ts +1 -0
  16. package/dist/rpc/port-file.js +1 -1
  17. package/dist/rpc/protocol.js +1 -1
  18. package/dist/rpc/rpc-client.js +1 -1
  19. package/dist/rpc/rpc-dir.js +1 -1
  20. package/dist/setup/command.d.ts +5 -14
  21. package/dist/setup/native-activation.d.ts +14 -6
  22. package/dist/setup/native-enrollment.d.ts +15 -0
  23. package/dist/setup/native-local.d.ts +31 -1
  24. package/dist/setup/process-fence.d.ts +0 -6
  25. package/dist/setup/types.d.ts +9 -0
  26. package/dist/sidebar-state.d.ts +20 -2
  27. package/dist/sidebar-state.js +1 -1
  28. package/dist/transform.d.ts +17 -2
  29. package/dist/tui-preferences.js +1 -1
  30. package/dist/tui.d.ts +0 -2
  31. package/dist/v2/activation.d.ts +2 -0
  32. package/dist/v2/adapter.d.ts +8 -2
  33. package/dist/v2/cachekeep.d.ts +19 -0
  34. package/dist/v2/menu.d.ts +2 -1
  35. package/dist/v2/server.js +4 -4
  36. package/dist/v2/setup.d.ts +2 -0
  37. package/dist/v2/source.d.ts +1 -0
  38. package/dist/v2/tui.js +1 -1
  39. package/package.json +5 -5
  40. package/src/sidebar-state.ts +165 -29
  41. package/src/tui-compiled/sidebar-state.ts +165 -29
  42. package/src/tui-compiled/tui.tsx +363 -239
  43. package/src/tui.tsx +149 -48
  44. package/dist/index-04syas8a.js +0 -2
  45. package/dist/index-b3mxpp4w.js +0 -2
  46. package/dist/index-ynq181e8.js +0 -42
  47. package/dist/index-yxtdke11.js +0 -449
  48. package/dist/setup/activation.d.ts +0 -7
  49. package/dist/setup/command.test.d.ts +0 -1
  50. package/dist/setup/detect.d.ts +0 -8
  51. package/dist/setup/host-executable.d.ts +0 -3
  52. package/dist/setup/jsonc.d.ts +0 -9
  53. package/dist/setup/opencode-config.d.ts +0 -18
  54. package/dist/setup/pi.d.ts +0 -18
package/src/tui.tsx CHANGED
@@ -3,12 +3,17 @@
3
3
  import { readFileSync } from 'node:fs'
4
4
  import { dirname, join } from 'node:path'
5
5
  import { fileURLToPath } from 'node:url'
6
- import { formatQuotaMoney } from '@cortexkit/anthropic-auth-core'
6
+ import {
7
+ type QuotaWindowPart,
8
+ quotaDisplayProjection,
9
+ quotaWindowParts,
10
+ } from '@cortexkit/anthropic-auth-core'
7
11
  import type {
8
12
  TuiPlugin,
9
13
  TuiPluginApi,
10
14
  TuiPluginModule,
11
15
  } from '@opencode-ai/plugin/tui'
16
+ import { type BoxRenderable, TextAttributes } from '@opentui/core'
12
17
  import {
13
18
  createEffect,
14
19
  createSignal,
@@ -25,7 +30,8 @@ import {
25
30
  DEFAULT_SIDEBAR_STATE,
26
31
  FIVE_HOUR_MS,
27
32
  formatPrimeAccountValue,
28
- formatScopedQuotaLabel,
33
+ formatQuotaRowLabel,
34
+ getCollapsedAccounts,
29
35
  getCollapsedQuotaSummary,
30
36
  getFableRecoverySummary,
31
37
  getSidebarState,
@@ -232,7 +238,60 @@ function CollapsedRow(props: {
232
238
  )
233
239
  }
234
240
 
235
- // Quota window row: muted label left, tone-colored bar + percentage right,
241
+ function CollapsedAccountRow(props: {
242
+ theme: ThemeCurrent
243
+ account: ReturnType<typeof getCollapsedAccounts>[number]
244
+ tone: Tone
245
+ }) {
246
+ const [width, setWidth] = createSignal(40)
247
+ let row: BoxRenderable | undefined
248
+ const summary = () => getCollapsedQuotaSummary(props.account.quota)
249
+ const value = () => summary().text ?? '—'
250
+ const labelWidth = () => Math.max(0, width() - Bun.stringWidth(value()) - 1)
251
+ const dim = () =>
252
+ !props.account.active || props.account.quotaDated || summary().stale
253
+ const attributes = () => (dim() ? TextAttributes.DIM : TextAttributes.BOLD)
254
+ const color = () =>
255
+ dim() ? props.theme.textMuted : toneColor(props.theme, props.tone)
256
+ return (
257
+ <box
258
+ width='100%'
259
+ height={1}
260
+ flexDirection='row'
261
+ ref={(element: BoxRenderable) => {
262
+ row = element
263
+ setWidth(element.width || 40)
264
+ }}
265
+ onSizeChange={() => setWidth(row?.width || 40)}
266
+ >
267
+ <Show when={labelWidth() > 0}>
268
+ <text
269
+ width={labelWidth()}
270
+ flexShrink={0}
271
+ wrapMode='none'
272
+ fg={color()}
273
+ attributes={attributes()}
274
+ >
275
+ {formatQuotaRowLabel(props.account.name, labelWidth())}
276
+ </text>
277
+ <text width={1} flexShrink={0}>
278
+ {' '}
279
+ </text>
280
+ </Show>
281
+ <text
282
+ width={Bun.stringWidth(value())}
283
+ flexShrink={0}
284
+ wrapMode='none'
285
+ fg={color()}
286
+ attributes={attributes()}
287
+ >
288
+ {value()}
289
+ </text>
290
+ </box>
291
+ )
292
+ }
293
+
294
+ // Quota window row: muted label left, tone-colored bar + shared figure right,
236
295
  // with an optional muted reset suffix. When pacing data is present, the bar
237
296
  // gains a pace segment and an off-pace window adds a muted subline with the
238
297
  // reserve/deficit delta and the projected runout.
@@ -240,12 +299,13 @@ function QuotaRow(props: {
240
299
  theme: ThemeCurrent
241
300
  appearance: AppearancePrefs
242
301
  label: string
243
- window: { usedPercent: number; resetsAt?: string } | undefined
302
+ part: QuotaWindowPart | undefined
303
+ usedPercent: number | undefined
244
304
  pacing: QuotaPacing | null
245
305
  binding?: boolean
246
306
  }) {
247
- const used = () => props.window?.usedPercent ?? 0
248
- const reset = () => formatResetIn(props.window?.resetsAt)
307
+ const used = () => props.usedPercent ?? 0
308
+ const reset = () => props.part?.resetIn
249
309
  const paceLine = () => {
250
310
  const pacing = props.pacing
251
311
  if (!pacing || pacing.state === 'on-pace') return null
@@ -257,20 +317,24 @@ function QuotaRow(props: {
257
317
  }
258
318
  return (
259
319
  <Show
260
- when={props.window}
320
+ when={props.part}
261
321
  fallback={
262
322
  <box width='100%' flexDirection='row'>
263
- <text fg={props.theme.textMuted}>{props.label.padEnd(3)}</text>
323
+ <text
324
+ fg={props.theme.textMuted}
325
+ >{`${formatQuotaRowLabel(props.label)} `}</text>
264
326
  <text fg={props.theme.textMuted}>{'\u2014'}</text>
265
327
  </box>
266
328
  }
267
329
  >
268
- {/* Left group (label · bar · pct) stays left-aligned in fixed columns so
269
- bars and percentages line up across rows; the reset time is pushed to
330
+ {/* Left group (label · bar · figure) stays left-aligned in fixed columns so
331
+ bars and figures line up across rows; the reset time is pushed to
270
332
  the right edge so reset times align in their own right column. */}
271
333
  <box width='100%' flexDirection='row' justifyContent='space-between'>
272
334
  <box flexDirection='row'>
273
- <text fg={props.theme.textMuted}>{props.label.padEnd(3)}</text>
335
+ <text
336
+ fg={props.theme.textMuted}
337
+ >{`${formatQuotaRowLabel(props.label)} `}</text>
274
338
  <For each={quotaBarSegments(used(), props.appearance, props.pacing)}>
275
339
  {(segment) => (
276
340
  <text fg={toneColor(props.theme, segment.tone)}>
@@ -281,7 +345,7 @@ function QuotaRow(props: {
281
345
  <text
282
346
  fg={toneColor(props.theme, usageTone(used(), props.appearance))}
283
347
  >
284
- {` ${String(Math.round(used())).padStart(3)}%${props.binding ? ' •' : ''}`}
348
+ {` ${props.part?.figure}${props.binding ? ' •' : ''}`}
285
349
  </text>
286
350
  </box>
287
351
  <Show when={reset()}>
@@ -290,7 +354,7 @@ function QuotaRow(props: {
290
354
  </box>
291
355
  <Show when={paceLine()}>
292
356
  <box width='100%' flexDirection='row'>
293
- <text fg={props.theme.textMuted}>{' '}</text>
357
+ <text fg={props.theme.textMuted}>{formatQuotaRowLabel('', 11)}</text>
294
358
  <text
295
359
  fg={toneColor(
296
360
  props.theme,
@@ -317,19 +381,23 @@ function AccountBlock(props: {
317
381
  pacingEnabled: boolean
318
382
  needsReauth?: boolean
319
383
  vaultReauth?: boolean
384
+ stateLine?: string
385
+ quotaDated?: boolean
320
386
  tierLabel?: string
321
387
  marginTop?: number
322
388
  }) {
323
389
  const statusWord = () =>
324
- props.needsReauth
325
- ? 're-login'
326
- : props.vaultReauth
327
- ? 'vault reauth'
328
- : props.active
329
- ? 'active'
330
- : 'idle'
390
+ props.quotaDated && props.quota
391
+ ? 'dated'
392
+ : props.needsReauth
393
+ ? 're-login'
394
+ : props.vaultReauth
395
+ ? 'needs sign-in in the vault'
396
+ : props.active
397
+ ? 'active'
398
+ : 'idle'
331
399
  const statusTone = (): Tone =>
332
- props.needsReauth || props.vaultReauth
400
+ props.needsReauth || props.vaultReauth || props.stateLine
333
401
  ? 'warn'
334
402
  : props.active
335
403
  ? 'ok'
@@ -340,9 +408,15 @@ function AccountBlock(props: {
340
408
  | undefined,
341
409
  windowMs: number,
342
410
  ) =>
343
- props.pacingEnabled && window
411
+ props.pacingEnabled && !props.quotaDated && window
344
412
  ? computeQuotaPacing(window, windowMs, Date.now())
345
413
  : null
414
+ const parts = () => {
415
+ const now = Date.now()
416
+ return quotaWindowParts(quotaDisplayProjection(props.quota, now), { now })
417
+ }
418
+ const partFor = (name: string) =>
419
+ parts().windows.find((part) => part.name === name)
346
420
  return (
347
421
  <box width='100%' flexDirection='column' marginTop={props.marginTop ?? 0}>
348
422
  <box width='100%' flexDirection='row' justifyContent='space-between'>
@@ -353,6 +427,9 @@ function AccountBlock(props: {
353
427
  <b>{statusWord()}</b>
354
428
  </text>
355
429
  </box>
430
+ <Show when={props.stateLine}>
431
+ <text fg={props.theme.textMuted}>{props.stateLine}</text>
432
+ </Show>
356
433
  <Show
357
434
  when={props.quota}
358
435
  fallback={<text fg={props.theme.textMuted}>{'checking\u2026'}</text>}
@@ -361,7 +438,8 @@ function AccountBlock(props: {
361
438
  theme={props.theme}
362
439
  appearance={props.appearance}
363
440
  label='5h'
364
- window={props.quota?.five_hour}
441
+ part={partFor('5h')}
442
+ usedPercent={props.quota?.five_hour?.usedPercent}
365
443
  pacing={pacingFor(props.quota?.five_hour, FIVE_HOUR_MS)}
366
444
  binding={props.quota?.bindingWindow === 'five_hour'}
367
445
  />
@@ -369,7 +447,8 @@ function AccountBlock(props: {
369
447
  theme={props.theme}
370
448
  appearance={props.appearance}
371
449
  label='7d'
372
- window={props.quota?.seven_day}
450
+ part={partFor('7d')}
451
+ usedPercent={props.quota?.seven_day?.usedPercent}
373
452
  pacing={pacingFor(props.quota?.seven_day, SEVEN_DAY_MS)}
374
453
  binding={props.quota?.bindingWindow === 'seven_day'}
375
454
  />
@@ -378,30 +457,34 @@ function AccountBlock(props: {
378
457
  <QuotaRow
379
458
  theme={props.theme}
380
459
  appearance={props.appearance}
381
- label={formatScopedQuotaLabel(window.title)}
382
- window={window}
460
+ label={partFor(window.title)?.name ?? window.title}
461
+ part={partFor(window.title)}
462
+ usedPercent={window.usedPercent}
383
463
  pacing={pacingFor(window, SEVEN_DAY_MS)}
384
464
  binding={props.quota?.bindingWindow === window.id}
385
465
  />
386
466
  )}
387
467
  </For>
388
- <Show when={props.quota?.extraUsage}>
389
- {(extraUsage: () => NonNullable<AccountQuota['extraUsage']>) => (
468
+ <Show when={partFor('credits')}>
469
+ {(budget: () => QuotaWindowPart) => (
390
470
  <text
391
471
  fg={toneColor(
392
472
  props.theme,
393
- extraUsage().severity === 'critical'
473
+ props.quota?.extraUsage?.severity === 'critical'
394
474
  ? 'err'
395
- : extraUsage().severity === 'warning' ||
396
- extraUsage().exhausted
475
+ : props.quota?.extraUsage?.severity === 'warning' ||
476
+ props.quota?.extraUsage?.exhausted
397
477
  ? 'warn'
398
478
  : 'muted',
399
479
  )}
400
480
  >
401
- {`credits ${formatQuotaMoney(extraUsage().used)}/${formatQuotaMoney(extraUsage().limit)}${extraUsage().exhausted ? ' · exhausted' : ''}`}
481
+ {budget().figure}
402
482
  </text>
403
483
  )}
404
484
  </Show>
485
+ <Show when={parts().age}>
486
+ <text fg={props.theme.textMuted}>{parts().age}</text>
487
+ </Show>
405
488
  <Show when={props.quota?.fallbackAdvised === true}>
406
489
  <text fg={props.theme.textMuted}>{'→ fallback advised'}</text>
407
490
  </Show>
@@ -410,8 +493,6 @@ function AccountBlock(props: {
410
493
  )
411
494
  }
412
495
 
413
- export { formatQuotaMoney }
414
-
415
496
  // --- Quota dialog content ---------------------------------------------------
416
497
 
417
498
  // Renders the same rich visualization as the sidebar (account blocks with
@@ -437,7 +518,9 @@ function QuotaDialogContent(props: {
437
518
  setTimeout(refresh, 0)
438
519
  const theme = () => props.api.theme.current
439
520
  const enabledFallbacks = () =>
440
- (state().fallbacks ?? []).filter((f) => f.enabled)
521
+ (state().fallbacks ?? []).filter(
522
+ (f) => f.enabled || (f.custodyState && f.custodyState !== 'off'),
523
+ )
441
524
  return (
442
525
  <box flexDirection='column' padding={2} width='100%' alignItems='center'>
443
526
  <box flexDirection='column' width={58}>
@@ -454,6 +537,8 @@ function QuotaDialogContent(props: {
454
537
  active={state().activeId === 'main'}
455
538
  pacingEnabled={prefs().sections.pacing}
456
539
  tierLabel={state().main?.tierLabel}
540
+ stateLine={state().main?.stateLine}
541
+ quotaDated={state().main?.quotaDated}
457
542
  />
458
543
  <Show when={prefs().sections.fallbackAccounts}>
459
544
  <For each={enabledFallbacks()}>
@@ -467,6 +552,9 @@ function QuotaDialogContent(props: {
467
552
  pacingEnabled={prefs().sections.pacing}
468
553
  tierLabel={fb.tierLabel}
469
554
  needsReauth={fb.needsReauth}
555
+ vaultReauth={fb.vaultReauth}
556
+ stateLine={fb.stateLine}
557
+ quotaDated={fb.quotaDated}
470
558
  marginTop={1}
471
559
  />
472
560
  )}
@@ -594,9 +682,13 @@ function QuotaSidebar(props: {
594
682
 
595
683
  const theme = () => props.api.theme.current
596
684
  const enabledFallbacks = () =>
597
- (state().fallbacks ?? []).filter((f) => f.enabled)
685
+ (state().fallbacks ?? []).filter(
686
+ (f) => f.enabled || (f.custodyState && f.custodyState !== 'off'),
687
+ )
598
688
  const hasData = () =>
599
- state().main?.quota != null || enabledFallbacks().length > 0
689
+ state().main?.quota != null ||
690
+ state().main?.stateLine != null ||
691
+ enabledFallbacks().length > 0
600
692
 
601
693
  const headerLabel = () => {
602
694
  const name = prefs().header.label
@@ -607,6 +699,7 @@ function QuotaSidebar(props: {
607
699
  getCollapsedQuotaSummary(activeAccount().quota)
608
700
  const activePacingDeficit = () => {
609
701
  if (!prefs().sections.pacing) return false
702
+ if (activeAccount().quotaDated) return null
610
703
  const quota = activeAccount().quota
611
704
  if (!quota) return false
612
705
  const now = Date.now()
@@ -724,18 +817,22 @@ function QuotaSidebar(props: {
724
817
  </Show>
725
818
  </box>
726
819
 
727
- {/* Collapsed: active account 5h + 7d quota, plus fast-mode when on */}
820
+ {/* Collapsed accounts keep placement order; only a fresh active row is emphasized. */}
728
821
  <Show when={collapsed() && hasData()}>
729
- <CollapsedRow theme={theme()} label={activeAccount().name}>
730
- <Show
731
- when={activeQuotaSummary().text != null}
732
- fallback={<text fg={theme().textMuted}>{'\u2014'}</text>}
733
- >
734
- <text fg={toneColor(theme(), activeQuotaTone())}>
735
- <b>{activeQuotaSummary().text}</b>
736
- </text>
737
- </Show>
738
- </CollapsedRow>
822
+ <For
823
+ each={getCollapsedAccounts(
824
+ state(),
825
+ prefs().sections.fallbackAccounts,
826
+ )}
827
+ >
828
+ {(account) => (
829
+ <CollapsedAccountRow
830
+ theme={theme()}
831
+ account={account}
832
+ tone={activeQuotaTone()}
833
+ />
834
+ )}
835
+ </For>
739
836
  <Show when={state().fastMode}>
740
837
  <CollapsedRow theme={theme()} label='Mode'>
741
838
  <text fg={toneColor(theme(), 'accent')}>
@@ -776,6 +873,8 @@ function QuotaSidebar(props: {
776
873
  active={state().activeId === 'main'}
777
874
  pacingEnabled={prefs().sections.pacing}
778
875
  tierLabel={state().main?.tierLabel}
876
+ stateLine={state().main?.stateLine}
877
+ quotaDated={state().main?.quotaDated}
779
878
  />
780
879
  <Show when={prefs().sections.fallbackAccounts}>
781
880
  <For each={enabledFallbacks()}>
@@ -790,6 +889,8 @@ function QuotaSidebar(props: {
790
889
  tierLabel={fb.tierLabel}
791
890
  needsReauth={fb.needsReauth}
792
891
  vaultReauth={fb.vaultReauth}
892
+ stateLine={fb.stateLine}
893
+ quotaDated={fb.quotaDated}
793
894
  marginTop={1}
794
895
  />
795
896
  )}
@@ -1,2 +0,0 @@
1
- import{zb as O}from"./index-yxtdke11.js";import{randomUUID as H}from"node:crypto";import{mkdir as g,readFile as F,rename as T,rm as z,rmdir as w,stat as P,unlink as y,writeFile as I}from"node:fs/promises";import{tmpdir as m}from"node:os";import{dirname as d,join as L}from"node:path";var v="OPENCODE_ANTHROPIC_AUTH_SIDEBAR_STATE_FILE",c=L(m(),"opencode-anthropic-auth"),u=L(c,"sidebar-state.json");function E(){return process.env[v]||u}var C={main:{quota:null},fallbacks:[],activeId:void 0,route:"main",relay:null,fastMode:!1,lastUpdated:0};function K(J){return J!==null&&typeof J==="object"&&!Array.isArray(J)}function W(J){return typeof J==="number"&&Number.isFinite(J)}function n(J){if(!K(J))return;let Z=Number(J.count),V=Number(J.inputTokens),x=Number(J.outputTokens),Y=Number(J.since);if(![Z,V,x,Y].every(Number.isFinite)||Z<0||V<0||x<0||Y<0)return;return{count:Math.floor(Z),inputTokens:Math.floor(V),outputTokens:Math.floor(x),since:Math.floor(Y)}}function i(J){if(!K(J))return;if(typeof J.id!=="string"||!J.id.trim())return;if(typeof J.label!=="string"||!J.label.trim())return;let Z={id:J.id.trim(),label:J.label.trim()};if(J.nextDueAt===null)Z.nextDueAt=null;else if(W(J.nextDueAt))Z.nextDueAt=J.nextDueAt;if(J.lastPrimedAt===null)Z.lastPrimedAt=null;else if(W(J.lastPrimedAt))Z.lastPrimedAt=J.lastPrimedAt;if(J.lastResult==="ok"||J.lastResult==="error"||J.lastResult==="skipped")Z.lastResult=J.lastResult;let V=n(J.usage);if(V)Z.usage=V;if(W(J.estimatedCostUsd))Z.estimatedCostUsd=J.estimatedCostUsd;return Z}function s(J){if(!K(J))return;if(typeof J.enabled!=="boolean")return;let Z=Array.isArray(J.accounts)?J.accounts.map(i).filter((V)=>V!=null):[];return{enabled:J.enabled,accounts:Z}}function h(J){if(!K(J))return;let Z=Number(J.usedPercent),V=Number(J.remainingPercent);if(!Number.isFinite(Z)||!Number.isFinite(V))return;return{usedPercent:Z,remainingPercent:V,resetsAt:typeof J.resetsAt==="string"?J.resetsAt:void 0}}function A(J){if(!K(J))return null;let Z={},V=h(J.five_hour),x=h(J.seven_day);if(V)Z.five_hour=V;if(x)Z.seven_day=x;if(Array.isArray(J.scoped)){let Y=J.scoped.map((X)=>{if(!K(X))return;let $=h(X);if(!$)return;if(typeof X.id!=="string"||!X.id.trim())return;if(typeof X.title!=="string"||!X.title.trim())return;if(typeof X.modelName!=="string"||!X.modelName.trim())return;let j=typeof X.modelId==="string"&&X.modelId.trim()?X.modelId.trim():void 0;return{...$,id:X.id.trim(),title:X.title.trim(),...j&&{modelId:j},modelName:X.modelName.trim()}}).filter((X)=>X!=null);Z.scoped=Y}if(K(J.extraUsage)){let Y=R(J.extraUsage.used),X=R(J.extraUsage.limit);if(Y&&X&&typeof J.extraUsage.exhausted==="boolean")Z.extraUsage={used:Y,limit:X,...typeof J.extraUsage.utilizationPercent==="number"&&Number.isFinite(J.extraUsage.utilizationPercent)&&{utilizationPercent:J.extraUsage.utilizationPercent},...typeof J.extraUsage.severity==="string"&&{severity:J.extraUsage.severity},exhausted:J.extraUsage.exhausted}}if(typeof J.bindingWindow==="string"&&J.bindingWindow.trim())Z.bindingWindow=J.bindingWindow.trim();if(typeof J.fallbackAdvised==="boolean")Z.fallbackAdvised=J.fallbackAdvised;return Object.keys(Z).length?Z:null}function R(J){if(!K(J))return;if(!Number.isInteger(J.amountMinor)||typeof J.currency!=="string"||!/^[A-Za-z]{3}$/.test(J.currency.trim())||!Number.isInteger(J.exponent)||J.exponent<0||J.exponent>20)return;return{amountMinor:J.amountMinor,currency:J.currency.trim(),exponent:J.exponent}}function p(J){if(!K(J))return{...C};let Z={quota:null};if(K(J.main)){let $=J.main;if(Z.quota=A($.quota),typeof $.tierLabel==="string"&&$.tierLabel.trim())Z.tierLabel=$.tierLabel.trim();if(typeof $.quotaBackedOff==="boolean")Z.quotaBackedOff=$.quotaBackedOff;if(typeof $.quotaBackoffUntil==="number")Z.quotaBackoffUntil=$.quotaBackoffUntil;if(typeof $.refreshBackedOff==="boolean")Z.refreshBackedOff=$.refreshBackedOff;if(typeof $.refreshBackoffUntil==="number")Z.refreshBackoffUntil=$.refreshBackoffUntil}let V=Array.isArray(J.fallbacks)?J.fallbacks.filter(K).filter(($)=>typeof $.id==="string").map(($)=>({id:$.id,label:typeof $.label==="string"?$.label:void 0,quota:A($.quota),enabled:typeof $.enabled==="boolean"?$.enabled:!1,needsReauth:typeof $.needsReauth==="boolean"?$.needsReauth:!1,...$.vaultReauth===!0&&{vaultReauth:!0},...$.vaultServed===!0&&{vaultServed:!0},...typeof $.custodyState==="string"&&{custodyState:$.custodyState},tierLabel:typeof $.tierLabel==="string"&&$.tierLabel.trim()?$.tierLabel.trim():void 0})):[],x=null;if(K(J.relay)){let $=J.relay;if(typeof $.enabled==="boolean"&&typeof $.transport==="string")x={enabled:$.enabled,transport:$.transport}}let Y;if(K(J.cacheKeep)){let $=J.cacheKeep;if(typeof $.enabled==="boolean")Y={enabled:$.enabled,window:typeof $.window==="string"?$.window:void 0,trackedSessions:typeof $.trackedSessions==="number"?$.trackedSessions:void 0}}let X=Array.isArray(J.fableRecoveries)?J.fableRecoveries.filter(K).flatMap(($)=>{if(typeof $.sessionId!=="string"||$.mode!=="opus"&&$.mode!=="fable"&&$.mode!=="server"||typeof $.remaining!=="number"||!Number.isFinite($.remaining)||typeof $.changedAt!=="number"||!Number.isFinite($.changedAt))return[];return[{sessionId:$.sessionId,mode:$.mode,remaining:Math.max(0,Math.floor($.remaining)),changedAt:$.changedAt,requestedModelId:typeof $.requestedModelId==="string"?$.requestedModelId:void 0,targetModelId:typeof $.targetModelId==="string"?$.targetModelId:void 0}]}):[];return{main:Z,fallbacks:V,activeId:typeof J.activeId==="string"?J.activeId:void 0,route:typeof J.route==="string"?J.route:C.route,relay:x,fastMode:typeof J.fastMode==="boolean"?J.fastMode:C.fastMode,cacheKeep:Y,prime:s(J.prime),fableRecoveries:X.length>0?X:void 0,lastUpdated:typeof J.lastUpdated==="number"?J.lastUpdated:0}}var q=Promise.resolve(),l=1000,o=2000,r=5,a=15,U=new Map;function QJ(J,Z=E()){if(J)U.set(Z,J);else U.delete(Z)}function M(J){return U.get(J)}var S=null;function BJ(J){S=J}function OJ(){return S}function t(J){return new Promise((Z)=>setTimeout(Z,J))}async function k(J){let Z=`${J}.lock`,V=M(J),x=V?.lockBudgetMs??l,Y=V?.lockRetryMinMs??r,X=V?.lockRetryMaxMs??a,$=Date.now()+x;while(!0){try{await g(Z);let G=H(),Q=L(Z,G);return await I(Q,"",{encoding:"utf8",mode:384,flag:"wx"}),await V?.onLockAcquired?.(Z),{ownsLock:async()=>{try{return await P(Q),!0}catch{return!1}},release:async()=>{try{await y(Q)}catch{return}await V?.beforeReleaseDirectoryRemoval?.(Z),await w(Z).catch(()=>{})}}}catch(G){if(G.code!=="EEXIST")return O.trace("sidebar","state lock unavailable; write skipped",{stateFile:J,error:G instanceof Error?G.message:String(G)}),null}try{let G=await P(Z);if(Date.now()-G.mtimeMs>o){await V?.afterStaleLockStat?.(Z);let Q=`${Z}.evict-${process.pid}-${H()}`;try{await T(Z,Q)}catch(N){if(N.code==="ENOENT")continue;throw N}await V?.onStaleLockClaimed?.(Z),await z(Q,{recursive:!0,force:!0}).catch(()=>{});continue}}catch(G){if(G.code==="ENOENT")continue;return O.trace("sidebar","state lock inspection failed; write skipped",{stateFile:J,error:G instanceof Error?G.message:String(G)}),null}let j=$-Date.now();if(j<=0)return O.warn("sidebar","lock budget exhausted, write skipped",{stateFile:J,budgetMs:x}),null;let B=Y+Math.floor(Math.random()*(X-Y+1));await t(Math.min(B,j))}}async function NJ(J){return(await k(J))?.release??null}async function e(J,Z,V){let x=M(J),Y=`${J}.${process.pid}.${H()}.tmp`;await I(Y,JSON.stringify(Z),{encoding:"utf8",mode:384});try{if(!await V())return O.trace("sidebar","state lock lost before rename; write aborted",{stateFile:J}),await z(Y,{force:!0}).catch(()=>{}),"lock-lost-before-rename";if(await x?.beforeRename?.(J,Y),!await V())return O.trace("sidebar","state lock lost before rename; write aborted",{stateFile:J}),await z(Y,{force:!0}).catch(()=>{}),"lock-lost-before-rename";if(await T(Y,J),await x?.afterRename?.(J),!await V())return"lock-lost-after-rename";return"written"}catch(X){throw await z(Y,{force:!0}).catch(()=>{}),X}}async function b(J=E()){try{let Z=await F(J,"utf8");return p(JSON.parse(Z))}catch{return C}}async function zJ(J,Z=E(),V={}){return q=q.then(async()=>{await g(d(Z),{recursive:!0});for(let x=0;x<2;x++){let Y=x===1,X=await k(Z);if(!X){if(Y)O.warn("sidebar","post-rename repair lock unavailable; write skipped",{stateFile:Z});return}let $=J,j;try{if(V.routingAuthoritative===!1){let B=await b(Z),G=await V.resolvePreservedRouting?.(B);if(G){let Q=G.state??J;$={...Q,activeId:G.activeId,route:G.route,lastUpdated:Math.max(Q.lastUpdated,B.lastUpdated)}}await M(Z)?.afterMergeRead?.(Z)}else if(Y){let B=await b(Z);$={...B,activeId:J.activeId,route:J.route,relay:J.relay,fastMode:J.fastMode,cacheKeep:J.cacheKeep,lastUpdated:Math.max(B.lastUpdated,J.lastUpdated)}}$=p($),j=await e(Z,$,X.ownsLock)}finally{await X.release()}if(j==="lock-lost-after-rename"){if(Y){O.warn("sidebar","post-rename repair lost lock; write skipped",{stateFile:Z});return}O.warn("sidebar","state lock lost after rename; repairing write",{stateFile:Z});continue}if(j==="lock-lost-before-rename")return;V.onRoutingResolved?.({activeId:$.activeId,route:$.route});return}}).catch(()=>{}),q}async function CJ(){return q}function qJ(J){let Z=J.activeId;if(Z&&Z!=="main"){let V=J.fallbacks?.find((x)=>x.enabled&&x.id===Z);if(V)return{id:V.id,name:V.label??V.id,quota:V.quota}}return{id:"main",name:"main",quota:J.main?.quota??null}}function JJ(J){let Z=J.replace(/\s+only$/i,"").trim();return/^fable$/i.test(Z)?"Fa":Z}function f(J){if(J==="claude-mythos-5-1"||J?.startsWith("claude-mythos-5-1-"))return"Mythos 5.1";if(J==="claude-fable-5-1"||J?.startsWith("claude-fable-5-1-"))return"Fable 5.1";if(J==="claude-fable-5"||J?.startsWith("claude-fable-5-"))return"Fable 5";if(J==="claude-opus-5-5"||J?.startsWith("claude-opus-5-5-"))return"Opus 5.5";if(J==="claude-opus-5"||J?.startsWith("claude-opus-5-"))return"Opus 5";if(J==="claude-opus-4-8"||J?.startsWith("claude-opus-4-8-"))return"Opus 4.8";return J??"Fable 5"}function D(J){return new Date(J).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function ZJ(J){if(J===0)return"0";if(J<0.0001)return J.toExponential(2);return J.toFixed(Math.min(6,Math.max(0,4)))}function WJ(J){if(J.lastResult==="error")return{text:"err",hasError:!0};if(J.lastResult==="skipped")return{text:"skip",hasError:!1};if(J.nextDueAt&&J.nextDueAt>Date.now())return{text:D(J.nextDueAt),hasError:!1};if(J.lastPrimedAt)return{text:`primed ${D(J.lastPrimedAt)} ✓`,hasError:!1};if(J.usage?.count)return{text:`✓ ${J.usage.count} ≈ $${ZJ(J.estimatedCostUsd??0)}`,hasError:!1};return{text:"—",hasError:!1}}function hJ(J,Z){let V=J.fableRecoveries?.find((x)=>x.sessionId===Z);if(!V)return;if(V.mode==="fable")return`${f(V.requestedModelId)} · restored`;if(V.mode==="server")return`${f(V.requestedModelId)}→${f(V.targetModelId)} · safety`;return`Opus 4.8 · ${V.remaining} left`}function fJ(J){let Z=J?.five_hour?.usedPercent??null,V=J?.seven_day?.usedPercent??null,x=J?.scoped??[],Y=x.map((j)=>j.usedPercent);if(Z==null&&V==null&&x.length===0)return{fiveHourUsedPercent:Z,sevenDayUsedPercent:V,scopedUsedPercents:Y,text:null};let X=x.map((j)=>`${JJ(j.title)}: ${Math.round(j.usedPercent)}%`),$=Z==null&&V==null?[]:[`5h: ${Z==null?"—":`${Math.round(Z)}%`}`,`7d: ${V==null?"—":`${Math.round(V)}%`}`];return{fiveHourUsedPercent:Z,sevenDayUsedPercent:V,scopedUsedPercents:Y,text:[...$,...X].join(" ")}}var HJ=18000000,UJ=604800000,$J=300000,VJ=0.01,XJ=1;function LJ(J,Z,V){if(!J.resetsAt)return null;let x=new Date(J.resetsAt).getTime();if(!Number.isFinite(x))return null;let Y=x-Z,X=V-Y;if(X<$J)return null;if(X<Z*VJ)return null;if(X>=Z)return null;let $=J.usedPercent,j=Math.min(Math.max(X/Z*100,0),100),B=$-j,G=Math.abs(B)<XJ?"on-pace":B>0?"deficit":"reserve",Q=null;if($>0){let N=X*100/$,_=Y+N;if(_<x)Q=new Date(_).toISOString()}return{pacePercent:j,deltaPercent:B,state:G,runsOutAt:Q}}
2
- export{E as F,C as G,p as H,QJ as I,BJ as J,OJ as K,NJ as L,b as M,zJ as N,CJ as O,qJ as P,JJ as Q,f as R,D as S,ZJ as T,WJ as U,hJ as V,fJ as W,HJ as X,UJ as Y,LJ as Z};
@@ -1,2 +0,0 @@
1
- import{existsSync as F,readFileSync as I}from"node:fs";import{homedir as J}from"node:os";import{dirname as X,join as B,resolve as V}from"node:path";import{fileURLToPath as Y}from"node:url";var Z="@cortexkit/opencode-anthropic-auth",L="@cortexkit/pi-anthropic-auth";function $(q=process.env,z=process.platform){return(z==="win32"?q.USERPROFILE||q.HOME:q.HOME)||J()}function K(q=process.env,z=process.platform){let w=q.OPENCODE_CONFIG_DIR?.trim();if(w)return V(w);return B(q.XDG_CONFIG_HOME||B($(q,z),".config"),"opencode")}function S(q=process.env){let z=q.XDG_DATA_HOME?.trim();if(z)return B(V(z),"opencode");return B(J(),".local","share","opencode")}function M(q=process.env){return B(S(q),"auth.json")}function R(q=process.env,z=process.platform){let w=q.PI_CODING_AGENT_DIR?.trim()||q.PI_AGENT_DIR?.trim();if(w)return V(w);return B($(q,z),".pi","agent")}function k(q=process.env){let w=q.PI_CODING_AGENT_DIR||B(J(),".pi","agent");if(w==="~")w=J();else if(w.startsWith("~/")||process.platform==="win32"&&w.startsWith("~\\"))w=B(J(),w.slice(2));if(w.startsWith("file://"))w=Y(w);return B(w,"auth.json")}function x(q){return`${Z}@${q}`}function y(q){return`${Z}@${q}`}function H(q){return`npm:${L}@${q}`}async function N(){let q=X(Y(import.meta.url));for(let z=0;z<5;z++){let w=B(q,"package.json");if(F(w))try{let Q=JSON.parse(I(w,"utf8"));if(typeof Q.version==="string"&&Q.version.trim())return Q.version.trim()}catch{}let W=X(q);if(W===q)break;q=W}return"1.22.0"}
2
- export{Z as u,L as v,$ as w,K as x,M as y,R as z,k as A,x as B,y as C,H as D,N as E};