mirror of
https://github.com/bmad-code-org/BMAD-METHOD.git
synced 2026-09-19 08:11:52 +08:00
01cc32540b
* refactor(installer): replace legacy_targets auto-cleanup with upgrade warnings Removes the legacy_targets YAML field and its install-time auto-migration of pre-v6.1.0 directories (.claude/commands, .opencode/agents, etc.). On install, surface a warning instead: read manifest version and scan 24 known legacy paths, then print rm -rf commands the user can run themselves. Also deletes orphan tools/platform-codes.yaml (never loaded by any code) and fixes a stale URL in the cs translation. * feat(installer): consolidate to .agents/skills and add global_target_dir for all platforms Updates platform-codes.yaml against verified primary docs for all 24 supported platforms. 14 platforms (auggie, codex, crush, cursor, gemini, github-copilot, kilo, kimi-code, opencode, pi, roo, rovo-dev, windsurf) move their project target_dir to the cross-tool .agents/skills/ standard. Junie moves from the broken .agents/skills/ to its own .junie/skills/ per JetBrains docs. Adds global_target_dir to every platform: 11 share ~/.agents/skills/, Crush uses XDG ~/.config/agents/skills/, Codex global stays ~/.codex/skills/, the rest are tool-specific. Ona and Trae omit global (no documented home path). Note: installer logic does not yet dedupe writes for platforms sharing a target_dir — users installing multiple .agents/skills/ tools together will overwrite the same files (harmless on install, but uninstalling one clears the dir for the others). Coordination logic is the next step. * feat(installer): add 18 new platforms, dedup shared target_dir, ownership-aware cleanup Adds 18 platforms from the verified Vercel list (adal, amp, bob, command-code, cortex, droid, firebender, goose, kode, mistral-vibe, mux, neovate, openclaw, openhands, pochi, replit, warp, zencoder). Marks codex and github-copilot as preferred alongside claude-code and cursor. Coordination for platforms sharing a target_dir: - IdeManager.setupBatch dedups skill writes when multiple selected platforms point at the same target_dir (e.g. .agents/skills/). The first platform writes, peers skip the redundant wipe-and-rewrite. Result reports the same count and target dir for every member so the install summary is consistent. - IdeManager.cleanupByList accepts remainingIdes; when removing one platform from a shared dir while another co-installed platform still owns it, the target_dir wipe is skipped. Platform-specific hooks (copilot markers, kilo modes, rovodev prompts) still run. - _setupIdes uses setupBatch; _removeDeselectedIdes passes remainingIdes so partial reconfigure preserves shared skills. Skill ownership now uses skill-manifest.csv canonicalIds, not the bmad- prefix. This unblocks custom modules that ship skills with non-bmad names (e.g. fred-cool-skill). Affected sites: - _config-driven.detect: reads canonicalIds from the project's bmadDir - _config-driven.findAncestorConflict: reads canonicalIds from the ancestor's own bmadDir, falling back to the prefix only when no manifest exists - legacy-warnings.findStaleLegacyDirs: same canonicalId-based detection Migration warnings: LEGACY_SKILL_PATHS adds 12 skill dirs that moved to the .agents/skills/ standard (cursor, gemini, github-copilot, kimi, opencode, pi, roo, rovodev, windsurf, plus their globals). Users with stale skills in those locations get a one-line warning with the rm command per dir. New shared helper tools/installer/ide/shared/installed-skills.js exposes getInstalledCanonicalIds(bmadDir) and isBmadOwnedEntry(entry, canonicalIds). Tests: 9 new assertions across two suites covering dedup, partial uninstall preservation, and custom-module skill detection. All 286 tests pass. * fix(installer): setupBatch must not claim a shared target_dir on failure If the first platform's setup throws or returns success: false, the dedup map previously still recorded the claim with skillCount: 0, causing every peer sharing the target_dir to skip its install — leaving the dir empty/broken behind a cascade of misleading "shares with X" rows. Now the claim is only recorded when the install succeeded and wrote skills. On failure, the next peer becomes the new first writer and recovers. Adds Suite 40b regression test that monkey-patches cursor.setup to throw and verifies gemini still populates the shared dir. * fix(installer): address PR #2313 review findings Three issues raised by augmentcode and coderabbit bot reviewers: 1. _removeDeselectedIdes silently swallowed cleanup failures after the refactor to cleanupByList. The old per-IDE try/catch logged a warning; the new path discarded the result array. Now logs a warning per failed ide so failures stay visible. 2. The legacy-dir cleanup hint printed `rm -rf "<path>"/bmad*` which both matched bmad-os-* utility skills the user should keep AND missed the custom-module skills (e.g. fred-cool-skill) that the new canonical-id detection now finds. Findings now carry the exact entry names from the scan, and the warning prints one precise rm line per entry. 3. warnPreNativeSkillsLegacy did unguarded fs reads at install start. A permission/IO error would have aborted the whole install. Wrapped the call site in try/catch so legacy-scan failures only emit a warning.
152 lines
4.8 KiB
JavaScript
152 lines
4.8 KiB
JavaScript
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const semver = require('semver');
|
|
const fs = require('../fs-native');
|
|
const prompts = require('../prompts');
|
|
const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils');
|
|
const { getInstalledCanonicalIds, isBmadOwnedEntry } = require('../ide/shared/installed-skills');
|
|
|
|
const MIN_NATIVE_SKILLS_VERSION = '6.1.0';
|
|
|
|
// Pre-v6.1.0 paths: BMAD used to install commands/workflows/etc in tool-specific dirs.
|
|
// In v6.1.0 BMAD switched to native SKILL.md format.
|
|
const LEGACY_COMMAND_PATHS = [
|
|
'.agent/workflows',
|
|
'.augment/commands',
|
|
'.claude/commands',
|
|
'.clinerules/workflows',
|
|
'.codex/prompts',
|
|
'~/.codex/prompts',
|
|
'.codebuddy/commands',
|
|
'.crush/commands',
|
|
'.cursor/commands',
|
|
'.gemini/commands',
|
|
'.github/agents',
|
|
'.github/prompts',
|
|
'.iflow/commands',
|
|
'.kilocode/workflows',
|
|
'.kiro/steering',
|
|
'.opencode/agents',
|
|
'.opencode/commands',
|
|
'.opencode/agent',
|
|
'.opencode/command',
|
|
'.qwen/commands',
|
|
'.roo/commands',
|
|
'.rovodev/workflows',
|
|
'.trae/rules',
|
|
'.windsurf/workflows',
|
|
];
|
|
|
|
// Skill paths that moved to the cross-tool .agents/skills/ standard.
|
|
// Users upgrading from a prior install may have stale BMAD skills here that
|
|
// the AI tool will load alongside the new ones, causing duplicates.
|
|
const LEGACY_SKILL_PATHS = [
|
|
'.augment/skills',
|
|
'~/.augment/skills',
|
|
'.codex/skills',
|
|
'.crush/skills',
|
|
'.cursor/skills',
|
|
'~/.cursor/skills',
|
|
'.gemini/skills',
|
|
'~/.gemini/skills',
|
|
'.github/skills',
|
|
'~/.github/skills',
|
|
'.kilocode/skills',
|
|
'.kimi/skills',
|
|
'~/.kimi/skills',
|
|
'.opencode/skills',
|
|
'~/.opencode/skills',
|
|
'.pi/skills',
|
|
'~/.pi/skills',
|
|
'.roo/skills',
|
|
'~/.roo/skills',
|
|
'.rovodev/skills',
|
|
'~/.rovodev/skills',
|
|
'.windsurf/skills',
|
|
'~/.windsurf/skills',
|
|
'~/.codeium/windsurf/skills',
|
|
];
|
|
|
|
const LEGACY_PATHS = [...LEGACY_COMMAND_PATHS, ...LEGACY_SKILL_PATHS];
|
|
|
|
function expandPath(p) {
|
|
if (p === '~') return os.homedir();
|
|
if (p.startsWith('~/')) return path.join(os.homedir(), p.slice(2));
|
|
return p;
|
|
}
|
|
|
|
function resolveLegacyPath(projectRoot, p) {
|
|
if (path.isAbsolute(p) || p.startsWith('~')) return expandPath(p);
|
|
return path.join(projectRoot, p);
|
|
}
|
|
|
|
async function findStaleLegacyDirs(projectRoot) {
|
|
const bmadDir = path.join(projectRoot, BMAD_FOLDER_NAME);
|
|
const canonicalIds = await getInstalledCanonicalIds(bmadDir);
|
|
|
|
const findings = [];
|
|
for (const legacyPath of LEGACY_PATHS) {
|
|
const resolved = resolveLegacyPath(projectRoot, legacyPath);
|
|
if (!(await fs.pathExists(resolved))) continue;
|
|
try {
|
|
const entries = await fs.readdir(resolved);
|
|
const bmadEntries = entries.filter((e) => isBmadOwnedEntry(e, canonicalIds));
|
|
if (bmadEntries.length > 0) {
|
|
findings.push({ path: resolved, displayPath: legacyPath, count: bmadEntries.length, entries: bmadEntries });
|
|
}
|
|
} catch {
|
|
// Unreadable dir — skip
|
|
}
|
|
}
|
|
return findings;
|
|
}
|
|
|
|
function isPreNativeSkillsVersion(version) {
|
|
if (!version) return false;
|
|
const coerced = semver.valid(version) || semver.valid(semver.coerce(version));
|
|
if (!coerced) return false;
|
|
return semver.lt(coerced, MIN_NATIVE_SKILLS_VERSION);
|
|
}
|
|
|
|
async function warnPreNativeSkillsLegacy({ projectRoot, existingVersion } = {}) {
|
|
const versionTriggered = isPreNativeSkillsVersion(existingVersion);
|
|
const staleDirs = await findStaleLegacyDirs(projectRoot);
|
|
|
|
if (!versionTriggered && staleDirs.length === 0) return;
|
|
|
|
if (versionTriggered) {
|
|
await prompts.log.warn(
|
|
`Detected previous BMAD install v${existingVersion} (pre-${MIN_NATIVE_SKILLS_VERSION}). ` +
|
|
`BMAD switched to native skills format in v${MIN_NATIVE_SKILLS_VERSION}; old command/workflow directories from your prior install may still be present.`,
|
|
);
|
|
}
|
|
|
|
if (staleDirs.length > 0) {
|
|
await prompts.log.warn(
|
|
`Found stale BMAD entries in ${staleDirs.length} legacy location(s) that the new installer no longer manages. ` +
|
|
`Your AI tool may load these alongside the new skills, causing duplicates. Remove them manually:`,
|
|
);
|
|
for (const finding of staleDirs) {
|
|
// Print each entry by exact name. A `bmad*` glob would (a) miss
|
|
// custom-module skills the canonicalId scan now picks up, and
|
|
// (b) match bmad-os-* utility skills the user should keep.
|
|
const entries = finding.entries || [];
|
|
for (const entry of entries) {
|
|
await prompts.log.message(` rm -rf "${path.join(finding.path, entry)}"`);
|
|
}
|
|
}
|
|
} else if (versionTriggered) {
|
|
await prompts.log.message(
|
|
' No stale legacy directories detected, but if your AI tool shows duplicate BMAD commands after install, check for old `bmad-*` entries in tool-specific dirs (e.g. .claude/commands, .cursor/commands).',
|
|
);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
warnPreNativeSkillsLegacy,
|
|
findStaleLegacyDirs,
|
|
isPreNativeSkillsVersion,
|
|
LEGACY_PATHS,
|
|
MIN_NATIVE_SKILLS_VERSION,
|
|
};
|