@cortexkit/opencode-anthropic-auth 1.21.0 → 1.23.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.
Files changed (68) hide show
  1. package/README.md +57 -12
  2. package/dist/billing-lineage.d.ts +51 -0
  3. package/dist/claustrum-enrollment-registry.d.ts +4 -0
  4. package/dist/cli.d.ts +2 -1
  5. package/dist/cli.js +89 -6
  6. package/dist/custody-dimensions.d.ts +36 -0
  7. package/dist/custody-enrollment.d.ts +14 -0
  8. package/dist/custody-live.d.ts +111 -0
  9. package/dist/custody-manifest-watcher.d.ts +16 -0
  10. package/dist/custody-mode.d.ts +186 -0
  11. package/dist/effort-history.d.ts +62 -0
  12. package/dist/fable-fallback.d.ts +6 -7
  13. package/dist/{index-w9d41yy9.js → index-0jfsxyn9.js} +1 -1
  14. package/dist/index-1fq7h6yd.js +430 -0
  15. package/dist/{index-y0khnbt6.js → index-1gr8v4fn.js} +1 -1
  16. package/dist/index-797pmamn.js +2 -0
  17. package/dist/{index-1db17bc2.js → index-8y2t4mwz.js} +2 -2
  18. package/dist/index-a5d6v3ba.js +5 -0
  19. package/dist/index-n96q8pks.js +2 -0
  20. package/dist/index-xxhyhp98.js +2 -0
  21. package/dist/index-xzbhzz0a.js +2 -0
  22. package/dist/index-z7gfdyv3.js +1 -0
  23. package/dist/index.js +28 -21
  24. package/dist/local-login.d.ts +64 -0
  25. package/dist/{logger-ftk4bg3p.js → logger-kk9vyem9.js} +1 -1
  26. package/dist/prime-manager-registry.d.ts +5 -1
  27. package/dist/rpc/notifications.d.ts +3 -3
  28. package/dist/rpc/port-file.js +1 -1
  29. package/dist/rpc/protocol.d.ts +23 -1
  30. package/dist/rpc/protocol.js +1 -1
  31. package/dist/rpc/rpc-client.d.ts +1 -1
  32. package/dist/rpc/rpc-client.js +1 -1
  33. package/dist/rpc/rpc-dir.js +1 -1
  34. package/dist/rpc/server-registry.d.ts +10 -0
  35. package/dist/setup/activation.d.ts +7 -0
  36. package/dist/setup/claustrum.d.ts +26 -0
  37. package/dist/setup/command-runner.d.ts +2 -0
  38. package/dist/setup/command.d.ts +8 -0
  39. package/dist/setup/detect.d.ts +5 -0
  40. package/dist/setup/jsonc.d.ts +9 -0
  41. package/dist/setup/opencode-config.d.ts +18 -0
  42. package/dist/setup/paths.d.ts +15 -0
  43. package/dist/setup/pi.d.ts +8 -0
  44. package/dist/setup/process-fence.d.ts +14 -0
  45. package/dist/setup/types.d.ts +37 -0
  46. package/dist/sidebar-state.d.ts +5 -2
  47. package/dist/sidebar-state.js +1 -1
  48. package/dist/transform.d.ts +17 -1
  49. package/dist/tui/command-dialogs.d.ts +28 -9
  50. package/dist/tui-preferences.js +2 -2
  51. package/package.json +10 -5
  52. package/src/rpc/notifications.ts +28 -24
  53. package/src/rpc/protocol.ts +34 -1
  54. package/src/rpc/rpc-client.ts +1 -1
  55. package/src/rpc/rpc-server.ts +18 -5
  56. package/src/rpc/server-registry.ts +61 -0
  57. package/src/sidebar-state.ts +42 -3
  58. package/src/tui/command-dialogs.tsx +301 -97
  59. package/src/tui-compiled/rpc/protocol.ts +34 -1
  60. package/src/tui-compiled/rpc/rpc-client.ts +1 -1
  61. package/src/tui-compiled/sidebar-state.ts +42 -3
  62. package/src/tui-compiled/tui/command-dialogs.tsx +240 -70
  63. package/src/tui-compiled/tui.tsx +8 -3
  64. package/src/tui.tsx +18 -3
  65. package/dist/index-4nz423bt.js +0 -4
  66. package/dist/index-4x20896x.js +0 -2
  67. package/dist/index-wezdyxst.js +0 -2
  68. package/dist/index-yskwj5e6.js +0 -428
@@ -1,11 +1,13 @@
1
1
  import { createTextNode as _$createTextNode } from "opentui:runtime-module:%40opentui%2Fsolid";
2
+ import { effect as _$effect } from "opentui:runtime-module:%40opentui%2Fsolid";
3
+ import { memo as _$memo } from "opentui:runtime-module:%40opentui%2Fsolid";
2
4
  import { createComponent as _$createComponent } from "opentui:runtime-module:%40opentui%2Fsolid";
3
5
  import { insertNode as _$insertNode } from "opentui:runtime-module:%40opentui%2Fsolid";
4
6
  import { insert as _$insert } from "opentui:runtime-module:%40opentui%2Fsolid";
5
7
  import { setProp as _$setProp } from "opentui:runtime-module:%40opentui%2Fsolid";
6
8
  import { createElement as _$createElement } from "opentui:runtime-module:%40opentui%2Fsolid";
7
9
  /** @jsxImportSource @opentui/solid */
8
-
10
+ import { custodyStatusLabel } from "@cortexkit/anthropic-auth-core";
9
11
  import { formatPrimeCost, formatPrimeTime } from "../sidebar-state.js";
10
12
  export const PRIME_DIALOG_OPTIONS = [{
11
13
  title: 'Enable',
@@ -42,17 +44,121 @@ export function buildKillswitchThresholdSeed(config, accountIds) {
42
44
  }
43
45
  return seedParts.join(' ');
44
46
  }
47
+ function normalizeTuiCustodyMode(value) {
48
+ return value === 'local' || value === 'claustrum' ? value : `mismatch: ${value}`;
49
+ }
50
+ export function normalizeAccountDialogPayload(value) {
51
+ const payload = value && typeof value === 'object' ? value : {};
52
+ const rawAccounts = Array.isArray(payload.accounts) ? payload.accounts : [];
53
+ const accounts = rawAccounts.flatMap(value => {
54
+ if (!value || typeof value !== 'object') return [];
55
+ const account = value;
56
+ const quotaPercent = account.quotaPercent;
57
+ if (typeof account.id !== 'string' || typeof account.label !== 'string' || account.role !== 'main' && account.role !== 'fallback' || typeof account.enabled !== 'boolean' || quotaPercent !== null && (typeof quotaPercent !== 'number' || !Number.isFinite(quotaPercent)) || account.claustrumGate !== 'on' && account.claustrumGate !== 'off' && account.claustrumGate !== 'na' || typeof account.vaultServed !== 'boolean') {
58
+ return [];
59
+ }
60
+ const normalized = {
61
+ id: account.id,
62
+ label: account.label,
63
+ role: account.role,
64
+ enabled: account.enabled,
65
+ quotaPercent,
66
+ ...(typeof account.tierLabel === 'string' && {
67
+ tierLabel: account.tierLabel
68
+ }),
69
+ claustrumGate: account.claustrumGate,
70
+ vaultServed: account.vaultServed
71
+ };
72
+ const custodyState = account.custodyState;
73
+ if ((custodyState === 'na' || custodyState === 'off' || custodyState === 'on-vault-served' || custodyState === 'on-vault-reauth' || custodyState === 'on-cold') && typeof account.vaultReauth === 'boolean') {
74
+ return [{
75
+ ...normalized,
76
+ custodyState,
77
+ vaultReauth: account.vaultReauth
78
+ }];
79
+ }
80
+ return [normalized];
81
+ });
82
+ const custodyMode = payload.custodyModeKnown === true && typeof payload.custodyMode === 'string' ? normalizeTuiCustodyMode(payload.custodyMode) : undefined;
83
+ return {
84
+ accounts,
85
+ claustrumDetection: typeof payload.claustrumDetection === 'string' ? payload.claustrumDetection : 'unknown',
86
+ ...(custodyMode && {
87
+ custodyMode
88
+ }),
89
+ ...(typeof payload.enrollmentStatus === 'string' && payload.enrollmentStatus.length <= 2_000 && {
90
+ enrollmentStatus: payload.enrollmentStatus
91
+ })
92
+ };
93
+ }
45
94
  export function buildAccountDialogOption(account) {
46
95
  const pct = account.quotaPercent != null ? ` ${Math.round(account.quotaPercent)}%` : ' \u2013%';
47
96
  const status = !account.enabled ? ' (disabled)' : '';
97
+ const custody = account.custodyState ? account.custodyState === 'na' ? undefined : custodyStatusLabel(account.custodyState).replace(' (OpenCode managed)', '') : undefined;
48
98
  return {
49
- title: `${account.label} [${account.role}]${status}${pct}`,
99
+ title: `${account.label} [${account.role}]${status}${pct}${custody ? ` · custody ${custody}` : ''}`,
50
100
  value: account.id,
51
101
  ...(account.tierLabel && {
52
102
  description: account.tierLabel
53
103
  })
54
104
  };
55
105
  }
106
+ export function buildManageAccountOptions(account) {
107
+ const options = [];
108
+ const toggleLabel = account.enabled ? 'Disable' : 'Enable';
109
+ options.push({
110
+ title: toggleLabel,
111
+ value: account.enabled ? 'disable' : 'enable',
112
+ description: account.enabled ? 'Stop using this fallback account' : 'Allow this fallback account to be used'
113
+ });
114
+ options.push({
115
+ title: 'Move up',
116
+ value: 'move-up',
117
+ description: 'Higher priority in fallback order'
118
+ });
119
+ options.push({
120
+ title: 'Move down',
121
+ value: 'move-down',
122
+ description: 'Lower priority in fallback order'
123
+ });
124
+ options.push({
125
+ title: 'Remove\u2026',
126
+ value: 'remove',
127
+ description: 'Delete this account permanently'
128
+ });
129
+ options.push({
130
+ title: 'Back',
131
+ value: 'back'
132
+ });
133
+ return options;
134
+ }
135
+ export function buildAccountDialogL1(value) {
136
+ const payload = normalizeAccountDialogPayload(value);
137
+ const modeAction = payload.custodyMode === 'local' || payload.custodyMode === 'claustrum' ? {
138
+ command: 'claude-account',
139
+ arguments: payload.custodyMode === 'local' ? 'claustrum' : 'local'
140
+ } : undefined;
141
+ return {
142
+ header: payload.custodyMode ? `Custody mode: ${payload.custodyMode}` : 'Custody mode: unavailable from older server',
143
+ options: [...(modeAction ? [{
144
+ title: payload.custodyMode === 'local' ? 'Use Claustrum custody' : 'Use local custody',
145
+ value: '__custody-mode__'
146
+ }] : []), {
147
+ title: 'Add account…',
148
+ value: '__add__',
149
+ description: 'Add an API key or OAuth fallback account'
150
+ }, ...payload.accounts.map(buildAccountDialogOption)],
151
+ ...(payload.enrollmentStatus && {
152
+ enrollmentStatus: payload.enrollmentStatus
153
+ }),
154
+ ...(modeAction && {
155
+ modeAction
156
+ })
157
+ };
158
+ }
159
+ export function retainAccountDialogProjection(current, incoming) {
160
+ return Array.isArray(incoming.accounts) ? incoming : current;
161
+ }
56
162
  function showText(api, text) {
57
163
  api.ui.dialog.setSize('xlarge');
58
164
  api.ui.dialog.replace(() => (() => {
@@ -86,6 +192,8 @@ export function buildPrimeStatusRows(accounts) {
86
192
  const time = formatPrimeTime(account.lastPrimedAt);
87
193
  if (account.lastResult === 'error') {
88
194
  rows.push(`${account.label} \u00b7 primed ${time} err`);
195
+ } else if (account.lastResult === 'skipped') {
196
+ rows.push(`${account.label} \u00b7 primed ${time} skipped`);
89
197
  } else {
90
198
  rows.push(`${account.label} \u00b7 primed ${time} \u2713`);
91
199
  }
@@ -352,40 +460,111 @@ export function openCommandDialog(api, payload, apply) {
352
460
  return;
353
461
  }
354
462
  if (payload.command === 'claude-account') {
355
- const accounts = payload.knobs.accounts ?? [];
463
+ let accountKnobs = payload.knobs;
464
+ const accounts = normalizeAccountDialogPayload(accountKnobs).accounts;
465
+ let statusMessage;
356
466
  const updateAccounts = r => {
357
- const updated = r.knobs.accounts;
358
- if (updated && updated.length > 0) {
467
+ accountKnobs = retainAccountDialogProjection(accountKnobs, r.knobs);
468
+ const updated = normalizeAccountDialogPayload(accountKnobs).accounts;
469
+ if (updated.length > 0) {
359
470
  accounts.length = 0;
360
471
  accounts.push(...updated);
361
472
  }
362
473
  };
363
474
  const buildL1 = () => {
364
475
  const DialogSelect = api.ui.DialogSelect;
365
- const l1Options = [{
366
- title: 'Add account\u2026',
367
- value: '__add__',
368
- description: 'Add an API key or OAuth fallback account'
369
- }, ...accounts.map(buildAccountDialogOption)];
476
+ const l1 = buildAccountDialogL1({
477
+ ...accountKnobs,
478
+ accounts
479
+ });
370
480
  api.ui.dialog.setSize('xlarge');
371
- api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
372
- title: "Claude accounts",
373
- options: l1Options,
374
- onSelect: option => {
375
- if (option.value === '__add__') {
376
- openAddType();
377
- return;
378
- }
379
- const account = accounts.find(a => a.id === option.value);
380
- if (!account) return;
381
- if (account.role === 'main') {
382
- const pct = account.quotaPercent != null ? ` ${Math.round(account.quotaPercent)}%` : ' \u2013%';
383
- showText(api, `${account.label}\nRole: main (read-only)\nQuota:${pct}`);
384
- return;
481
+ api.ui.dialog.replace(() => (() => {
482
+ var _el$8 = _$createElement("box"),
483
+ _el$9 = _$createElement("text"),
484
+ _el$0 = _$createElement("text"),
485
+ _el$1 = _$createElement("box");
486
+ _$insertNode(_el$8, _el$9);
487
+ _$insertNode(_el$8, _el$0);
488
+ _$insertNode(_el$8, _el$1);
489
+ _$setProp(_el$8, "flexDirection", 'column');
490
+ _$setProp(_el$8, "padding", 1);
491
+ _$setProp(_el$8, "width", '100%');
492
+ _$insert(_el$9, () => `Claustrum: ${normalizeAccountDialogPayload(accountKnobs).claustrumDetection}`);
493
+ _$insert(_el$0, () => l1.header);
494
+ _$insert(_el$8, (() => {
495
+ var _c$ = _$memo(() => !!l1.enrollmentStatus);
496
+ return () => _c$() && (() => {
497
+ var _el$10 = _$createElement("box"),
498
+ _el$11 = _$createElement("text");
499
+ _$insertNode(_el$10, _el$11);
500
+ _$setProp(_el$10, "marginTop", 1);
501
+ _$insert(_el$11, () => l1.enrollmentStatus);
502
+ return _el$10;
503
+ })();
504
+ })(), _el$1);
505
+ _$insert(_el$8, statusMessage && (() => {
506
+ var _el$12 = _$createElement("box"),
507
+ _el$13 = _$createElement("text");
508
+ _$insertNode(_el$12, _el$13);
509
+ _$setProp(_el$12, "marginTop", 1);
510
+ _$insert(_el$13, () => statusMessage.text);
511
+ _$effect(_$p => _$setProp(_el$13, "fg", statusMessage.error ? '#ef4444' : '#22c55e', _$p));
512
+ return _el$12;
513
+ })(), _el$1);
514
+ _$setProp(_el$1, "marginTop", 1);
515
+ _$insert(_el$1, _$createComponent(DialogSelect, {
516
+ title: "Claude accounts",
517
+ get options() {
518
+ return l1.options;
519
+ },
520
+ onSelect: option => {
521
+ if (option.value === '__add__') {
522
+ statusMessage = undefined;
523
+ openAddType();
524
+ return;
525
+ }
526
+ if (option.value === '__custody-mode__' && l1.modeAction) {
527
+ void apply(l1.modeAction.command, l1.modeAction.arguments).then(r => {
528
+ const isRefusalOrError = r.text.includes('refused') || r.text.includes('unavailable') || r.text.includes('failed') || r.text.includes('Error') || r.text.includes('error');
529
+ if (isRefusalOrError) {
530
+ statusMessage = {
531
+ text: r.text,
532
+ error: true
533
+ };
534
+ } else {
535
+ statusMessage = {
536
+ text: r.text,
537
+ error: false
538
+ };
539
+ api.ui.toast({
540
+ message: r.text
541
+ });
542
+ }
543
+ updateAccounts(r);
544
+ buildL1();
545
+ }).catch(err => {
546
+ const msg = err instanceof Error ? err.message : String(err);
547
+ statusMessage = {
548
+ text: `Error: ${msg}`,
549
+ error: true
550
+ };
551
+ buildL1();
552
+ });
553
+ return;
554
+ }
555
+ statusMessage = undefined;
556
+ const account = accounts.find(a => a.id === option.value);
557
+ if (!account) return;
558
+ if (account.role === 'main') {
559
+ const pct = account.quotaPercent != null ? ` ${Math.round(account.quotaPercent)}%` : ' \u2013%';
560
+ showText(api, `${account.label}\nRole: main (read-only)\nQuota:${pct}`);
561
+ return;
562
+ }
563
+ openManage(account, false);
385
564
  }
386
- openManage(account, false);
387
- }
388
- }));
565
+ }));
566
+ return _el$8;
567
+ })());
389
568
  };
390
569
 
391
570
  // -- Add type selection (OAuth vs API key) ------------------------------
@@ -429,9 +608,9 @@ export function openCommandDialog(api, payload, apply) {
429
608
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
430
609
  title: "Add API key account \\u2014 API key",
431
610
  description: () => (() => {
432
- var _el$8 = _$createElement("text");
433
- _$insertNode(_el$8, _$createTextNode(`Paste your API key (required).`));
434
- return _el$8;
611
+ var _el$14 = _$createElement("text");
612
+ _$insertNode(_el$14, _$createTextNode(`Paste your API key (required).`));
613
+ return _el$14;
435
614
  })(),
436
615
  placeholder: "sk-ant-...",
437
616
  value: "",
@@ -453,9 +632,9 @@ export function openCommandDialog(api, payload, apply) {
453
632
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
454
633
  title: "Add API key account \\u2014 base URL",
455
634
  description: () => (() => {
456
- var _el$0 = _$createElement("text");
457
- _$insertNode(_el$0, _$createTextNode(`Anthropic-compatible API base URL. Default: https://api.kie.ai/claude`));
458
- return _el$0;
635
+ var _el$16 = _$createElement("text");
636
+ _$insertNode(_el$16, _$createTextNode(`Anthropic-compatible API base URL. Default: https://api.kie.ai/claude`));
637
+ return _el$16;
459
638
  })(),
460
639
  placeholder: "https://api.kie.ai/claude",
461
640
  value: "",
@@ -493,9 +672,9 @@ export function openCommandDialog(api, payload, apply) {
493
672
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
494
673
  title: "Add API key account \\u2014 label",
495
674
  description: () => (() => {
496
- var _el$10 = _$createElement("text");
497
- _$insertNode(_el$10, _$createTextNode(`A short name for this account (optional).`));
498
- return _el$10;
675
+ var _el$18 = _$createElement("text");
676
+ _$insertNode(_el$18, _$createTextNode(`A short name for this account (optional).`));
677
+ return _el$18;
499
678
  })(),
500
679
  placeholder: "e.g. Work API",
501
680
  value: "",
@@ -589,9 +768,9 @@ export function openCommandDialog(api, payload, apply) {
589
768
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
590
769
  title: "OAuth sign-in \\u2014 enter code",
591
770
  description: () => (() => {
592
- var _el$12 = _$createElement("text");
593
- _$insertNode(_el$12, _$createTextNode(`After signing in you will be redirected. Paste the full callback URL or authorization code below.`));
594
- return _el$12;
771
+ var _el$20 = _$createElement("text");
772
+ _$insertNode(_el$20, _$createTextNode(`After signing in you will be redirected. Paste the full callback URL or authorization code below.`));
773
+ return _el$20;
595
774
  })(),
596
775
  placeholder: "Paste callback URL or code here",
597
776
  value: "",
@@ -612,9 +791,9 @@ export function openCommandDialog(api, payload, apply) {
612
791
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
613
792
  title: "OAuth sign-in \\u2014 label",
614
793
  description: () => (() => {
615
- var _el$14 = _$createElement("text");
616
- _$insertNode(_el$14, _$createTextNode(`A short name for this account (optional).`));
617
- return _el$14;
794
+ var _el$22 = _$createElement("text");
795
+ _$insertNode(_el$22, _$createTextNode(`A short name for this account (optional).`));
796
+ return _el$22;
618
797
  })(),
619
798
  placeholder: "e.g. work",
620
799
  value: "",
@@ -638,34 +817,10 @@ export function openCommandDialog(api, payload, apply) {
638
817
  const DialogSelect = api.ui.DialogSelect;
639
818
  const DialogConfirm = api.ui.DialogConfirm;
640
819
  api.ui.dialog.setSize('xlarge');
641
- const options = [];
642
- if (!isMain) {
643
- const toggleLabel = account.enabled ? 'Disable' : 'Enable';
644
- options.push({
645
- title: toggleLabel,
646
- value: account.enabled ? 'disable' : 'enable',
647
- description: account.enabled ? 'Stop using this fallback account' : 'Allow this fallback account to be used'
648
- });
649
- options.push({
650
- title: 'Move up',
651
- value: 'move-up',
652
- description: 'Higher priority in fallback order'
653
- });
654
- options.push({
655
- title: 'Move down',
656
- value: 'move-down',
657
- description: 'Lower priority in fallback order'
658
- });
659
- options.push({
660
- title: 'Remove\u2026',
661
- value: 'remove',
662
- description: 'Delete this account permanently'
663
- });
664
- }
665
- options.push({
820
+ const options = isMain ? [{
666
821
  title: 'Back',
667
822
  value: 'back'
668
- });
823
+ }] : buildManageAccountOptions(account);
669
824
  api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
670
825
  get title() {
671
826
  return `Manage ${account.label}`;
@@ -691,20 +846,35 @@ export function openCommandDialog(api, payload, apply) {
691
846
  });
692
847
  updateAccounts(r);
693
848
  buildL1();
849
+ }).catch(err => {
850
+ const msg = err instanceof Error ? err.message : String(err);
851
+ statusMessage = {
852
+ text: `Error: ${msg}`,
853
+ error: true
854
+ };
855
+ buildL1();
694
856
  });
695
857
  },
696
858
  onCancel: () => openManage(account, isMain)
697
859
  }));
698
860
  return;
699
861
  }
700
- void apply('claude-account', `${option.value} ${account.id}`).then(r => {
862
+ const args = `${option.value} ${account.id}`;
863
+ void apply('claude-account', args).then(r => {
701
864
  api.ui.toast({
702
865
  message: r.text
703
866
  });
704
867
  updateAccounts(r);
705
- const updatedList = r.knobs.accounts;
868
+ const updatedList = normalizeAccountDialogPayload(r.knobs).accounts;
706
869
  const refreshed = (updatedList && updatedList.length > 0 ? updatedList.find(a => a.id === account.id) : undefined) ?? account;
707
870
  openManage(refreshed, isMain);
871
+ }).catch(err => {
872
+ const msg = err instanceof Error ? err.message : String(err);
873
+ statusMessage = {
874
+ text: `Error: ${msg}`,
875
+ error: true
876
+ };
877
+ buildL1();
708
878
  });
709
879
  }
710
880
  }));
@@ -324,8 +324,8 @@ function QuotaRow(props) {
324
324
  // Pacing is computed here — per window, against the wall clock at render time
325
325
  // (re-evaluated on every state poll) — and disabled by passing false.
326
326
  function AccountBlock(props) {
327
- const statusWord = () => props.needsReauth ? 're-login' : props.active ? 'active' : 'idle';
328
- const statusTone = () => props.needsReauth ? 'err' : props.active ? 'ok' : 'muted';
327
+ const statusWord = () => props.needsReauth ? 're-login' : props.vaultReauth ? 'vault reauth' : props.active ? 'active' : 'idle';
328
+ const statusTone = () => props.needsReauth || props.vaultReauth ? 'warn' : props.active ? 'ok' : 'muted';
329
329
  const pacingFor = (window, windowMs) => props.pacingEnabled && window ? computeQuotaPacing(window, windowMs, Date.now()) : null;
330
330
  return (() => {
331
331
  var _el$22 = _$createElement("box"),
@@ -680,7 +680,8 @@ function QuotaSidebar(props) {
680
680
  const quotaBackedOff = () => state().main?.quotaBackedOff === true;
681
681
  const refreshBackedOff = () => state().main?.refreshBackedOff === true;
682
682
  const needsReauth = () => enabledFallbacks().some(f => f.needsReauth);
683
- const degraded = () => quotaBackedOff() || refreshBackedOff() || needsReauth();
683
+ const vaultReauth = () => enabledFallbacks().some(f => f.vaultReauth);
684
+ const degraded = () => quotaBackedOff() || refreshBackedOff() || needsReauth() || vaultReauth();
684
685
  const fableRecoverySummary = () => getFableRecoverySummary(state(), props.sessionId);
685
686
  const fableRecoveryTone = () => state().fableRecoveries?.find(recovery => recovery.sessionId === props.sessionId)?.mode === 'fable' ? 'ok' : 'warn';
686
687
  const cacheKeep = () => state().cacheKeep;
@@ -921,6 +922,9 @@ function QuotaSidebar(props) {
921
922
  get needsReauth() {
922
923
  return fb.needsReauth;
923
924
  },
925
+ get vaultReauth() {
926
+ return fb.vaultReauth;
927
+ },
924
928
  marginTop: 1
925
929
  })
926
930
  });
@@ -1156,6 +1160,7 @@ const tui = async api => {
1156
1160
  const current = api.route.current;
1157
1161
  const resolved = typeof current === 'function' ? current() : current;
1158
1162
  const sessionId = resolved?.params?.sessionID;
1163
+ if (!sessionId) return;
1159
1164
  rpcInFlight = true;
1160
1165
  void rpcClient.pending(lastNotificationId, sessionId).then(messages => {
1161
1166
  for (const message of [...messages].sort((a, b) => a.id - b.id)) {
package/src/tui.tsx CHANGED
@@ -313,13 +313,24 @@ function AccountBlock(props: {
313
313
  active: boolean
314
314
  pacingEnabled: boolean
315
315
  needsReauth?: boolean
316
+ vaultReauth?: boolean
316
317
  tierLabel?: string
317
318
  marginTop?: number
318
319
  }) {
319
320
  const statusWord = () =>
320
- props.needsReauth ? 're-login' : props.active ? 'active' : 'idle'
321
+ props.needsReauth
322
+ ? 're-login'
323
+ : props.vaultReauth
324
+ ? 'vault reauth'
325
+ : props.active
326
+ ? 'active'
327
+ : 'idle'
321
328
  const statusTone = (): Tone =>
322
- props.needsReauth ? 'err' : props.active ? 'ok' : 'muted'
329
+ props.needsReauth || props.vaultReauth
330
+ ? 'warn'
331
+ : props.active
332
+ ? 'ok'
333
+ : 'muted'
323
334
  const pacingFor = (
324
335
  window:
325
336
  | { usedPercent: number; remainingPercent: number; resetsAt?: string }
@@ -638,7 +649,9 @@ function QuotaSidebar(props: {
638
649
  const quotaBackedOff = () => state().main?.quotaBackedOff === true
639
650
  const refreshBackedOff = () => state().main?.refreshBackedOff === true
640
651
  const needsReauth = () => enabledFallbacks().some((f) => f.needsReauth)
641
- const degraded = () => quotaBackedOff() || refreshBackedOff() || needsReauth()
652
+ const vaultReauth = () => enabledFallbacks().some((f) => f.vaultReauth)
653
+ const degraded = () =>
654
+ quotaBackedOff() || refreshBackedOff() || needsReauth() || vaultReauth()
642
655
 
643
656
  const fableRecoverySummary = () =>
644
657
  getFableRecoverySummary(state(), props.sessionId)
@@ -773,6 +786,7 @@ function QuotaSidebar(props: {
773
786
  pacingEnabled={prefs().sections.pacing}
774
787
  tierLabel={fb.tierLabel}
775
788
  needsReauth={fb.needsReauth}
789
+ vaultReauth={fb.vaultReauth}
776
790
  marginTop={1}
777
791
  />
778
792
  )}
@@ -916,6 +930,7 @@ const tui: TuiPlugin = async (api) => {
916
930
  const sessionId = (
917
931
  resolved as { params?: { sessionID?: string } } | undefined
918
932
  )?.params?.sessionID
933
+ if (!sessionId) return
919
934
  rpcInFlight = true
920
935
  void rpcClient
921
936
  .pending(lastNotificationId, sessionId)
@@ -1,4 +0,0 @@
1
- import*as j from"node:fs";import*as P from"node:os";import*as V from"node:path";var U={error:0,warn:1,info:2,debug:3,trace:4},O=new Set(Object.keys(U));function F(q){if(!q)return null;let Q=q.trim().toLowerCase();return O.has(Q)?Q:null}var S=F(process.env.OPENCODE_ANTHROPIC_AUTH_LOG_LEVEL),M=S??"info";function L(q){M=q}function i(){return M}function X(q){return U[q]<=U[M]}var J=process.env.OPENCODE_ANTHROPIC_AUTH_LOG_FILE??V.join(P.tmpdir(),"opencode-anthropic-auth.log");function h(){return J}var R=5242880,N=3;function I(){try{if(!j.existsSync(J))return;if(j.statSync(J).size<R)return}catch{return}try{for(let q=N;q>=1;q--){let Q=q===1?J:`${J}.${q-1}`,W=`${J}.${q}`;try{if(q===N)try{j.unlinkSync(W)}catch{}if(j.existsSync(Q))j.renameSync(Q,W)}catch{}}}catch{}}var T=/^(authorization|x-api-key|cookie|set-cookie|refresh|access|token)$/i;function k(q){if(T.test(q))return!0;let Q=q.toLowerCase().replace(/[-_]/g,"");if(Q.includes("apikey"))return!0;if(Q.endsWith("secret")||Q.endsWith("password"))return!0;if(Q.endsWith("token")&&!Q.endsWith("tokens"))return!0;return!1}var f=[/Bearer\s+\S+/,/sk-[A-Za-z0-9-]+/,/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/];function _(q){if(typeof q!=="string")return!1;return f.some((Q)=>Q.test(q))}function G(q){if(q==null||Object.keys(q).length===0)return;let Q=new WeakSet;function W($){if($==null||typeof $!=="object"){if(_($))return"***REDACTED***";return $}if(Q.has($))return"[Circular]";Q.add($);try{if(Array.isArray($))return $.map(W);let x=$,B={};for(let[H,C]of Object.entries(x)){if(k(H)){B[H]="***REDACTED***";continue}B[H]=W(C)}return B}finally{Q.delete($)}}return W(q)}function g(q,Q,W,$){let x=new Date().toISOString(),B=q.toUpperCase().padEnd(5),H=Q?` [${Q}]`:"",C=(()=>{try{let w=G($),A=w?{...w,pid:process.pid}:{pid:process.pid};return` ${JSON.stringify(A)}`}catch{return` {"pid":${process.pid},"payload":"[unserializable]"}`}})();return`[${x}] ${B}${H} ${W}${C}`}var D=null;function E(q){D=q}function Y(q,Q,W,$){if(!X(q))return;if(D)try{D({level:q,channel:Q,message:W,payload:G($)})}catch{}if(Z)return;try{let x=`${g(q,Q,W,$)}
2
- `;if(K.push(x),K.length>=p)b();else r()}catch{}}var m={error(q,Q,W){Y("error",q,Q,W)},warn(q,Q,W){Y("warn",q,Q,W)},info(q,Q,W){Y("info",q,Q,W)},debug(q,Q,W){Y("debug",q,Q,W)},trace(q,Q,W){Y("trace",q,Q,W)}},Z=!1,c=500,p=50,K=[],z=null;function b(){if(z)clearTimeout(z),z=null;if(K.length===0)return;let q=K.join("");K=[];try{I(),j.appendFileSync(J,q)}catch{}}function r(){if(z)return;z=setTimeout(()=>{z=null,b()},c)}var y=/^\[([\w-]+)\]\s*/;function o(q,Q){if(!X("debug"))return;if(Z)return;try{let W="",$=q,x=q.match(y);if(x)W=x[1]??"",$=q.slice(x[0].length);let B;if(Q!=null){if(Q instanceof Error)B={error:`${Q.message}${Q.stack?`
3
- ${Q.stack}`:""}`};else if(typeof Q==="object")B=Q}Y("debug",W,$,B)}catch{}}function v(q,Q){if(!X("debug"))return;if(Z)return;try{let W;if(Q!=null){if(typeof Q==="object"&&!(Q instanceof Error))W=Q}Y("debug","relay",q,W)}catch{}}if(!Z)process.on("exit",b);
4
- export{F as Fc,L as Gc,i as Hc,X as Ic,h as Jc,T as Kc,k as Lc,G as Mc,g as Nc,E as Oc,m as Pc,o as Qc,v as Rc};
@@ -1,2 +0,0 @@
1
- import{createRequire as q}from"node:module";var j=Object.create;var{getPrototypeOf:k,defineProperty:i,getOwnPropertyNames:l}=Object;var m=Object.prototype.hasOwnProperty;function n(a){return this[a]}var o,p,r=(a,b,d)=>{var f=a!=null&&typeof a==="object";if(f){var g=b?o??=new WeakMap:p??=new WeakMap,h=g.get(a);if(h)return h}d=a!=null?j(k(a)):{};let c=b||!a||!a.__esModule?i(d,"default",{value:a,enumerable:!0}):d;for(let e of l(a))if(!m.call(c,e))i(c,e,{get:n.bind(a,e),enumerable:!0});if(f)g.set(a,c);return c};var s=(a,b)=>()=>(b||a((b={exports:{}}).exports,b),b.exports);var u=q(import.meta.url);
2
- export{r as Xc,s as Yc,u as Zc};
@@ -1,2 +0,0 @@
1
- import{Pc as O}from"./index-4nz423bt.js";import{randomUUID as H}from"node:crypto";import{mkdir as I,readFile as k,rename as g,rm as N,rmdir as F,stat as P,unlink as w,writeFile as T}from"node:fs/promises";import{tmpdir as m}from"node:os";import{dirname as y,join as L}from"node:path";var d="OPENCODE_ANTHROPIC_AUTH_SIDEBAR_STATE_FILE",v=L(m(),"opencode-anthropic-auth"),c=L(v,"sidebar-state.json");function E(){return process.env[d]||c}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 q(J){return typeof J==="number"&&Number.isFinite(J)}function u(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 n(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(q(J.nextDueAt))Z.nextDueAt=J.nextDueAt;if(J.lastPrimedAt===null)Z.lastPrimedAt=null;else if(q(J.lastPrimedAt))Z.lastPrimedAt=J.lastPrimedAt;if(J.lastResult==="ok"||J.lastResult==="error")Z.lastResult=J.lastResult;let V=u(J.usage);if(V)Z.usage=V;if(q(J.estimatedCostUsd))Z.estimatedCostUsd=J.estimatedCostUsd;return Z}function i(J){if(!K(J))return;if(typeof J.enabled!=="boolean")return;let Z=Array.isArray(J.accounts)?J.accounts.map(n).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 b(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=A(J.extraUsage.used),X=A(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 A(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 s(J){if(!K(J))return{...C};let Z={quota:null};if(K(J.main)){let $=J.main;if(Z.quota=b($.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:b($.quota),enabled:typeof $.enabled==="boolean"?$.enabled:!1,needsReauth:typeof $.needsReauth==="boolean"?$.needsReauth:!1,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:i(J.prime),fableRecoveries:X.length>0?X:void 0,lastUpdated:typeof J.lastUpdated==="number"?J.lastUpdated:0}}var W=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 p(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 I(Z);let G=H(),Q=L(Z,G);return await T(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 w(Q)}catch{return}await V?.beforeReleaseDirectoryRemoval?.(Z),await F(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 g(Z,Q)}catch(z){if(z.code==="ENOENT")continue;throw z}await V?.onStaleLockClaimed?.(Z),await N(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 zJ(J){return(await p(J))?.release??null}async function e(J,Z,V){let x=M(J),Y=`${J}.${process.pid}.${H()}.tmp`;await T(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 N(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 N(Y,{force:!0}).catch(()=>{}),"lock-lost-before-rename";if(await g(Y,J),await x?.afterRename?.(J),!await V())return"lock-lost-after-rename";return"written"}catch(X){throw await N(Y,{force:!0}).catch(()=>{}),X}}async function R(J=E()){try{let Z=await k(J,"utf8");return s(JSON.parse(Z))}catch{return C}}async function NJ(J,Z=E(),V={}){return W=W.then(async()=>{await I(y(Z),{recursive:!0});for(let x=0;x<2;x++){let Y=x===1,X=await p(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 R(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 R(Z);$={...B,activeId:J.activeId,route:J.route,relay:J.relay,fastMode:J.fastMode,cacheKeep:J.cacheKeep,lastUpdated:Math.max(B.lastUpdated,J.lastUpdated)}}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(()=>{}),W}async function CJ(){return W}function WJ(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-fable-5"||J?.startsWith("claude-fable-5-"))return"Fable 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 qJ(J){if(J.lastResult==="error")return{text:"err",hasError:!0};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 z=X*100/$,_=Y+z;if(_<x)Q=new Date(_).toISOString()}return{pacePercent:j,deltaPercent:B,state:G,runsOutAt:Q}}
2
- export{E as a,C as b,s as c,QJ as d,BJ as e,OJ as f,zJ as g,R as h,NJ as i,CJ as j,WJ as k,JJ as l,f as m,D as n,ZJ as o,qJ as p,hJ as q,fJ as r,HJ as s,UJ as t,LJ as u};