hedgequantx 2.5.24 → 2.5.26

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.
@@ -10,7 +10,6 @@ const { getLogoWidth, drawBoxHeader, drawBoxHeaderContinue, drawBoxFooter, displ
10
10
  const { prompts } = require('../utils');
11
11
  const aiService = require('../services/ai');
12
12
  const { getCategories, getProvidersByCategory } = require('../services/ai/providers');
13
- const tokenScanner = require('../services/ai/token-scanner');
14
13
  const oauthAnthropic = require('../services/ai/oauth-anthropic');
15
14
 
16
15
  /**
@@ -39,7 +38,7 @@ const aiAgentMenu = async () => {
39
38
  const agentCount = agents.length;
40
39
 
41
40
  if (agentCount === 0) {
42
- console.log(makeLine(chalk.gray('STATUS: NO AGENTS CONNECTED'), 'left'));
41
+ console.log(makeLine(chalk.white('STATUS: NO AGENTS CONNECTED'), 'left'));
43
42
  } else {
44
43
  console.log(makeLine(chalk.green(`STATUS: ${agentCount} AGENT${agentCount > 1 ? 'S' : ''} CONNECTED`), 'left'));
45
44
  console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
@@ -49,16 +48,26 @@ const aiAgentMenu = async () => {
49
48
  const agent = agents[i];
50
49
  // Show ACTIVE marker (if single agent, it's always active)
51
50
  const isActive = agent.isActive || agents.length === 1;
52
- const activeMarker = isActive ? chalk.green(' [ACTIVE]') : '';
51
+ const activeMarker = isActive ? ' [ACTIVE]' : '';
53
52
  const providerColor = agent.providerId === 'anthropic' ? chalk.magenta :
54
53
  agent.providerId === 'openai' ? chalk.green :
55
54
  agent.providerId === 'openrouter' ? chalk.yellow : chalk.cyan;
56
55
 
56
+ // Calculate max lengths to fit in box
57
+ const prefix = `[${i + 1}] `;
58
+ const suffix = ` - ${agent.model || 'N/A'}`;
59
+ const maxNameLen = W - prefix.length - activeMarker.length - suffix.length - 2;
60
+
61
+ // Truncate agent name if too long
62
+ const displayName = agent.name.length > maxNameLen
63
+ ? agent.name.substring(0, maxNameLen - 3) + '...'
64
+ : agent.name;
65
+
57
66
  console.log(makeLine(
58
- chalk.white(`[${i + 1}] `) +
59
- providerColor(agent.name) +
60
- activeMarker +
61
- chalk.gray(` - ${agent.model}`)
67
+ chalk.white(prefix) +
68
+ providerColor(displayName) +
69
+ chalk.green(activeMarker) +
70
+ chalk.white(suffix)
62
71
  ));
63
72
  }
64
73
  }
@@ -96,13 +105,13 @@ const aiAgentMenu = async () => {
96
105
  if (agentCount > 1) {
97
106
  menuRow2(menuItem('+', 'ADD AGENT', chalk.green), menuItem('S', 'SET ACTIVE', chalk.cyan));
98
107
  menuRow2(menuItem('M', 'CHANGE MODEL', chalk.yellow), menuItem('R', 'REMOVE AGENT', chalk.red));
99
- menuRow2(menuItem('X', 'REMOVE ALL', chalk.red), menuItem('<', 'BACK', chalk.gray));
108
+ menuRow2(menuItem('X', 'REMOVE ALL', chalk.red), menuItem('<', 'BACK', chalk.white));
100
109
  } else {
101
110
  menuRow2(menuItem('+', 'ADD AGENT', chalk.green), menuItem('M', 'CHANGE MODEL', chalk.yellow));
102
- menuRow2(menuItem('R', 'REMOVE AGENT', chalk.red), menuItem('<', 'BACK', chalk.gray));
111
+ menuRow2(menuItem('R', 'REMOVE AGENT', chalk.red), menuItem('<', 'BACK', chalk.white));
103
112
  }
104
113
  } else {
105
- menuRow2(menuItem('+', 'ADD AGENT', chalk.green), menuItem('<', 'BACK', chalk.gray));
114
+ menuRow2(menuItem('+', 'ADD AGENT', chalk.green), menuItem('<', 'BACK', chalk.white));
106
115
  }
107
116
 
108
117
  drawBoxFooter(boxWidth);
@@ -118,7 +127,7 @@ const aiAgentMenu = async () => {
118
127
 
119
128
  switch (input) {
120
129
  case '+':
121
- return await showExistingTokens();
130
+ return await selectCategory();
122
131
  case 's':
123
132
  if (agentCount > 1) {
124
133
  return await selectActiveAgent();
@@ -171,9 +180,9 @@ const showAgentDetails = async (agent) => {
171
180
  agent.providerId === 'openrouter' ? chalk.yellow : chalk.cyan;
172
181
 
173
182
  console.log(makeLine(chalk.white('NAME: ') + providerColor(agent.name)));
174
- console.log(makeLine(chalk.white('PROVIDER: ') + chalk.gray(agent.provider?.name || agent.providerId)));
175
- console.log(makeLine(chalk.white('MODEL: ') + chalk.gray(agent.model)));
176
- console.log(makeLine(chalk.white('STATUS: ') + (agent.isActive ? chalk.green('ACTIVE') : chalk.gray('STANDBY'))));
183
+ console.log(makeLine(chalk.white('PROVIDER: ') + chalk.white(agent.provider?.name || agent.providerId)));
184
+ console.log(makeLine(chalk.white('MODEL: ') + chalk.white(agent.model)));
185
+ console.log(makeLine(chalk.white('STATUS: ') + (agent.isActive ? chalk.green('ACTIVE') : chalk.white('STANDBY'))));
177
186
 
178
187
  console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
179
188
 
@@ -182,7 +191,7 @@ const showAgentDetails = async (agent) => {
182
191
  }
183
192
  console.log(makeLine(chalk.yellow('[M] CHANGE MODEL')));
184
193
  console.log(makeLine(chalk.red('[R] REMOVE')));
185
- console.log(makeLine(chalk.gray('[<] BACK')));
194
+ console.log(makeLine(chalk.white('[<] BACK')));
186
195
 
187
196
  drawBoxFooter(boxWidth);
188
197
 
@@ -242,7 +251,7 @@ const selectActiveAgent = async () => {
242
251
  }
243
252
 
244
253
  console.log(makeLine(''));
245
- console.log(makeLine(chalk.gray('[<] BACK')));
254
+ console.log(makeLine(chalk.white('[<] BACK')));
246
255
 
247
256
  drawBoxFooter(boxWidth);
248
257
 
@@ -289,12 +298,12 @@ const selectAgentForModelChange = async () => {
289
298
  for (let i = 0; i < agents.length; i++) {
290
299
  const agent = agents[i];
291
300
  console.log(makeLine(
292
- chalk.white(`[${i + 1}] `) + chalk.cyan(agent.name) + chalk.gray(` - ${agent.model}`)
301
+ chalk.white(`[${i + 1}] `) + chalk.cyan(agent.name) + chalk.white(` - ${agent.model}`)
293
302
  ));
294
303
  }
295
304
 
296
305
  console.log(makeLine(''));
297
- console.log(makeLine(chalk.gray('[<] BACK')));
306
+ console.log(makeLine(chalk.white('[<] BACK')));
298
307
 
299
308
  drawBoxFooter(boxWidth);
300
309
 
@@ -346,7 +355,7 @@ const selectAgentToRemove = async () => {
346
355
  }
347
356
 
348
357
  console.log(makeLine(''));
349
- console.log(makeLine(chalk.gray('[<] BACK')));
358
+ console.log(makeLine(chalk.white('[<] BACK')));
350
359
 
351
360
  drawBoxFooter(boxWidth);
352
361
 
@@ -367,178 +376,6 @@ const selectAgentToRemove = async () => {
367
376
  return await aiAgentMenu();
368
377
  };
369
378
 
370
- // Cache for scanned tokens (avoid multiple Keychain prompts)
371
- let cachedTokens = null;
372
- let cacheTimestamp = 0;
373
- const CACHE_TTL = 60000; // 1 minute cache
374
-
375
- /**
376
- * Show existing tokens found on the system
377
- */
378
- const showExistingTokens = async () => {
379
- const boxWidth = getLogoWidth();
380
- const W = boxWidth - 2;
381
-
382
- const makeLine = (content) => {
383
- const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
384
- const padding = W - plainLen;
385
- return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
386
- };
387
-
388
- // Check cache first
389
- const now = Date.now();
390
- let tokens;
391
-
392
- if (cachedTokens && (now - cacheTimestamp) < CACHE_TTL) {
393
- tokens = cachedTokens;
394
- } else {
395
- console.clear();
396
- displayBanner();
397
- drawBoxHeaderContinue('SCANNING FOR EXISTING SESSIONS...', boxWidth);
398
- console.log(makeLine(''));
399
- console.log(makeLine(chalk.gray('CHECKING VS CODE, CURSOR, CLAUDE CLI, OPENCODE...')));
400
- console.log(makeLine(''));
401
- drawBoxFooter(boxWidth);
402
-
403
- // Scan for tokens and cache
404
- tokens = tokenScanner.scanAllSources();
405
- cachedTokens = tokens;
406
- cacheTimestamp = now;
407
- }
408
-
409
- if (tokens.length === 0) {
410
- // No tokens found, go directly to category selection
411
- return await selectCategory();
412
- }
413
-
414
- // Show found tokens
415
- console.clear();
416
- displayBanner();
417
- drawBoxHeaderContinue('EXISTING SESSIONS FOUND', boxWidth);
418
-
419
- console.log(makeLine(chalk.green(`FOUND ${tokens.length} EXISTING SESSION(S)`)));
420
- console.log(makeLine(''));
421
-
422
- const formatted = tokenScanner.formatResults(tokens);
423
-
424
- for (const t of formatted) {
425
- const providerColor = t.provider.includes('CLAUDE') ? chalk.magenta :
426
- t.provider.includes('OPENAI') ? chalk.green :
427
- t.provider.includes('OPENROUTER') ? chalk.yellow : chalk.cyan;
428
-
429
- console.log(makeLine(
430
- chalk.white(`[${t.index}] `) +
431
- providerColor(t.provider) +
432
- chalk.gray(` (${t.type})`)
433
- ));
434
- console.log(makeLine(
435
- chalk.gray(` ${t.icon} ${t.source} - ${t.lastUsed}`)
436
- ));
437
- console.log(makeLine(
438
- chalk.gray(` TOKEN: ${t.tokenPreview}`)
439
- ));
440
- console.log(makeLine(''));
441
- }
442
-
443
- console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
444
- console.log(makeLine(chalk.cyan('[N] CONNECT NEW PROVIDER')));
445
- console.log(makeLine(chalk.gray('[<] BACK')));
446
-
447
- drawBoxFooter(boxWidth);
448
-
449
- const choice = await prompts.textInput(chalk.cyan('SELECT (1-' + tokens.length + '/N/<):'));
450
-
451
- if (choice === '<' || choice?.toLowerCase() === 'b') {
452
- return await aiAgentMenu();
453
- }
454
-
455
- if (choice?.toLowerCase() === 'n') {
456
- return await selectCategory();
457
- }
458
-
459
- const index = parseInt(choice) - 1;
460
- if (isNaN(index) || index < 0 || index >= tokens.length) {
461
- return await showExistingTokens();
462
- }
463
-
464
- // Use selected token
465
- const selectedToken = tokens[index];
466
-
467
- const spinner = ora({ text: 'VALIDATING TOKEN...', color: 'cyan' }).start();
468
-
469
- try {
470
- // Validate the token - include metadata from scanner
471
- const credentials = {
472
- apiKey: selectedToken.token,
473
- sessionKey: selectedToken.token,
474
- accessToken: selectedToken.token,
475
- fromKeychain: selectedToken.sourceId === 'secureStorage' || selectedToken.sourceId === 'keychain',
476
- subscriptionType: selectedToken.subscriptionType,
477
- refreshToken: selectedToken.refreshToken,
478
- expiresAt: selectedToken.expiresAt
479
- };
480
- const validation = await aiService.validateConnection(selectedToken.provider, selectedToken.type, credentials);
481
-
482
- if (!validation.valid) {
483
- spinner.fail(`TOKEN INVALID OR EXPIRED: ${validation.error}`);
484
- await prompts.waitForEnter();
485
- return await showExistingTokens();
486
- }
487
-
488
- // Get provider info
489
- const { getProvider } = require('../services/ai/providers');
490
- const provider = getProvider(selectedToken.provider);
491
-
492
- if (!provider) {
493
- spinner.fail('PROVIDER NOT SUPPORTED');
494
- await prompts.waitForEnter();
495
- return await showExistingTokens();
496
- }
497
-
498
- spinner.text = 'FETCHING AVAILABLE MODELS...';
499
-
500
- // Fetch models from API with the token
501
- const { fetchAnthropicModels, fetchOpenAIModels } = require('../services/ai/client');
502
-
503
- let models = null;
504
- if (selectedToken.provider === 'anthropic') {
505
- models = await fetchAnthropicModels(credentials.apiKey);
506
- } else {
507
- models = await fetchOpenAIModels(provider.endpoint, credentials.apiKey);
508
- }
509
-
510
- if (!models || models.length === 0) {
511
- spinner.fail('COULD NOT FETCH MODELS FROM API');
512
- await prompts.waitForEnter();
513
- return await showExistingTokens();
514
- }
515
-
516
- spinner.succeed(`FOUND ${models.length} MODELS`);
517
-
518
- // Let user select model
519
- const selectedModel = await selectModelFromList(models, provider.name);
520
- if (!selectedModel) {
521
- return await showExistingTokens();
522
- }
523
-
524
- // Add agent with selected model
525
- const agentName = `${provider.name} (${selectedToken.source})`;
526
- await aiService.addAgent(selectedToken.provider, 'api_key', credentials, selectedModel, agentName);
527
-
528
- console.log(chalk.green(`\n AGENT ADDED: ${provider.name}`));
529
- console.log(chalk.gray(` SOURCE: ${selectedToken.source}`));
530
- console.log(chalk.gray(` MODEL: ${selectedModel}`));
531
-
532
- await prompts.waitForEnter();
533
- return await aiAgentMenu();
534
-
535
- } catch (error) {
536
- spinner.fail(`CONNECTION FAILED: ${error.message}`);
537
- await prompts.waitForEnter();
538
- return await showExistingTokens();
539
- }
540
- };
541
-
542
379
  /**
543
380
  * Select provider category
544
381
  */
@@ -573,20 +410,20 @@ const selectCategory = async () => {
573
410
  chalk.cyan('[2] DIRECT PROVIDERS')
574
411
  ));
575
412
  console.log(make2ColRow(
576
- chalk.gray(' 1 API = 100+ models'),
577
- chalk.gray(' Connect to each provider')
413
+ chalk.white(' 1 API = 100+ models'),
414
+ chalk.white(' Connect to each provider')
578
415
  ));
579
416
  console.log(makeLine(''));
580
417
  console.log(make2ColRow(
581
418
  chalk.yellow('[3] LOCAL (FREE)'),
582
- chalk.gray('[4] CUSTOM')
419
+ chalk.white('[4] CUSTOM')
583
420
  ));
584
421
  console.log(make2ColRow(
585
- chalk.gray(' Run on your machine'),
586
- chalk.gray(' Self-hosted solutions')
422
+ chalk.white(' Run on your machine'),
423
+ chalk.white(' Self-hosted solutions')
587
424
  ));
588
425
  console.log(makeLine(''));
589
- console.log(makeLine(chalk.gray('[<] BACK')));
426
+ console.log(makeLine(chalk.white('[<] BACK')));
590
427
 
591
428
  drawBoxFooter(boxWidth);
592
429
 
@@ -637,7 +474,7 @@ const selectProvider = async (categoryId) => {
637
474
  const providers = getProvidersByCategory(categoryId);
638
475
 
639
476
  if (providers.length === 0) {
640
- console.log(makeLine(chalk.gray('NO PROVIDERS IN THIS CATEGORY')));
477
+ console.log(makeLine(chalk.white('NO PROVIDERS IN THIS CATEGORY')));
641
478
  drawBoxFooter(boxWidth);
642
479
  await prompts.waitForEnter();
643
480
  return await selectCategory();
@@ -662,14 +499,14 @@ const selectProvider = async (categoryId) => {
662
499
  const rightDesc = right ? ' ' + right.description : '';
663
500
 
664
501
  console.log(make2ColRow(
665
- chalk.gray(leftDesc.length > col1Width - 3 ? leftDesc.substring(0, col1Width - 6) + '...' : leftDesc),
666
- chalk.gray(rightDesc.length > col1Width - 3 ? rightDesc.substring(0, col1Width - 6) + '...' : rightDesc)
502
+ chalk.white(leftDesc.length > col1Width - 3 ? leftDesc.substring(0, col1Width - 6) + '...' : leftDesc),
503
+ chalk.white(rightDesc.length > col1Width - 3 ? rightDesc.substring(0, col1Width - 6) + '...' : rightDesc)
667
504
  ));
668
505
 
669
506
  console.log(makeLine(''));
670
507
  }
671
508
 
672
- console.log(makeLine(chalk.gray('[<] BACK')));
509
+ console.log(makeLine(chalk.white('[<] BACK')));
673
510
 
674
511
  drawBoxFooter(boxWidth);
675
512
 
@@ -738,8 +575,8 @@ const selectProviderOption = async (provider) => {
738
575
  const leftDesc1 = left.description[0] ? ' ' + left.description[0] : '';
739
576
  const rightDesc1 = right?.description[0] ? ' ' + right.description[0] : '';
740
577
  console.log(make2ColRow(
741
- chalk.gray(leftDesc1.length > col1Width - 2 ? leftDesc1.substring(0, col1Width - 5) + '...' : leftDesc1),
742
- chalk.gray(rightDesc1.length > col1Width - 2 ? rightDesc1.substring(0, col1Width - 5) + '...' : rightDesc1)
578
+ chalk.white(leftDesc1.length > col1Width - 2 ? leftDesc1.substring(0, col1Width - 5) + '...' : leftDesc1),
579
+ chalk.white(rightDesc1.length > col1Width - 2 ? rightDesc1.substring(0, col1Width - 5) + '...' : rightDesc1)
743
580
  ));
744
581
 
745
582
  // Second description line if exists
@@ -747,15 +584,15 @@ const selectProviderOption = async (provider) => {
747
584
  const rightDesc2 = right?.description[1] ? ' ' + right.description[1] : '';
748
585
  if (leftDesc2 || rightDesc2) {
749
586
  console.log(make2ColRow(
750
- chalk.gray(leftDesc2.length > col1Width - 2 ? leftDesc2.substring(0, col1Width - 5) + '...' : leftDesc2),
751
- chalk.gray(rightDesc2.length > col1Width - 2 ? rightDesc2.substring(0, col1Width - 5) + '...' : rightDesc2)
587
+ chalk.white(leftDesc2.length > col1Width - 2 ? leftDesc2.substring(0, col1Width - 5) + '...' : leftDesc2),
588
+ chalk.white(rightDesc2.length > col1Width - 2 ? rightDesc2.substring(0, col1Width - 5) + '...' : rightDesc2)
752
589
  ));
753
590
  }
754
591
 
755
592
  console.log(makeLine(''));
756
593
  }
757
594
 
758
- console.log(makeLine(chalk.gray('[<] BACK')));
595
+ console.log(makeLine(chalk.white('[<] BACK')));
759
596
 
760
597
  drawBoxFooter(boxWidth);
761
598
 
@@ -787,7 +624,7 @@ const openBrowser = (url) => {
787
624
  else cmd = `xdg-open "${url}"`;
788
625
 
789
626
  exec(cmd, (err) => {
790
- if (err) console.log(chalk.gray(' Could not open browser automatically'));
627
+ if (err) console.log(chalk.white(' Could not open browser automatically'));
791
628
  });
792
629
  };
793
630
 
@@ -870,7 +707,7 @@ const setupOAuthConnection = async (provider) => {
870
707
  console.log(makeLine(chalk.white('3. COPY THE AUTHORIZATION CODE')));
871
708
  console.log(makeLine(chalk.white('4. PASTE IT HERE')));
872
709
  console.log(makeLine(''));
873
- console.log(makeLine(chalk.gray('OPENING BROWSER IN 3 SECONDS...')));
710
+ console.log(makeLine(chalk.white('OPENING BROWSER IN 3 SECONDS...')));
874
711
 
875
712
  drawBoxFooter(boxWidth);
876
713
 
@@ -891,9 +728,9 @@ const setupOAuthConnection = async (provider) => {
891
728
  console.log(makeLine(chalk.white('AFTER LOGGING IN, YOU WILL SEE A CODE')));
892
729
  console.log(makeLine(chalk.white('COPY THE ENTIRE CODE AND PASTE IT BELOW')));
893
730
  console.log(makeLine(''));
894
- console.log(makeLine(chalk.gray('THE CODE LOOKS LIKE: abc123...#xyz789...')));
731
+ console.log(makeLine(chalk.white('THE CODE LOOKS LIKE: abc123...#xyz789...')));
895
732
  console.log(makeLine(''));
896
- console.log(makeLine(chalk.gray('TYPE < TO CANCEL')));
733
+ console.log(makeLine(chalk.white('TYPE < TO CANCEL')));
897
734
 
898
735
  drawBoxFooter(boxWidth);
899
736
  console.log();
@@ -937,16 +774,18 @@ const setupOAuthConnection = async (provider) => {
937
774
  spinner.succeed(`FOUND ${models.length} MODELS`);
938
775
  }
939
776
 
777
+ if (!models || models.length === 0) {
778
+ spinner.fail('COULD NOT FETCH MODELS FROM API');
779
+ console.log(chalk.white(' OAuth authentication may not support model listing.'));
780
+ console.log(chalk.white(' Please use API KEY authentication instead.'));
781
+ await prompts.waitForEnter();
782
+ return await selectProviderOption(provider);
783
+ }
784
+
785
+ spinner.succeed(`FOUND ${models.length} MODELS`);
786
+
940
787
  // Let user select model
941
- const availableModels = models && models.length > 0 ? models : [
942
- 'claude-sonnet-4-20250514',
943
- 'claude-sonnet-4-5-20250514',
944
- 'claude-3-5-sonnet-20241022',
945
- 'claude-3-5-haiku-20241022',
946
- 'claude-3-opus-20240229'
947
- ];
948
-
949
- const selectedModel = await selectModelFromList(availableModels, 'CLAUDE PRO/MAX');
788
+ const selectedModel = await selectModelFromList(models, 'CLAUDE PRO/MAX');
950
789
  if (!selectedModel) {
951
790
  return await selectProviderOption(provider);
952
791
  }
@@ -956,8 +795,8 @@ const setupOAuthConnection = async (provider) => {
956
795
  await aiService.addAgent('anthropic', 'oauth_max', credentials, selectedModel, 'Claude Pro/Max');
957
796
 
958
797
  console.log(chalk.green('\n CONNECTED TO CLAUDE PRO/MAX'));
959
- console.log(chalk.gray(` MODEL: ${selectedModel}`));
960
- console.log(chalk.gray(' UNLIMITED USAGE WITH YOUR SUBSCRIPTION'));
798
+ console.log(chalk.white(` MODEL: ${selectedModel}`));
799
+ console.log(chalk.white(' UNLIMITED USAGE WITH YOUR SUBSCRIPTION'));
961
800
  } catch (error) {
962
801
  console.log(chalk.red(`\n FAILED TO SAVE: ${error.message}`));
963
802
  }
@@ -1009,17 +848,17 @@ const setupConnection = async (provider, option) => {
1009
848
  if (option.url && (field === 'apiKey' || field === 'sessionKey' || field === 'accessToken')) {
1010
849
  console.log(makeLine(chalk.cyan('LINK: ') + chalk.green(option.url)));
1011
850
  console.log(makeLine(''));
1012
- console.log(makeLine(chalk.gray('OPENING BROWSER...')));
851
+ console.log(makeLine(chalk.white('OPENING BROWSER...')));
1013
852
  openBrowser(option.url);
1014
853
  }
1015
854
 
1016
855
  // Show default for endpoint
1017
856
  if (field === 'endpoint' && option.defaultEndpoint) {
1018
- console.log(makeLine(chalk.gray(`DEFAULT: ${option.defaultEndpoint}`)));
857
+ console.log(makeLine(chalk.white(`DEFAULT: ${option.defaultEndpoint}`)));
1019
858
  }
1020
859
 
1021
860
  console.log(makeLine(''));
1022
- console.log(makeLine(chalk.gray('TYPE < TO GO BACK')));
861
+ console.log(makeLine(chalk.white('TYPE < TO GO BACK')));
1023
862
 
1024
863
  drawBoxFooter(boxWidth);
1025
864
  console.log();
@@ -1029,33 +868,33 @@ const setupConnection = async (provider, option) => {
1029
868
  switch (field) {
1030
869
  case 'apiKey':
1031
870
  value = await prompts.textInput(chalk.cyan('PASTE API KEY:'));
1032
- if (!value || value === '<') return await selectProviderOption(provider);
871
+ if (!value || value.trim() === '<' || value.trim() === '') return await selectProviderOption(provider);
1033
872
  credentials.apiKey = value.trim();
1034
873
  break;
1035
874
 
1036
875
  case 'sessionKey':
1037
876
  value = await prompts.textInput(chalk.cyan('PASTE SESSION KEY:'));
1038
- if (!value || value === '<') return await selectProviderOption(provider);
877
+ if (!value || value.trim() === '<' || value.trim() === '') return await selectProviderOption(provider);
1039
878
  credentials.sessionKey = value.trim();
1040
879
  break;
1041
880
 
1042
881
  case 'accessToken':
1043
882
  value = await prompts.textInput(chalk.cyan('PASTE ACCESS TOKEN:'));
1044
- if (!value || value === '<') return await selectProviderOption(provider);
883
+ if (!value || value.trim() === '<' || value.trim() === '') return await selectProviderOption(provider);
1045
884
  credentials.accessToken = value.trim();
1046
885
  break;
1047
886
 
1048
887
  case 'endpoint':
1049
888
  const defaultEndpoint = option.defaultEndpoint || '';
1050
889
  value = await prompts.textInput(chalk.cyan(`ENDPOINT [${defaultEndpoint || 'required'}]:`));
1051
- if (value === '<') return await selectProviderOption(provider);
890
+ if (value && value.trim() === '<') return await selectProviderOption(provider);
1052
891
  credentials.endpoint = (value || defaultEndpoint).trim();
1053
892
  if (!credentials.endpoint) return await selectProviderOption(provider);
1054
893
  break;
1055
894
 
1056
895
  case 'model':
1057
896
  value = await prompts.textInput(chalk.cyan('MODEL NAME:'));
1058
- if (!value || value === '<') return await selectProviderOption(provider);
897
+ if (!value || value.trim() === '<' || value.trim() === '') return await selectProviderOption(provider);
1059
898
  credentials.model = value.trim();
1060
899
  break;
1061
900
  }
@@ -1081,10 +920,10 @@ const setupConnection = async (provider, option) => {
1081
920
 
1082
921
  // Show available models for local providers
1083
922
  if (validation.models && validation.models.length > 0) {
1084
- console.log(chalk.gray(` AVAILABLE MODELS: ${validation.models.slice(0, 5).join(', ')}`));
923
+ console.log(chalk.white(` AVAILABLE MODELS: ${validation.models.slice(0, 5).join(', ')}`));
1085
924
  }
1086
925
 
1087
- console.log(chalk.gray(` USING MODEL: ${model}`));
926
+ console.log(chalk.white(` USING MODEL: ${model}`));
1088
927
  } catch (error) {
1089
928
  spinner.fail(`FAILED TO SAVE: ${error.message}`);
1090
929
  }
@@ -1117,7 +956,7 @@ const selectModelFromList = async (models, providerName) => {
1117
956
 
1118
957
  if (!models || models.length === 0) {
1119
958
  console.log(makeLine(chalk.red('NO MODELS AVAILABLE')));
1120
- console.log(makeLine(chalk.gray('[<] BACK')));
959
+ console.log(makeLine(chalk.white('[<] BACK')));
1121
960
  drawBoxFooter(boxWidth);
1122
961
  await prompts.waitForEnter();
1123
962
  return null;
@@ -1126,14 +965,44 @@ const selectModelFromList = async (models, providerName) => {
1126
965
  // Sort models (newest first)
1127
966
  const sortedModels = [...models].sort((a, b) => b.localeCompare(a));
1128
967
 
1129
- // Display models from API
1130
- sortedModels.forEach((model, index) => {
1131
- const displayModel = model.length > W - 10 ? model.substring(0, W - 13) + '...' : model;
1132
- console.log(makeLine(chalk.cyan(`[${index + 1}] ${displayModel}`)));
1133
- });
968
+ // Display models in 2 columns
969
+ const rows = Math.ceil(sortedModels.length / 2);
970
+ const colWidth = Math.floor((W - 4) / 2);
971
+
972
+ for (let i = 0; i < rows; i++) {
973
+ const leftIndex = i;
974
+ const rightIndex = i + rows;
975
+
976
+ // Left column
977
+ const leftModel = sortedModels[leftIndex];
978
+ const leftNum = chalk.cyan(`[${leftIndex + 1}]`);
979
+ const leftName = leftModel.length > colWidth - 6
980
+ ? leftModel.substring(0, colWidth - 9) + '...'
981
+ : leftModel;
982
+ const leftText = `${leftNum} ${chalk.yellow(leftName)}`;
983
+ const leftPlain = `[${leftIndex + 1}] ${leftName}`;
984
+
985
+ // Right column (if exists)
986
+ let rightText = '';
987
+ let rightPlain = '';
988
+ if (rightIndex < sortedModels.length) {
989
+ const rightModel = sortedModels[rightIndex];
990
+ const rightNum = chalk.cyan(`[${rightIndex + 1}]`);
991
+ const rightName = rightModel.length > colWidth - 6
992
+ ? rightModel.substring(0, colWidth - 9) + '...'
993
+ : rightModel;
994
+ rightText = `${rightNum} ${chalk.yellow(rightName)}`;
995
+ rightPlain = `[${rightIndex + 1}] ${rightName}`;
996
+ }
997
+
998
+ // Pad left column and combine
999
+ const leftPadding = colWidth - leftPlain.length;
1000
+ const line = leftText + ' '.repeat(Math.max(2, leftPadding)) + rightText;
1001
+ console.log(makeLine(line));
1002
+ }
1134
1003
 
1135
1004
  console.log(makeLine(''));
1136
- console.log(makeLine(chalk.gray('[<] BACK')));
1005
+ console.log(makeLine(chalk.white('[<] BACK')));
1137
1006
 
1138
1007
  drawBoxFooter(boxWidth);
1139
1008
 
@@ -1169,17 +1038,28 @@ const selectModel = async (agent) => {
1169
1038
  displayBanner();
1170
1039
  drawBoxHeaderContinue(`SELECT MODEL - ${agent.name}`, boxWidth);
1171
1040
 
1172
- console.log(makeLine(chalk.gray('FETCHING AVAILABLE MODELS FROM API...')));
1041
+ console.log(makeLine(chalk.white('FETCHING AVAILABLE MODELS FROM API...')));
1173
1042
  drawBoxFooter(boxWidth);
1174
1043
 
1175
1044
  // Fetch models from real API
1176
- const { fetchAnthropicModels, fetchOpenAIModels } = require('../services/ai/client');
1045
+ const { fetchAnthropicModels, fetchAnthropicModelsOAuth, fetchOpenAIModels } = require('../services/ai/client');
1177
1046
 
1178
1047
  let models = null;
1179
1048
  const agentCredentials = aiService.getAgentCredentials(agent.id);
1180
1049
 
1181
1050
  if (agent.providerId === 'anthropic') {
1182
- models = await fetchAnthropicModels(agentCredentials?.apiKey);
1051
+ // Check if OAuth credentials or OAuth-like token (sk-ant-oat...)
1052
+ const token = agentCredentials?.apiKey || agentCredentials?.accessToken || agentCredentials?.sessionKey;
1053
+ const isOAuthToken = agentCredentials?.oauth?.access || (token && token.startsWith('sk-ant-oat'));
1054
+
1055
+ if (isOAuthToken) {
1056
+ // Use OAuth endpoint with Bearer token
1057
+ const accessToken = agentCredentials?.oauth?.access || token;
1058
+ models = await fetchAnthropicModelsOAuth(accessToken);
1059
+ } else {
1060
+ // Standard API key
1061
+ models = await fetchAnthropicModels(token);
1062
+ }
1183
1063
  } else {
1184
1064
  // OpenAI-compatible providers
1185
1065
  const endpoint = agentCredentials?.endpoint || agent.provider?.endpoint;
@@ -1193,9 +1073,9 @@ const selectModel = async (agent) => {
1193
1073
 
1194
1074
  if (!models || models.length === 0) {
1195
1075
  console.log(makeLine(chalk.red('COULD NOT FETCH MODELS FROM API')));
1196
- console.log(makeLine(chalk.gray('Check your API key or network connection.')));
1076
+ console.log(makeLine(chalk.white('Check your API key or network connection.')));
1197
1077
  console.log(makeLine(''));
1198
- console.log(makeLine(chalk.gray('[<] BACK')));
1078
+ console.log(makeLine(chalk.white('[<] BACK')));
1199
1079
  drawBoxFooter(boxWidth);
1200
1080
 
1201
1081
  await prompts.waitForEnter();
@@ -1205,15 +1085,46 @@ const selectModel = async (agent) => {
1205
1085
  // Sort models (newest first typically)
1206
1086
  models.sort((a, b) => b.localeCompare(a));
1207
1087
 
1208
- // Display models from API
1209
- models.forEach((model, index) => {
1210
- const displayModel = model.length > W - 10 ? model.substring(0, W - 13) + '...' : model;
1211
- const currentMarker = model === agent.model ? chalk.yellow(' (CURRENT)') : '';
1212
- console.log(makeLine(chalk.cyan(`[${index + 1}] ${displayModel}`) + currentMarker));
1213
- });
1088
+ // Display models in 2 columns
1089
+ const rows = Math.ceil(models.length / 2);
1090
+ const colWidth = Math.floor((W - 4) / 2);
1091
+
1092
+ for (let i = 0; i < rows; i++) {
1093
+ const leftIndex = i;
1094
+ const rightIndex = i + rows;
1095
+
1096
+ // Left column
1097
+ const leftModel = models[leftIndex];
1098
+ const leftNum = chalk.cyan(`[${leftIndex + 1}]`);
1099
+ const leftCurrent = leftModel === agent.model ? chalk.green(' *') : '';
1100
+ const leftName = leftModel.length > colWidth - 8
1101
+ ? leftModel.substring(0, colWidth - 11) + '...'
1102
+ : leftModel;
1103
+ const leftText = `${leftNum} ${chalk.yellow(leftName)}${leftCurrent}`;
1104
+ const leftPlain = `[${leftIndex + 1}] ${leftName}${leftModel === agent.model ? ' *' : ''}`;
1105
+
1106
+ // Right column (if exists)
1107
+ let rightText = '';
1108
+ let rightPlain = '';
1109
+ if (rightIndex < models.length) {
1110
+ const rightModel = models[rightIndex];
1111
+ const rightNum = chalk.cyan(`[${rightIndex + 1}]`);
1112
+ const rightCurrent = rightModel === agent.model ? chalk.green(' *') : '';
1113
+ const rightName = rightModel.length > colWidth - 8
1114
+ ? rightModel.substring(0, colWidth - 11) + '...'
1115
+ : rightModel;
1116
+ rightText = `${rightNum} ${chalk.yellow(rightName)}${rightCurrent}`;
1117
+ rightPlain = `[${rightIndex + 1}] ${rightName}${rightModel === agent.model ? ' *' : ''}`;
1118
+ }
1119
+
1120
+ // Pad left column and combine
1121
+ const leftPadding = colWidth - leftPlain.length;
1122
+ const line = leftText + ' '.repeat(Math.max(2, leftPadding)) + rightText;
1123
+ console.log(makeLine(line));
1124
+ }
1214
1125
 
1215
1126
  console.log(makeLine(''));
1216
- console.log(makeLine(chalk.gray('[<] BACK')));
1127
+ console.log(makeLine(chalk.white('[<] BACK') + chalk.white(' * = CURRENT')));
1217
1128
 
1218
1129
  drawBoxFooter(boxWidth);
1219
1130