fix(installer): suspend Kilo Code and add verified Gemini/Crush results
Kilo Code does not support the Agent Skills standard — the migration from modes+workflows to skills was based on a false fork assumption. - Add suspended field to platform-codes.yaml, hiding Kilo from the IDE picker and blocking setup with a clear message - Fail the installer early (before writing _bmad/) if all selected IDEs are suspended, protecting existing installations from being corrupted - Still clean up legacy Kilo artifacts (.kilocodemodes, .kilocode/workflows) when users switch to a different IDE - Mark Crush and Gemini CLI as manually verified (both work end-to-end) - Replace Suite 22 install tests with suspended-behavior tests (7 assertions)
This commit is contained in:
parent
837ccca0e4
commit
b5d894999a
|
|
@ -1135,82 +1135,59 @@ async function runTests() {
|
|||
console.log('');
|
||||
|
||||
// ============================================================
|
||||
// Suite 22: KiloCoder Native Skills
|
||||
// Suite 22: KiloCoder Suspended
|
||||
// ============================================================
|
||||
console.log(`${colors.yellow}Test Suite 22: KiloCoder Native Skills${colors.reset}\n`);
|
||||
console.log(`${colors.yellow}Test Suite 22: KiloCoder Suspended${colors.reset}\n`);
|
||||
|
||||
try {
|
||||
clearCache();
|
||||
const platformCodes22 = await loadPlatformCodes();
|
||||
const kiloInstaller = platformCodes22.platforms.kilo?.installer;
|
||||
const kiloConfig22 = platformCodes22.platforms.kilo;
|
||||
|
||||
assert(kiloInstaller?.target_dir === '.kilocode/skills', 'KiloCoder target_dir uses native skills path');
|
||||
assert(typeof kiloConfig22?.suspended === 'string', 'KiloCoder has a suspended message in platform config');
|
||||
|
||||
assert(kiloInstaller?.skill_format === true, 'KiloCoder installer enables native skill output');
|
||||
assert(kiloConfig22?.installer?.target_dir === '.kilocode/skills', 'KiloCoder retains target_dir config for future use');
|
||||
|
||||
assert(
|
||||
Array.isArray(kiloInstaller?.legacy_targets) && kiloInstaller.legacy_targets.includes('.kilocode/workflows'),
|
||||
'KiloCoder installer cleans legacy workflows output',
|
||||
);
|
||||
const ideManager22 = new IdeManager();
|
||||
await ideManager22.ensureInitialized();
|
||||
|
||||
// Fresh install test
|
||||
// Should not appear in available IDEs
|
||||
const availableIdes22 = ideManager22.getAvailableIdes();
|
||||
assert(!availableIdes22.some((ide) => ide.value === 'kilo'), 'KiloCoder is hidden from IDE selection');
|
||||
|
||||
// Setup should be blocked but legacy files should be cleaned up
|
||||
const tempProjectDir22 = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-kilo-test-'));
|
||||
const installedBmadDir22 = await createTestBmadFixture();
|
||||
|
||||
// Pre-populate legacy Kilo artifacts that should be cleaned up
|
||||
const legacyDir22 = path.join(tempProjectDir22, '.kilocode', 'workflows');
|
||||
await fs.ensureDir(legacyDir22);
|
||||
await fs.writeFile(path.join(legacyDir22, 'bmad-legacy.md'), 'legacy\n');
|
||||
|
||||
// Create a .kilocodemodes file with BMAD modes and a user mode
|
||||
const kiloModesPath22 = path.join(tempProjectDir22, '.kilocodemodes');
|
||||
const yaml22 = require('yaml');
|
||||
const kiloModesContent = yaml22.stringify({
|
||||
customModes: [
|
||||
{ slug: 'bmad-bmm-architect', name: 'BMAD Architect', roleDefinition: 'test' },
|
||||
{ slug: 'bmad-core-master', name: 'BMAD Master', roleDefinition: 'test' },
|
||||
{ slug: 'user-custom-mode', name: 'My Custom Mode', roleDefinition: 'user mode' },
|
||||
],
|
||||
});
|
||||
await fs.writeFile(kiloModesPath22, kiloModesContent);
|
||||
|
||||
const ideManager22 = new IdeManager();
|
||||
await ideManager22.ensureInitialized();
|
||||
const result22 = await ideManager22.setup('kilo', tempProjectDir22, installedBmadDir22, {
|
||||
silent: true,
|
||||
selectedModules: ['bmm'],
|
||||
});
|
||||
|
||||
assert(result22.success === true, 'KiloCoder setup succeeds against temp project');
|
||||
assert(result22.success === false, 'KiloCoder setup is blocked when suspended');
|
||||
assert(result22.error === 'suspended', 'KiloCoder setup returns suspended error');
|
||||
|
||||
const skillFile22 = path.join(tempProjectDir22, '.kilocode', 'skills', 'bmad-master', 'SKILL.md');
|
||||
assert(await fs.pathExists(skillFile22), 'KiloCoder install writes SKILL.md directory output');
|
||||
|
||||
const skillContent22 = await fs.readFile(skillFile22, 'utf8');
|
||||
const nameMatch22 = skillContent22.match(/^name:\s*(.+)$/m);
|
||||
assert(nameMatch22 && nameMatch22[1].trim() === 'bmad-master', 'KiloCoder skill name frontmatter matches directory name exactly');
|
||||
|
||||
assert(!(await fs.pathExists(path.join(tempProjectDir22, '.kilocode', 'workflows'))), 'KiloCoder setup removes legacy workflows dir');
|
||||
|
||||
// Verify .kilocodemodes cleanup: BMAD modes removed, user mode preserved
|
||||
const cleanedModes22 = yaml22.parse(await fs.readFile(kiloModesPath22, 'utf8'));
|
||||
// Should not write new skill files
|
||||
assert(
|
||||
Array.isArray(cleanedModes22.customModes) && cleanedModes22.customModes.length === 1,
|
||||
'KiloCoder cleanup removes BMAD modes from .kilocodemodes',
|
||||
!(await fs.pathExists(path.join(tempProjectDir22, '.kilocode', 'skills'))),
|
||||
'KiloCoder does not create skills directory when suspended',
|
||||
);
|
||||
assert(cleanedModes22.customModes[0].slug === 'user-custom-mode', 'KiloCoder cleanup preserves non-BMAD modes in .kilocodemodes');
|
||||
|
||||
// Reinstall test
|
||||
const result22b = await ideManager22.setup('kilo', tempProjectDir22, installedBmadDir22, {
|
||||
silent: true,
|
||||
selectedModules: ['bmm'],
|
||||
});
|
||||
|
||||
assert(result22b.success === true, 'KiloCoder reinstall/upgrade succeeds over existing skills');
|
||||
assert(await fs.pathExists(skillFile22), 'KiloCoder reinstall preserves SKILL.md output');
|
||||
// Legacy files should be cleaned up
|
||||
assert(
|
||||
!(await fs.pathExists(path.join(tempProjectDir22, '.kilocode', 'workflows'))),
|
||||
'KiloCoder legacy workflows are cleaned up even when suspended',
|
||||
);
|
||||
|
||||
await fs.remove(tempProjectDir22);
|
||||
await fs.remove(installedBmadDir22);
|
||||
} catch (error) {
|
||||
assert(false, 'KiloCoder native skills migration test succeeds', error.message);
|
||||
assert(false, 'KiloCoder suspended test succeeds', error.message);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
|
|
|||
|
|
@ -717,6 +717,25 @@ class Installer {
|
|||
config.skipIde = toolSelection.skipIde;
|
||||
const ideConfigurations = toolSelection.configurations;
|
||||
|
||||
// Early check: fail fast if ALL selected IDEs are suspended
|
||||
if (config.ides && config.ides.length > 0) {
|
||||
await this.ideManager.ensureInitialized();
|
||||
const suspendedIdes = config.ides.filter((ide) => {
|
||||
const handler = this.ideManager.handlers.get(ide);
|
||||
return handler?.platformConfig?.suspended;
|
||||
});
|
||||
|
||||
if (suspendedIdes.length > 0 && suspendedIdes.length === config.ides.length) {
|
||||
for (const ide of suspendedIdes) {
|
||||
const handler = this.ideManager.handlers.get(ide);
|
||||
await prompts.log.error(`${handler.displayName || ide}: ${handler.platformConfig.suspended}`);
|
||||
}
|
||||
throw new Error(
|
||||
`All selected tool(s) are suspended: ${suspendedIdes.join(', ')}. Installation aborted to prevent upgrading _bmad/ without a working IDE configuration.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Detect IDEs that were previously installed but are NOT in the new selection (to be removed)
|
||||
if (config._isUpdate && config._existingInstall) {
|
||||
const previouslyInstalledIdes = new Set(config._existingInstall.ides || []);
|
||||
|
|
|
|||
|
|
@ -128,6 +128,11 @@ class IdeManager {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Skip suspended platforms (e.g., IDE doesn't support skills yet)
|
||||
if (handler.platformConfig?.suspended) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ides.push({
|
||||
value: key,
|
||||
name: name,
|
||||
|
|
@ -177,6 +182,18 @@ class IdeManager {
|
|||
return { success: false, ide: ideName, error: 'unsupported IDE' };
|
||||
}
|
||||
|
||||
// Block suspended platforms — clean up legacy files but don't install
|
||||
if (handler.platformConfig?.suspended) {
|
||||
if (!options.silent) {
|
||||
await prompts.log.warn(`${handler.displayName || ideName}: ${handler.platformConfig.suspended}`);
|
||||
}
|
||||
// Still clean up legacy artifacts so old broken configs don't linger
|
||||
if (typeof handler.cleanup === 'function') {
|
||||
await handler.cleanup(projectDir, { silent: true });
|
||||
}
|
||||
return { success: false, ide: ideName, error: 'suspended' };
|
||||
}
|
||||
|
||||
try {
|
||||
const handlerResult = await handler.setup(projectDir, bmadDir, options);
|
||||
// Build detail string from handler-returned data
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ platforms:
|
|||
preferred: false
|
||||
category: ide
|
||||
description: "AI coding platform"
|
||||
suspended: "Kilo Code does not yet support the Agent Skills standard. Support is paused until they implement it. See https://github.com/kilocode/kilo-code/issues for updates."
|
||||
installer:
|
||||
legacy_targets:
|
||||
- .kilocode/workflows
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ Support assumption: full Agent Skills support. Crush scans project-local `.crush
|
|||
- [x] Test fresh install — 43 skills installed to `.crush/skills/`
|
||||
- [x] Test reinstall/upgrade from legacy command output
|
||||
- [x] Confirm no ancestor conflict protection is needed because Crush only scans project-local `.crush/skills/`, no ancestor inheritance
|
||||
- [ ] **NEEDS MANUAL IDE VERIFICATION** — install Crush via brew and confirm skills appear in UI
|
||||
- [x] Manual CLI verification — `crush run` lists all 10 skills and successfully triggers bmad-help
|
||||
- [x] Implement/extend automated tests — 9 assertions in test suite 20
|
||||
- [x] Commit
|
||||
|
||||
|
|
@ -235,7 +235,7 @@ Support assumption: full Agent Skills support. Gemini CLI docs confirm workspace
|
|||
- [x] Test reinstall/upgrade from legacy TOML command output — legacy dir removed, skills installed
|
||||
- [x] Confirm no ancestor conflict protection is needed — Gemini CLI uses workspace > user > extension precedence, no ancestor directory inheritance
|
||||
- [x] Implement/extend automated tests — 9 assertions in test suite 23 (config, fresh install, legacy cleanup, reinstall)
|
||||
- [ ] **NEEDS MANUAL IDE VERIFICATION** — run `gemini` CLI in a project with installed skills and confirm they appear and can be triggered
|
||||
- [x] Manual CLI verification — `gemini` lists all 10 skills and successfully triggers bmad-help
|
||||
- [ ] Commit
|
||||
|
||||
## iFlow
|
||||
|
|
|
|||
Loading…
Reference in New Issue