@cortexkit/opencode-anthropic-auth 1.15.0 → 1.15.1

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.
@@ -0,0 +1,615 @@
1
+ import { createTextNode as _$createTextNode } from "opentui:runtime-module:%40opentui%2Fsolid";
2
+ import { createComponent as _$createComponent } from "opentui:runtime-module:%40opentui%2Fsolid";
3
+ import { insertNode as _$insertNode } from "opentui:runtime-module:%40opentui%2Fsolid";
4
+ import { insert as _$insert } from "opentui:runtime-module:%40opentui%2Fsolid";
5
+ import { setProp as _$setProp } from "opentui:runtime-module:%40opentui%2Fsolid";
6
+ import { createElement as _$createElement } from "opentui:runtime-module:%40opentui%2Fsolid";
7
+ /** @jsxImportSource @opentui/solid */
8
+
9
+ export function buildKillswitchThresholdSeed(config, accountIds) {
10
+ const readT = t => {
11
+ const fh = t?.five_hour ?? t?.['5h'] ?? 5;
12
+ const sd = t?.seven_day ?? t?.['1w'] ?? 10;
13
+ const scoped = t?.scoped ?? 0;
14
+ return {
15
+ fh,
16
+ sd,
17
+ scoped
18
+ };
19
+ };
20
+ const mainT = readT(config.main);
21
+ const seedParts = [`main:${mainT.fh},${mainT.sd},${mainT.scoped}`];
22
+ for (const id of accountIds) {
23
+ const t = readT(config.accounts?.[id] ?? config.main);
24
+ seedParts.push(`${id}:${t.fh},${t.sd},${t.scoped}`);
25
+ }
26
+ return seedParts.join(' ');
27
+ }
28
+ function showText(api, text) {
29
+ api.ui.dialog.setSize('xlarge');
30
+ api.ui.dialog.replace(() => (() => {
31
+ var _el$ = _$createElement("box"),
32
+ _el$2 = _$createElement("text");
33
+ _$insertNode(_el$, _el$2);
34
+ _$setProp(_el$, "flexDirection", 'column');
35
+ _$setProp(_el$, "padding", 1);
36
+ _$setProp(_el$, "width", '100%');
37
+ _$insert(_el$2, text);
38
+ return _el$;
39
+ })());
40
+ }
41
+ export function openCommandDialog(api, payload, apply) {
42
+ if (payload.command === 'claude-routing') {
43
+ const current = payload.knobs.mode ?? 'main-first';
44
+ const DialogSelect = api.ui.DialogSelect;
45
+ api.ui.dialog.setSize('xlarge');
46
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
47
+ title: "Claude routing",
48
+ current: current,
49
+ options: [{
50
+ title: 'Main first',
51
+ value: 'main-first',
52
+ description: 'Use the main account until exhausted'
53
+ }, {
54
+ title: 'Fallback first',
55
+ value: 'fallback-first',
56
+ description: 'Prefer fallback accounts, preserve main'
57
+ }],
58
+ onSelect: option => {
59
+ void apply('claude-routing', String(option.value)).then(r => {
60
+ api.ui.toast({
61
+ message: r.text
62
+ });
63
+ api.ui.dialog.clear();
64
+ });
65
+ }
66
+ }));
67
+ return;
68
+ }
69
+ if (payload.command === 'claude-fast' || payload.command === 'claude-dump') {
70
+ const enabled = payload.knobs.enabled === true;
71
+ const label = payload.command === 'claude-fast' ? 'fast mode' : 'request dump';
72
+ const DialogConfirm = api.ui.DialogConfirm;
73
+ api.ui.dialog.setSize('xlarge');
74
+ api.ui.dialog.replace(() => _$createComponent(DialogConfirm, {
75
+ title: `Claude ${label}`,
76
+ get message() {
77
+ return `${payload.text}\n\n${enabled ? 'Disable' : 'Enable'} ${label}?`;
78
+ },
79
+ onConfirm: () => {
80
+ void apply(payload.command, enabled ? 'off' : 'on').then(r => {
81
+ api.ui.toast({
82
+ message: r.text
83
+ });
84
+ api.ui.dialog.clear();
85
+ });
86
+ },
87
+ onCancel: () => api.ui.dialog.clear()
88
+ }));
89
+ return;
90
+ }
91
+ if (payload.command === 'claude-cache') {
92
+ const enabled = payload.knobs.enabled === true;
93
+ const mode = payload.knobs.mode ?? 'hybrid';
94
+ const currentValue = enabled ? mode : 'off';
95
+ const DialogSelect = api.ui.DialogSelect;
96
+ api.ui.dialog.setSize('xlarge');
97
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
98
+ title: "Claude 1h cache",
99
+ current: currentValue,
100
+ options: [{
101
+ title: 'Off',
102
+ value: 'off',
103
+ description: 'Disable 1h cache'
104
+ }, {
105
+ title: 'Explicit',
106
+ value: 'explicit',
107
+ description: 'Existing OpenCode breakpoints'
108
+ }, {
109
+ title: 'Automatic',
110
+ value: 'automatic',
111
+ description: 'Top-level cache_control only'
112
+ }, {
113
+ title: 'Hybrid',
114
+ value: 'hybrid',
115
+ description: 'system + messages[0] + top-level'
116
+ }],
117
+ onSelect: option => {
118
+ if (option.value === 'off') {
119
+ void apply('claude-cache', 'off').then(r => {
120
+ api.ui.toast({
121
+ message: r.text
122
+ });
123
+ api.ui.dialog.clear();
124
+ });
125
+ return;
126
+ }
127
+ void apply('claude-cache', `mode ${option.value}`).then(() => apply('claude-cache', 'on')).then(r => {
128
+ api.ui.toast({
129
+ message: r.text
130
+ });
131
+ api.ui.dialog.clear();
132
+ });
133
+ }
134
+ }));
135
+ return;
136
+ }
137
+ if (payload.command === 'claude-cachekeep') {
138
+ const window = payload.knobs.window;
139
+ const seed = window ? `${String(window.startHour).padStart(2, '0')}-${String(window.endHour).padStart(2, '0')}` : '';
140
+ const DialogPrompt = api.ui.DialogPrompt;
141
+ api.ui.dialog.setSize('xlarge');
142
+ api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
143
+ title: "Claude cachekeep window",
144
+ description: () => (() => {
145
+ var _el$3 = _$createElement("text");
146
+ _$insert(_el$3, () => payload.text);
147
+ return _el$3;
148
+ })(),
149
+ placeholder: "HH-HH (e.g. 08-20) or 'off'",
150
+ value: seed,
151
+ onConfirm: value => {
152
+ void apply('claude-cachekeep', value.trim()).then(r => {
153
+ api.ui.toast({
154
+ message: r.text
155
+ });
156
+ api.ui.dialog.clear();
157
+ });
158
+ },
159
+ onCancel: () => api.ui.dialog.clear()
160
+ }));
161
+ return;
162
+ }
163
+ if (payload.command === 'claude-killswitch') {
164
+ const config = payload.knobs.config ?? {};
165
+ const accountIds = payload.knobs.accountIds ?? [];
166
+ const enabled = config.enabled === true;
167
+ const seed = buildKillswitchThresholdSeed(config, accountIds);
168
+ const openEdit = () => {
169
+ const DialogPrompt = api.ui.DialogPrompt;
170
+ api.ui.dialog.setSize('xlarge');
171
+ api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
172
+ title: "Killswitch thresholds",
173
+ description: () => (() => {
174
+ var _el$4 = _$createElement("text");
175
+ _$insert(_el$4, () => payload.text);
176
+ return _el$4;
177
+ })(),
178
+ placeholder: "main:5,10,0 work-alt:5,10,0",
179
+ value: seed,
180
+ onConfirm: value => {
181
+ void apply('claude-killswitch', `set ${value.trim()}`).then(r => {
182
+ api.ui.toast({
183
+ message: r.text
184
+ });
185
+ api.ui.dialog.clear();
186
+ });
187
+ },
188
+ onCancel: () => api.ui.dialog.clear()
189
+ }));
190
+ };
191
+ const DialogSelect = api.ui.DialogSelect;
192
+ api.ui.dialog.setSize('xlarge');
193
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
194
+ title: "Claude killswitch",
195
+ options: [{
196
+ title: enabled ? 'Disable killswitch' : 'Enable killswitch',
197
+ value: enabled ? 'off' : 'on',
198
+ description: enabled ? 'Stop hard-blocking on low quota' : 'Hard-block requests when quota drops below thresholds'
199
+ }, {
200
+ title: 'Edit thresholds…',
201
+ value: 'edit',
202
+ description: 'Set per-account 5h,1w,scoped cutoffs'
203
+ }],
204
+ onSelect: option => {
205
+ if (option.value === 'edit') {
206
+ openEdit();
207
+ return;
208
+ }
209
+ void apply('claude-killswitch', String(option.value)).then(r => {
210
+ api.ui.toast({
211
+ message: r.text
212
+ });
213
+ api.ui.dialog.clear();
214
+ });
215
+ }
216
+ }));
217
+ return;
218
+ }
219
+ if (payload.command === 'claude-account') {
220
+ const accounts = payload.knobs.accounts ?? [];
221
+ const updateAccounts = r => {
222
+ const updated = r.knobs.accounts;
223
+ if (updated && updated.length > 0) {
224
+ accounts.length = 0;
225
+ accounts.push(...updated);
226
+ }
227
+ };
228
+ const buildL1 = () => {
229
+ const DialogSelect = api.ui.DialogSelect;
230
+ const l1Options = [{
231
+ title: 'Add account\u2026',
232
+ value: '__add__',
233
+ description: 'Add an API key or OAuth fallback account'
234
+ }, ...accounts.map(a => {
235
+ const pct = a.quotaPercent != null ? ` ${Math.round(a.quotaPercent)}%` : ' \u2013%';
236
+ const status = !a.enabled ? ' (disabled)' : '';
237
+ return {
238
+ title: `${a.label} [${a.role}]${status}${pct}`,
239
+ value: a.id
240
+ };
241
+ })];
242
+ api.ui.dialog.setSize('xlarge');
243
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
244
+ title: "Claude accounts",
245
+ options: l1Options,
246
+ onSelect: option => {
247
+ if (option.value === '__add__') {
248
+ openAddType();
249
+ return;
250
+ }
251
+ const account = accounts.find(a => a.id === option.value);
252
+ if (!account) return;
253
+ if (account.role === 'main') {
254
+ const pct = account.quotaPercent != null ? ` ${Math.round(account.quotaPercent)}%` : ' \u2013%';
255
+ showText(api, `${account.label}\nRole: main (read-only)\nQuota:${pct}`);
256
+ return;
257
+ }
258
+ openManage(account, false);
259
+ }
260
+ }));
261
+ };
262
+
263
+ // -- Add type selection (OAuth vs API key) ------------------------------
264
+ const openAddType = () => {
265
+ const DialogSelect = api.ui.DialogSelect;
266
+ api.ui.dialog.setSize('xlarge');
267
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
268
+ title: "Add account",
269
+ options: [{
270
+ title: 'OAuth (login)',
271
+ value: 'oauth',
272
+ description: 'Sign in to Claude via browser — works with Pro, Max, and Team plans'
273
+ }, {
274
+ title: 'API key',
275
+ value: 'apikey',
276
+ description: 'Provide an API key for an Anthropic-compatible endpoint'
277
+ }, {
278
+ title: 'Back',
279
+ value: 'back'
280
+ }],
281
+ onSelect: option => {
282
+ if (option.value === 'back') {
283
+ buildL1();
284
+ return;
285
+ }
286
+ if (option.value === 'apikey') {
287
+ openAddApiKey();
288
+ return;
289
+ }
290
+ openAddOAuthStart();
291
+ }
292
+ }));
293
+ };
294
+
295
+ // -- Add API key (multi-step: key → baseURL → authHeader → label) ------
296
+ const openAddApiKey = () => {
297
+ const collected = {};
298
+ const openApiKeyPrompt = () => {
299
+ const DialogPrompt = api.ui.DialogPrompt;
300
+ api.ui.dialog.setSize('xlarge');
301
+ api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
302
+ title: "Add API key account \\u2014 API key",
303
+ description: () => (() => {
304
+ var _el$5 = _$createElement("text");
305
+ _$insertNode(_el$5, _$createTextNode(`Paste your API key (required).`));
306
+ return _el$5;
307
+ })(),
308
+ placeholder: "sk-ant-...",
309
+ value: "",
310
+ onConfirm: value => {
311
+ const trimmed = value.trim();
312
+ if (!trimmed) {
313
+ openAddType();
314
+ return;
315
+ }
316
+ collected.apiKey = trimmed;
317
+ openBaseURLPrompt();
318
+ },
319
+ onCancel: () => openAddType()
320
+ }));
321
+ };
322
+ const openBaseURLPrompt = () => {
323
+ const DialogPrompt = api.ui.DialogPrompt;
324
+ api.ui.dialog.setSize('xlarge');
325
+ api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
326
+ title: "Add API key account \\u2014 base URL",
327
+ description: () => (() => {
328
+ var _el$7 = _$createElement("text");
329
+ _$insertNode(_el$7, _$createTextNode(`Anthropic-compatible API base URL. Default: https://api.kie.ai/claude`));
330
+ return _el$7;
331
+ })(),
332
+ placeholder: "https://api.kie.ai/claude",
333
+ value: "",
334
+ onConfirm: value => {
335
+ const trimmed = value.trim();
336
+ collected.baseURL = trimmed || 'https://api.kie.ai/claude';
337
+ openAuthHeaderSelect();
338
+ },
339
+ onCancel: () => openApiKeyPrompt()
340
+ }));
341
+ };
342
+ const openAuthHeaderSelect = () => {
343
+ const DialogSelect = api.ui.DialogSelect;
344
+ api.ui.dialog.setSize('xlarge');
345
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
346
+ title: "Add API key account \\u2014 auth header",
347
+ options: [{
348
+ title: 'Authorization: Bearer (default)',
349
+ value: 'authorization-bearer',
350
+ description: 'Standard bearer token authentication'
351
+ }, {
352
+ title: 'X-API-Key',
353
+ value: 'x-api-key',
354
+ description: 'Custom header-based API key'
355
+ }],
356
+ onSelect: option => {
357
+ collected.authHeader = option.value;
358
+ openLabelPrompt();
359
+ }
360
+ }));
361
+ };
362
+ const openLabelPrompt = () => {
363
+ const DialogPrompt = api.ui.DialogPrompt;
364
+ api.ui.dialog.setSize('xlarge');
365
+ api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
366
+ title: "Add API key account \\u2014 label",
367
+ description: () => (() => {
368
+ var _el$9 = _$createElement("text");
369
+ _$insertNode(_el$9, _$createTextNode(`A short name for this account (optional).`));
370
+ return _el$9;
371
+ })(),
372
+ placeholder: "e.g. Work API",
373
+ value: "",
374
+ onConfirm: value => {
375
+ const trimmed = value.trim();
376
+ collected.label = trimmed || undefined;
377
+ const apiKey = collected.apiKey;
378
+ if (!apiKey) return;
379
+ let args = `add-apikey ${apiKey}`;
380
+ if (collected.baseURL && collected.baseURL !== 'https://api.kie.ai/claude') {
381
+ args += ` --base-url ${collected.baseURL}`;
382
+ }
383
+ if (collected.authHeader && collected.authHeader !== 'authorization-bearer') {
384
+ args += ` --auth-header ${collected.authHeader}`;
385
+ }
386
+ if (collected.label) {
387
+ args += ` --label ${collected.label}`;
388
+ }
389
+ void apply('claude-account', args).then(r => {
390
+ api.ui.toast({
391
+ message: r.text
392
+ });
393
+ updateAccounts(r);
394
+ buildL1();
395
+ });
396
+ },
397
+ onCancel: () => openAuthHeaderSelect()
398
+ }));
399
+ };
400
+ openApiKeyPrompt();
401
+ };
402
+
403
+ // -- Add OAuth (OSC-52 copy + code entry) ------------------------------
404
+ const openAddOAuthStart = () => {
405
+ void apply('claude-account', 'add-oauth-start').then(r => {
406
+ const oauthUrl = r.knobs.oauthUrl;
407
+ updateAccounts(r);
408
+ if (oauthUrl) {
409
+ openOAuthUrlScreen(oauthUrl);
410
+ } else {
411
+ api.ui.toast({
412
+ message: r.text
413
+ });
414
+ buildL1();
415
+ }
416
+ });
417
+ };
418
+ const openOAuthUrlScreen = oauthUrl => {
419
+ const DialogSelect = api.ui.DialogSelect;
420
+ api.ui.dialog.setSize('xlarge');
421
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
422
+ title: "OAuth sign-in",
423
+ options: [{
424
+ title: 'Copy URL to clipboard',
425
+ value: 'copy',
426
+ description: oauthUrl
427
+ }, {
428
+ title: 'Enter sign-in code',
429
+ value: 'code',
430
+ description: 'Open the URL in your browser, sign in, then paste the callback URL or code'
431
+ }, {
432
+ title: 'Cancel',
433
+ value: 'cancel'
434
+ }],
435
+ onSelect: option => {
436
+ if (option.value === 'cancel') {
437
+ buildL1();
438
+ return;
439
+ }
440
+ if (option.value === 'copy') {
441
+ const ok = api.renderer.copyToClipboardOSC52(oauthUrl);
442
+ if (ok) {
443
+ api.ui.toast({
444
+ message: 'URL copied to clipboard'
445
+ });
446
+ } else {
447
+ api.ui.toast({
448
+ message: 'Copy unavailable \u2014 select the URL text above to copy'
449
+ });
450
+ }
451
+ openOAuthUrlScreen(oauthUrl);
452
+ return;
453
+ }
454
+ openOAuthCodePrompt(oauthUrl);
455
+ }
456
+ }));
457
+ };
458
+ const openOAuthCodePrompt = oauthUrl => {
459
+ const DialogPrompt = api.ui.DialogPrompt;
460
+ api.ui.dialog.setSize('xlarge');
461
+ api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
462
+ title: "OAuth sign-in \\u2014 enter code",
463
+ description: () => (() => {
464
+ var _el$1 = _$createElement("text");
465
+ _$insertNode(_el$1, _$createTextNode(`After signing in you will be redirected. Paste the full callback URL or authorization code below.`));
466
+ return _el$1;
467
+ })(),
468
+ placeholder: "Paste callback URL or code here",
469
+ value: "",
470
+ onConfirm: value => {
471
+ const trimmed = value.trim();
472
+ if (!trimmed) {
473
+ buildL1();
474
+ return;
475
+ }
476
+ openOAuthLabelPrompt(trimmed, oauthUrl);
477
+ },
478
+ onCancel: () => openOAuthUrlScreen(oauthUrl)
479
+ }));
480
+ };
481
+ const openOAuthLabelPrompt = (code, oauthUrl) => {
482
+ const DialogPrompt = api.ui.DialogPrompt;
483
+ api.ui.dialog.setSize('xlarge');
484
+ api.ui.dialog.replace(() => _$createComponent(DialogPrompt, {
485
+ title: "OAuth sign-in \\u2014 label",
486
+ description: () => (() => {
487
+ var _el$11 = _$createElement("text");
488
+ _$insertNode(_el$11, _$createTextNode(`A short name for this account (optional).`));
489
+ return _el$11;
490
+ })(),
491
+ placeholder: "e.g. work",
492
+ value: "",
493
+ onConfirm: value => {
494
+ const label = value.trim();
495
+ const args = label ? `add-oauth-finish ${code} --label ${label}` : `add-oauth-finish ${code}`;
496
+ void apply('claude-account', args).then(r => {
497
+ api.ui.toast({
498
+ message: r.text
499
+ });
500
+ updateAccounts(r);
501
+ buildL1();
502
+ });
503
+ },
504
+ onCancel: () => openOAuthCodePrompt(oauthUrl)
505
+ }));
506
+ };
507
+
508
+ // -- Manage existing account -------------------------------------------
509
+ const openManage = (account, isMain) => {
510
+ const DialogSelect = api.ui.DialogSelect;
511
+ const DialogConfirm = api.ui.DialogConfirm;
512
+ api.ui.dialog.setSize('xlarge');
513
+ const options = [];
514
+ if (!isMain) {
515
+ const toggleLabel = account.enabled ? 'Disable' : 'Enable';
516
+ options.push({
517
+ title: toggleLabel,
518
+ value: account.enabled ? 'disable' : 'enable',
519
+ description: account.enabled ? 'Stop using this fallback account' : 'Allow this fallback account to be used'
520
+ });
521
+ options.push({
522
+ title: 'Move up',
523
+ value: 'move-up',
524
+ description: 'Higher priority in fallback order'
525
+ });
526
+ options.push({
527
+ title: 'Move down',
528
+ value: 'move-down',
529
+ description: 'Lower priority in fallback order'
530
+ });
531
+ options.push({
532
+ title: 'Remove\u2026',
533
+ value: 'remove',
534
+ description: 'Delete this account permanently'
535
+ });
536
+ }
537
+ options.push({
538
+ title: 'Back',
539
+ value: 'back'
540
+ });
541
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
542
+ get title() {
543
+ return `Manage ${account.label}`;
544
+ },
545
+ options: options,
546
+ onSelect: option => {
547
+ if (option.value === 'back') {
548
+ buildL1();
549
+ return;
550
+ }
551
+ if (option.value === 'remove') {
552
+ api.ui.dialog.replace(() => _$createComponent(DialogConfirm, {
553
+ get title() {
554
+ return `Remove ${account.label}?`;
555
+ },
556
+ get message() {
557
+ return `Are you sure you want to remove the fallback account "${account.label}"?`;
558
+ },
559
+ onConfirm: () => {
560
+ void apply('claude-account', `remove ${account.id}`).then(r => {
561
+ api.ui.toast({
562
+ message: r.text
563
+ });
564
+ updateAccounts(r);
565
+ buildL1();
566
+ });
567
+ },
568
+ onCancel: () => openManage(account, isMain)
569
+ }));
570
+ return;
571
+ }
572
+ void apply('claude-account', `${option.value} ${account.id}`).then(r => {
573
+ api.ui.toast({
574
+ message: r.text
575
+ });
576
+ updateAccounts(r);
577
+ const updatedList = r.knobs.accounts;
578
+ const refreshed = (updatedList && updatedList.length > 0 ? updatedList.find(a => a.id === account.id) : undefined) ?? account;
579
+ openManage(refreshed, isMain);
580
+ });
581
+ }
582
+ }));
583
+ };
584
+ buildL1();
585
+ return;
586
+ }
587
+ if (payload.command === 'claude-logging') {
588
+ const current = payload.knobs.level ?? 'info';
589
+ const levels = ['error', 'warn', 'info', 'debug', 'trace'];
590
+ const DialogSelect = api.ui.DialogSelect;
591
+ api.ui.dialog.setSize('xlarge');
592
+ api.ui.dialog.replace(() => _$createComponent(DialogSelect, {
593
+ title: "Claude log level",
594
+ current: current,
595
+ get options() {
596
+ return levels.map(level => ({
597
+ title: level === current ? `\u2022 ${level}` : level,
598
+ value: level
599
+ }));
600
+ },
601
+ onSelect: option => {
602
+ void apply('claude-logging', String(option.value)).then(r => {
603
+ api.ui.toast({
604
+ message: r.text
605
+ });
606
+ api.ui.dialog.clear();
607
+ });
608
+ }
609
+ }));
610
+ return;
611
+ }
612
+
613
+ // fallback for quota (display-only)
614
+ showText(api, payload.text);
615
+ }