diff --git a/bin/install.js b/bin/install.js index 015a263d..ec1cf32c 100755 --- a/bin/install.js +++ b/bin/install.js @@ -76,7 +76,7 @@ const hasUninstall = args.includes('--uninstall') || args.includes('-u'); // Runtime selection - can be set by flags or interactive prompt let selectedRuntimes = []; if (hasAll) { - selectedRuntimes = ['claude', 'opencode', 'gemini', 'kilo', 'codex', 'copilot', 'antigravity', 'cursor', 'windsurf']; + selectedRuntimes = ['claude', 'kilo', 'opencode', 'gemini', 'codex', 'copilot', 'antigravity', 'cursor', 'windsurf']; } else if (hasBoth) { selectedRuntimes = ['claude', 'opencode']; } else { @@ -5117,21 +5117,21 @@ function promptRuntime(callback) { const runtimeMap = { '1': 'claude', - '2': 'opencode', - '3': 'gemini', - '4': 'kilo', + '2': 'kilo', + '3': 'opencode', + '4': 'gemini', '5': 'codex', '6': 'copilot', '7': 'antigravity', '8': 'cursor', '9': 'windsurf' }; - const allRuntimes = ['claude', 'opencode', 'gemini', 'kilo', 'codex', 'copilot', 'antigravity', 'cursor', 'windsurf']; + const allRuntimes = ['claude', 'kilo', 'opencode', 'gemini', 'codex', 'copilot', 'antigravity', 'cursor', 'windsurf']; console.log(` ${yellow}Which runtime(s) would you like to install for?${reset}\n\n ${cyan}1${reset}) Claude Code ${dim}(~/.claude)${reset} - ${cyan}2${reset}) OpenCode ${dim}(~/.config/opencode)${reset} - open source, free models - ${cyan}3${reset}) Gemini ${dim}(~/.gemini)${reset} - ${cyan}4${reset}) Kilo ${dim}(~/.config/kilo)${reset} - OpenCode fork + ${cyan}2${reset}) Kilo ${dim}(~/.config/kilo)${reset} - open source, the #1 AI coding platform on OpenRouter + ${cyan}3${reset}) OpenCode ${dim}(~/.config/opencode)${reset} - open source, free models + ${cyan}4${reset}) Gemini ${dim}(~/.gemini)${reset} ${cyan}5${reset}) Codex ${dim}(~/.codex)${reset} ${cyan}6${reset}) Copilot ${dim}(~/.copilot)${reset} ${cyan}7${reset}) Antigravity ${dim}(~/.gemini/antigravity)${reset} @@ -5139,7 +5139,7 @@ function promptRuntime(callback) { ${cyan}9${reset}) Windsurf ${dim}(~/.windsurf)${reset} ${cyan}10${reset}) All - ${dim}Select multiple: 1,4,6 or 1 4 6${reset} + ${dim}Select multiple: 1,2,6 or 1 2 6${reset} `); rl.question(` Choice ${dim}[1]${reset}: `, (answer) => { diff --git a/tests/copilot-install.test.cjs b/tests/copilot-install.test.cjs index 1e9439e7..cd57766f 100644 --- a/tests/copilot-install.test.cjs +++ b/tests/copilot-install.test.cjs @@ -148,6 +148,12 @@ describe('Source code integration (Copilot)', () => { assert.ok(allMatch && allMatch[1].includes('copilot'), 'allRuntimes includes copilot'); }); + test('CLI-02: promptRuntime keeps Kilo above OpenCode in allRuntimes', () => { + const allMatch = src.match(/const allRuntimes = \[([^\]]+)\]/); + assert.ok(allMatch, 'allRuntimes array found'); + assert.ok(allMatch[1].indexOf("'kilo'") < allMatch[1].indexOf("'opencode'"), 'kilo appears before opencode'); + }); + test('isCopilot variable exists in install function', () => { assert.ok(src.includes("const isCopilot = runtime === 'copilot'"), 'isCopilot defined'); }); diff --git a/tests/kilo-install.test.cjs b/tests/kilo-install.test.cjs index c92d0a90..87d4896c 100644 --- a/tests/kilo-install.test.cjs +++ b/tests/kilo-install.test.cjs @@ -215,8 +215,13 @@ describe('Source code integration (Kilo)', () => { assert.ok(src.includes("'kilo'"), '--all includes kilo runtime'); }); - test('promptRuntime runtimeMap has Kilo as option 4', () => { - assert.ok(src.includes("'4': 'kilo'"), 'runtimeMap has 4 -> kilo'); + test('promptRuntime runtimeMap has Kilo as option 2', () => { + assert.ok(src.includes("'2': 'kilo'"), 'runtimeMap has 2 -> kilo'); + }); + + test('prompt text shows Kilo above OpenCode with updated description', () => { + assert.ok(src.includes('2${reset}) Kilo'), 'prompt lists Kilo as option 2'); + assert.ok(src.includes('the #1 AI coding platform on OpenRouter'), 'prompt includes updated Kilo description'); }); test('hooks are skipped for Kilo', () => { diff --git a/tests/multi-runtime-select.test.cjs b/tests/multi-runtime-select.test.cjs index f75e83a2..9782bd6c 100644 --- a/tests/multi-runtime-select.test.cjs +++ b/tests/multi-runtime-select.test.cjs @@ -19,16 +19,16 @@ const installSrc = fs.readFileSync( // Extract runtimeMap from source for validation const runtimeMap = { '1': 'claude', - '2': 'opencode', - '3': 'gemini', - '4': 'kilo', + '2': 'kilo', + '3': 'opencode', + '4': 'gemini', '5': 'codex', '6': 'copilot', '7': 'antigravity', '8': 'cursor', '9': 'windsurf' }; -const allRuntimes = ['claude', 'opencode', 'gemini', 'kilo', 'codex', 'copilot', 'antigravity', 'cursor', 'windsurf']; +const allRuntimes = ['claude', 'kilo', 'opencode', 'gemini', 'codex', 'copilot', 'antigravity', 'cursor', 'windsurf']; /** * Simulate the parsing logic from promptRuntime without requiring readline. @@ -56,15 +56,16 @@ function parseRuntimeInput(input) { describe('multi-runtime selection parsing', () => { test('single choice returns single runtime', () => { assert.deepStrictEqual(parseRuntimeInput('1'), ['claude']); - assert.deepStrictEqual(parseRuntimeInput('4'), ['kilo']); + assert.deepStrictEqual(parseRuntimeInput('2'), ['kilo']); + assert.deepStrictEqual(parseRuntimeInput('4'), ['gemini']); assert.deepStrictEqual(parseRuntimeInput('5'), ['codex']); assert.deepStrictEqual(parseRuntimeInput('8'), ['cursor']); }); test('comma-separated choices return multiple runtimes', () => { assert.deepStrictEqual(parseRuntimeInput('1,5,7'), ['claude', 'codex', 'antigravity']); - assert.deepStrictEqual(parseRuntimeInput('2,3'), ['opencode', 'gemini']); - assert.deepStrictEqual(parseRuntimeInput('2,4'), ['opencode', 'kilo']); + assert.deepStrictEqual(parseRuntimeInput('2,3'), ['kilo', 'opencode']); + assert.deepStrictEqual(parseRuntimeInput('3,4'), ['opencode', 'gemini']); }); test('space-separated choices return multiple runtimes', () => { @@ -74,7 +75,7 @@ describe('multi-runtime selection parsing', () => { test('mixed comma and space separators work', () => { assert.deepStrictEqual(parseRuntimeInput('1, 5, 7'), ['claude', 'codex', 'antigravity']); - assert.deepStrictEqual(parseRuntimeInput('2 , 6'), ['opencode', 'copilot']); + assert.deepStrictEqual(parseRuntimeInput('2 , 6'), ['kilo', 'copilot']); }); test('single choice for windsurf', () => { @@ -98,7 +99,7 @@ describe('multi-runtime selection parsing', () => { test('invalid choices mixed with valid are filtered out', () => { assert.deepStrictEqual(parseRuntimeInput('1,11,5'), ['claude', 'codex']); - assert.deepStrictEqual(parseRuntimeInput('abc 3 xyz'), ['gemini']); + assert.deepStrictEqual(parseRuntimeInput('abc 3 xyz'), ['opencode']); }); test('duplicate choices are deduplicated', () => { @@ -108,7 +109,7 @@ describe('multi-runtime selection parsing', () => { test('preserves selection order', () => { assert.deepStrictEqual(parseRuntimeInput('7,1,5'), ['antigravity', 'claude', 'codex']); - assert.deepStrictEqual(parseRuntimeInput('8,2,6'), ['cursor', 'opencode', 'copilot']); + assert.deepStrictEqual(parseRuntimeInput('8,2,6'), ['cursor', 'kilo', 'copilot']); }); });