@kikkimo/claude-launcher 2.3.0 → 2.5.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.
- package/CHANGELOG.md +70 -0
- package/README.md +35 -13
- package/claude-launcher +425 -48
- package/docs/README-zh.md +35 -13
- package/docs/superpowers/plans/2026-03-31-update-models-and-auto-mode.md +1414 -0
- package/docs/superpowers/specs/2026-03-31-update-models-and-auto-mode-design.md +187 -0
- package/lib/api-manager.js +135 -1
- package/lib/i18n/locales/de.js +74 -3
- package/lib/i18n/locales/en.js +72 -2
- package/lib/i18n/locales/es.js +74 -3
- package/lib/i18n/locales/fr.js +74 -3
- package/lib/i18n/locales/it.js +72 -2
- package/lib/i18n/locales/ja.js +74 -3
- package/lib/i18n/locales/ko.js +74 -3
- package/lib/i18n/locales/pt.js +72 -2
- package/lib/i18n/locales/ru.js +72 -2
- package/lib/i18n/locales/zh-TW.js +74 -3
- package/lib/i18n/locales/zh.js +74 -3
- package/lib/launcher.js +10 -0
- package/lib/presets/providers.js +86 -15
- package/lib/ui/menu.js +17 -5
- package/lib/utils/model-upgrade-checker.js +103 -0
- package/lib/utils/version-checker.js +22 -3
- package/package.json +2 -2
package/claude-launcher
CHANGED
|
@@ -46,6 +46,7 @@ const {
|
|
|
46
46
|
const {
|
|
47
47
|
launchClaudeDefault,
|
|
48
48
|
launchClaudeSkipPermissions,
|
|
49
|
+
launchClaudeAutoMode,
|
|
49
50
|
launchClaudeWithApi
|
|
50
51
|
} = require('./lib/launcher');
|
|
51
52
|
const { getPasswordInput } = require('./lib/auth/password-input');
|
|
@@ -263,9 +264,52 @@ async function addNewThirdPartyApi() {
|
|
|
263
264
|
}
|
|
264
265
|
|
|
265
266
|
/**
|
|
266
|
-
* Remove third-party API
|
|
267
|
+
* Remove third-party API menu with submenu
|
|
267
268
|
*/
|
|
268
269
|
async function removeThirdPartyApi() {
|
|
270
|
+
console.clear();
|
|
271
|
+
console.log('');
|
|
272
|
+
console.log(colors.bright + colors.orange + '🗑️ ' + await i18n.t('menu.remove_api.title') + colors.reset);
|
|
273
|
+
console.log('');
|
|
274
|
+
|
|
275
|
+
const apis = apiManager.getApis();
|
|
276
|
+
|
|
277
|
+
// Show current API count
|
|
278
|
+
if (apis.length > 0) {
|
|
279
|
+
console.log(colors.cyan + ' ' + await i18n.t('messages.info.current_api_count', apis.length) + colors.reset);
|
|
280
|
+
console.log('');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const menuOptions = [
|
|
284
|
+
await i18n.t('menu.remove_api.delete_single'),
|
|
285
|
+
await i18n.t('menu.remove_api.clear_all'),
|
|
286
|
+
await i18n.t('menu.remove_api.back')
|
|
287
|
+
];
|
|
288
|
+
|
|
289
|
+
initializeGlobalMenus();
|
|
290
|
+
globalApiManagementMenu.setOptions(menuOptions);
|
|
291
|
+
const choice = await globalApiManagementMenu.navigate();
|
|
292
|
+
|
|
293
|
+
switch (choice) {
|
|
294
|
+
case 0: // Delete Single API
|
|
295
|
+
await deleteSingleApi();
|
|
296
|
+
return;
|
|
297
|
+
|
|
298
|
+
case 1: // Clear All APIs
|
|
299
|
+
await clearAllApis();
|
|
300
|
+
return;
|
|
301
|
+
|
|
302
|
+
case 2: // Back
|
|
303
|
+
case -1:
|
|
304
|
+
default:
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Delete a single API
|
|
311
|
+
*/
|
|
312
|
+
async function deleteSingleApi() {
|
|
269
313
|
try {
|
|
270
314
|
// Get API list
|
|
271
315
|
const apis = apiManager.getApis();
|
|
@@ -281,7 +325,7 @@ async function removeThirdPartyApi() {
|
|
|
281
325
|
);
|
|
282
326
|
|
|
283
327
|
if (!selectedApi) {
|
|
284
|
-
return
|
|
328
|
+
return;
|
|
285
329
|
}
|
|
286
330
|
|
|
287
331
|
// Show confirmation dialog
|
|
@@ -299,23 +343,20 @@ async function removeThirdPartyApi() {
|
|
|
299
343
|
`${await i18n.t('api.details.provider')}: ${selectedApi.provider}`
|
|
300
344
|
]);
|
|
301
345
|
|
|
302
|
-
// Show success message
|
|
346
|
+
// Show success message
|
|
303
347
|
const remainingApis = apiManager.getApis();
|
|
304
348
|
if (remainingApis.length === 0) {
|
|
305
349
|
showInfo(await i18n.t('messages.info.all_apis_removed'));
|
|
306
350
|
}
|
|
307
351
|
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
308
|
-
return showMenu();
|
|
309
352
|
|
|
310
353
|
} catch (removeError) {
|
|
311
354
|
showError(await i18n.t('errors.api.failed_remove', removeError.message));
|
|
312
355
|
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
313
|
-
return showMenu();
|
|
314
356
|
}
|
|
315
357
|
} else {
|
|
316
358
|
showInfo(await i18n.t('messages.info.removal_cancelled'));
|
|
317
359
|
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
318
|
-
return showMenu();
|
|
319
360
|
}
|
|
320
361
|
|
|
321
362
|
} catch (error) {
|
|
@@ -325,6 +366,42 @@ async function removeThirdPartyApi() {
|
|
|
325
366
|
}
|
|
326
367
|
}
|
|
327
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Clear all APIs with confirmation
|
|
371
|
+
*/
|
|
372
|
+
async function clearAllApis() {
|
|
373
|
+
const { simpleInput } = require('./lib/ui/prompts');
|
|
374
|
+
|
|
375
|
+
const apis = apiManager.getApis();
|
|
376
|
+
const count = apis.length;
|
|
377
|
+
|
|
378
|
+
if (count === 0) {
|
|
379
|
+
console.clear();
|
|
380
|
+
showInfo(await i18n.t('messages.info.no_apis'));
|
|
381
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
console.clear();
|
|
386
|
+
console.log('');
|
|
387
|
+
console.log(colors.bright + colors.red + '⚠️ ' + await i18n.t('menu.remove_api.clear_all') + colors.reset);
|
|
388
|
+
console.log('');
|
|
389
|
+
console.log(colors.yellow + ' ' + await i18n.t('messages.prompts.confirm_clear_all', count) + colors.reset);
|
|
390
|
+
console.log('');
|
|
391
|
+
|
|
392
|
+
const input = await simpleInput(colors.cyan + ' ' + await i18n.t('messages.prompts.confirm_clear_all_input') + colors.reset);
|
|
393
|
+
|
|
394
|
+
if (input === 'CLEAR') {
|
|
395
|
+
const clearedCount = apiManager.clearAllApis();
|
|
396
|
+
console.clear();
|
|
397
|
+
showSuccess(await i18n.t('messages.info.all_apis_cleared', clearedCount));
|
|
398
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
399
|
+
} else {
|
|
400
|
+
showInfo(await i18n.t('messages.info.clear_cancelled'));
|
|
401
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
328
405
|
/**
|
|
329
406
|
* Switch active third-party API
|
|
330
407
|
*/
|
|
@@ -357,40 +434,110 @@ async function switchThirdPartyApi() {
|
|
|
357
434
|
/**
|
|
358
435
|
* View API statistics
|
|
359
436
|
*/
|
|
437
|
+
/**
|
|
438
|
+
* Format timestamp to relative time
|
|
439
|
+
* @param {string|null} timestamp - ISO timestamp or null
|
|
440
|
+
* @returns {string} Relative time string
|
|
441
|
+
*/
|
|
442
|
+
function formatRelativeTime(timestamp) {
|
|
443
|
+
if (!timestamp) return i18n.tSync('statistics.time_never');
|
|
444
|
+
|
|
445
|
+
const now = Date.now();
|
|
446
|
+
const diff = now - new Date(timestamp).getTime();
|
|
447
|
+
const minutes = Math.floor(diff / 60000);
|
|
448
|
+
const hours = Math.floor(diff / 3600000);
|
|
449
|
+
const days = Math.floor(diff / 86400000);
|
|
450
|
+
|
|
451
|
+
if (minutes < 1) return i18n.tSync('statistics.time_just_now');
|
|
452
|
+
if (minutes < 60) return i18n.tSync('statistics.time_minutes_ago', minutes);
|
|
453
|
+
if (hours < 24) return i18n.tSync('statistics.time_hours_ago', hours);
|
|
454
|
+
return i18n.tSync('statistics.time_days_ago', days);
|
|
455
|
+
}
|
|
456
|
+
|
|
360
457
|
async function viewStatistics() {
|
|
361
458
|
console.clear();
|
|
362
459
|
console.log('');
|
|
363
460
|
console.log(colors.bright + colors.orange + '📊 ' + await i18n.t('statistics.title') + colors.reset);
|
|
364
461
|
console.log('');
|
|
365
462
|
|
|
366
|
-
const
|
|
367
|
-
|
|
463
|
+
const menuOptions = [
|
|
464
|
+
await i18n.t('statistics.menu_view'),
|
|
465
|
+
await i18n.t('statistics.menu_reset'),
|
|
466
|
+
await i18n.t('statistics.menu_back')
|
|
467
|
+
];
|
|
468
|
+
|
|
469
|
+
initializeGlobalMenus();
|
|
470
|
+
globalApiManagementMenu.setOptions(menuOptions);
|
|
471
|
+
const choice = await globalApiManagementMenu.navigate();
|
|
472
|
+
|
|
473
|
+
switch (choice) {
|
|
474
|
+
case 0: // View Statistics Details
|
|
475
|
+
await showStatisticsDetails();
|
|
476
|
+
return viewStatistics();
|
|
477
|
+
|
|
478
|
+
case 1: // Reset Statistics
|
|
479
|
+
const { simpleInput } = require('./lib/ui/prompts');
|
|
480
|
+
const confirm = await simpleInput(colors.yellow + ' ' + await i18n.t('statistics.reset_confirm') + ' ' + colors.reset);
|
|
481
|
+
if (confirm.toLowerCase() === 'y') {
|
|
482
|
+
apiManager.resetStatistics();
|
|
483
|
+
console.log(colors.green + ' ✓ ' + await i18n.t('statistics.reset_success') + colors.reset);
|
|
484
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
485
|
+
}
|
|
486
|
+
return viewStatistics();
|
|
487
|
+
|
|
488
|
+
case 2: // Back
|
|
489
|
+
case -1:
|
|
490
|
+
default:
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Show detailed statistics
|
|
497
|
+
*/
|
|
498
|
+
async function showStatisticsDetails() {
|
|
499
|
+
const { padStringToWidth } = require('./lib/utils/string-width');
|
|
500
|
+
|
|
501
|
+
console.clear();
|
|
502
|
+
console.log('');
|
|
503
|
+
console.log(colors.bright + colors.orange + '📊 ' + await i18n.t('statistics.title') + colors.reset);
|
|
504
|
+
console.log('');
|
|
505
|
+
|
|
506
|
+
const stats = apiManager.getEnhancedStatistics();
|
|
368
507
|
|
|
369
|
-
|
|
508
|
+
// Summary section
|
|
509
|
+
console.log(colors.cyan + ' ' + i18n.tSync('ui.general.summary') + ':' + colors.reset);
|
|
370
510
|
console.log(colors.gray + ` ${await i18n.t('statistics.total_apis', stats.totalApis)}` + colors.reset);
|
|
371
511
|
console.log(colors.gray + ` ${await i18n.t('statistics.active_api', stats.activeApiName)}` + colors.reset);
|
|
372
512
|
console.log(colors.gray + ` ${await i18n.t('statistics.most_used', stats.mostUsedApi)}` + colors.reset);
|
|
373
513
|
console.log(colors.gray + ` ${await i18n.t('statistics.total_usage', stats.totalUsage)}` + colors.reset);
|
|
514
|
+
console.log(colors.gray + ` ${await i18n.t('statistics.success_rate', stats.successRate)}` + colors.reset);
|
|
374
515
|
console.log('');
|
|
375
516
|
|
|
376
|
-
if (
|
|
377
|
-
console.log(colors.cyan + ' ' + i18n.tSync('ui.general.configured_apis') + colors.reset);
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
console.log(colors.
|
|
392
|
-
|
|
393
|
-
|
|
517
|
+
if (stats.apiStats.length > 0) {
|
|
518
|
+
console.log(colors.cyan + ' ' + i18n.tSync('ui.general.configured_apis') + ':' + colors.reset);
|
|
519
|
+
console.log('');
|
|
520
|
+
|
|
521
|
+
// Table header
|
|
522
|
+
console.log(colors.dim + ' ' +
|
|
523
|
+
padStringToWidth(await i18n.t('statistics.header_name'), 20) +
|
|
524
|
+
padStringToWidth(await i18n.t('statistics.header_usage'), 10) +
|
|
525
|
+
padStringToWidth(await i18n.t('statistics.header_success'), 10) +
|
|
526
|
+
await i18n.t('statistics.header_last_used') +
|
|
527
|
+
colors.reset);
|
|
528
|
+
console.log(colors.dim + ' ' + '─'.repeat(60) + colors.reset);
|
|
529
|
+
|
|
530
|
+
for (const api of stats.apiStats) {
|
|
531
|
+
const lastUsedText = formatRelativeTime(api.lastUsed);
|
|
532
|
+
console.log(colors.gray + ' ' +
|
|
533
|
+
padStringToWidth(api.name, 20) +
|
|
534
|
+
padStringToWidth(String(api.usageCount), 10) +
|
|
535
|
+
padStringToWidth(api.successRate, 10) +
|
|
536
|
+
lastUsedText +
|
|
537
|
+
colors.reset);
|
|
538
|
+
}
|
|
539
|
+
} else {
|
|
540
|
+
console.log(colors.gray + ' ' + await i18n.t('statistics.no_usage') + colors.reset);
|
|
394
541
|
}
|
|
395
542
|
|
|
396
543
|
console.log('');
|
|
@@ -568,20 +715,23 @@ async function showApiManagementMenu() {
|
|
|
568
715
|
|
|
569
716
|
// Build menu options based on password setup status
|
|
570
717
|
const menuOptions = [
|
|
571
|
-
await i18n.t('menu.api_management.add_new'),
|
|
572
|
-
await i18n.t('menu.api_management.remove'),
|
|
573
|
-
await i18n.t('menu.api_management.switch'),
|
|
574
|
-
await i18n.t('menu.api_management.statistics')
|
|
718
|
+
await i18n.t('menu.api_management.add_new'), // 0
|
|
719
|
+
await i18n.t('menu.api_management.remove'), // 1
|
|
720
|
+
await i18n.t('menu.api_management.switch'), // 2
|
|
721
|
+
await i18n.t('menu.api_management.statistics') // 3
|
|
575
722
|
];
|
|
576
723
|
|
|
577
724
|
// Add import/export options only if password is set
|
|
578
725
|
if (apiManager.canUseImportExport()) {
|
|
579
|
-
menuOptions.push(await i18n.t('menu.api_management.export'));
|
|
580
|
-
menuOptions.push(await i18n.t('menu.api_management.import'));
|
|
581
|
-
menuOptions.push(await i18n.t('menu.api_management.change_password'));
|
|
726
|
+
menuOptions.push(await i18n.t('menu.api_management.export')); // 4
|
|
727
|
+
menuOptions.push(await i18n.t('menu.api_management.import')); // 5
|
|
728
|
+
menuOptions.push(await i18n.t('menu.api_management.change_password')); // 6
|
|
582
729
|
}
|
|
583
730
|
|
|
584
|
-
|
|
731
|
+
// Add model upgrade settings (always available)
|
|
732
|
+
menuOptions.push(await i18n.t('model_upgrade.settings_title')); // 4 or 7 (depending on import/export)
|
|
733
|
+
|
|
734
|
+
menuOptions.push(await i18n.t('menu.api_management.back')); // 5 or 8
|
|
585
735
|
|
|
586
736
|
// Ensure global menus are initialized
|
|
587
737
|
initializeGlobalMenus();
|
|
@@ -604,7 +754,7 @@ async function showApiManagementMenu() {
|
|
|
604
754
|
await viewStatistics();
|
|
605
755
|
return showMenu();
|
|
606
756
|
} else if (apiManager.canUseImportExport()) {
|
|
607
|
-
//
|
|
757
|
+
// With import/export enabled: indices 4-8
|
|
608
758
|
if (choice === 4) { // Export Configuration
|
|
609
759
|
await exportConfiguration();
|
|
610
760
|
return showMenu();
|
|
@@ -614,12 +764,16 @@ async function showApiManagementMenu() {
|
|
|
614
764
|
} else if (choice === 6) { // Change Password
|
|
615
765
|
await changePassword();
|
|
616
766
|
return showMenu();
|
|
617
|
-
} else if (choice === 7) { //
|
|
767
|
+
} else if (choice === 7) { // Model Upgrade Settings (NEW)
|
|
768
|
+
return await showModelUpgradeSettings();
|
|
769
|
+
} else if (choice === 8) { // Back to Main Menu
|
|
618
770
|
return showMenu();
|
|
619
771
|
}
|
|
620
772
|
} else {
|
|
621
|
-
//
|
|
622
|
-
if (choice === 4) { //
|
|
773
|
+
// Without import/export: indices 4-5
|
|
774
|
+
if (choice === 4) { // Model Upgrade Settings (NEW)
|
|
775
|
+
return await showModelUpgradeSettings();
|
|
776
|
+
} else if (choice === 5) { // Back to Main Menu
|
|
623
777
|
return showMenu();
|
|
624
778
|
}
|
|
625
779
|
}
|
|
@@ -628,6 +782,144 @@ async function showApiManagementMenu() {
|
|
|
628
782
|
return showMenu();
|
|
629
783
|
}
|
|
630
784
|
|
|
785
|
+
/**
|
|
786
|
+
* Show model upgrade settings menu
|
|
787
|
+
*/
|
|
788
|
+
async function showModelUpgradeSettings() {
|
|
789
|
+
const versionChecker = require('./lib/utils/version-checker');
|
|
790
|
+
const upgradeChecker = require('./lib/utils/model-upgrade-checker');
|
|
791
|
+
|
|
792
|
+
console.clear();
|
|
793
|
+
console.log('');
|
|
794
|
+
console.log(colors.bright + colors.orange + '⚙️ ' + await i18n.t('model_upgrade.settings_title') + colors.reset);
|
|
795
|
+
console.log('');
|
|
796
|
+
|
|
797
|
+
const config = await versionChecker.loadConfig();
|
|
798
|
+
const isAutoOn = config.autoModelUpgrade === true;
|
|
799
|
+
|
|
800
|
+
console.log(colors.cyan + ' ' + await i18n.t('model_upgrade.current_config') + ':' + colors.reset);
|
|
801
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.auto_upgrade_label') + ': ' +
|
|
802
|
+
(isAutoOn
|
|
803
|
+
? colors.green + await i18n.t('model_upgrade.auto_upgrade_on')
|
|
804
|
+
: colors.dim + await i18n.t('model_upgrade.auto_upgrade_off')
|
|
805
|
+
) + colors.reset);
|
|
806
|
+
console.log('');
|
|
807
|
+
|
|
808
|
+
const menuOptions = [
|
|
809
|
+
isAutoOn
|
|
810
|
+
? await i18n.t('model_upgrade.menu_toggle_auto_on')
|
|
811
|
+
: await i18n.t('model_upgrade.menu_toggle_auto_off'),
|
|
812
|
+
await i18n.t('model_upgrade.menu_manual_upgrade'),
|
|
813
|
+
await i18n.t('model_upgrade.menu_back')
|
|
814
|
+
];
|
|
815
|
+
|
|
816
|
+
initializeGlobalMenus();
|
|
817
|
+
globalApiManagementMenu.setOptions(menuOptions);
|
|
818
|
+
const choice = await globalApiManagementMenu.navigate();
|
|
819
|
+
|
|
820
|
+
switch (choice) {
|
|
821
|
+
case 0: // Toggle auto upgrade
|
|
822
|
+
await versionChecker.setAutoModelUpgrade(!isAutoOn);
|
|
823
|
+
console.log('');
|
|
824
|
+
console.log(colors.green + '✓ ' + await i18n.t('model_upgrade.auto_upgrade_label') + ': ' +
|
|
825
|
+
(!isAutoOn
|
|
826
|
+
? await i18n.t('model_upgrade.auto_upgrade_on')
|
|
827
|
+
: await i18n.t('model_upgrade.auto_upgrade_off')
|
|
828
|
+
) + colors.reset);
|
|
829
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
830
|
+
return showModelUpgradeSettings();
|
|
831
|
+
|
|
832
|
+
case 1: // Manual upgrade
|
|
833
|
+
await performManualUpgrade();
|
|
834
|
+
return showModelUpgradeSettings();
|
|
835
|
+
|
|
836
|
+
case 2: // Back
|
|
837
|
+
case -1:
|
|
838
|
+
default:
|
|
839
|
+
return showApiManagementMenu();
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Perform manual upgrade for all APIs with interactive confirmation
|
|
845
|
+
*/
|
|
846
|
+
async function performManualUpgrade() {
|
|
847
|
+
const { getLatestModel, getProvider } = require('./lib/presets/providers');
|
|
848
|
+
const { simpleInput } = require('./lib/ui/prompts');
|
|
849
|
+
|
|
850
|
+
console.clear();
|
|
851
|
+
console.log('');
|
|
852
|
+
console.log(colors.bright + colors.orange + '🔄 ' + await i18n.t('model_upgrade.manual_title') + colors.reset);
|
|
853
|
+
console.log('');
|
|
854
|
+
|
|
855
|
+
const apis = apiManager.getApis();
|
|
856
|
+
|
|
857
|
+
if (apis.length === 0) {
|
|
858
|
+
console.log(colors.yellow + ' ' + await i18n.t('messages.info.no_apis') + colors.reset);
|
|
859
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.manual_checking', apis.length) + colors.reset);
|
|
864
|
+
console.log('');
|
|
865
|
+
|
|
866
|
+
let upgradedCount = 0;
|
|
867
|
+
let skippedUpToDate = 0;
|
|
868
|
+
let skippedNoInfo = 0;
|
|
869
|
+
let skippedByUser = 0;
|
|
870
|
+
|
|
871
|
+
for (let i = 0; i < apis.length; i++) {
|
|
872
|
+
const api = apis[i];
|
|
873
|
+
const latestModel = getLatestModel(api.model, api.provider);
|
|
874
|
+
|
|
875
|
+
console.log(colors.cyan + ' ─────────────────────────────────────────────────' + colors.reset);
|
|
876
|
+
console.log(colors.bright + ` ${i + 1}/${apis.length} ${api.name}` + colors.reset);
|
|
877
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.manual_api_current', api.model) + colors.reset);
|
|
878
|
+
|
|
879
|
+
if (latestModel) {
|
|
880
|
+
console.log(colors.green + ' ' + await i18n.t('model_upgrade.manual_api_latest', latestModel) + colors.reset);
|
|
881
|
+
console.log('');
|
|
882
|
+
|
|
883
|
+
// Ask for confirmation
|
|
884
|
+
const answer = await simpleInput(colors.yellow + ' ' + await i18n.t('model_upgrade.manual_confirm') + ' ' + colors.reset);
|
|
885
|
+
|
|
886
|
+
if (answer.toLowerCase() === 'y') {
|
|
887
|
+
apiManager.updateApiModel(api.id, latestModel);
|
|
888
|
+
console.log(colors.green + ' ✓ ' + await i18n.t('model_upgrade.manual_upgraded', api.model, latestModel) + colors.reset);
|
|
889
|
+
upgradedCount++;
|
|
890
|
+
} else {
|
|
891
|
+
console.log(colors.dim + ' ' + await i18n.t('model_upgrade.manual_skipped') + colors.reset);
|
|
892
|
+
skippedByUser++;
|
|
893
|
+
}
|
|
894
|
+
} else {
|
|
895
|
+
// No upgrade info available - check if model exists in provider
|
|
896
|
+
const provider = getProvider(api.provider);
|
|
897
|
+
if (provider && provider.models && provider.models.includes(api.model)) {
|
|
898
|
+
// Model exists in provider, likely already latest or no alias defined
|
|
899
|
+
console.log(colors.dim + ' ' + await i18n.t('model_upgrade.manual_api_uptodate') + colors.reset);
|
|
900
|
+
skippedUpToDate++;
|
|
901
|
+
} else {
|
|
902
|
+
console.log(colors.dim + ' ' + await i18n.t('model_upgrade.manual_api_no_info') + colors.reset);
|
|
903
|
+
skippedNoInfo++;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
console.log('');
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
console.log(colors.cyan + ' ─────────────────────────────────────────────────' + colors.reset);
|
|
911
|
+
console.log('');
|
|
912
|
+
console.log(colors.green + ' ' + await i18n.t('model_upgrade.manual_complete') + colors.reset);
|
|
913
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.manual_stats_upgraded', upgradedCount) + colors.reset);
|
|
914
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.manual_stats_skipped',
|
|
915
|
+
skippedUpToDate + skippedNoInfo + skippedByUser,
|
|
916
|
+
skippedUpToDate,
|
|
917
|
+
skippedNoInfo) + colors.reset);
|
|
918
|
+
console.log('');
|
|
919
|
+
|
|
920
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
921
|
+
}
|
|
922
|
+
|
|
631
923
|
/**
|
|
632
924
|
* Handle third-party API launch
|
|
633
925
|
*/
|
|
@@ -646,12 +938,15 @@ async function handleThirdPartyApiLaunch(skipPermissions = false) {
|
|
|
646
938
|
return showMenu();
|
|
647
939
|
}
|
|
648
940
|
|
|
649
|
-
//
|
|
650
|
-
apiManager.
|
|
941
|
+
// Record successful launch BEFORE launching (since process exits after)
|
|
942
|
+
apiManager.recordSuccessfulLaunch();
|
|
651
943
|
|
|
652
944
|
launchClaudeWithApi(activeApi, skipPermissions);
|
|
653
945
|
|
|
654
946
|
} catch (error) {
|
|
947
|
+
// Record failed launch
|
|
948
|
+
apiManager.recordFailedLaunch(error.message);
|
|
949
|
+
|
|
655
950
|
showError('Failed to launch with third-party API', [error.message]);
|
|
656
951
|
|
|
657
952
|
setTimeout(() => {
|
|
@@ -673,24 +968,28 @@ async function executeSelection(selectedIndex) {
|
|
|
673
968
|
launchClaudeSkipPermissions();
|
|
674
969
|
break;
|
|
675
970
|
|
|
676
|
-
case 2: // Launch Claude Code
|
|
971
|
+
case 2: // Launch Claude Code (Enable Auto Mode)
|
|
972
|
+
launchClaudeAutoMode();
|
|
973
|
+
break;
|
|
974
|
+
|
|
975
|
+
case 3: // Launch Claude Code with 3rd-party API
|
|
677
976
|
await handleThirdPartyApiLaunch(false);
|
|
678
977
|
break;
|
|
679
978
|
|
|
680
|
-
case
|
|
979
|
+
case 4: // Launch Claude Code with 3rd-party API (Skip Permissions)
|
|
681
980
|
await handleThirdPartyApiLaunch(true);
|
|
682
981
|
break;
|
|
683
982
|
|
|
684
|
-
case
|
|
983
|
+
case 5: // 3rd-party API Management
|
|
685
984
|
return await showApiManagementMenu();
|
|
686
985
|
|
|
687
|
-
case
|
|
986
|
+
case 6: // Language Settings
|
|
688
987
|
return await showLanguageSettings();
|
|
689
988
|
|
|
690
|
-
case
|
|
989
|
+
case 7: // Version Update Check
|
|
691
990
|
return await showVersionUpdateCheck();
|
|
692
991
|
|
|
693
|
-
case
|
|
992
|
+
case 8: // Exit
|
|
694
993
|
console.log('');
|
|
695
994
|
console.log(colors.green + '👋 ' + await i18n.t('menu.main.exit') + '!' + colors.reset);
|
|
696
995
|
process.exit(0);
|
|
@@ -741,10 +1040,65 @@ async function showMenu() {
|
|
|
741
1040
|
// Silently ignore update check errors
|
|
742
1041
|
}
|
|
743
1042
|
|
|
1043
|
+
// ========================================
|
|
1044
|
+
// Model upgrade check (new feature)
|
|
1045
|
+
// ========================================
|
|
1046
|
+
let modelUpgradeInfo = null;
|
|
1047
|
+
try {
|
|
1048
|
+
const upgradeChecker = require('./lib/utils/model-upgrade-checker');
|
|
1049
|
+
const autoUpgrade = await upgradeChecker.isAutoUpgradeEnabled();
|
|
1050
|
+
|
|
1051
|
+
if (autoUpgrade) {
|
|
1052
|
+
// Auto upgrade enabled: always check and upgrade (bypass cache)
|
|
1053
|
+
const upgrades = upgradeChecker.checkAllApiUpgrades(apiManager);
|
|
1054
|
+
if (upgrades.length > 0) {
|
|
1055
|
+
const upgraded = upgradeChecker.performAutoUpgrade(apiManager, upgrades);
|
|
1056
|
+
if (upgraded.length > 0) {
|
|
1057
|
+
modelUpgradeInfo = colors.green + ' ✓ ' +
|
|
1058
|
+
i18n.tSync('model_upgrade.auto_upgraded', upgraded[0].from, upgraded[0].to) + colors.reset;
|
|
1059
|
+
if (upgraded.length > 1) {
|
|
1060
|
+
modelUpgradeInfo += '\n' + colors.green + ' ' +
|
|
1061
|
+
`(+${upgraded.length - 1} more)` + colors.reset;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
} else {
|
|
1066
|
+
// Auto upgrade disabled: use cache for notification
|
|
1067
|
+
const result = await upgradeChecker.checkForModelUpgrades(apiManager);
|
|
1068
|
+
if (result.needsCheck && result.upgrades.length > 0) {
|
|
1069
|
+
const first = result.upgrades[0];
|
|
1070
|
+
modelUpgradeInfo = colors.yellow + ' ⚠️ ' +
|
|
1071
|
+
i18n.tSync('model_upgrade.notification', first.currentModel, first.latestModel) +
|
|
1072
|
+
colors.reset + '\n' +
|
|
1073
|
+
colors.yellow + ' ' +
|
|
1074
|
+
i18n.tSync('model_upgrade.notification_api', first.apiName) +
|
|
1075
|
+
colors.reset + '\n' +
|
|
1076
|
+
colors.gray + ' ' +
|
|
1077
|
+
i18n.tSync('model_upgrade.notification_hint') +
|
|
1078
|
+
colors.reset;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
} catch (error) {
|
|
1082
|
+
// Silently ignore model upgrade check errors
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// Combine version info and model upgrade info
|
|
1086
|
+
let displayInfo = '';
|
|
1087
|
+
if (versionInfo) {
|
|
1088
|
+
displayInfo += versionInfo;
|
|
1089
|
+
}
|
|
1090
|
+
if (modelUpgradeInfo) {
|
|
1091
|
+
if (displayInfo) {
|
|
1092
|
+
displayInfo += '\n';
|
|
1093
|
+
}
|
|
1094
|
+
displayInfo += modelUpgradeInfo;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
744
1097
|
// Populate menu options dynamically with i18n translations
|
|
745
1098
|
menuOptions = [
|
|
746
1099
|
await i18n.t('menu.main.launch_default'),
|
|
747
1100
|
await i18n.t('menu.main.launch_skip'),
|
|
1101
|
+
await i18n.t('menu.main.launch_auto_mode'),
|
|
748
1102
|
await i18n.t('menu.main.launch_api'),
|
|
749
1103
|
await i18n.t('menu.main.launch_api_skip'),
|
|
750
1104
|
await i18n.t('menu.main.api_management'),
|
|
@@ -753,8 +1107,31 @@ async function showMenu() {
|
|
|
753
1107
|
await i18n.t('menu.main.exit')
|
|
754
1108
|
];
|
|
755
1109
|
|
|
1110
|
+
// Pre-compute hint texts synchronously for menu callback
|
|
1111
|
+
const hintAutoMode = i18n.tSync('hints.auto_mode_info');
|
|
1112
|
+
const activeApi = apiManager.getActiveApi();
|
|
1113
|
+
let hintApiInfo = null;
|
|
1114
|
+
if (activeApi) {
|
|
1115
|
+
const { getProvider } = require('./lib/presets/providers');
|
|
1116
|
+
const providerConfig = getProvider(activeApi.provider);
|
|
1117
|
+
const providerName = providerConfig ? providerConfig.name : (activeApi.provider || 'Custom');
|
|
1118
|
+
hintApiInfo = i18n.tSync('hints.active_api_info', providerName, activeApi.model);
|
|
1119
|
+
} else {
|
|
1120
|
+
hintApiInfo = i18n.tSync('hints.no_active_api');
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// Synchronous hint callback — must not use await
|
|
1124
|
+
const hintCallback = (selectedIndex) => {
|
|
1125
|
+
switch (selectedIndex) {
|
|
1126
|
+
case 2: return hintAutoMode;
|
|
1127
|
+
case 3: return hintApiInfo;
|
|
1128
|
+
case 4: return hintApiInfo;
|
|
1129
|
+
default: return null;
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
|
|
756
1133
|
globalMainMenu.setOptions(menuOptions);
|
|
757
|
-
const selection = await globalMainMenu.navigate(false,
|
|
1134
|
+
const selection = await globalMainMenu.navigate(false, displayInfo || null, hintCallback);
|
|
758
1135
|
|
|
759
1136
|
if (selection === -1) {
|
|
760
1137
|
console.log('');
|