@cortexkit/opencode-anthropic-auth 1.22.0 → 2.0.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 (91) hide show
  1. package/README.md +259 -198
  2. package/dist/billing-lineage.d.ts +51 -0
  3. package/dist/cli-failure.d.ts +69 -0
  4. package/dist/cli.d.ts +16 -10
  5. package/dist/cli.js +111 -6
  6. package/dist/custody-dimensions.d.ts +19 -0
  7. package/dist/custody-mode.d.ts +46 -0
  8. package/dist/effort-history.d.ts +11 -2
  9. package/dist/fable-fallback.d.ts +1 -1
  10. package/dist/index-1jkyhgyr.js +2 -0
  11. package/dist/{index-bx5hsgf8.js → index-2arfb1y3.js} +2 -2
  12. package/dist/{index-926t2bzc.js → index-4ya27n12.js} +1 -1
  13. package/dist/{index-cgez4m0h.js → index-aaajxwzd.js} +1 -1
  14. package/dist/index-ae3fq4n6.js +42 -0
  15. package/dist/index-fds0s2j4.js +2 -0
  16. package/dist/index-nngmvczq.js +450 -0
  17. package/dist/index-pn597b6f.js +2 -0
  18. package/dist/{index-7f57ewkp.js → index-rqync0pc.js} +1 -1
  19. package/dist/index.js +1 -33
  20. package/dist/native-command.d.ts +19 -0
  21. package/dist/prime-manager-registry.d.ts +5 -1
  22. package/dist/rpc/notifications.d.ts +4 -3
  23. package/dist/rpc/port-file.js +1 -1
  24. package/dist/rpc/protocol.d.ts +15 -4
  25. package/dist/rpc/protocol.js +1 -1
  26. package/dist/rpc/rpc-client.d.ts +3 -1
  27. package/dist/rpc/rpc-client.js +1 -1
  28. package/dist/rpc/rpc-dir.js +1 -1
  29. package/dist/rpc/rpc-server.d.ts +5 -1
  30. package/dist/rpc/server-registry.d.ts +10 -0
  31. package/dist/setup/activation.d.ts +7 -0
  32. package/dist/setup/claustrum.d.ts +26 -0
  33. package/dist/setup/command-runner.d.ts +2 -0
  34. package/dist/setup/command.d.ts +20 -0
  35. package/dist/setup/command.test.d.ts +1 -0
  36. package/dist/setup/detect.d.ts +5 -0
  37. package/dist/setup/jsonc.d.ts +9 -0
  38. package/dist/setup/native-activation.d.ts +29 -0
  39. package/dist/setup/native-enrollment.d.ts +26 -0
  40. package/dist/setup/native-enrollment.test.d.ts +1 -0
  41. package/dist/setup/native-local.d.ts +20 -0
  42. package/dist/setup/native-login.d.ts +3 -0
  43. package/dist/setup/native-paths.d.ts +15 -0
  44. package/dist/setup/native-paths.test.d.ts +1 -0
  45. package/dist/setup/opencode-config.d.ts +18 -0
  46. package/dist/setup/paths.d.ts +15 -0
  47. package/dist/setup/pi.d.ts +18 -0
  48. package/dist/setup/process-fence.d.ts +20 -0
  49. package/dist/setup/process-fence.test.d.ts +1 -0
  50. package/dist/setup/types.d.ts +37 -0
  51. package/dist/sidebar-state.d.ts +3 -1
  52. package/dist/sidebar-state.js +1 -1
  53. package/dist/transform.d.ts +5 -1
  54. package/dist/tui/command-dialogs.d.ts +32 -2
  55. package/dist/tui-preferences.js +2 -2
  56. package/dist/v2/activation.d.ts +7 -0
  57. package/dist/v2/adapter.d.ts +276 -0
  58. package/dist/v2/install.d.ts +13 -0
  59. package/dist/v2/lifecycle.d.ts +8 -0
  60. package/dist/v2/menu-contract.d.ts +8 -0
  61. package/dist/v2/menu.d.ts +10 -0
  62. package/dist/v2/models.d.ts +6 -0
  63. package/dist/v2/ownership.d.ts +11 -0
  64. package/dist/v2/prime.d.ts +12 -0
  65. package/dist/v2/rpc.d.ts +50 -0
  66. package/dist/v2/server.d.ts +8 -0
  67. package/dist/v2/server.js +4 -0
  68. package/dist/v2/setup.d.ts +58 -0
  69. package/dist/v2/source.d.ts +41 -0
  70. package/dist/v2/tui.d.ts +13 -0
  71. package/dist/v2/tui.js +2 -0
  72. package/dist/v2/wire.d.ts +36 -0
  73. package/package.json +26 -6
  74. package/src/rpc/notifications.ts +37 -26
  75. package/src/rpc/protocol.ts +24 -7
  76. package/src/rpc/rpc-client.ts +18 -1
  77. package/src/rpc/rpc-server.ts +38 -8
  78. package/src/rpc/server-registry.ts +61 -0
  79. package/src/sidebar-state.ts +26 -2
  80. package/src/tui/command-dialogs.tsx +537 -68
  81. package/src/tui/entry.mjs +44 -18
  82. package/src/tui-compiled/rpc/protocol.ts +24 -7
  83. package/src/tui-compiled/rpc/rpc-client.ts +18 -1
  84. package/src/tui-compiled/sidebar-state.ts +26 -2
  85. package/src/tui-compiled/tui/command-dialogs.tsx +488 -95
  86. package/src/tui-compiled/tui.tsx +25 -7
  87. package/src/tui.tsx +38 -9
  88. package/dist/index-8aga2zwv.js +0 -4
  89. package/dist/index-d3f8g6ve.js +0 -428
  90. package/dist/index-sh51yqxs.js +0 -2
  91. package/dist/logger-jrkranbz.js +0 -1
@@ -1,12 +1,253 @@
1
1
  import { createTextNode as _$createTextNode } from "opentui:runtime-module:%40opentui%2Fsolid";
2
- import { createComponent as _$createComponent } 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";
3
4
  import { insertNode as _$insertNode } from "opentui:runtime-module:%40opentui%2Fsolid";
4
5
  import { insert as _$insert } from "opentui:runtime-module:%40opentui%2Fsolid";
5
6
  import { setProp as _$setProp } from "opentui:runtime-module:%40opentui%2Fsolid";
6
7
  import { createElement as _$createElement } from "opentui:runtime-module:%40opentui%2Fsolid";
8
+ import { createComponent as _$createComponent } from "opentui:runtime-module:%40opentui%2Fsolid";
7
9
  /** @jsxImportSource @opentui/solid */
8
10
 
11
+ import { custodyStatusLabel } from "@cortexkit/anthropic-auth-core";
9
12
  import { formatPrimeCost, formatPrimeTime } from "../sidebar-state.js";
13
+
14
+ /** Render menu sections, accounts and action inputs; send changes to the host instead of writing credentials here. */
15
+ export function openNativeMenuDialog(api, payload, apply, isCurrentSession) {
16
+ let menu = payload.menu;
17
+ let inFlight = false;
18
+ const DialogSelect = api.ui.DialogSelect;
19
+ const DialogPrompt = api.ui.DialogPrompt;
20
+ const DialogConfirm = api.ui.DialogConfirm;
21
+ const active = () => isCurrentSession() && !inFlight;
22
+ const root = () => {
23
+ if (!active()) return;
24
+ api.ui.dialog.setSize('xlarge');
25
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
26
+ get title() {
27
+ return menu.title;
28
+ },
29
+ get options() {
30
+ return [...menu.sections.map(section => ({
31
+ title: section.title,
32
+ value: section.id
33
+ })), {
34
+ title: 'Close',
35
+ value: '__close'
36
+ }];
37
+ },
38
+ onSelect: option => {
39
+ if (!active()) return;
40
+ const section = menu.sections.find(entry => entry.id === option.value);
41
+ if (section) showSection(section);else if (option.value === '__close') api.ui.dialog.clear();
42
+ }
43
+ }));
44
+ };
45
+ const showSection = section => {
46
+ if (!active()) return;
47
+ api.ui.dialog.replace(() => (() => {
48
+ var _el$ = _$createElement("box"),
49
+ _el$2 = _$createElement("text");
50
+ _$insertNode(_el$, _el$2);
51
+ _$setProp(_el$, "flexDirection", 'column');
52
+ _$setProp(_el$, "padding", 1);
53
+ _$insert(_el$2, () => section.lines.join('\n'));
54
+ _$insert(_el$, _$createComponent(DialogSelect, {
55
+ get title() {
56
+ return section.title;
57
+ },
58
+ get options() {
59
+ return [...section.items.map(item => ({
60
+ title: item.label,
61
+ value: `item:${item.id}`,
62
+ description: item.detail
63
+ })), ...section.actions.map(action => ({
64
+ title: action.label,
65
+ value: `action:${action.id}`,
66
+ description: action.description
67
+ })), {
68
+ title: 'Back',
69
+ value: '__back'
70
+ }];
71
+ },
72
+ onSelect: option => {
73
+ if (!active()) return;
74
+ if (option.value === '__back') return root();
75
+ const action = section.actions.find(entry => `action:${entry.id}` === option.value);
76
+ if (action) return collect(section, action);
77
+ const item = section.items.find(entry => `item:${entry.id}` === option.value);
78
+ if (item) showItem(section, item);
79
+ }
80
+ }), null);
81
+ return _el$;
82
+ })());
83
+ };
84
+ const showItem = (section, item) => {
85
+ if (!active()) return;
86
+ api.ui.dialog.replace(() => (() => {
87
+ var _el$3 = _$createElement("box"),
88
+ _el$4 = _$createElement("text");
89
+ _$insertNode(_el$3, _el$4);
90
+ _$setProp(_el$3, "flexDirection", 'column');
91
+ _$setProp(_el$3, "padding", 1);
92
+ _$insert(_el$4, () => item.detail ?? '');
93
+ _$insert(_el$3, _$createComponent(DialogSelect, {
94
+ get title() {
95
+ return item.label;
96
+ },
97
+ get options() {
98
+ return [...item.actions.map(action => ({
99
+ title: action.label,
100
+ value: action.id,
101
+ description: action.description
102
+ })), {
103
+ title: 'Back',
104
+ value: '__back'
105
+ }];
106
+ },
107
+ onSelect: option => {
108
+ if (!active()) return;
109
+ const action = item.actions.find(entry => entry.id === option.value);
110
+ if (action) collect(section, action, item);else if (option.value === '__back') showSection(section);
111
+ }
112
+ }), null);
113
+ return _el$3;
114
+ })());
115
+ };
116
+ const collect = (section, action, item) => {
117
+ const values = {};
118
+ const back = () => {
119
+ for (const key of Object.keys(values)) delete values[key];
120
+ if (item) showItem(section, item);else showSection(section);
121
+ };
122
+ const submit = async () => {
123
+ if (!active()) return;
124
+ inFlight = true;
125
+ try {
126
+ const result = await apply({
127
+ command: menu.command,
128
+ sectionId: section.id,
129
+ actionId: action.id,
130
+ ...(item ? {
131
+ itemId: item.id
132
+ } : {}),
133
+ values: {
134
+ ...values
135
+ },
136
+ ...(action.confirm ? {
137
+ confirmed: true
138
+ } : {})
139
+ });
140
+ if (!isCurrentSession()) return;
141
+ menu = result.menu;
142
+ api.ui.toast({
143
+ message: result.text
144
+ });
145
+ } catch {
146
+ if (isCurrentSession()) api.ui.toast({
147
+ message: 'Menu apply unavailable; outcome unknown.'
148
+ });
149
+ } finally {
150
+ for (const key of Object.keys(values)) delete values[key];
151
+ inFlight = false;
152
+ if (isCurrentSession()) {
153
+ const refreshed = menu.sections.find(entry => entry.id === section.id);
154
+ if (refreshed) showSection(refreshed);else root();
155
+ }
156
+ }
157
+ };
158
+ const next = index => {
159
+ if (!active()) return;
160
+ const knob = action.knobs[index];
161
+ if (!knob) {
162
+ if (!action.confirm) return void submit();
163
+ api.ui.dialog.replace(() => _$createComponent(DialogConfirm, {
164
+ get title() {
165
+ return action.label;
166
+ },
167
+ get message() {
168
+ return action.confirm?.message ?? '';
169
+ },
170
+ onConfirm: () => void submit(),
171
+ onCancel: back
172
+ }));
173
+ return;
174
+ }
175
+ if (knob.kind === 'choice' || knob.kind === 'toggle') {
176
+ const choices = knob.kind === 'choice' ? knob.choices : [{
177
+ value: 'on',
178
+ label: 'On'
179
+ }, {
180
+ value: 'off',
181
+ label: 'Off'
182
+ }];
183
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
184
+ get title() {
185
+ return knob.label;
186
+ },
187
+ get options() {
188
+ return [...choices.map(choice => ({
189
+ title: choice.label,
190
+ value: choice.value
191
+ })), {
192
+ title: 'Cancel',
193
+ value: '__cancel'
194
+ }];
195
+ },
196
+ onSelect: option => {
197
+ if (!active()) return;
198
+ if (option.value === '__cancel') return back();
199
+ values[knob.id] = knob.kind === 'toggle' ? option.value === 'on' : option.value;
200
+ next(index + 1);
201
+ }
202
+ }));
203
+ return;
204
+ }
205
+ // DialogPrompt has no masking capability in the host API. Never seed a
206
+ // protected input or claim it is hidden; warn before collecting it.
207
+ api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
208
+ get title() {
209
+ return knob.label;
210
+ },
211
+ description: () => (() => {
212
+ var _el$5 = _$createElement("text");
213
+ _$insert(_el$5, (() => {
214
+ var _c$ = _$memo(() => !!(knob.kind === 'text' && knob.masked));
215
+ return () => _c$() ? 'This host prompt displays input. Avoid screen sharing; the value is not echoed in menu results.' : knob.required ? 'Required input' : 'Optional; leave empty for the default';
216
+ })());
217
+ return _el$5;
218
+ })(),
219
+ get value() {
220
+ return _$memo(() => !!(knob.kind === 'text' && knob.masked))() ? '' : _$memo(() => knob.value === undefined)() ? '' : String(knob.value);
221
+ },
222
+ get placeholder() {
223
+ return _$memo(() => knob.kind === 'text')() ? knob.placeholder : `${knob.min ?? ''}-${knob.max ?? ''}`;
224
+ },
225
+ onCancel: back,
226
+ onConfirm: typed => {
227
+ if (!active()) return;
228
+ const text = typed.trim();
229
+ if (!text && knob.required) {
230
+ api.ui.toast({
231
+ message: `${knob.label} is required.`
232
+ });
233
+ return;
234
+ }
235
+ const value = text === '' ? null : knob.kind === 'number' ? Number(text) : text;
236
+ if (knob.kind === 'number' && typeof value === 'number' && (!Number.isFinite(value) || knob.min !== undefined && value < knob.min || knob.max !== undefined && value > knob.max)) {
237
+ api.ui.toast({
238
+ message: `${knob.label} needs a number in range.`
239
+ });
240
+ return;
241
+ }
242
+ values[knob.id] = value;
243
+ next(index + 1);
244
+ }
245
+ }));
246
+ };
247
+ next(0);
248
+ };
249
+ root();
250
+ }
10
251
  export const PRIME_DIALOG_OPTIONS = [{
11
252
  title: 'Enable',
12
253
  value: 'on'
@@ -42,30 +283,132 @@ export function buildKillswitchThresholdSeed(config, accountIds) {
42
283
  }
43
284
  return seedParts.join(' ');
44
285
  }
286
+ function normalizeTuiCustodyMode(value) {
287
+ return value === 'local' || value === 'claustrum' ? value : `mismatch: ${value}`;
288
+ }
289
+ export function normalizeAccountDialogPayload(value) {
290
+ const payload = value && typeof value === 'object' ? value : {};
291
+ const rawAccounts = Array.isArray(payload.accounts) ? payload.accounts : [];
292
+ const accounts = rawAccounts.flatMap(value => {
293
+ if (!value || typeof value !== 'object') return [];
294
+ const account = value;
295
+ const quotaPercent = account.quotaPercent;
296
+ 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') {
297
+ return [];
298
+ }
299
+ const normalized = {
300
+ id: account.id,
301
+ label: account.label,
302
+ role: account.role,
303
+ enabled: account.enabled,
304
+ quotaPercent,
305
+ ...(typeof account.tierLabel === 'string' && {
306
+ tierLabel: account.tierLabel
307
+ }),
308
+ claustrumGate: account.claustrumGate,
309
+ vaultServed: account.vaultServed
310
+ };
311
+ const custodyState = account.custodyState;
312
+ if ((custodyState === 'na' || custodyState === 'off' || custodyState === 'on-vault-served' || custodyState === 'on-vault-reauth' || custodyState === 'on-cold') && typeof account.vaultReauth === 'boolean') {
313
+ return [{
314
+ ...normalized,
315
+ custodyState,
316
+ vaultReauth: account.vaultReauth
317
+ }];
318
+ }
319
+ return [normalized];
320
+ });
321
+ const custodyMode = payload.custodyModeKnown === true && typeof payload.custodyMode === 'string' ? normalizeTuiCustodyMode(payload.custodyMode) : undefined;
322
+ return {
323
+ accounts,
324
+ claustrumDetection: typeof payload.claustrumDetection === 'string' ? payload.claustrumDetection : 'unknown',
325
+ ...(custodyMode && {
326
+ custodyMode
327
+ }),
328
+ ...(typeof payload.enrollmentStatus === 'string' && payload.enrollmentStatus.length <= 2_000 && {
329
+ enrollmentStatus: payload.enrollmentStatus
330
+ })
331
+ };
332
+ }
45
333
  export function buildAccountDialogOption(account) {
46
334
  const pct = account.quotaPercent != null ? ` ${Math.round(account.quotaPercent)}%` : ' \u2013%';
47
335
  const status = !account.enabled ? ' (disabled)' : '';
48
- const gate = ` · gate ${account.claustrumGate === 'na' ? 'n/a' : account.claustrumGate}`;
49
- const vault = account.role === 'main' ? ' · vault n/a' : ` · vault ${account.vaultServed ? 'served' : 'cold'}`;
336
+ const custody = account.custodyState ? account.custodyState === 'na' ? undefined : custodyStatusLabel(account.custodyState).replace(' (OpenCode managed)', '') : undefined;
50
337
  return {
51
- title: `${account.label} [${account.role}]${status}${pct}${gate}${vault}`,
338
+ title: `${account.label} [${account.role}]${status}${pct}${custody ? ` · custody ${custody}` : ''}`,
52
339
  value: account.id,
53
340
  ...(account.tierLabel && {
54
341
  description: account.tierLabel
55
342
  })
56
343
  };
57
344
  }
345
+ export function buildManageAccountOptions(account) {
346
+ const options = [];
347
+ const toggleLabel = account.enabled ? 'Disable' : 'Enable';
348
+ options.push({
349
+ title: toggleLabel,
350
+ value: account.enabled ? 'disable' : 'enable',
351
+ description: account.enabled ? 'Stop using this fallback account' : 'Allow this fallback account to be used'
352
+ });
353
+ options.push({
354
+ title: 'Move up',
355
+ value: 'move-up',
356
+ description: 'Higher priority in fallback order'
357
+ });
358
+ options.push({
359
+ title: 'Move down',
360
+ value: 'move-down',
361
+ description: 'Lower priority in fallback order'
362
+ });
363
+ options.push({
364
+ title: 'Remove\u2026',
365
+ value: 'remove',
366
+ description: 'Delete this account permanently'
367
+ });
368
+ options.push({
369
+ title: 'Back',
370
+ value: 'back'
371
+ });
372
+ return options;
373
+ }
374
+ export function buildAccountDialogL1(value) {
375
+ const payload = normalizeAccountDialogPayload(value);
376
+ const modeAction = payload.custodyMode === 'local' || payload.custodyMode === 'claustrum' ? {
377
+ command: 'claude-account',
378
+ arguments: payload.custodyMode === 'local' ? 'claustrum' : 'local'
379
+ } : undefined;
380
+ return {
381
+ header: payload.custodyMode ? `Custody mode: ${payload.custodyMode}` : 'Custody mode: unavailable from older server',
382
+ options: [...(modeAction ? [{
383
+ title: payload.custodyMode === 'local' ? 'Use Claustrum custody' : 'Use local custody',
384
+ value: '__custody-mode__'
385
+ }] : []), {
386
+ title: 'Add account…',
387
+ value: '__add__',
388
+ description: 'Add an API key or OAuth fallback account'
389
+ }, ...payload.accounts.map(buildAccountDialogOption)],
390
+ ...(payload.enrollmentStatus && {
391
+ enrollmentStatus: payload.enrollmentStatus
392
+ }),
393
+ ...(modeAction && {
394
+ modeAction
395
+ })
396
+ };
397
+ }
398
+ export function retainAccountDialogProjection(current, incoming) {
399
+ return Array.isArray(incoming.accounts) ? incoming : current;
400
+ }
58
401
  function showText(api, text) {
59
402
  api.ui.dialog.setSize('xlarge');
60
403
  api.ui.dialog.replace(() => (() => {
61
- var _el$ = _$createElement("box"),
62
- _el$2 = _$createElement("text");
63
- _$insertNode(_el$, _el$2);
64
- _$setProp(_el$, "flexDirection", 'column');
65
- _$setProp(_el$, "padding", 1);
66
- _$setProp(_el$, "width", '100%');
67
- _$insert(_el$2, text);
68
- return _el$;
404
+ var _el$6 = _$createElement("box"),
405
+ _el$7 = _$createElement("text");
406
+ _$insertNode(_el$6, _el$7);
407
+ _$setProp(_el$6, "flexDirection", 'column');
408
+ _$setProp(_el$6, "padding", 1);
409
+ _$setProp(_el$6, "width", '100%');
410
+ _$insert(_el$7, text);
411
+ return _el$6;
69
412
  })());
70
413
  }
71
414
 
@@ -88,6 +431,8 @@ export function buildPrimeStatusRows(accounts) {
88
431
  const time = formatPrimeTime(account.lastPrimedAt);
89
432
  if (account.lastResult === 'error') {
90
433
  rows.push(`${account.label} \u00b7 primed ${time} err`);
434
+ } else if (account.lastResult === 'skipped') {
435
+ rows.push(`${account.label} \u00b7 primed ${time} skipped`);
91
436
  } else {
92
437
  rows.push(`${account.label} \u00b7 primed ${time} \u2713`);
93
438
  }
@@ -211,9 +556,9 @@ export function openCommandDialog(api, payload, apply) {
211
556
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
212
557
  title: "Claude cachekeep schedule",
213
558
  description: () => (() => {
214
- var _el$3 = _$createElement("text");
215
- _$insert(_el$3, () => payload.text);
216
- return _el$3;
559
+ var _el$8 = _$createElement("text");
560
+ _$insert(_el$8, () => payload.text);
561
+ return _el$8;
217
562
  })(),
218
563
  placeholder: "'always', HH-HH (e.g. 08-20), or 'off'",
219
564
  value: seed,
@@ -242,17 +587,17 @@ export function openCommandDialog(api, payload, apply) {
242
587
  const statusText = `Claude prime status:\n\n${lines.join('\n')}`;
243
588
  api.ui.dialog.setSize('xlarge');
244
589
  api.ui.dialog.replace(() => (() => {
245
- var _el$4 = _$createElement("box"),
246
- _el$5 = _$createElement("text"),
247
- _el$6 = _$createElement("box");
248
- _$insertNode(_el$4, _el$5);
249
- _$insertNode(_el$4, _el$6);
250
- _$setProp(_el$4, "flexDirection", 'column');
251
- _$setProp(_el$4, "padding", 1);
252
- _$setProp(_el$4, "width", '100%');
253
- _$insert(_el$5, statusText);
254
- _$setProp(_el$6, "marginTop", 1);
255
- _$insert(_el$6, _$createComponent(DialogSelect, {
590
+ var _el$9 = _$createElement("box"),
591
+ _el$0 = _$createElement("text"),
592
+ _el$1 = _$createElement("box");
593
+ _$insertNode(_el$9, _el$0);
594
+ _$insertNode(_el$9, _el$1);
595
+ _$setProp(_el$9, "flexDirection", 'column');
596
+ _$setProp(_el$9, "padding", 1);
597
+ _$setProp(_el$9, "width", '100%');
598
+ _$insert(_el$0, statusText);
599
+ _$setProp(_el$1, "marginTop", 1);
600
+ _$insert(_el$1, _$createComponent(DialogSelect, {
256
601
  title: "Claude prime \u2014 status",
257
602
  current: "back",
258
603
  options: [{
@@ -261,7 +606,7 @@ export function openCommandDialog(api, payload, apply) {
261
606
  }],
262
607
  onSelect: option => handlePrimeStatusOption(option, renderMain)
263
608
  }));
264
- return _el$4;
609
+ return _el$9;
265
610
  })());
266
611
  };
267
612
  const renderMain = () => {
@@ -308,9 +653,9 @@ export function openCommandDialog(api, payload, apply) {
308
653
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
309
654
  title: "Killswitch thresholds",
310
655
  description: () => (() => {
311
- var _el$7 = _$createElement("text");
312
- _$insert(_el$7, () => payload.text);
313
- return _el$7;
656
+ var _el$10 = _$createElement("text");
657
+ _$insert(_el$10, () => payload.text);
658
+ return _el$10;
314
659
  })(),
315
660
  placeholder: "main:5,10,0 work-alt:5,10,0",
316
661
  value: seed,
@@ -354,42 +699,99 @@ export function openCommandDialog(api, payload, apply) {
354
699
  return;
355
700
  }
356
701
  if (payload.command === 'claude-account') {
357
- const accounts = payload.knobs.accounts ?? [];
358
- const claustrumDetection = payload.knobs.claustrumDetection ?? 'unknown';
702
+ let accountKnobs = payload.knobs;
703
+ const accounts = normalizeAccountDialogPayload(accountKnobs).accounts;
704
+ let statusMessage;
359
705
  const updateAccounts = r => {
360
- const updated = r.knobs.accounts;
361
- if (updated && updated.length > 0) {
706
+ accountKnobs = retainAccountDialogProjection(accountKnobs, r.knobs);
707
+ const updated = normalizeAccountDialogPayload(accountKnobs).accounts;
708
+ if (updated.length > 0) {
362
709
  accounts.length = 0;
363
710
  accounts.push(...updated);
364
711
  }
365
712
  };
366
713
  const buildL1 = () => {
367
714
  const DialogSelect = api.ui.DialogSelect;
368
- const l1Options = [{
369
- title: 'Add account\u2026',
370
- value: '__add__',
371
- description: 'Add an API key or OAuth fallback account'
372
- }, ...accounts.map(buildAccountDialogOption)];
715
+ const l1 = buildAccountDialogL1({
716
+ ...accountKnobs,
717
+ accounts
718
+ });
373
719
  api.ui.dialog.setSize('xlarge');
374
720
  api.ui.dialog.replace(() => (() => {
375
- var _el$8 = _$createElement("box"),
376
- _el$9 = _$createElement("text"),
377
- _el$0 = _$createElement("box");
378
- _$insertNode(_el$8, _el$9);
379
- _$insertNode(_el$8, _el$0);
380
- _$setProp(_el$8, "flexDirection", 'column');
381
- _$setProp(_el$8, "padding", 1);
382
- _$setProp(_el$8, "width", '100%');
383
- _$insert(_el$9, `Claustrum: ${claustrumDetection}`);
384
- _$setProp(_el$0, "marginTop", 1);
385
- _$insert(_el$0, _$createComponent(DialogSelect, {
721
+ var _el$11 = _$createElement("box"),
722
+ _el$12 = _$createElement("text"),
723
+ _el$13 = _$createElement("text"),
724
+ _el$14 = _$createElement("box");
725
+ _$insertNode(_el$11, _el$12);
726
+ _$insertNode(_el$11, _el$13);
727
+ _$insertNode(_el$11, _el$14);
728
+ _$setProp(_el$11, "flexDirection", 'column');
729
+ _$setProp(_el$11, "padding", 1);
730
+ _$setProp(_el$11, "width", '100%');
731
+ _$insert(_el$12, () => `Claustrum: ${normalizeAccountDialogPayload(accountKnobs).claustrumDetection}`);
732
+ _$insert(_el$13, () => l1.header);
733
+ _$insert(_el$11, (() => {
734
+ var _c$2 = _$memo(() => !!l1.enrollmentStatus);
735
+ return () => _c$2() && (() => {
736
+ var _el$15 = _$createElement("box"),
737
+ _el$16 = _$createElement("text");
738
+ _$insertNode(_el$15, _el$16);
739
+ _$setProp(_el$15, "marginTop", 1);
740
+ _$insert(_el$16, () => l1.enrollmentStatus);
741
+ return _el$15;
742
+ })();
743
+ })(), _el$14);
744
+ _$insert(_el$11, statusMessage && (() => {
745
+ var _el$17 = _$createElement("box"),
746
+ _el$18 = _$createElement("text");
747
+ _$insertNode(_el$17, _el$18);
748
+ _$setProp(_el$17, "marginTop", 1);
749
+ _$insert(_el$18, () => statusMessage.text);
750
+ _$effect(_$p => _$setProp(_el$18, "fg", statusMessage.error ? '#ef4444' : '#22c55e', _$p));
751
+ return _el$17;
752
+ })(), _el$14);
753
+ _$setProp(_el$14, "marginTop", 1);
754
+ _$insert(_el$14, _$createComponent(DialogSelect, {
386
755
  title: "Claude accounts",
387
- options: l1Options,
756
+ get options() {
757
+ return l1.options;
758
+ },
388
759
  onSelect: option => {
389
760
  if (option.value === '__add__') {
761
+ statusMessage = undefined;
390
762
  openAddType();
391
763
  return;
392
764
  }
765
+ if (option.value === '__custody-mode__' && l1.modeAction) {
766
+ void apply(l1.modeAction.command, l1.modeAction.arguments).then(r => {
767
+ const isRefusalOrError = r.text.includes('refused') || r.text.includes('unavailable') || r.text.includes('failed') || r.text.includes('Error') || r.text.includes('error');
768
+ if (isRefusalOrError) {
769
+ statusMessage = {
770
+ text: r.text,
771
+ error: true
772
+ };
773
+ } else {
774
+ statusMessage = {
775
+ text: r.text,
776
+ error: false
777
+ };
778
+ api.ui.toast({
779
+ message: r.text
780
+ });
781
+ }
782
+ updateAccounts(r);
783
+ buildL1();
784
+ }).catch(err => {
785
+ const msg = err instanceof Error ? err.message : String(err);
786
+ statusMessage = {
787
+ text: `Error: ${msg}`,
788
+ error: true
789
+ };
790
+ buildL1();
791
+ });
792
+ return;
793
+ }
794
+ statusMessage = undefined;
393
795
  const account = accounts.find(a => a.id === option.value);
394
796
  if (!account) return;
395
797
  if (account.role === 'main') {
@@ -400,7 +802,7 @@ export function openCommandDialog(api, payload, apply) {
400
802
  openManage(account, false);
401
803
  }
402
804
  }));
403
- return _el$8;
805
+ return _el$11;
404
806
  })());
405
807
  };
406
808
 
@@ -445,9 +847,9 @@ export function openCommandDialog(api, payload, apply) {
445
847
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
446
848
  title: "Add API key account \\u2014 API key",
447
849
  description: () => (() => {
448
- var _el$1 = _$createElement("text");
449
- _$insertNode(_el$1, _$createTextNode(`Paste your API key (required).`));
450
- return _el$1;
850
+ var _el$19 = _$createElement("text");
851
+ _$insertNode(_el$19, _$createTextNode(`Paste your API key (required).`));
852
+ return _el$19;
451
853
  })(),
452
854
  placeholder: "sk-ant-...",
453
855
  value: "",
@@ -469,9 +871,9 @@ export function openCommandDialog(api, payload, apply) {
469
871
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
470
872
  title: "Add API key account \\u2014 base URL",
471
873
  description: () => (() => {
472
- var _el$11 = _$createElement("text");
473
- _$insertNode(_el$11, _$createTextNode(`Anthropic-compatible API base URL. Default: https://api.kie.ai/claude`));
474
- return _el$11;
874
+ var _el$21 = _$createElement("text");
875
+ _$insertNode(_el$21, _$createTextNode(`Anthropic-compatible API base URL. Default: https://api.kie.ai/claude`));
876
+ return _el$21;
475
877
  })(),
476
878
  placeholder: "https://api.kie.ai/claude",
477
879
  value: "",
@@ -509,9 +911,9 @@ export function openCommandDialog(api, payload, apply) {
509
911
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
510
912
  title: "Add API key account \\u2014 label",
511
913
  description: () => (() => {
512
- var _el$13 = _$createElement("text");
513
- _$insertNode(_el$13, _$createTextNode(`A short name for this account (optional).`));
514
- return _el$13;
914
+ var _el$23 = _$createElement("text");
915
+ _$insertNode(_el$23, _$createTextNode(`A short name for this account (optional).`));
916
+ return _el$23;
515
917
  })(),
516
918
  placeholder: "e.g. Work API",
517
919
  value: "",
@@ -605,9 +1007,9 @@ export function openCommandDialog(api, payload, apply) {
605
1007
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
606
1008
  title: "OAuth sign-in \\u2014 enter code",
607
1009
  description: () => (() => {
608
- var _el$15 = _$createElement("text");
609
- _$insertNode(_el$15, _$createTextNode(`After signing in you will be redirected. Paste the full callback URL or authorization code below.`));
610
- return _el$15;
1010
+ var _el$25 = _$createElement("text");
1011
+ _$insertNode(_el$25, _$createTextNode(`After signing in you will be redirected. Paste the full callback URL or authorization code below.`));
1012
+ return _el$25;
611
1013
  })(),
612
1014
  placeholder: "Paste callback URL or code here",
613
1015
  value: "",
@@ -628,9 +1030,9 @@ export function openCommandDialog(api, payload, apply) {
628
1030
  api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
629
1031
  title: "OAuth sign-in \\u2014 label",
630
1032
  description: () => (() => {
631
- var _el$17 = _$createElement("text");
632
- _$insertNode(_el$17, _$createTextNode(`A short name for this account (optional).`));
633
- return _el$17;
1033
+ var _el$27 = _$createElement("text");
1034
+ _$insertNode(_el$27, _$createTextNode(`A short name for this account (optional).`));
1035
+ return _el$27;
634
1036
  })(),
635
1037
  placeholder: "e.g. work",
636
1038
  value: "",
@@ -654,34 +1056,10 @@ export function openCommandDialog(api, payload, apply) {
654
1056
  const DialogSelect = api.ui.DialogSelect;
655
1057
  const DialogConfirm = api.ui.DialogConfirm;
656
1058
  api.ui.dialog.setSize('xlarge');
657
- const options = [];
658
- if (!isMain) {
659
- const toggleLabel = account.enabled ? 'Disable' : 'Enable';
660
- options.push({
661
- title: toggleLabel,
662
- value: account.enabled ? 'disable' : 'enable',
663
- description: account.enabled ? 'Stop using this fallback account' : 'Allow this fallback account to be used'
664
- });
665
- options.push({
666
- title: 'Move up',
667
- value: 'move-up',
668
- description: 'Higher priority in fallback order'
669
- });
670
- options.push({
671
- title: 'Move down',
672
- value: 'move-down',
673
- description: 'Lower priority in fallback order'
674
- });
675
- options.push({
676
- title: 'Remove\u2026',
677
- value: 'remove',
678
- description: 'Delete this account permanently'
679
- });
680
- }
681
- options.push({
1059
+ const options = isMain ? [{
682
1060
  title: 'Back',
683
1061
  value: 'back'
684
- });
1062
+ }] : buildManageAccountOptions(account);
685
1063
  api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
686
1064
  get title() {
687
1065
  return `Manage ${account.label}`;
@@ -707,20 +1085,35 @@ export function openCommandDialog(api, payload, apply) {
707
1085
  });
708
1086
  updateAccounts(r);
709
1087
  buildL1();
1088
+ }).catch(err => {
1089
+ const msg = err instanceof Error ? err.message : String(err);
1090
+ statusMessage = {
1091
+ text: `Error: ${msg}`,
1092
+ error: true
1093
+ };
1094
+ buildL1();
710
1095
  });
711
1096
  },
712
1097
  onCancel: () => openManage(account, isMain)
713
1098
  }));
714
1099
  return;
715
1100
  }
716
- void apply('claude-account', `${option.value} ${account.id}`).then(r => {
1101
+ const args = `${option.value} ${account.id}`;
1102
+ void apply('claude-account', args).then(r => {
717
1103
  api.ui.toast({
718
1104
  message: r.text
719
1105
  });
720
1106
  updateAccounts(r);
721
- const updatedList = r.knobs.accounts;
1107
+ const updatedList = normalizeAccountDialogPayload(r.knobs).accounts;
722
1108
  const refreshed = (updatedList && updatedList.length > 0 ? updatedList.find(a => a.id === account.id) : undefined) ?? account;
723
1109
  openManage(refreshed, isMain);
1110
+ }).catch(err => {
1111
+ const msg = err instanceof Error ? err.message : String(err);
1112
+ statusMessage = {
1113
+ text: `Error: ${msg}`,
1114
+ error: true
1115
+ };
1116
+ buildL1();
724
1117
  });
725
1118
  }
726
1119
  }));