@kikkimo/claude-launcher 2.5.0 → 3.1.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 +23 -13
- package/claude-launcher +1244 -432
- package/docs/README-zh.md +23 -13
- package/lib/api-manager.js +629 -70
- 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 +229 -13
- package/lib/i18n/locales/en.js +235 -13
- package/lib/i18n/locales/es.js +229 -13
- package/lib/i18n/locales/fr.js +229 -13
- package/lib/i18n/locales/it.js +229 -13
- package/lib/i18n/locales/ja.js +229 -13
- package/lib/i18n/locales/ko.js +229 -13
- package/lib/i18n/locales/pt.js +229 -13
- package/lib/i18n/locales/ru.js +229 -13
- package/lib/i18n/locales/zh-TW.js +229 -13
- package/lib/i18n/locales/zh.js +235 -13
- package/lib/launcher.js +167 -110
- package/lib/presets/providers.js +143 -39
- package/lib/ui/api-editor.js +668 -0
- package/lib/ui/i18n-labels.js +16 -0
- package/lib/ui/interactive-table.js +216 -99
- package/lib/ui/menu.js +79 -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 +65 -4
- package/lib/validators.js +102 -1
- 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,78 @@ 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
|
+
* @param {string} navigationKey - i18n key for navigation hint (default: 'navigation.use_arrows')
|
|
64
65
|
*/
|
|
65
|
-
displayMenu(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
console.log('');
|
|
66
|
+
displayMenu(versionInfo = null, hintCallback = null, navigationKey = 'navigation.use_arrows') {
|
|
67
|
+
this._navigationKey = navigationKey;
|
|
68
|
+
const isTTY = process.stdin.isTTY;
|
|
69
|
+
const lines = [];
|
|
70
|
+
lines.push('');
|
|
71
|
+
lines.push(colors.orange + ' ┌──────────────────────────────────────────────────────┐' + colors.reset);
|
|
72
|
+
lines.push(colors.orange + ' │' + colors.white + colors.bright + ' Claude Code Launcher ' + colors.orange + '│' + colors.reset);
|
|
73
|
+
lines.push(colors.orange + ' └──────────────────────────────────────────────────────┘' + colors.reset);
|
|
74
|
+
lines.push('');
|
|
75
75
|
|
|
76
|
-
// Display version info if provided (between banner and navigation tips, like Claude Code)
|
|
77
76
|
if (versionInfo) {
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
lines.push(versionInfo);
|
|
78
|
+
lines.push('');
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
lines.push(colors.gray + ' ' + i18n.tSync(navigationKey) + colors.reset);
|
|
82
|
+
lines.push('');
|
|
84
83
|
|
|
85
|
-
// Display menu options
|
|
86
84
|
this.menuOptions.forEach((option, index) => {
|
|
85
|
+
const prefix = isTTY ? '' : (index + 1) + '. ';
|
|
87
86
|
if (index === this.selectedIndex) {
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
87
|
+
const prefixedOption = prefix + option;
|
|
88
|
+
const displayWidth = getStringWidth(prefixedOption);
|
|
89
|
+
const paddedOption = padStringToWidth(prefixedOption, Math.max(40, displayWidth + 2));
|
|
90
|
+
lines.push(colors.orange + ' → ' + colors.black + colors.bgAmber + paddedOption + colors.reset);
|
|
91
91
|
} else {
|
|
92
|
-
|
|
92
|
+
lines.push(colors.gray + ' ' + prefix + option + colors.reset);
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
// Fixed 4-line hint area for stable menu height
|
|
97
|
+
const hintText = hintCallback ? hintCallback(this.selectedIndex) : null;
|
|
98
|
+
if (hintText) {
|
|
99
|
+
const hintLines = hintText.split('\n').slice(0, 4);
|
|
100
|
+
while (hintLines.length < 4) hintLines.push('');
|
|
101
|
+
lines.push('');
|
|
102
|
+
hintLines.forEach((line, i) => {
|
|
103
|
+
if (line === '') {
|
|
104
|
+
lines.push('');
|
|
105
|
+
} else if (i === 0) {
|
|
106
|
+
lines.push(colors.green + ' \u2139 ' + line + colors.reset);
|
|
107
|
+
} else {
|
|
108
|
+
lines.push(colors.gray + ' ' + line + colors.reset);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
lines.push('');
|
|
113
|
+
lines.push('');
|
|
114
|
+
lines.push('');
|
|
115
|
+
lines.push('');
|
|
116
|
+
lines.push('');
|
|
103
117
|
}
|
|
104
118
|
|
|
105
|
-
|
|
119
|
+
lines.push('');
|
|
120
|
+
screen.render(lines);
|
|
106
121
|
}
|
|
107
122
|
|
|
108
123
|
/**
|
|
@@ -115,14 +130,14 @@ class Menu {
|
|
|
115
130
|
|
|
116
131
|
/**
|
|
117
132
|
* Handle keyboard navigation
|
|
118
|
-
* @param {boolean} clearScreen - Whether to clear screen on initial display (default: true)
|
|
119
133
|
* @param {string} versionInfo - Optional version info to display
|
|
120
134
|
* @param {Function|null} hintCallback - Optional sync callback(selectedIndex) returning hint string or null
|
|
135
|
+
* @param {string} navigationKey - i18n key for navigation hint (default: 'navigation.use_arrows')
|
|
121
136
|
*/
|
|
122
|
-
async navigate(
|
|
137
|
+
async navigate(versionInfo = null, hintCallback = null, navigationKey = 'navigation.use_arrows') {
|
|
123
138
|
// Guard against empty menu to prevent NaN from modulo operations
|
|
124
139
|
if (!this.menuOptions || this.menuOptions.length === 0) {
|
|
125
|
-
|
|
140
|
+
screen.write(colors.yellow + ' Warning: No menu options available' + colors.reset + '\n');
|
|
126
141
|
return -1; // Return cancel/exit code
|
|
127
142
|
}
|
|
128
143
|
|
|
@@ -130,7 +145,7 @@ class Menu {
|
|
|
130
145
|
this.hintCallback = hintCallback; // Store for redrawing
|
|
131
146
|
|
|
132
147
|
return new Promise((resolve, reject) => {
|
|
133
|
-
this.displayMenu(
|
|
148
|
+
this.displayMenu(versionInfo, hintCallback, navigationKey);
|
|
134
149
|
|
|
135
150
|
if (process.stdin.isTTY) {
|
|
136
151
|
const scope = stdinManager.acquire('raw', {
|
|
@@ -183,15 +198,16 @@ class Menu {
|
|
|
183
198
|
switch (key) {
|
|
184
199
|
case '\u001b[A': // Up arrow
|
|
185
200
|
this.selectedIndex = (this.selectedIndex - 1 + this.menuOptions.length) % this.menuOptions.length;
|
|
186
|
-
this.displayMenu(
|
|
201
|
+
this.displayMenu(this.versionInfo, this.hintCallback, this._navigationKey);
|
|
187
202
|
break;
|
|
188
203
|
|
|
189
204
|
case '\u001b[B': // Down arrow
|
|
190
205
|
this.selectedIndex = (this.selectedIndex + 1) % this.menuOptions.length;
|
|
191
|
-
this.displayMenu(
|
|
206
|
+
this.displayMenu(this.versionInfo, this.hintCallback, this._navigationKey);
|
|
192
207
|
break;
|
|
193
208
|
|
|
194
209
|
case '\r': // Enter
|
|
210
|
+
case ' ': // Space
|
|
195
211
|
safeResolve(this.selectedIndex);
|
|
196
212
|
break;
|
|
197
213
|
|
|
@@ -219,7 +235,7 @@ class Menu {
|
|
|
219
235
|
|
|
220
236
|
const rl = lineScope.createReadline();
|
|
221
237
|
|
|
222
|
-
|
|
238
|
+
screen.write(colors.yellow + ' ' + i18n.tSync('navigation.arrow_keys_not_available', this.menuOptions.length) + colors.reset + '\n');
|
|
223
239
|
|
|
224
240
|
rl.on('line', (input) => {
|
|
225
241
|
const choice = parseInt(input.trim());
|
|
@@ -232,7 +248,7 @@ class Menu {
|
|
|
232
248
|
lineScope.release();
|
|
233
249
|
resolve(-1);
|
|
234
250
|
} else {
|
|
235
|
-
|
|
251
|
+
screen.write(colors.red + ' ' + i18n.tSync('navigation.invalid_selection', this.menuOptions.length) + colors.reset + '\n');
|
|
236
252
|
}
|
|
237
253
|
});
|
|
238
254
|
}
|
|
@@ -242,7 +258,7 @@ class Menu {
|
|
|
242
258
|
async selectFromList(title, items, activeIndex = -1) {
|
|
243
259
|
// Guard against empty items list to prevent NaN from modulo operations
|
|
244
260
|
if (!items || items.length === 0) {
|
|
245
|
-
|
|
261
|
+
screen.write(colors.yellow + ' Warning: No items available to select' + colors.reset + '\n');
|
|
246
262
|
return null; // Return null to indicate no selection
|
|
247
263
|
}
|
|
248
264
|
|
|
@@ -251,12 +267,12 @@ class Menu {
|
|
|
251
267
|
let selectedIndex = activeIndex >= 0 ? activeIndex : 0;
|
|
252
268
|
|
|
253
269
|
const displayList = () => {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
270
|
+
const lines = [];
|
|
271
|
+
lines.push('');
|
|
272
|
+
lines.push(colors.bright + colors.orange + `[*] ${title}` + colors.reset);
|
|
273
|
+
lines.push('');
|
|
274
|
+
lines.push(colors.gray + ' ' + i18n.tSync('navigation.use_arrows_esc', i18n.tSync('navigation.action.select')) + colors.reset);
|
|
275
|
+
lines.push('');
|
|
260
276
|
|
|
261
277
|
items.forEach((item, index) => {
|
|
262
278
|
const isActive = index === activeIndex;
|
|
@@ -265,19 +281,20 @@ class Menu {
|
|
|
265
281
|
|
|
266
282
|
if (index === selectedIndex) {
|
|
267
283
|
const itemText = `${item.name}${activeIndicator}`;
|
|
268
|
-
const paddedItem = padStringToWidth(itemText, Math.max(40, itemText
|
|
269
|
-
|
|
284
|
+
const paddedItem = padStringToWidth(itemText, Math.max(40, getStringWidth(itemText) + 2));
|
|
285
|
+
lines.push(colors.orange + prefix + colors.black + colors.bgAmber + paddedItem + colors.reset);
|
|
270
286
|
if (item.details) {
|
|
271
287
|
item.details.forEach(detail => {
|
|
272
|
-
|
|
288
|
+
lines.push(colors.gray + ' ' + detail + colors.reset);
|
|
273
289
|
});
|
|
274
290
|
}
|
|
275
291
|
} else {
|
|
276
|
-
|
|
292
|
+
lines.push(colors.gray + prefix + `${item.name}${activeIndicator}` + colors.reset);
|
|
277
293
|
}
|
|
278
294
|
});
|
|
279
295
|
|
|
280
|
-
|
|
296
|
+
lines.push('');
|
|
297
|
+
screen.render(lines);
|
|
281
298
|
};
|
|
282
299
|
|
|
283
300
|
return new Promise((resolve, reject) => {
|
|
@@ -370,7 +387,7 @@ class Menu {
|
|
|
370
387
|
|
|
371
388
|
const rl = lineScope.createReadline();
|
|
372
389
|
|
|
373
|
-
|
|
390
|
+
screen.write(colors.yellow + ' ' + i18n.tSync('navigation.arrow_keys_not_available', items.length) + colors.reset + '\n');
|
|
374
391
|
|
|
375
392
|
rl.on('line', (input) => {
|
|
376
393
|
const choice = parseInt(input.trim());
|
|
@@ -383,7 +400,7 @@ class Menu {
|
|
|
383
400
|
lineScope.release();
|
|
384
401
|
resolve(null);
|
|
385
402
|
} else {
|
|
386
|
-
|
|
403
|
+
screen.write(colors.red + ' ' + i18n.tSync('navigation.invalid_selection', items.length) + colors.reset + '\n');
|
|
387
404
|
}
|
|
388
405
|
});
|
|
389
406
|
}
|