@kikkimo/claude-launcher 2.3.0 → 2.4.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 +41 -0
- package/README.md +22 -8
- package/claude-launcher +390 -42
- package/docs/README-zh.md +22 -8
- package/lib/api-manager.js +135 -1
- package/lib/i18n/locales/de.js +68 -3
- package/lib/i18n/locales/en.js +66 -2
- package/lib/i18n/locales/es.js +68 -3
- package/lib/i18n/locales/fr.js +68 -3
- package/lib/i18n/locales/it.js +66 -2
- package/lib/i18n/locales/ja.js +68 -3
- package/lib/i18n/locales/ko.js +68 -3
- package/lib/i18n/locales/pt.js +66 -2
- package/lib/i18n/locales/ru.js +66 -2
- package/lib/i18n/locales/zh-TW.js +68 -3
- package/lib/i18n/locales/zh.js +68 -3
- package/lib/presets/providers.js +61 -11
- package/lib/utils/model-upgrade-checker.js +103 -0
- package/lib/utils/version-checker.js +22 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,47 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.4.0] - 2026-02-12
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **GLM-5 Model Support**: Added GLM-5 model for ZhiPu AI providers (`zhipu` and `zai`)
|
|
12
|
+
- **Claude Opus 4.6 Model**: Added `claude-opus-4-6` model support with unified hyphen naming format
|
|
13
|
+
- **Model Upgrade Notification**: Automatic startup notification when newer model versions are available for configured APIs
|
|
14
|
+
- **Model Upgrade Settings Menu**: New submenu under API Management with:
|
|
15
|
+
- Auto Upgrade toggle (ON/OFF) - automatically use latest model versions
|
|
16
|
+
- Manual Upgrade option - review and confirm each model upgrade individually
|
|
17
|
+
- **Enhanced Usage Statistics**: Added success/failure rate tracking for API calls:
|
|
18
|
+
- Overall success rate display
|
|
19
|
+
- Per-API success rate in statistics table
|
|
20
|
+
- Time-based last used display (just now, minutes ago, hours ago, days ago)
|
|
21
|
+
- **Statistics Submenu**: Restructured statistics page with submenu:
|
|
22
|
+
- View Statistics Details
|
|
23
|
+
- Reset Statistics
|
|
24
|
+
- **Clear All APIs**: New bulk delete option in Remove API submenu:
|
|
25
|
+
- Delete Single API
|
|
26
|
+
- Clear All APIs (with CLEAR confirmation prompt)
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- **Model Naming Convention**: Unified all model names to use hyphen format (e.g., `claude-opus-4-6` instead of mixed formats)
|
|
30
|
+
- **Auto Upgrade Toggle**: Changed to radio button style for better visual feedback
|
|
31
|
+
- **Statistics Display**: Enhanced table format with success rate column and relative time display
|
|
32
|
+
- **Menu Structure**: Reorganized API management with logical submenu groupings
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
- **Auto Upgrade Execution**: Fixed auto upgrade to bypass cache and execute immediately when enabled
|
|
36
|
+
- **Model Upgrade Notification**: Corrected menu name reference in upgrade notification hint
|
|
37
|
+
- **i18n Synchronization**: Synced all 41 missing translation entries across 9 non-English locale files:
|
|
38
|
+
- Added `statistics` enhanced fields (15 entries) to all locales
|
|
39
|
+
- Added complete `model_upgrade` module (25 entries) to all locales
|
|
40
|
+
- Added missing `confirm_password_prompt` to affected locales
|
|
41
|
+
|
|
42
|
+
### Documentation
|
|
43
|
+
- **README Updates**: Updated both English and Chinese README files with:
|
|
44
|
+
- Model upgrade feature documentation
|
|
45
|
+
- Updated API management menu structure
|
|
46
|
+
- Success/failure rate tracking description
|
|
47
|
+
- Updated supported providers list
|
|
48
|
+
|
|
8
49
|
## [2.3.0] - 2025-12-24
|
|
9
50
|
|
|
10
51
|
### Added
|
package/README.md
CHANGED
|
@@ -25,11 +25,12 @@ An elegant interactive launcher for Claude Code with a beautiful Claude-style in
|
|
|
25
25
|
- Strong password requirements and validation
|
|
26
26
|
|
|
27
27
|
### 🚀 **Third-party API Management**
|
|
28
|
-
- Full support for multiple third-party API providers (OpenAI, Anthropic, DeepSeek, Kimi, MiniMax, GLM
|
|
28
|
+
- Full support for multiple third-party API providers (OpenAI, Anthropic, DeepSeek, Kimi, MiniMax, GLM/ZhiPu AI, and custom APIs)
|
|
29
29
|
- Interactive API configuration with validation
|
|
30
|
-
- API usage statistics
|
|
30
|
+
- API usage statistics with success/failure tracking
|
|
31
|
+
- Model upgrade notifications and auto-upgrade support
|
|
31
32
|
- Secure configuration backup and restore
|
|
32
|
-
- Easy API switching and
|
|
33
|
+
- Easy API switching, removal, and bulk clear
|
|
33
34
|
|
|
34
35
|
### 🌍 **Enterprise-grade Features**
|
|
35
36
|
- Global installation - use `claude-launcher` from anywhere
|
|
@@ -85,7 +86,11 @@ node claude-launcher
|
|
|
85
86
|
2. **Launch Claude Code (Skip Permissions)** - Launch with `--dangerously-skip-permissions`
|
|
86
87
|
3. **Launch Claude Code with Third-party API** - Use configured third-party API
|
|
87
88
|
4. **Launch Claude Code with Third-party API (Skip Permissions)** - Combine third-party API with permission skipping
|
|
88
|
-
5. **Third-party API Management** -
|
|
89
|
+
5. **Third-party API Management** - Full API lifecycle management:
|
|
90
|
+
- Add, switch, and remove APIs
|
|
91
|
+
- View usage statistics with success/failure rates
|
|
92
|
+
- Model upgrade settings (auto/manual upgrade)
|
|
93
|
+
- Import/export configurations
|
|
89
94
|
6. **Language Settings** - Switch between 11 supported languages
|
|
90
95
|
7. **Version Update Check** - Check for launcher updates
|
|
91
96
|
8. **Exit** - Close the launcher
|
|
@@ -126,15 +131,23 @@ Access comprehensive API management through the dedicated menu:
|
|
|
126
131
|
📋 Third-party API Management
|
|
127
132
|
|
|
128
133
|
→ Add New API
|
|
129
|
-
Remove API
|
|
134
|
+
Remove API → Delete Single API / Clear All APIs
|
|
130
135
|
Switch Active API
|
|
131
|
-
View Statistics
|
|
136
|
+
View Statistics → View Details / Reset Statistics
|
|
137
|
+
Model Upgrade → Auto Upgrade [ON/OFF] / Manual Upgrade
|
|
132
138
|
Export Configuration
|
|
133
139
|
Import Configuration
|
|
134
140
|
Change Password
|
|
135
141
|
Back to Main Menu
|
|
136
142
|
```
|
|
137
143
|
|
|
144
|
+
### Model Upgrade Feature
|
|
145
|
+
|
|
146
|
+
The launcher automatically checks for model upgrades when you start:
|
|
147
|
+
- **Auto Upgrade**: Automatically use the latest model version
|
|
148
|
+
- **Manual Upgrade**: Review and confirm each model upgrade
|
|
149
|
+
- **Startup Notifications**: Get notified when newer model versions are available
|
|
150
|
+
|
|
138
151
|
## ⚙️ Configuration
|
|
139
152
|
|
|
140
153
|
### Modern Configuration System
|
|
@@ -158,10 +171,11 @@ Claude Launcher 2.0 uses an advanced configuration system:
|
|
|
158
171
|
|
|
159
172
|
Configure any third-party API provider through the interactive interface:
|
|
160
173
|
|
|
161
|
-
- **Supported Providers**:
|
|
174
|
+
- **Supported Providers**: Anthropic, OpenAI, DeepSeek, Moonshot/Kimi, MiniMax (CN/Global), GLM/ZhiPu AI (GLM-4, GLM-5), and custom Anthropic-compatible APIs
|
|
162
175
|
- **Secure Storage**: All API tokens encrypted before storage
|
|
163
176
|
- **Validation**: Real-time validation of URLs, tokens, and models
|
|
164
|
-
- **Usage Tracking**: Monitor API usage statistics
|
|
177
|
+
- **Usage Tracking**: Monitor API usage statistics with success/failure rates
|
|
178
|
+
- **Model Upgrade**: Automatic detection and upgrade to latest model versions
|
|
165
179
|
- **Provider-specific Features**: Optimized configuration for each provider with helpful notes and recommendations
|
|
166
180
|
|
|
167
181
|
### Configuration Import/Export
|
package/claude-launcher
CHANGED
|
@@ -263,9 +263,52 @@ async function addNewThirdPartyApi() {
|
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
/**
|
|
266
|
-
* Remove third-party API
|
|
266
|
+
* Remove third-party API menu with submenu
|
|
267
267
|
*/
|
|
268
268
|
async function removeThirdPartyApi() {
|
|
269
|
+
console.clear();
|
|
270
|
+
console.log('');
|
|
271
|
+
console.log(colors.bright + colors.orange + '🗑️ ' + await i18n.t('menu.remove_api.title') + colors.reset);
|
|
272
|
+
console.log('');
|
|
273
|
+
|
|
274
|
+
const apis = apiManager.getApis();
|
|
275
|
+
|
|
276
|
+
// Show current API count
|
|
277
|
+
if (apis.length > 0) {
|
|
278
|
+
console.log(colors.cyan + ' ' + await i18n.t('messages.info.current_api_count', apis.length) + colors.reset);
|
|
279
|
+
console.log('');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const menuOptions = [
|
|
283
|
+
await i18n.t('menu.remove_api.delete_single'),
|
|
284
|
+
await i18n.t('menu.remove_api.clear_all'),
|
|
285
|
+
await i18n.t('menu.remove_api.back')
|
|
286
|
+
];
|
|
287
|
+
|
|
288
|
+
initializeGlobalMenus();
|
|
289
|
+
globalApiManagementMenu.setOptions(menuOptions);
|
|
290
|
+
const choice = await globalApiManagementMenu.navigate();
|
|
291
|
+
|
|
292
|
+
switch (choice) {
|
|
293
|
+
case 0: // Delete Single API
|
|
294
|
+
await deleteSingleApi();
|
|
295
|
+
return;
|
|
296
|
+
|
|
297
|
+
case 1: // Clear All APIs
|
|
298
|
+
await clearAllApis();
|
|
299
|
+
return;
|
|
300
|
+
|
|
301
|
+
case 2: // Back
|
|
302
|
+
case -1:
|
|
303
|
+
default:
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Delete a single API
|
|
310
|
+
*/
|
|
311
|
+
async function deleteSingleApi() {
|
|
269
312
|
try {
|
|
270
313
|
// Get API list
|
|
271
314
|
const apis = apiManager.getApis();
|
|
@@ -281,7 +324,7 @@ async function removeThirdPartyApi() {
|
|
|
281
324
|
);
|
|
282
325
|
|
|
283
326
|
if (!selectedApi) {
|
|
284
|
-
return
|
|
327
|
+
return;
|
|
285
328
|
}
|
|
286
329
|
|
|
287
330
|
// Show confirmation dialog
|
|
@@ -299,23 +342,20 @@ async function removeThirdPartyApi() {
|
|
|
299
342
|
`${await i18n.t('api.details.provider')}: ${selectedApi.provider}`
|
|
300
343
|
]);
|
|
301
344
|
|
|
302
|
-
// Show success message
|
|
345
|
+
// Show success message
|
|
303
346
|
const remainingApis = apiManager.getApis();
|
|
304
347
|
if (remainingApis.length === 0) {
|
|
305
348
|
showInfo(await i18n.t('messages.info.all_apis_removed'));
|
|
306
349
|
}
|
|
307
350
|
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
308
|
-
return showMenu();
|
|
309
351
|
|
|
310
352
|
} catch (removeError) {
|
|
311
353
|
showError(await i18n.t('errors.api.failed_remove', removeError.message));
|
|
312
354
|
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
313
|
-
return showMenu();
|
|
314
355
|
}
|
|
315
356
|
} else {
|
|
316
357
|
showInfo(await i18n.t('messages.info.removal_cancelled'));
|
|
317
358
|
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
318
|
-
return showMenu();
|
|
319
359
|
}
|
|
320
360
|
|
|
321
361
|
} catch (error) {
|
|
@@ -325,6 +365,42 @@ async function removeThirdPartyApi() {
|
|
|
325
365
|
}
|
|
326
366
|
}
|
|
327
367
|
|
|
368
|
+
/**
|
|
369
|
+
* Clear all APIs with confirmation
|
|
370
|
+
*/
|
|
371
|
+
async function clearAllApis() {
|
|
372
|
+
const { simpleInput } = require('./lib/ui/prompts');
|
|
373
|
+
|
|
374
|
+
const apis = apiManager.getApis();
|
|
375
|
+
const count = apis.length;
|
|
376
|
+
|
|
377
|
+
if (count === 0) {
|
|
378
|
+
console.clear();
|
|
379
|
+
showInfo(await i18n.t('messages.info.no_apis'));
|
|
380
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
console.clear();
|
|
385
|
+
console.log('');
|
|
386
|
+
console.log(colors.bright + colors.red + '⚠️ ' + await i18n.t('menu.remove_api.clear_all') + colors.reset);
|
|
387
|
+
console.log('');
|
|
388
|
+
console.log(colors.yellow + ' ' + await i18n.t('messages.prompts.confirm_clear_all', count) + colors.reset);
|
|
389
|
+
console.log('');
|
|
390
|
+
|
|
391
|
+
const input = await simpleInput(colors.cyan + ' ' + await i18n.t('messages.prompts.confirm_clear_all_input') + colors.reset);
|
|
392
|
+
|
|
393
|
+
if (input === 'CLEAR') {
|
|
394
|
+
const clearedCount = apiManager.clearAllApis();
|
|
395
|
+
console.clear();
|
|
396
|
+
showSuccess(await i18n.t('messages.info.all_apis_cleared', clearedCount));
|
|
397
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
398
|
+
} else {
|
|
399
|
+
showInfo(await i18n.t('messages.info.clear_cancelled'));
|
|
400
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
328
404
|
/**
|
|
329
405
|
* Switch active third-party API
|
|
330
406
|
*/
|
|
@@ -357,40 +433,110 @@ async function switchThirdPartyApi() {
|
|
|
357
433
|
/**
|
|
358
434
|
* View API statistics
|
|
359
435
|
*/
|
|
436
|
+
/**
|
|
437
|
+
* Format timestamp to relative time
|
|
438
|
+
* @param {string|null} timestamp - ISO timestamp or null
|
|
439
|
+
* @returns {string} Relative time string
|
|
440
|
+
*/
|
|
441
|
+
function formatRelativeTime(timestamp) {
|
|
442
|
+
if (!timestamp) return i18n.tSync('statistics.time_never');
|
|
443
|
+
|
|
444
|
+
const now = Date.now();
|
|
445
|
+
const diff = now - new Date(timestamp).getTime();
|
|
446
|
+
const minutes = Math.floor(diff / 60000);
|
|
447
|
+
const hours = Math.floor(diff / 3600000);
|
|
448
|
+
const days = Math.floor(diff / 86400000);
|
|
449
|
+
|
|
450
|
+
if (minutes < 1) return i18n.tSync('statistics.time_just_now');
|
|
451
|
+
if (minutes < 60) return i18n.tSync('statistics.time_minutes_ago', minutes);
|
|
452
|
+
if (hours < 24) return i18n.tSync('statistics.time_hours_ago', hours);
|
|
453
|
+
return i18n.tSync('statistics.time_days_ago', days);
|
|
454
|
+
}
|
|
455
|
+
|
|
360
456
|
async function viewStatistics() {
|
|
361
457
|
console.clear();
|
|
362
458
|
console.log('');
|
|
363
459
|
console.log(colors.bright + colors.orange + '📊 ' + await i18n.t('statistics.title') + colors.reset);
|
|
364
460
|
console.log('');
|
|
365
461
|
|
|
366
|
-
const
|
|
367
|
-
|
|
462
|
+
const menuOptions = [
|
|
463
|
+
await i18n.t('statistics.menu_view'),
|
|
464
|
+
await i18n.t('statistics.menu_reset'),
|
|
465
|
+
await i18n.t('statistics.menu_back')
|
|
466
|
+
];
|
|
467
|
+
|
|
468
|
+
initializeGlobalMenus();
|
|
469
|
+
globalApiManagementMenu.setOptions(menuOptions);
|
|
470
|
+
const choice = await globalApiManagementMenu.navigate();
|
|
471
|
+
|
|
472
|
+
switch (choice) {
|
|
473
|
+
case 0: // View Statistics Details
|
|
474
|
+
await showStatisticsDetails();
|
|
475
|
+
return viewStatistics();
|
|
476
|
+
|
|
477
|
+
case 1: // Reset Statistics
|
|
478
|
+
const { simpleInput } = require('./lib/ui/prompts');
|
|
479
|
+
const confirm = await simpleInput(colors.yellow + ' ' + await i18n.t('statistics.reset_confirm') + ' ' + colors.reset);
|
|
480
|
+
if (confirm.toLowerCase() === 'y') {
|
|
481
|
+
apiManager.resetStatistics();
|
|
482
|
+
console.log(colors.green + ' ✓ ' + await i18n.t('statistics.reset_success') + colors.reset);
|
|
483
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
484
|
+
}
|
|
485
|
+
return viewStatistics();
|
|
486
|
+
|
|
487
|
+
case 2: // Back
|
|
488
|
+
case -1:
|
|
489
|
+
default:
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Show detailed statistics
|
|
496
|
+
*/
|
|
497
|
+
async function showStatisticsDetails() {
|
|
498
|
+
const { padStringToWidth } = require('./lib/utils/string-width');
|
|
368
499
|
|
|
369
|
-
console.
|
|
500
|
+
console.clear();
|
|
501
|
+
console.log('');
|
|
502
|
+
console.log(colors.bright + colors.orange + '📊 ' + await i18n.t('statistics.title') + colors.reset);
|
|
503
|
+
console.log('');
|
|
504
|
+
|
|
505
|
+
const stats = apiManager.getEnhancedStatistics();
|
|
506
|
+
|
|
507
|
+
// Summary section
|
|
508
|
+
console.log(colors.cyan + ' ' + i18n.tSync('ui.general.summary') + ':' + colors.reset);
|
|
370
509
|
console.log(colors.gray + ` ${await i18n.t('statistics.total_apis', stats.totalApis)}` + colors.reset);
|
|
371
510
|
console.log(colors.gray + ` ${await i18n.t('statistics.active_api', stats.activeApiName)}` + colors.reset);
|
|
372
511
|
console.log(colors.gray + ` ${await i18n.t('statistics.most_used', stats.mostUsedApi)}` + colors.reset);
|
|
373
512
|
console.log(colors.gray + ` ${await i18n.t('statistics.total_usage', stats.totalUsage)}` + colors.reset);
|
|
513
|
+
console.log(colors.gray + ` ${await i18n.t('statistics.success_rate', stats.successRate)}` + colors.reset);
|
|
374
514
|
console.log('');
|
|
375
515
|
|
|
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
|
-
|
|
516
|
+
if (stats.apiStats.length > 0) {
|
|
517
|
+
console.log(colors.cyan + ' ' + i18n.tSync('ui.general.configured_apis') + ':' + colors.reset);
|
|
518
|
+
console.log('');
|
|
519
|
+
|
|
520
|
+
// Table header
|
|
521
|
+
console.log(colors.dim + ' ' +
|
|
522
|
+
padStringToWidth(await i18n.t('statistics.header_name'), 20) +
|
|
523
|
+
padStringToWidth(await i18n.t('statistics.header_usage'), 10) +
|
|
524
|
+
padStringToWidth(await i18n.t('statistics.header_success'), 10) +
|
|
525
|
+
await i18n.t('statistics.header_last_used') +
|
|
526
|
+
colors.reset);
|
|
527
|
+
console.log(colors.dim + ' ' + '─'.repeat(60) + colors.reset);
|
|
528
|
+
|
|
529
|
+
for (const api of stats.apiStats) {
|
|
530
|
+
const lastUsedText = formatRelativeTime(api.lastUsed);
|
|
531
|
+
console.log(colors.gray + ' ' +
|
|
532
|
+
padStringToWidth(api.name, 20) +
|
|
533
|
+
padStringToWidth(String(api.usageCount), 10) +
|
|
534
|
+
padStringToWidth(api.successRate, 10) +
|
|
535
|
+
lastUsedText +
|
|
536
|
+
colors.reset);
|
|
537
|
+
}
|
|
538
|
+
} else {
|
|
539
|
+
console.log(colors.gray + ' ' + await i18n.t('statistics.no_usage') + colors.reset);
|
|
394
540
|
}
|
|
395
541
|
|
|
396
542
|
console.log('');
|
|
@@ -568,20 +714,23 @@ async function showApiManagementMenu() {
|
|
|
568
714
|
|
|
569
715
|
// Build menu options based on password setup status
|
|
570
716
|
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')
|
|
717
|
+
await i18n.t('menu.api_management.add_new'), // 0
|
|
718
|
+
await i18n.t('menu.api_management.remove'), // 1
|
|
719
|
+
await i18n.t('menu.api_management.switch'), // 2
|
|
720
|
+
await i18n.t('menu.api_management.statistics') // 3
|
|
575
721
|
];
|
|
576
722
|
|
|
577
723
|
// Add import/export options only if password is set
|
|
578
724
|
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'));
|
|
725
|
+
menuOptions.push(await i18n.t('menu.api_management.export')); // 4
|
|
726
|
+
menuOptions.push(await i18n.t('menu.api_management.import')); // 5
|
|
727
|
+
menuOptions.push(await i18n.t('menu.api_management.change_password')); // 6
|
|
582
728
|
}
|
|
583
729
|
|
|
584
|
-
|
|
730
|
+
// Add model upgrade settings (always available)
|
|
731
|
+
menuOptions.push(await i18n.t('model_upgrade.settings_title')); // 4 or 7 (depending on import/export)
|
|
732
|
+
|
|
733
|
+
menuOptions.push(await i18n.t('menu.api_management.back')); // 5 or 8
|
|
585
734
|
|
|
586
735
|
// Ensure global menus are initialized
|
|
587
736
|
initializeGlobalMenus();
|
|
@@ -604,7 +753,7 @@ async function showApiManagementMenu() {
|
|
|
604
753
|
await viewStatistics();
|
|
605
754
|
return showMenu();
|
|
606
755
|
} else if (apiManager.canUseImportExport()) {
|
|
607
|
-
//
|
|
756
|
+
// With import/export enabled: indices 4-8
|
|
608
757
|
if (choice === 4) { // Export Configuration
|
|
609
758
|
await exportConfiguration();
|
|
610
759
|
return showMenu();
|
|
@@ -614,12 +763,16 @@ async function showApiManagementMenu() {
|
|
|
614
763
|
} else if (choice === 6) { // Change Password
|
|
615
764
|
await changePassword();
|
|
616
765
|
return showMenu();
|
|
617
|
-
} else if (choice === 7) { //
|
|
766
|
+
} else if (choice === 7) { // Model Upgrade Settings (NEW)
|
|
767
|
+
return await showModelUpgradeSettings();
|
|
768
|
+
} else if (choice === 8) { // Back to Main Menu
|
|
618
769
|
return showMenu();
|
|
619
770
|
}
|
|
620
771
|
} else {
|
|
621
|
-
//
|
|
622
|
-
if (choice === 4) { //
|
|
772
|
+
// Without import/export: indices 4-5
|
|
773
|
+
if (choice === 4) { // Model Upgrade Settings (NEW)
|
|
774
|
+
return await showModelUpgradeSettings();
|
|
775
|
+
} else if (choice === 5) { // Back to Main Menu
|
|
623
776
|
return showMenu();
|
|
624
777
|
}
|
|
625
778
|
}
|
|
@@ -628,6 +781,144 @@ async function showApiManagementMenu() {
|
|
|
628
781
|
return showMenu();
|
|
629
782
|
}
|
|
630
783
|
|
|
784
|
+
/**
|
|
785
|
+
* Show model upgrade settings menu
|
|
786
|
+
*/
|
|
787
|
+
async function showModelUpgradeSettings() {
|
|
788
|
+
const versionChecker = require('./lib/utils/version-checker');
|
|
789
|
+
const upgradeChecker = require('./lib/utils/model-upgrade-checker');
|
|
790
|
+
|
|
791
|
+
console.clear();
|
|
792
|
+
console.log('');
|
|
793
|
+
console.log(colors.bright + colors.orange + '⚙️ ' + await i18n.t('model_upgrade.settings_title') + colors.reset);
|
|
794
|
+
console.log('');
|
|
795
|
+
|
|
796
|
+
const config = await versionChecker.loadConfig();
|
|
797
|
+
const isAutoOn = config.autoModelUpgrade === true;
|
|
798
|
+
|
|
799
|
+
console.log(colors.cyan + ' ' + await i18n.t('model_upgrade.current_config') + ':' + colors.reset);
|
|
800
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.auto_upgrade_label') + ': ' +
|
|
801
|
+
(isAutoOn
|
|
802
|
+
? colors.green + await i18n.t('model_upgrade.auto_upgrade_on')
|
|
803
|
+
: colors.dim + await i18n.t('model_upgrade.auto_upgrade_off')
|
|
804
|
+
) + colors.reset);
|
|
805
|
+
console.log('');
|
|
806
|
+
|
|
807
|
+
const menuOptions = [
|
|
808
|
+
isAutoOn
|
|
809
|
+
? await i18n.t('model_upgrade.menu_toggle_auto_on')
|
|
810
|
+
: await i18n.t('model_upgrade.menu_toggle_auto_off'),
|
|
811
|
+
await i18n.t('model_upgrade.menu_manual_upgrade'),
|
|
812
|
+
await i18n.t('model_upgrade.menu_back')
|
|
813
|
+
];
|
|
814
|
+
|
|
815
|
+
initializeGlobalMenus();
|
|
816
|
+
globalApiManagementMenu.setOptions(menuOptions);
|
|
817
|
+
const choice = await globalApiManagementMenu.navigate();
|
|
818
|
+
|
|
819
|
+
switch (choice) {
|
|
820
|
+
case 0: // Toggle auto upgrade
|
|
821
|
+
await versionChecker.setAutoModelUpgrade(!isAutoOn);
|
|
822
|
+
console.log('');
|
|
823
|
+
console.log(colors.green + '✓ ' + await i18n.t('model_upgrade.auto_upgrade_label') + ': ' +
|
|
824
|
+
(!isAutoOn
|
|
825
|
+
? await i18n.t('model_upgrade.auto_upgrade_on')
|
|
826
|
+
: await i18n.t('model_upgrade.auto_upgrade_off')
|
|
827
|
+
) + colors.reset);
|
|
828
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
829
|
+
return showModelUpgradeSettings();
|
|
830
|
+
|
|
831
|
+
case 1: // Manual upgrade
|
|
832
|
+
await performManualUpgrade();
|
|
833
|
+
return showModelUpgradeSettings();
|
|
834
|
+
|
|
835
|
+
case 2: // Back
|
|
836
|
+
case -1:
|
|
837
|
+
default:
|
|
838
|
+
return showApiManagementMenu();
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Perform manual upgrade for all APIs with interactive confirmation
|
|
844
|
+
*/
|
|
845
|
+
async function performManualUpgrade() {
|
|
846
|
+
const { getLatestModel, getProvider } = require('./lib/presets/providers');
|
|
847
|
+
const { simpleInput } = require('./lib/ui/prompts');
|
|
848
|
+
|
|
849
|
+
console.clear();
|
|
850
|
+
console.log('');
|
|
851
|
+
console.log(colors.bright + colors.orange + '🔄 ' + await i18n.t('model_upgrade.manual_title') + colors.reset);
|
|
852
|
+
console.log('');
|
|
853
|
+
|
|
854
|
+
const apis = apiManager.getApis();
|
|
855
|
+
|
|
856
|
+
if (apis.length === 0) {
|
|
857
|
+
console.log(colors.yellow + ' ' + await i18n.t('messages.info.no_apis') + colors.reset);
|
|
858
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.manual_checking', apis.length) + colors.reset);
|
|
863
|
+
console.log('');
|
|
864
|
+
|
|
865
|
+
let upgradedCount = 0;
|
|
866
|
+
let skippedUpToDate = 0;
|
|
867
|
+
let skippedNoInfo = 0;
|
|
868
|
+
let skippedByUser = 0;
|
|
869
|
+
|
|
870
|
+
for (let i = 0; i < apis.length; i++) {
|
|
871
|
+
const api = apis[i];
|
|
872
|
+
const latestModel = getLatestModel(api.model, api.provider);
|
|
873
|
+
|
|
874
|
+
console.log(colors.cyan + ' ─────────────────────────────────────────────────' + colors.reset);
|
|
875
|
+
console.log(colors.bright + ` ${i + 1}/${apis.length} ${api.name}` + colors.reset);
|
|
876
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.manual_api_current', api.model) + colors.reset);
|
|
877
|
+
|
|
878
|
+
if (latestModel) {
|
|
879
|
+
console.log(colors.green + ' ' + await i18n.t('model_upgrade.manual_api_latest', latestModel) + colors.reset);
|
|
880
|
+
console.log('');
|
|
881
|
+
|
|
882
|
+
// Ask for confirmation
|
|
883
|
+
const answer = await simpleInput(colors.yellow + ' ' + await i18n.t('model_upgrade.manual_confirm') + ' ' + colors.reset);
|
|
884
|
+
|
|
885
|
+
if (answer.toLowerCase() === 'y') {
|
|
886
|
+
apiManager.updateApiModel(api.id, latestModel);
|
|
887
|
+
console.log(colors.green + ' ✓ ' + await i18n.t('model_upgrade.manual_upgraded', api.model, latestModel) + colors.reset);
|
|
888
|
+
upgradedCount++;
|
|
889
|
+
} else {
|
|
890
|
+
console.log(colors.dim + ' ' + await i18n.t('model_upgrade.manual_skipped') + colors.reset);
|
|
891
|
+
skippedByUser++;
|
|
892
|
+
}
|
|
893
|
+
} else {
|
|
894
|
+
// No upgrade info available - check if model exists in provider
|
|
895
|
+
const provider = getProvider(api.provider);
|
|
896
|
+
if (provider && provider.models && provider.models.includes(api.model)) {
|
|
897
|
+
// Model exists in provider, likely already latest or no alias defined
|
|
898
|
+
console.log(colors.dim + ' ' + await i18n.t('model_upgrade.manual_api_uptodate') + colors.reset);
|
|
899
|
+
skippedUpToDate++;
|
|
900
|
+
} else {
|
|
901
|
+
console.log(colors.dim + ' ' + await i18n.t('model_upgrade.manual_api_no_info') + colors.reset);
|
|
902
|
+
skippedNoInfo++;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
console.log('');
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
console.log(colors.cyan + ' ─────────────────────────────────────────────────' + colors.reset);
|
|
910
|
+
console.log('');
|
|
911
|
+
console.log(colors.green + ' ' + await i18n.t('model_upgrade.manual_complete') + colors.reset);
|
|
912
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.manual_stats_upgraded', upgradedCount) + colors.reset);
|
|
913
|
+
console.log(colors.gray + ' ' + await i18n.t('model_upgrade.manual_stats_skipped',
|
|
914
|
+
skippedUpToDate + skippedNoInfo + skippedByUser,
|
|
915
|
+
skippedUpToDate,
|
|
916
|
+
skippedNoInfo) + colors.reset);
|
|
917
|
+
console.log('');
|
|
918
|
+
|
|
919
|
+
await waitForKey(await i18n.t('messages.prompts.press_any_key'));
|
|
920
|
+
}
|
|
921
|
+
|
|
631
922
|
/**
|
|
632
923
|
* Handle third-party API launch
|
|
633
924
|
*/
|
|
@@ -646,12 +937,15 @@ async function handleThirdPartyApiLaunch(skipPermissions = false) {
|
|
|
646
937
|
return showMenu();
|
|
647
938
|
}
|
|
648
939
|
|
|
649
|
-
//
|
|
650
|
-
apiManager.
|
|
940
|
+
// Record successful launch BEFORE launching (since process exits after)
|
|
941
|
+
apiManager.recordSuccessfulLaunch();
|
|
651
942
|
|
|
652
943
|
launchClaudeWithApi(activeApi, skipPermissions);
|
|
653
944
|
|
|
654
945
|
} catch (error) {
|
|
946
|
+
// Record failed launch
|
|
947
|
+
apiManager.recordFailedLaunch(error.message);
|
|
948
|
+
|
|
655
949
|
showError('Failed to launch with third-party API', [error.message]);
|
|
656
950
|
|
|
657
951
|
setTimeout(() => {
|
|
@@ -741,6 +1035,60 @@ async function showMenu() {
|
|
|
741
1035
|
// Silently ignore update check errors
|
|
742
1036
|
}
|
|
743
1037
|
|
|
1038
|
+
// ========================================
|
|
1039
|
+
// Model upgrade check (new feature)
|
|
1040
|
+
// ========================================
|
|
1041
|
+
let modelUpgradeInfo = null;
|
|
1042
|
+
try {
|
|
1043
|
+
const upgradeChecker = require('./lib/utils/model-upgrade-checker');
|
|
1044
|
+
const autoUpgrade = await upgradeChecker.isAutoUpgradeEnabled();
|
|
1045
|
+
|
|
1046
|
+
if (autoUpgrade) {
|
|
1047
|
+
// Auto upgrade enabled: always check and upgrade (bypass cache)
|
|
1048
|
+
const upgrades = upgradeChecker.checkAllApiUpgrades(apiManager);
|
|
1049
|
+
if (upgrades.length > 0) {
|
|
1050
|
+
const upgraded = upgradeChecker.performAutoUpgrade(apiManager, upgrades);
|
|
1051
|
+
if (upgraded.length > 0) {
|
|
1052
|
+
modelUpgradeInfo = colors.green + ' ✓ ' +
|
|
1053
|
+
i18n.tSync('model_upgrade.auto_upgraded', upgraded[0].from, upgraded[0].to) + colors.reset;
|
|
1054
|
+
if (upgraded.length > 1) {
|
|
1055
|
+
modelUpgradeInfo += '\n' + colors.green + ' ' +
|
|
1056
|
+
`(+${upgraded.length - 1} more)` + colors.reset;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
} else {
|
|
1061
|
+
// Auto upgrade disabled: use cache for notification
|
|
1062
|
+
const result = await upgradeChecker.checkForModelUpgrades(apiManager);
|
|
1063
|
+
if (result.needsCheck && result.upgrades.length > 0) {
|
|
1064
|
+
const first = result.upgrades[0];
|
|
1065
|
+
modelUpgradeInfo = colors.yellow + ' ⚠️ ' +
|
|
1066
|
+
i18n.tSync('model_upgrade.notification', first.currentModel, first.latestModel) +
|
|
1067
|
+
colors.reset + '\n' +
|
|
1068
|
+
colors.yellow + ' ' +
|
|
1069
|
+
i18n.tSync('model_upgrade.notification_api', first.apiName) +
|
|
1070
|
+
colors.reset + '\n' +
|
|
1071
|
+
colors.gray + ' ' +
|
|
1072
|
+
i18n.tSync('model_upgrade.notification_hint') +
|
|
1073
|
+
colors.reset;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
} catch (error) {
|
|
1077
|
+
// Silently ignore model upgrade check errors
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// Combine version info and model upgrade info
|
|
1081
|
+
let displayInfo = '';
|
|
1082
|
+
if (versionInfo) {
|
|
1083
|
+
displayInfo += versionInfo;
|
|
1084
|
+
}
|
|
1085
|
+
if (modelUpgradeInfo) {
|
|
1086
|
+
if (displayInfo) {
|
|
1087
|
+
displayInfo += '\n';
|
|
1088
|
+
}
|
|
1089
|
+
displayInfo += modelUpgradeInfo;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
744
1092
|
// Populate menu options dynamically with i18n translations
|
|
745
1093
|
menuOptions = [
|
|
746
1094
|
await i18n.t('menu.main.launch_default'),
|
|
@@ -754,7 +1102,7 @@ async function showMenu() {
|
|
|
754
1102
|
];
|
|
755
1103
|
|
|
756
1104
|
globalMainMenu.setOptions(menuOptions);
|
|
757
|
-
const selection = await globalMainMenu.navigate(false,
|
|
1105
|
+
const selection = await globalMainMenu.navigate(false, displayInfo || null); // Pass combined info to display between banner and nav
|
|
758
1106
|
|
|
759
1107
|
if (selection === -1) {
|
|
760
1108
|
console.log('');
|