fix: move Kilo above OpenCode in installer

This commit is contained in:
Alex Alecu
2026-04-02 11:34:31 +03:00
parent ac4836d270
commit 52585de4ab
4 changed files with 33 additions and 21 deletions

View File

@@ -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) => {

View File

@@ -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');
});

View File

@@ -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', () => {

View File

@@ -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']);
});
});