fix: move Kilo above OpenCode in installer
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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']);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user