diff --git a/test/test-installation-components.js b/test/test-installation-components.js index befdf6e74..1b09178ed 100644 --- a/test/test-installation-components.js +++ b/test/test-installation-components.js @@ -726,6 +726,15 @@ async function runTests() { assert(!(await fs.pathExists(path.join(tempProjectDir13, '.roo', 'commands'))), 'Roo setup removes legacy commands dir'); + // Reinstall/upgrade: run setup again over existing skills output + const result13b = await ideManager13.setup('roo', tempProjectDir13, installedBmadDir13, { + silent: true, + selectedModules: ['bmm'], + }); + + assert(result13b.success === true, 'Roo reinstall/upgrade succeeds over existing skills'); + assert(await fs.pathExists(skillFile13), 'Roo reinstall preserves SKILL.md output'); + await fs.remove(tempProjectDir13); await fs.remove(installedBmadDir13); } catch (error) { @@ -802,6 +811,70 @@ async function runTests() { console.log(''); + // ============================================================ + // Test 17: GitHub Copilot Native Skills Install + // ============================================================ + console.log(`${colors.yellow}Test Suite 17: GitHub Copilot Native Skills${colors.reset}\n`); + + try { + clearCache(); + const platformCodes17 = await loadPlatformCodes(); + const copilotInstaller = platformCodes17.platforms['github-copilot']?.installer; + + assert(copilotInstaller?.target_dir === '.github/skills', 'GitHub Copilot target_dir uses native skills path'); + + assert(copilotInstaller?.skill_format === true, 'GitHub Copilot installer enables native skill output'); + + assert( + Array.isArray(copilotInstaller?.legacy_targets) && copilotInstaller.legacy_targets.includes('.github/agents'), + 'GitHub Copilot installer cleans legacy agents output', + ); + + assert( + Array.isArray(copilotInstaller?.legacy_targets) && copilotInstaller.legacy_targets.includes('.github/prompts'), + 'GitHub Copilot installer cleans legacy prompts output', + ); + + const tempProjectDir17 = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-copilot-test-')); + const installedBmadDir17 = await createTestBmadFixture(); + + // Create legacy .github/agents/ and .github/prompts/ files + const legacyAgentsDir17 = path.join(tempProjectDir17, '.github', 'agents'); + const legacyPromptsDir17 = path.join(tempProjectDir17, '.github', 'prompts'); + await fs.ensureDir(legacyAgentsDir17); + await fs.ensureDir(legacyPromptsDir17); + await fs.writeFile(path.join(legacyAgentsDir17, 'bmad-legacy.agent.md'), 'legacy agent\n'); + await fs.writeFile(path.join(legacyPromptsDir17, 'bmad-legacy.prompt.md'), 'legacy prompt\n'); + + const ideManager17 = new IdeManager(); + await ideManager17.ensureInitialized(); + const result17 = await ideManager17.setup('github-copilot', tempProjectDir17, installedBmadDir17, { + silent: true, + selectedModules: ['bmm'], + }); + + assert(result17.success === true, 'GitHub Copilot setup succeeds against temp project'); + + const skillFile17 = path.join(tempProjectDir17, '.github', 'skills', 'bmad-master', 'SKILL.md'); + assert(await fs.pathExists(skillFile17), 'GitHub Copilot install writes SKILL.md directory output'); + + // Verify name frontmatter matches directory name + const skillContent17 = await fs.readFile(skillFile17, 'utf8'); + const nameMatch17 = skillContent17.match(/^name:\s*(.+)$/m); + assert(nameMatch17 && nameMatch17[1].trim() === 'bmad-master', 'GitHub Copilot skill name frontmatter matches directory name exactly'); + + assert(!(await fs.pathExists(legacyAgentsDir17)), 'GitHub Copilot setup removes legacy agents dir'); + + assert(!(await fs.pathExists(legacyPromptsDir17)), 'GitHub Copilot setup removes legacy prompts dir'); + + await fs.remove(tempProjectDir17); + await fs.remove(installedBmadDir17); + } catch (error) { + assert(false, 'GitHub Copilot native skills migration test succeeds', error.message); + } + + console.log(''); + // ============================================================ // Summary // ============================================================ diff --git a/tools/docs/native-skills-migration-checklist.md b/tools/docs/native-skills-migration-checklist.md index f1c43db2a..57302589b 100644 --- a/tools/docs/native-skills-migration-checklist.md +++ b/tools/docs/native-skills-migration-checklist.md @@ -48,7 +48,7 @@ Support assumption: full Agent Skills support. BMAD currently installs legacy co - [x] Test reinstall/upgrade from legacy command output - [x] Confirm no ancestor conflict protection is needed because a child workspace surfaced child `.cursor/skills` entries but not a parent-only skill during manual verification - [x] Implement/extend automated tests -- [ ] Commit +- [x] Commit ## Windsurf @@ -167,7 +167,7 @@ Support assumption: full Agent Skills support. BMAD currently installs commands - [x] Implement installer migration to native skills output - [x] Add legacy cleanup for `.roo/commands` - [x] Test fresh install — 43 skills installed, verified in Roo Code v3.51 -- [ ] Test reinstall/upgrade from legacy command output +- [x] Test reinstall/upgrade from legacy command output - [x] Confirm no ancestor conflict protection is needed because manual Roo Code v3.51 verification showed child-local `child-only` skill loaded while parent-only skill was not inherited - [x] Implement/extend automated tests — 7 assertions in test suite 13 - [x] Commit @@ -193,13 +193,13 @@ Support assumption: full Agent Skills support. BMAD currently uses a custom inst **Install:** VS Code extension `GitHub.copilot` — search "GitHub Copilot" in Extensions or `code --install-extension GitHub.copilot` -- [ ] Confirm GitHub Copilot native skills path and whether `.github/agents` remains necessary as a compatibility layer +- [x] Confirm GitHub Copilot native skills path is `.github/skills/{skill-name}/SKILL.md` — also reads `.claude/skills/` automatically - [ ] Design the migration away from the custom prompt/agent installer model - [ ] Implement native skills output, ideally with shared config-driven code where practical - [ ] Add legacy cleanup for `.github/agents`, `.github/prompts`, and any BMAD-owned Copilot instruction file behavior that should be retired - [ ] Test fresh install - [ ] Test reinstall/upgrade from legacy custom installer output -- [ ] Confirm ancestor conflict protection where applicable +- [x] Confirm no ancestor conflict protection is needed because manual Copilot verification showed child-local `child-only` skill loaded while parent-only skill was not inherited - [ ] Implement/extend automated tests - [ ] Commit