This work was developed in a separate bmad-marketplace repo and is now
landing directly in BMAD-METHOD, so the migration framing is obsolete:
- remove links to docs/spec.md (only existed in the temp repo) and the
bmad-marketplace / 'upstream patch' / 'sibling checkout' references in
README, the integration test, and the acme-md-lint fixture
- drop dead 'spec §N' pointers in install.mjs, install-plan.mjs, and
plugin-json.mjs (including a user-facing reserved-code error message)
- reword the manifest-generator 'patch' note as in-repo behavior
- correct the documented install path from _bmad/ to the IDE skills
directories the installer now distributes skills to (.claude/skills/, etc.)
No behavior change. Integration suite: 73 pass / 0 fail.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bmad-module skill copied a module's files and distributed skills to IDEs,
but skipped four post-copy steps the full `bmad install --custom-source` path
performs, leaving modules incompletely installed:
- Merge each module's module-help.csv into _bmad/_config/bmad-help.csv (the
catalog bmad-help reads) — new lib/help-catalog.mjs
- Generate [modules.<code>] / [agents.<code>] blocks in config.toml /
config.user.toml from module.yaml (defaults + --set overrides), via a
targeted merge that preserves [core] and sibling modules — new lib/config-gen.mjs
- Create the working directories a module declares under `directories:`
(with move-on-path-change and wds_folders) — new lib/module-dirs.mjs
- Run `npm install --omit=dev` in place when a module ships package.json
(opt out via bmad.install.skipNpm) — new lib/npm-deps.mjs
All four run as a shared finishModuleInstall step wired into install, update,
and remove; every step is non-fatal so a module already committed to _bmad/
isn't lost to a post-copy hiccup. Adds a repeatable --set <code>.<key>=<value>
flag mirroring the installer.
Also fixes two latent issues in the manifest-driven copy that the new steps
depend on:
- moduleDefinition / moduleHelpCsv are now flattened to the module root even
when they live inside a declared skill dir (the setup-skill assets pattern);
previously claimedSrc dedup skipped them and the rewritten plugin.json
pointed at a non-existent ./module.yaml.
- package.json / package-lock.json are now copied so npm deps can install.
Tests: extends the integration suite with config/agent-roster, --set,
directory-creation, help-catalog, removal-cleanup, and npm assertions
(73/73 pass); adds a minimal-npm fixture and rewrites the comprehensive
fixture's module-help.csv to the canonical schema.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bmad-module skill staged community modules under _bmad/<code>/ but never
pushed their skills out to the coding assistants the user selected at
`bmad install` time, so a freshly installed module was invisible to Claude
Code / Cursor / Copilot / etc. until a full reinstall; remove left skills
orphaned in the IDE dirs.
install/update/remove now distribute (or prune) skills to every IDE listed in
_bmad/_config/manifest.yaml and clean the redundant skill dirs from _bmad/,
matching how official modules end up.
Single engine, three callers — no fork:
- New tools/installer/core/ide-sync.js (syncIdes) wraps the real
IdeManager.setupBatch + platform-codes engine. The full installer
(_setupIdes/_cleanupSkillDirs), the new `bmad ide-sync` command, and the
skill all route through it, so new IDEs and engine changes propagate
everywhere automatically.
Local, dependency-free delivery — no npx/network at runtime:
- build-ide-sync.mjs esbuild-bundles the engine into vendor/ide-sync.mjs
(+ platform-codes.yaml), aliasing ../prompts and ../project-root to small
shims so @clack and the installer graph are dropped. The bundle ships inside
the skill tree (like yaml.mjs); the skill execs it locally. It's
generated-from-source and gated by vendor:check, refreshed on every install.
update/remove pass --prune with the module's canonicalIds so skills dropped
between versions (or on uninstall) are removed from IDE dirs + command
pointers. Graceful degradation: if the bundle is unreachable, the verb still
succeeds and points the user at `bmad ide-sync`.
Tests: new test/test-ide-sync.js drift-guard (engine == bundle, incl. prune),
integration.test.sh IDE-distribution section (offline), bundle self-check in
the build. All gates green (vendor:check, lint, format, test:install 349/349).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The copy planner treated every skills/agents/commands entry as a
directory and ran it through addDirRecursive, which lists files *under*
the path. For a subagent declared as a file (e.g.
`"agents": ["./agents/foo.md"]` — a standard Claude-Code shape) that
listed nothing, so the agent was silently dropped from the install even
though rewriteManifestPaths already remapped it to `./agents/foo.md`.
Stat each entry and branch: directories recurse as before, files are
queued directly (honoring the ignore matcher). Verified by the
comprehensive fixture's changelog-archivist.md agent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the flat copy-list staging with a manifest-driven copy plan:
- buildCopyPlan maps declared skills/agents/commands and string-typed
Claude-Code surfaces into canonical install slots, copies conventional
top-level metadata, and drops anything not covered (no more leaking of
tools/, website/, .github/, etc.).
- rewriteManifestPaths emits a plugin.json whose paths point at the
canonical post-install locations, keeping the on-disk manifest
self-consistent inside _bmad/<code>/.
- stageCopyPlan stages the plan plus synthesized files (rewritten
plugin.json) into the tmp dir for the atomic swap.
install.mjs and update.mjs switch to the new plan/skillDestDirs flow and
drop the now-unused copy-list helpers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The skill is copied into _bmad/core/skills/bmad-module/ by the installer,
which strips node_modules, ships no package.json under the skill, and never
runs npm install there. Bare `import 'yaml'`/`import 'semver'` therefore
crashed at module load (ERR_MODULE_NOT_FOUND, exit 1) before any structured
exit code could fire. Every other installed script is zero-third-party-dep.
- Vendor the real yaml@2.8.4 as a deterministic esbuild single-file bundle
(scripts/lib/vendor/yaml.mjs), imported by relative path. Guarantees
byte-identical manifest.yaml round-trips with BMAD core's writer, which uses
the same library + options (tools/installer/core/manifest.js).
- Drop semver for a node:-only semver-lite.mjs (valid/validRange),
parity-tested against the real semver across 469 cases (400 fuzzed).
- Fix a third bare yaml import that the original report missed (frontmatter.mjs).
- Make bmad-module.mjs a zero-import launcher that maps any load failure to a
new documented EXIT.TOOLING (5) with reinstall guidance instead of leaking a
raw ESM stack trace; the verb dispatcher moves to cli.mjs.
- Enforce vendor freshness so a yaml/esbuild bump can't ship a stale bundle:
build-vendor.mjs --check is wired into npm test (pre-commit), npm run quality,
and the quality.yaml CI validate job. Adds vendor:build / vendor:check scripts.
- Ignore the generated vendor/ dir in eslint + prettier; document the rationale
in SKILL.md, README.md, and vendor/README.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>