@kikkimo/claude-launcher 2.5.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +17 -10
- package/claude-launcher +614 -398
- package/docs/README-zh.md +17 -10
- package/lib/api-manager.js +136 -11
- package/lib/auth/password-input.js +8 -4
- package/lib/auth/password-validator.js +83 -48
- package/lib/i18n/index.js +4 -3
- package/lib/i18n/language-manager.js +4 -3
- package/lib/i18n/locales/de.js +89 -11
- package/lib/i18n/locales/en.js +89 -11
- package/lib/i18n/locales/es.js +89 -11
- package/lib/i18n/locales/fr.js +89 -11
- package/lib/i18n/locales/it.js +89 -11
- package/lib/i18n/locales/ja.js +89 -11
- package/lib/i18n/locales/ko.js +89 -11
- package/lib/i18n/locales/pt.js +89 -11
- package/lib/i18n/locales/ru.js +89 -11
- package/lib/i18n/locales/zh-TW.js +89 -11
- package/lib/i18n/locales/zh.js +89 -11
- package/lib/launcher.js +121 -93
- package/lib/ui/api-editor.js +210 -0
- package/lib/ui/interactive-table.js +216 -99
- package/lib/ui/menu.js +73 -62
- package/lib/ui/prompts.js +168 -139
- package/lib/ui/screen.js +125 -0
- package/lib/utils/stdin-manager.js +11 -9
- package/lib/utils/version-checker.js +63 -3
- package/package.json +2 -2
- package/docs/superpowers/plans/2026-03-31-update-models-and-auto-mode.md +0 -1414
- package/docs/superpowers/specs/2026-03-31-update-models-and-auto-mode-design.md +0 -187
package/lib/ui/menu.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
const readline = require('readline');
|
|
6
6
|
const colors = require('./colors');
|
|
7
7
|
const i18n = require('../i18n');
|
|
8
|
-
const { padStringToWidth } = require('../utils/string-width');
|
|
8
|
+
const { padStringToWidth, getStringWidth } = require('../utils/string-width');
|
|
9
9
|
const stdinManager = require('../utils/stdin-manager');
|
|
10
|
+
const screen = require('./screen');
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Force cleanup stdin state before displaying any menu
|
|
@@ -27,7 +28,7 @@ function forceCleanupBeforeMenu() {
|
|
|
27
28
|
} catch (error) {
|
|
28
29
|
// Ignore cleanup errors but log for debugging
|
|
29
30
|
if (process.env.DEBUG_STDIN) {
|
|
30
|
-
|
|
31
|
+
screen.debug('[DEBUG] forceCleanupBeforeMenu error: ' + error.message);
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
}
|
|
@@ -45,64 +46,73 @@ class Menu {
|
|
|
45
46
|
// Force cleanup stdin state before any menu display
|
|
46
47
|
forceCleanupBeforeMenu();
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
const lines = [];
|
|
50
|
+
lines.push('');
|
|
51
|
+
lines.push(colors.orange + ' ┌──────────────────────────────────────────────────────┐' + colors.reset);
|
|
52
|
+
lines.push(colors.orange + ' │' + colors.white + colors.bright + ' Claude Code Launcher ' + colors.orange + '│' + colors.reset);
|
|
53
|
+
lines.push(colors.orange + ' └──────────────────────────────────────────────────────┘' + colors.reset);
|
|
54
|
+
lines.push('');
|
|
55
|
+
lines.push(colors.gray + ' ' + i18n.tSync('navigation.use_arrows') + colors.reset);
|
|
56
|
+
lines.push('');
|
|
57
|
+
screen.render(lines);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
61
|
* Display menu with current selection
|
|
61
|
-
* @param {boolean} clearScreen - Whether to clear screen before displaying (default: true)
|
|
62
62
|
* @param {string} versionInfo - Optional version info to display between banner and navigation
|
|
63
63
|
* @param {Function|null} hintCallback - Optional sync callback(selectedIndex) returning hint string or null
|
|
64
64
|
*/
|
|
65
|
-
displayMenu(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
console.log(colors.orange + ' │' + colors.white + colors.bright + ' Claude Code Launcher ' + colors.orange + '│' + colors.reset);
|
|
73
|
-
console.log(colors.orange + ' └──────────────────────────────────────────────────────┘' + colors.reset);
|
|
74
|
-
console.log('');
|
|
65
|
+
displayMenu(versionInfo = null, hintCallback = null) {
|
|
66
|
+
const lines = [];
|
|
67
|
+
lines.push('');
|
|
68
|
+
lines.push(colors.orange + ' ┌──────────────────────────────────────────────────────┐' + colors.reset);
|
|
69
|
+
lines.push(colors.orange + ' │' + colors.white + colors.bright + ' Claude Code Launcher ' + colors.orange + '│' + colors.reset);
|
|
70
|
+
lines.push(colors.orange + ' └──────────────────────────────────────────────────────┘' + colors.reset);
|
|
71
|
+
lines.push('');
|
|
75
72
|
|
|
76
|
-
// Display version info if provided (between banner and navigation tips, like Claude Code)
|
|
77
73
|
if (versionInfo) {
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
lines.push(versionInfo);
|
|
75
|
+
lines.push('');
|
|
80
76
|
}
|
|
81
77
|
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
lines.push(colors.gray + ' ' + i18n.tSync('navigation.use_arrows') + colors.reset);
|
|
79
|
+
lines.push('');
|
|
84
80
|
|
|
85
|
-
// Display menu options
|
|
86
81
|
this.menuOptions.forEach((option, index) => {
|
|
87
82
|
if (index === this.selectedIndex) {
|
|
88
|
-
|
|
89
|
-
const paddedOption = padStringToWidth(option, Math.max(40,
|
|
90
|
-
|
|
83
|
+
const displayWidth = getStringWidth(option);
|
|
84
|
+
const paddedOption = padStringToWidth(option, Math.max(40, displayWidth + 2));
|
|
85
|
+
lines.push(colors.orange + ' → ' + colors.black + colors.bgAmber + paddedOption + colors.reset);
|
|
91
86
|
} else {
|
|
92
|
-
|
|
87
|
+
lines.push(colors.gray + ' ' + option + colors.reset);
|
|
93
88
|
}
|
|
94
89
|
});
|
|
95
90
|
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
91
|
+
// Fixed 4-line hint area for stable menu height
|
|
92
|
+
const hintText = hintCallback ? hintCallback(this.selectedIndex) : null;
|
|
93
|
+
if (hintText) {
|
|
94
|
+
const hintLines = hintText.split('\n').slice(0, 4);
|
|
95
|
+
while (hintLines.length < 4) hintLines.push('');
|
|
96
|
+
lines.push('');
|
|
97
|
+
hintLines.forEach((line, i) => {
|
|
98
|
+
if (line === '') {
|
|
99
|
+
lines.push('');
|
|
100
|
+
} else if (i === 0) {
|
|
101
|
+
lines.push(colors.green + ' \u2139 ' + line + colors.reset);
|
|
102
|
+
} else {
|
|
103
|
+
lines.push(colors.gray + ' ' + line + colors.reset);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
} else {
|
|
107
|
+
lines.push('');
|
|
108
|
+
lines.push('');
|
|
109
|
+
lines.push('');
|
|
110
|
+
lines.push('');
|
|
111
|
+
lines.push('');
|
|
103
112
|
}
|
|
104
113
|
|
|
105
|
-
|
|
114
|
+
lines.push('');
|
|
115
|
+
screen.render(lines);
|
|
106
116
|
}
|
|
107
117
|
|
|
108
118
|
/**
|
|
@@ -115,14 +125,13 @@ class Menu {
|
|
|
115
125
|
|
|
116
126
|
/**
|
|
117
127
|
* Handle keyboard navigation
|
|
118
|
-
* @param {boolean} clearScreen - Whether to clear screen on initial display (default: true)
|
|
119
128
|
* @param {string} versionInfo - Optional version info to display
|
|
120
129
|
* @param {Function|null} hintCallback - Optional sync callback(selectedIndex) returning hint string or null
|
|
121
130
|
*/
|
|
122
|
-
async navigate(
|
|
131
|
+
async navigate(versionInfo = null, hintCallback = null) {
|
|
123
132
|
// Guard against empty menu to prevent NaN from modulo operations
|
|
124
133
|
if (!this.menuOptions || this.menuOptions.length === 0) {
|
|
125
|
-
|
|
134
|
+
screen.write(colors.yellow + ' Warning: No menu options available' + colors.reset + '\n');
|
|
126
135
|
return -1; // Return cancel/exit code
|
|
127
136
|
}
|
|
128
137
|
|
|
@@ -130,7 +139,7 @@ class Menu {
|
|
|
130
139
|
this.hintCallback = hintCallback; // Store for redrawing
|
|
131
140
|
|
|
132
141
|
return new Promise((resolve, reject) => {
|
|
133
|
-
this.displayMenu(
|
|
142
|
+
this.displayMenu(versionInfo, hintCallback);
|
|
134
143
|
|
|
135
144
|
if (process.stdin.isTTY) {
|
|
136
145
|
const scope = stdinManager.acquire('raw', {
|
|
@@ -183,15 +192,16 @@ class Menu {
|
|
|
183
192
|
switch (key) {
|
|
184
193
|
case '\u001b[A': // Up arrow
|
|
185
194
|
this.selectedIndex = (this.selectedIndex - 1 + this.menuOptions.length) % this.menuOptions.length;
|
|
186
|
-
this.displayMenu(
|
|
195
|
+
this.displayMenu(this.versionInfo, this.hintCallback);
|
|
187
196
|
break;
|
|
188
197
|
|
|
189
198
|
case '\u001b[B': // Down arrow
|
|
190
199
|
this.selectedIndex = (this.selectedIndex + 1) % this.menuOptions.length;
|
|
191
|
-
this.displayMenu(
|
|
200
|
+
this.displayMenu(this.versionInfo, this.hintCallback);
|
|
192
201
|
break;
|
|
193
202
|
|
|
194
203
|
case '\r': // Enter
|
|
204
|
+
case ' ': // Space
|
|
195
205
|
safeResolve(this.selectedIndex);
|
|
196
206
|
break;
|
|
197
207
|
|
|
@@ -219,7 +229,7 @@ class Menu {
|
|
|
219
229
|
|
|
220
230
|
const rl = lineScope.createReadline();
|
|
221
231
|
|
|
222
|
-
|
|
232
|
+
screen.write(colors.yellow + ' ' + i18n.tSync('navigation.arrow_keys_not_available', this.menuOptions.length) + colors.reset + '\n');
|
|
223
233
|
|
|
224
234
|
rl.on('line', (input) => {
|
|
225
235
|
const choice = parseInt(input.trim());
|
|
@@ -232,7 +242,7 @@ class Menu {
|
|
|
232
242
|
lineScope.release();
|
|
233
243
|
resolve(-1);
|
|
234
244
|
} else {
|
|
235
|
-
|
|
245
|
+
screen.write(colors.red + ' Invalid selection. Please enter 1-' + this.menuOptions.length + '.' + colors.reset + '\n');
|
|
236
246
|
}
|
|
237
247
|
});
|
|
238
248
|
}
|
|
@@ -242,7 +252,7 @@ class Menu {
|
|
|
242
252
|
async selectFromList(title, items, activeIndex = -1) {
|
|
243
253
|
// Guard against empty items list to prevent NaN from modulo operations
|
|
244
254
|
if (!items || items.length === 0) {
|
|
245
|
-
|
|
255
|
+
screen.write(colors.yellow + ' Warning: No items available to select' + colors.reset + '\n');
|
|
246
256
|
return null; // Return null to indicate no selection
|
|
247
257
|
}
|
|
248
258
|
|
|
@@ -251,12 +261,12 @@ class Menu {
|
|
|
251
261
|
let selectedIndex = activeIndex >= 0 ? activeIndex : 0;
|
|
252
262
|
|
|
253
263
|
const displayList = () => {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
264
|
+
const lines = [];
|
|
265
|
+
lines.push('');
|
|
266
|
+
lines.push(colors.bright + colors.orange + `[*] ${title}` + colors.reset);
|
|
267
|
+
lines.push('');
|
|
268
|
+
lines.push(colors.gray + ' Use ↑↓ arrow keys to navigate, Enter to select, Esc to cancel' + colors.reset);
|
|
269
|
+
lines.push('');
|
|
260
270
|
|
|
261
271
|
items.forEach((item, index) => {
|
|
262
272
|
const isActive = index === activeIndex;
|
|
@@ -265,19 +275,20 @@ class Menu {
|
|
|
265
275
|
|
|
266
276
|
if (index === selectedIndex) {
|
|
267
277
|
const itemText = `${item.name}${activeIndicator}`;
|
|
268
|
-
const paddedItem = padStringToWidth(itemText, Math.max(40, itemText
|
|
269
|
-
|
|
278
|
+
const paddedItem = padStringToWidth(itemText, Math.max(40, getStringWidth(itemText) + 2));
|
|
279
|
+
lines.push(colors.orange + prefix + colors.black + colors.bgAmber + paddedItem + colors.reset);
|
|
270
280
|
if (item.details) {
|
|
271
281
|
item.details.forEach(detail => {
|
|
272
|
-
|
|
282
|
+
lines.push(colors.gray + ' ' + detail + colors.reset);
|
|
273
283
|
});
|
|
274
284
|
}
|
|
275
285
|
} else {
|
|
276
|
-
|
|
286
|
+
lines.push(colors.gray + prefix + `${item.name}${activeIndicator}` + colors.reset);
|
|
277
287
|
}
|
|
278
288
|
});
|
|
279
289
|
|
|
280
|
-
|
|
290
|
+
lines.push('');
|
|
291
|
+
screen.render(lines);
|
|
281
292
|
};
|
|
282
293
|
|
|
283
294
|
return new Promise((resolve, reject) => {
|
|
@@ -370,7 +381,7 @@ class Menu {
|
|
|
370
381
|
|
|
371
382
|
const rl = lineScope.createReadline();
|
|
372
383
|
|
|
373
|
-
|
|
384
|
+
screen.write(colors.yellow + ' Arrow keys not available. Enter item number (1-' + items.length + ') or q to cancel:' + colors.reset + '\n');
|
|
374
385
|
|
|
375
386
|
rl.on('line', (input) => {
|
|
376
387
|
const choice = parseInt(input.trim());
|
|
@@ -383,7 +394,7 @@ class Menu {
|
|
|
383
394
|
lineScope.release();
|
|
384
395
|
resolve(null);
|
|
385
396
|
} else {
|
|
386
|
-
|
|
397
|
+
screen.write(colors.red + ' Invalid selection. Please enter 1-' + items.length + '.' + colors.reset + '\n');
|
|
387
398
|
}
|
|
388
399
|
});
|
|
389
400
|
}
|