Compare commits

..

No commits in common. "bca9388750e1f51753d4845c0762989662f5832d" and "9bc76acdcbfbe933ed1dfa4446c75d9ba69d7054" have entirely different histories.

8 changed files with 16 additions and 14 deletions

View File

@ -1,12 +1,12 @@
# bmad-module
The core BMAD skill for installing, updating, removing, and listing community BMAD modules. Modules are standalone GitHub repos that conform to the BMAD Module Manifest Spec.
The core BMAD skill for installing, updating, removing, and listing community BMAD modules. Modules are standalone GitHub repos that conform to the BMAD Module Manifest Spec (see `docs/spec.md` in `bmad-marketplace`).
## How it fits
- **Authors** publish a single repo with `.claude-plugin/plugin.json` that works in both Claude Code's plugin marketplace and BMAD-METHOD.
- **Users** install via this skill — no CLI required. Modules are staged under `_bmad/<bmad.code>/`, then their skills are distributed to the coding assistants the user chose at `bmad install` time (the `ides:` list in `_bmad/_config/manifest.yaml`), exactly like official modules.
- **BMAD-METHOD** treats community-installed modules as a new `source: 'community'` row in `manifest.yaml`; re-running `bmad install` preserves them (`manifest-generator.js` carries `source: 'community'` rows through regeneration).
- **BMAD-METHOD** treats community-installed modules as a new `source: 'community'` row in `manifest.yaml`; re-running `bmad install` preserves them (with the paired `manifest-generator.js` patch).
## Verbs
@ -29,11 +29,13 @@ bmad-module list [--json]
## Implementation
The skill itself is a thin verb router (`SKILL.md`). `scripts/bmad-module.mjs` is a zero-import launcher that guards the import graph (a missing/corrupt runtime file becomes a documented exit code, not a raw stack trace); the verb dispatcher lives in `scripts/cli.mjs` and all filesystem work happens in the `lib/` modules. These carry **no registry dependencies** — important because the installer copies the skill into the IDE skills directories (e.g. `.claude/skills/bmad-module/`) without `node_modules` and never runs `npm install` there:
The skill itself is a thin verb router (`SKILL.md`). `scripts/bmad-module.mjs` is a zero-import launcher that guards the import graph (a missing/corrupt runtime file becomes a documented exit code, not a raw stack trace); the verb dispatcher lives in `scripts/cli.mjs` and all filesystem work happens in the `lib/` modules. These carry **no registry dependencies** — important because the installer copies the skill into `_bmad/` without `node_modules` and never runs `npm install` there:
- `manifest.yaml` is read/written with a **vendored copy of the real `yaml` library** (`lib/vendor/yaml.mjs`, regenerated by `lib/vendor/build-vendor.mjs`) so it stays byte-identical to BMAD core's writer.
- `semver` validity/range checks use a small `node:`-only helper (`lib/semver-lite.mjs`).
They re-use no BMAD-METHOD internal modules — the same code runs during development inside `bmad-marketplace` and after the skill is PR'd into BMAD-METHOD core.
## Exit codes
See `SKILL.md` for the full table. The script's stderr always names the condition; the codes are stable so tooling can branch.

View File

@ -59,7 +59,7 @@ Run from the project root (the dir containing `_bmad/`):
node <skill-dir>/scripts/bmad-module.mjs <verb> [args...]
```
`<skill-dir>` is this skill's own directory — the script ships alongside this `SKILL.md`, so it lives wherever `bmad install` distributed skills for the coding assistant you're running under. That's `<target_dir>/bmad-module/` (e.g. `.claude/skills/bmad-module/` for Claude Code, `.agents/skills/bmad-module/` for Cursor/Copilot/etc.), making the script `<target_dir>/bmad-module/scripts/bmad-module.mjs`. During development in this repo it's `src/core-skills/bmad-module/scripts/bmad-module.mjs`. Resolve it relative to this `SKILL.md` rather than assuming a fixed path. If the script isn't found next to it, the skill's bundled runtime is missing — that's the exit-code-5 case (see CRITICAL RULES and EXIT CODES): relay the "reinstall the skill" guidance rather than guessing another location.
`<skill-dir>` is wherever the skill files live in the current install. After this skill ships into BMAD-METHOD that's `_bmad/core/skills/bmad-module/`; during development it's this repo's `src/core-skills/bmad-module/`.
Stream stdout and stderr verbatim. Do NOT silence or rewrite them — the script's own messages are designed for end-user consumption.

View File

@ -58,7 +58,7 @@ export async function runInstall(opts) {
EXIT.PREFIX_COLLISION,
`code "${code}" already used by ${existingEntry.source} module ` +
`${existingEntry.repoUrl || existingEntry.rawSource || existingEntry.npmPackage || '(local)'}. ` +
`Module authors should pick a unique bmad.code.`,
`Module authors should pick a unique bmad.code (spec §7.1).`,
);
}

View File

@ -39,8 +39,8 @@ export function buildIgnoreMatcher(userPatterns) {
};
}
// Load user ignore patterns from manifest first, then .bmadignore. Declaring
// both at once is disallowed — readUserIgnores enforces it.
// Load user ignore patterns from manifest first, then .bmadignore. Spec §15
// disallows both at once — readUserIgnores enforces it.
export async function readUserIgnores(sourceDir, manifest) {
const fromManifest = manifest?.bmad?.install?.ignore;
const ignoreFilePath = path.join(sourceDir, '.bmadignore');

View File

@ -3,8 +3,8 @@ import path from 'node:path';
import { valid as semverValid, validRange as semverValidRange } from './semver-lite.mjs';
import { EXIT, BmadModuleError } from './exit.mjs';
// Reserved bmad.code values — must match the validator's RESERVED_CODES
// set. Single source of truth for the runtime.
// Reserved bmad.code values — must match docs/spec.md §7.1 and the
// validator's RESERVED_CODES set. Single source of truth for the runtime.
export const RESERVED_CODES = new Set([
'core',
'bmm',
@ -70,7 +70,7 @@ export async function readAndValidateManifest(sourceDir) {
throw new BmadModuleError(EXIT.BAD_MANIFEST, `plugin.json#bmad.code "${m.bmad.code}" must match ${CODE_REGEX}`);
}
if (RESERVED_CODES.has(m.bmad.code)) {
throw new BmadModuleError(EXIT.RESERVED_PREFIX, `plugin.json#bmad.code "${m.bmad.code}" is reserved`);
throw new BmadModuleError(EXIT.RESERVED_PREFIX, `plugin.json#bmad.code "${m.bmad.code}" is reserved (spec §7.1)`);
}
if (!semverValidRange(m.bmad.compatibility.bmadMethod)) {
throw new BmadModuleError(

View File

@ -4,7 +4,7 @@ This directory holds **self-contained, generated** copies of third-party librari
## Why vendor at all?
The `bmad-module` skill is **copied into a user's project** — into the IDE skills directories chosen at `bmad install` time (e.g. `.claude/skills/bmad-module/`, `.agents/skills/bmad-module/`) — by `npx bmad-method install`. The installer:
The `bmad-module` skill is **copied into a user's project** at `_bmad/core/skills/bmad-module/` by `npx bmad-method install`. The installer:
- strips `node_modules` while copying (`tools/installer/core/installer.js`),
- ships **no** `package.json` under the skill, and

View File

@ -2,7 +2,7 @@
A minimal BMAD module: one skill that lints markdown files under `_bmad/` for heading-hierarchy mistakes and broken relative links.
This is the **smallest valid module** that conforms to the BMAD Module Manifest Specification. Use it as a starting template.
This is the **smallest valid module** that conforms to the [BMAD Module Manifest Specification](https://github.com/bmad-code-org/bmad-marketplace/blob/main/docs/spec.md). Use it as a starting template.
## Install

View File

@ -4,7 +4,7 @@
# Hermetic: fabricates a minimal _bmad/_config/manifest.yaml skeleton in a
# tmp dir and exercises every verb against the vendored reference modules
# (tests/fixtures/examples/) and negative fixtures. Does NOT require
# BMAD-METHOD's installer; installer integration is verified separately.
# BMAD-METHOD's installer; the upstream patch (§5) is verified separately.
#
# Run from anywhere:
# bash src/core-skills/bmad-module/tests/integration.test.sh
@ -17,7 +17,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
MODULE_JS="${SKILL_DIR}/scripts/bmad-module.mjs"
# Reference modules are vendored under tests/fixtures/examples/ so the suite is
# self-contained — the fixtures travel with the test, no external checkout.
# self-contained — it does not depend on a sibling bmad-marketplace checkout.
EXAMPLES="${SCRIPT_DIR}/fixtures/examples"
FIXTURES="${SCRIPT_DIR}/fixtures"