mirror of
https://github.com/bmad-code-org/BMAD-METHOD.git
synced 2026-09-19 08:11:52 +08:00
docs/getting-started-activation
33 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c2530ea53f |
feat: add inspectable workflow snapshots (#2601)
Render complete dev-auto workflows into root-scoped immutable snapshots using shared declarative rendering and strict TOML configuration layers. Keep generated render state out of installer module discovery and custom file preservation, preserve quick-dev behavior, and provide deterministic Python version failures for standalone resolver use. |
||
|
|
c23f23400d |
feat: streamline core to an 8-skill set with merged review and editorial skills (#2603)
* feat: streamline core to a 5-skill kernel with standalone skill modules
Core installs 14 -> 5 catalog-visible skills; atoms exit to standalone
modules; installer gains real dependency resolution; zero npm deps.
- Merge bmad-editorial-review-prose/-structure into bmad-editorial-review
(structure models JIT-loaded, new customize.toml)
- Merge bmad-review-adversarial-general/-edge-case-hunter/-verification-gap
into bmad-review as selectable lenses; hidden husk-forwarders remain at
the old IDs (no catalog rows) so gds/loop/os-utils keep working
- Move bmad-brainstorming, bmad-party-mode, bmad-forge-idea out of core to
src/standalone-skills/ as single-skill modules; add bmad-analysis bundle
module (curated dependency list over the atoms)
- Move bmad-spec into bmm (2-plan-workflows)
- Modernize bmad-advanced-elicitation: uv run, customize.toml, methods
pick offloaded to scripts/pick_methods.py (with tests)
- Delete bmad-index-docs, bmad-shard-doc (removes the tree's only external
npm dependency), and the four deprecation shims (bmad-create-prd,
bmad-edit-prd, bmad-validate-prd, bmad-create-architecture); all added
to removals.txt
- Installer: activate the dependencies field (recursive union into
selectedModules, cycle-guarded, warn on unknown), config-driven picker
visibility; core stays force-installed
- bmm module.yaml declares deps on the three atoms
- Docs updated across all locales; new reference/standalone-skills.md;
shard-doc how-tos removed
* Restore original critical wording lost in the review/editorial merges
The merges into bmad-review and bmad-editorial-review were meant to keep
the source skills' critical wording behind progressive disclosure, not
paraphrase it away. Restore what was lost:
- lens-adversarial: clueless-weasel framing, extreme-skepticism wording,
the at-least-ten-issues quota, and zero-findings-is-suspicious (the
merge had inverted this to zero-is-valid)
- bmad-review SKILL: zero-findings stance is now per-lens
- lens-edge-case: mandatory exact-order step enforcement
- lens-verification-gap: exact 'No verification gaps found.' clean line
- editorial-review: full Human/LLM reader principles restored to new
references/reader-principles.md; structure-pass HIGH-VALUE DENSITY
role, front-load-value, anti-patterns, pacing check, and length_target
assessment; prose-pass role sentence, analyze-style-first step, and
merge-overlapping-fixes rule; output summary block and min-3-words HALT
* feat(installer): promote bmad-analysis bundle to src/bmad-analysis-skills
Move the bmad-analysis bundle module out of src/standalone-skills/ into its
own src/bmad-analysis-skills root, teach the installer to resolve it there
(getModulePath, official-modules listing, isBuiltInModule helper), and
update the marketplace manifest and standalone-skills docs to match.
* refactor(bmad-review): rename edge-case lens to edge-case-hunter
Rename the lens code and reference file (lens-edge-case.md ->
lens-edge-case-hunter.md), add explicit when = "always" to the shipped
lenses, and tighten the lens-selection wording in SKILL.md.
* feat(bmad-editorial-review): configurable style guide + analysis-driven rework
Apply the workflow-builder analysis recommendations:
- Make the baseline style guide configurable: style_guide in customize.toml
now IS the baseline (default "Microsoft Writing Style Guide") instead of
an empty override slot; SKILL.md no longer hardcodes the guide.
- Inline reader-principles.md into SKILL.md and delete the reference (it
loaded on every run and was half-duplicated inline).
- Complete the customization surface: activation_steps_prepend/append,
persistent_facts (project-context glob), on_complete, and a
review_output_path scalar split out of output_preferences; add a
file:-load fallback convention.
- Ground word metrics: new scripts/word_metrics.py (stdlib, PEP 723, tests)
emits total/per-section word counts so impact estimates and the reduction
summary use exact numbers.
- Cross-pass dedup: prose pass skips CUT-tagged passages and re-attaches
fixes in MERGE'd ones; output ranks by impact with a long-tail rollup.
- Polish: HALT threshold replaced with plain outcome, duplicate LLM-reader
bullets merged, all-caps lowered, literal Overview heading added.
* fix(installer): stop cache-refresh git commands from escaping to the parent repo
Two compounding bugs let a pre-commit test run shallow-fetch and hard-reset
the developer's own repository:
1. Git spawns in custom-module-manager and external-manager inherited the
hook environment. Git exports GIT_DIR (absolute, in worktree checkouts)
into pre-commit hooks; a child git then targets the hook's repo regardless
of cwd, and treats its cwd — the module cache dir — as the work tree. The
cache refresh's 'git fetch --depth 1' + 'git reset --hard origin/main'
therefore shallowed the shared .bare and moved the checked-out branch.
New git-env.js strips repo-targeting GIT_* vars from every git spawn in
both managers, including calls that previously inherited process.env
implicitly.
2. Test suite 51 (quickUpdate dependency expansion) ran the real
CustomModuleManager lookup, which scans ~/.bmad/cache/custom-modules and
network-refreshes every cached clone — real user state. The suite now
stubs findModuleSourceByCode.
Verified by rerunning the suite with GIT_DIR pointed at the repo and a PATH
shim blocking fetch/reset/clone: 432 passing, zero blocked calls.
* De-scope standalone-skills mechanism: atoms return to core, shims reinstated
Shrink the PR to its heart — the skill merges — and defer the module
mechanics to a follow-up where all skills become module-driven:
- bmad-brainstorming, bmad-party-mode, bmad-forge-idea move back to
src/core-skills/ as ordinary core skills with their catalog rows
restored; src/standalone-skills/ and the bmad-analysis bundle module
are removed
- Installer reverted to main: standalone discovery, hidden-module
filtering, dependency resolution, manifest changes (test suites 49-51
removed with the code); the cache-refresh git fix is retained
- The four bmm deprecation shims (create/edit/validate-prd,
create-architecture) are reinstated so enterprise installs that
invoke the old IDs or carry _bmad/custom overrides keep working;
descriptions trimmed to the short husk style; their removals.txt
entries dropped (removal rides the v7 cut as their frontmatter
promises)
- marketplace.json keeps the five plugin entries with atom paths
pointing at src/core-skills/
- Docs (en/cs/fr/vi/zh) reframe the three skills as core thinking
skills; standalone-skills.md reference page removed
* Fix all findings from the max-effort adversarial review
Correctness:
- Finish the edge-case -> edge-case-hunter lens rename at every caller:
the forwarder husk, the code-review/dev-auto/quick-dev review layers,
the renderer test assertion, and the stale example path in
bmad-review/SKILL.md
- marketplace.json: ship the five core kernel skills with
bmad-method-lifecycle so its skills' bmad-review/bmad-editorial-review/
bmad-help/bmad-advanced-elicitation invocations resolve in a
marketplace install
- pick_methods.py / word_metrics.py: force UTF-8 stdout (Windows locale
code pages crashed on the catalog's arrows and CJK headings)
- word_metrics.py: pair fences CommonMark-style so 4-backtick fences can
embed 3-backtick examples without corrupting sections; count CJK
characters as words
- pick_methods.py: validate --extra entries are JSON objects (was an
uncaught AttributeError); read catalogs with utf-8-sig (BOM'd CSVs
silently blanked every num)
- bmad-spec: activation now resolves {output_folder} (which the
Workspace uses) instead of the unused {planning_artifacts}; drop the
stale core-only-installs comment
- Editorial husks: pin the legacy output contracts (three-column table /
Document Summary report and exact empty-state lines) like the review
husks do
- PRD shims: advertise the real bmad-prd customize keys
(validation_checklist_template, prd_output_path, run_folder_pattern,
finalize_reviewers) instead of three that don't exist
- bmad-prd: add the forwarded-activation clause its shims rely on
(ported from bmad-architecture)
- Locale workflow-maps (fr/cs/vi/zh): add the bmad-spec Phase-2 row the
English map gained, which every locale's core-tools note points at
- git-env.js: also strip GIT_CONFIG_PARAMETERS and the
GIT_CONFIG_COUNT/KEY_n/VALUE_n family; pass gitEnv() to the three npm
install spawns whose transitive git calls inherited hook vars
Consistency:
- brain.py --extra overlay now replaces-by-name like pick_methods.py
(same customize.toml additional_* semantics across sibling skills),
with a regression test
* Fix prettier formatting in marketplace.json
* Apply valid CodeRabbit findings
- brain.py: catch malformed --extra overlays (bad JSON, non-array root,
non-object entries) into the clean error path instead of a raw
traceback, with a regression test; read catalogs and overlays with
utf-8-sig; normalize ALL CSV fields (required ones were unstripped and
could arrive as None from short rows)
- brain-selector: clamp the random-technique count to what the pool can
supply so the Total badge matches the actual draw (template +
regenerated assets/brain-selector.html)
- bmad-editorial-review: word_metrics command now uses the explicit
{skill-root}/ prefix
- resolve_party.py / resolve_personas.py: custom member overrides now
start from the installed entry, so omitted fields (icon, title,
description, module, team) survive; non-string member tokens land in
unresolved instead of raising TypeError; party's member loop gains the
isinstance guards its personas twin already had
- bmad-brainstorming: fix the SKILL.md claim that headless is the only
context for self-generated ideas (autonomous mode is interactive);
autonomous mode honors user-supplied techniques before self-selecting
- Docs: drop duplicate 'only' in the spec template; align zh-cn
forge-idea's bmad-review description with the English wording
* Create only the output folder at install time
bmm no longer pre-creates planning_artifacts, implementation_artifacts,
and project_knowledge — the last of which put an empty docs/ at every
project root. Skills create those lazily on first write. core now
declares {output_folder} in its directories block, which was previously
created only as a side effect of the artifact folders nesting under it.
|
||
|
|
c0fa3231a2 |
v6.10.0: bmad-loop replaces bmad-automator, changelog draft (#2545)
* docs: draft v6.10.0 changelog; rebrand bmad-auto to bmad-loop; simplify uv check message Drafts the v6.10.0 changelog entry, headlined by bmad-loop landing as an installable module and bmad-automator's deprecation in its favor. Renames the installer's bmad-auto module registry entry (code, name, url, module-definition path, post-install message) to bmad-loop ahead of the upstream repo rename. Also simplifies the uv-detected install message to a plain pass/fail line with a checkmark, since the prior "ready to run BMAD's Python-powered scripts via uv run" phrasing read as more actionable than it was. * feat(installer): support module-code aliases, migrate bauto to bmad-loop Adds a bauto -> bmad-loop registry alias so existing installs migrate forward on quick-update (and the interactive Modify flow) instead of being orphaned as "no source available" the way the prior baut -> automator rename was (CHANGELOG v6.7.1). ExternalModuleManager resolves aliases in getModuleByCode/resolveCanonicalCode; quickUpdate translates installed ids up front and removes the stale _bmad/<alias>/ directory after a successful migration. removals.txt gains bmad-auto-setup, the renamed skill id, so stale IDE-side skill dirs get pruned too. Also corrects bmad-modules.yaml's bmad-loop entry to match the real upstream repo content (src/bmad_loop/..., bmad-loop-setup skill) now that the bmad-auto -> bmad-loop rename has actually landed there, and moves bmad-loop to the top of the installer picker with a shorter, less wrap-prone description. |
||
|
|
4b6288d836 |
feat(installer): deprecate automator, add bmad-auto marketplace module (#2532)
* feat(installer): deprecate automator, add bmad-auto marketplace module Add a `deprecated` registry property (with `deprecation-message`): deprecated modules are hidden from the installer picker unless already installed, and the message is surfaced in the picker hint so existing users see the replacement. Mark bmad-automator deprecated, pointing to bmad-auto. Add bmad-auto as a new official module. Since its installable skills live outside a single module.yaml directory (it ships .claude-plugin/marketplace.json with module.yaml inside the -setup skill's assets/), add a `marketplace-plugin` flag that routes such registry modules through the PluginResolver — the same machinery custom-URL installs use — to copy the resolved skill dirs and module-help.csv. Manifest/version handling is unchanged (source: external). The flag is opt-in, so existing modules (e.g. WDS) are unaffected. * fix(installer): harden marketplace-plugin install (review #1/#5/#8) - Fail loud when a marketplace-plugin module's skills cannot be resolved from marketplace.json, instead of silently copying the -setup skill's assets/ dir (module.yaml + module-help.csv) with no skills — a broken partial install. - Extract _copyResolvedSkills() shared by install() and installFromResolution() so the official registry and custom-URL plugin paths cannot drift; this also picks up the synthesizedHelpCsv (strategy 5) handling in both paths. - Detect duplicate skill leaf names in _copyResolvedSkills and throw instead of letting two skills silently overwrite each other. * feat(installer): registry-driven post-install messages Add a `post-install-message` property to the module registry. After the install summary, any installed module that defines one shows an "action needed" notice; interactive installs require the user to acknowledge it (press Enter), while non-interactive (--yes) installs print it and continue so CI never blocks. Use it on bmad-auto to tell the user to run the bmad-auto-setup skill from their agent to finish setup (install the orchestrator + wire hooks/policy). * fix(installer): acknowledge post-install messages before the summary Show the "action needed" post-install messages (and gate on acknowledgment) before rendering the install summary, so "BMAD is ready to use!" remains the last thing the user sees. |
||
|
|
35b19db2e3 |
fix(installer): accept windows custom module paths (#2511)
* fix(installer): accept windows custom module paths * fix(installer): reject versioned windows local paths * style: format custom module manager --------- Co-authored-by: Brian <bmadcode@gmail.com> |
||
|
|
db744d405f |
fix: support nested group paths in SSH Git URLs (#2379)
Co-authored-by: Brian <bmadcode@gmail.com> |
||
|
|
9c291b7ca9 |
fix: resolve default branch explicitly when updating shallow-cloned custom modules (#2332)
With shallow clones (--depth 1), `origin/HEAD` becomes stale after the initial clone. The update path used `git reset --hard origin/HEAD` which never picked up new commits pushed to the default branch. Resolve the default branch name via `git symbolic-ref refs/remotes/origin/HEAD`, then fetch and reset against `origin/<branch>` explicitly. Falls back to `main` if origin/HEAD is not set. Co-authored-by: Brian <bmadcode@gmail.com> |
||
|
|
fea431fd2e |
fix(installer): read config.toml on re-run so user_name (and other user-scoped answers) are preserved as defaults (#2411)
loadExistingConfig only read from legacy _bmad/<module>/config.yaml files, but the installer writes user-scoped answers (user_name, communication_language, etc.) to _bmad/config.user.toml. On every subsequent reinstall those values were not loaded back, so the user got re-prompted instead of seeing their prior answers as defaults. Adds parseCentralToml — a lightweight line scanner matching the installer's own TOML output format — and updates loadExistingConfig to read config.toml and config.user.toml first (merging both into the same section buckets). Legacy per-module config.yaml files are kept as a fallback for pre-v6 installations. Co-authored-by: RobertOcsko <robert.ocsko@;seon.io> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Brian <bmadcode@gmail.com> |
||
|
|
065003fc95 |
Fix stale custom-source redeploys on quick-update (#2399)
* fix(installer): refresh custom-source cache on quick-update and persist channel marker * fix(installer): persist real next ref and atomically dedupe custom refresh * fix(installer): preserve custom-source cache when remote unreachable When git fetch fails against an existing custom-module cache, cloneRepo previously wiped the cache and attempted a fresh clone, which then also failed for the same reason (network down, repo deleted/moved, auth revoked) — leaving the user with no usable cache. With the new quick-update refresh path calling cloneRepo for every cached custom module, this turned transient remote outages into cache loss on every quick-update. - cloneRepo: on fetch failure with an existing cache, keep the previous clone and surface a warning via prompts.log.warn instead of removing the cache. The downstream metadata write uses the existing HEAD. - _refreshRepoCacheOnce: update the comment to reflect that the common "remote unreachable but cache exists" case is now handled inside cloneRepo; warn on the remaining unrecoverable failures so they aren't silent. Tests: 349 passed, 0 failed. --------- Co-authored-by: Brian Madison <bmadcode@gmail.com> |
||
|
|
74cf467d57 |
v6.7.0: bundle module registry, retire marketplace, refresh display names (#2388)
* feat(installer): bundle module registry, retire marketplace, refresh display names Prepares v6.7.0 for release: - Moves bundled module list from tools/installer/modules/registry-fallback.yaml to bmad-modules.yaml at repo root; renames to reflect single-source-of-truth role. - Retires the remote marketplace registry fetch in ExternalModuleManager; the installer now reads the bundled YAML only. - Adds WDS (Whiteport Design Studio) entry alongside BMM, BMB, BMA, CIS, GDS, TEA. - Refreshes display names and descriptions on every bundled module; TEA repositioned after BMM in the picker. - Adds plugin_name override field on registry entries so modules whose marketplace.json declares a plugin under a different name than the installer code (e.g. WDS uses bmad-wds) match without falling back to the single-plugin heuristic. - Removes the community modules picker from the interactive installer; previously installed community modules are preserved on update and can still be installed via --custom-source. - Renames the custom-source confirm prompt for clarity. CHANGELOG.md updated with the full v6.7.0 entry. * feat(installer): fully retire community catalog plumbing Removes the last marketplace network connections from the installer. The v6.7.0 first pass retired the official-registry fetch but left CommunityModuleManager + RegistryClient in place, which still fetched community-index.yaml and categories.yaml on every install to support the channel-gate and update flows. This commit: - Deletes tools/installer/modules/community-manager.js and registry-client.js entirely. - Strips CommunityModuleManager calls from ui.js (channel gate + update channels), core/manifest.js (getModuleVersionInfo), core/installer.js (resolution + installed-modules listing), and modules/official-modules.js (findModuleSource fallback + pre-install plugin resolution + post-install manifest entry). - Simplifies installFromResolution: community branch removed; all non-external installs are now treated as custom-source. - Removes corresponding test suites (CommunityModuleManager unit tests and the entire RegistryClient suite). - Updates CHANGELOG with the migration note. After this commit, grep confirms zero references to the bmad-plugins- marketplace registry from the installer. The only remaining 'marketplace' references are about per-repo .claude-plugin/marketplace.json files, which the installer reads from cloned custom-source repos. |
||
|
|
724867d48d |
fix(installer): descriptive error when module definition missing after clone (#2377)
* fix(installer): throw descriptive error when module definition missing after clone When a stable tag predates a module restructure (e.g. baut v1.14.0 had payload/source dirs, but the registry pointed to skills/module.yaml which only exists on main), findExternalModuleSource silently returned the configured but non-existent path. This caused a confusing ENOENT inside getFileList/copyModuleWithFiltering rather than a clear error. Now throws with the version that was cloned and a --next hint when the install channel was stable, so users know exactly how to recover. Closes #2372 * style: fix prettier formatting in external-manager.js * style: apply prettier formatting |
||
|
|
a3e0545847 | feat(installer): register automator module | ||
|
|
e36f219c81 |
refactor(catalog): rename after/before to preceded-by/followed-by (#2360)
* refactor(catalog): rename after/before columns to preceded-by/followed-by The bare prepositions `after` and `before` had no subject anchor, leaving the dependency direction ambiguous: "X has Y in its `after` column" reads plausibly as either "Y comes after X" or "X comes after Y". An LLM catalog consumer just got the direction wrong because of this. `preceded-by` / `followed-by` are passive-voice participles whose grammar locks the subject (the skill in this row) and forces a single reading: "X is preceded by Y" can only mean Y comes first. Rename applied to: - module-help.csv headers (bmm-skills, core-skills) - bmad-help SKILL.md schema doc + descriptions - installer.js mergeModuleHelpCatalogs header string - plugin-resolver.js _buildSynthesizedHelpCsv header string - bmad-manifest.json keys (bmad-product-brief, bmad-prfaq) - distillate-format-reference.md example manifest The separate `required` column continues to carry hard-gate semantics; the renamed columns are pure soft sequencing hints, as already documented in bmad-help. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * style(installer): wrap long header strings per prettier * feat(installer): warn on non-canonical module-help.csv headers mergeModuleHelpCatalogs now compares each per-module file's header against the canonical schema and emits a one-shot prompts.log.warn per module on drift, naming both the expected and actual header. Data continues to load positionally so external modules built against the old after/before schema still install cleanly — the warning is the maintainer signal to rename their columns. Centralize the canonical header in modules/module-help-schema.js so the merger and the synthesizer (PluginResolver._buildSynthesizedHelpCsv) read the same source of truth; future column renames are one edit. Verified by installing all four bmad-org external modules (bmb, cis, gds, tea) — every one ships the legacy after/before header today and now fires an advisory warning while still merging cleanly into _bmad/_config/bmad-help.csv with the canonical column names. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
fcf20f1c7b |
Fix/azure devops url parsing (#2269)
* fix(installer): handle deep-path URLs in custom module source parser Rewrite parseSource() from host-specific regex to generic URL-based parser so Azure DevOps _git paths and other multi-segment repo URLs are preserved in cloneUrl and cacheKey. Closes #2268 * test(installer): add Azure DevOps URL tests and wire into CI - Add 18 assertions for dev.azure.com and visualstudio.com URLs - Cover modern ADO, legacy ADO, .git suffix, ?path= subdir variants - Add test:urls script to test and quality npm chains --------- Co-authored-by: Brian <bmadcode@gmail.com> |
||
|
|
3da984a491 |
fix(config): promote project_name to core (closes #2279) (#2348)
* fix(config): promote project_name to core, fixes #2279 project_name was a bmm-specific prompt despite being a universal project-level concept used by every module — including core skills like bmad-brainstorming, which loads from _bmad/core/config.yaml and was silently broken because project_name lived under bmm. Users without bmm installed could not run brainstorming at all. Move: - src/core-skills/module.yaml: declare project_name with prompt "What is your project called?" and default {directory_name}, matching what bmm previously had. - src/bmm-skills/module.yaml: remove the bmm definition; add project_name to the "Variables from Core Config inserted" header comment so contributors can see what's inherited. Migration for existing installs: - tools/installer/modules/official-modules.js: after loadExistingConfig reads each per-module config.yaml, hoist any keys that are now declared in core but appear under non-core modules. Without this, the partition logic in writeCentralConfig (which strips core keys from non-core buckets) would silently drop the user's prior project_name on the next quick-update. Generic — handles project_name today and any future module→core promotions. - The hoist preserves precedence: an existing core value beats a stale module-side copy. --yes seed: - tools/installer/ui.js: add project_name to the hardcoded core seed (using path.basename(directory) to match the {directory_name} default) so non-interactive fresh installs populate it. Without this the seed silently omits project_name and core skills fall back to literals. Tests: - test/test-installation-components.js Suite 43 (9 assertions) covers the schema move, the loadExistingConfig hoist, and the precedence rule. - Suite 35 fixture updated: project_name moved from bmm bucket to core, with a stale bmm copy left in place to verify it gets stripped. Verified manually: - Fresh install -y: project_name lands in [core] of config.toml. - Existing install with project_name in bmm/config.yaml: quick-update hoists it to [core] and strips it from [modules.bmm]. * fix(installer): harden config-load against malformed config.yaml Per augment review on #2348: loadExistingConfig stored any truthy yaml.parse result (including scalars like '42'), which would later crash _hoistCoreKeysFromLegacyModuleConfigs at \`key in cfg\` with "Cannot use 'in' operator to search for ... in 42". - loadExistingConfig: only keep parses that are plain objects (not scalars or arrays). A corrupt config.yaml is now treated the same as a parse error — skipped, not crashed-on. - _hoistCoreKeysFromLegacyModuleConfigs: belt-and-suspenders type guards on _existingConfig.core (in case it's populated by some other path) and on each module cfg in the loop. - Test Suite 43 adds 2 assertions covering a scalar core/config.yaml: loadExistingConfig must not crash, and bmm.project_name must still hoist into a clean core bucket. |
||
|
|
3e89b30b3c |
fix: use full update path when --custom-source is passed with --yes (#2336)
* fix: use full update path when --custom-source is passed with --yes When --yes is used on an existing install, the installer auto-selects quick-update. However, quick-update never re-clones custom module repos — it only reads whatever is already in the cache. This means --custom-source with a new version tag (e.g. @1.1.0) is silently ignored and the previously cached version (e.g. 1.0.1) is reported as "already up to date". Default to the full update path when --custom-source is present, so the custom repo gets re-cloned at the requested version. Also ensure all installed modules are included in the selection when --yes is combined with --custom-source, preventing previously installed modules from being removed. * fix: address review feedback on choices.find() and comment clarity * style: prettier fix for empty-body methods in custom-module-manager --------- Co-authored-by: Brian <bmadcode@gmail.com> |
||
|
|
b4d73b7daf |
Fix installer custom modules http (#2344)
* fix(installer): preserve http protocol in custom module clone URLs Previously, parseSource() hardcoded 'https://' when building cloneUrl, forcing http:// Git URLs (e.g., internal LAN hosts) to upgrade to https. This broke cloning for self-hosted Git servers that only serve over HTTP. - Capture the protocol from the regex match instead of discarding it - Update JSDoc and inline comments to document HTTP support - Update install-custom-modules docs (EN, ZH, VN) to list HTTP URL type Fixes the --custom-source flag for http:// addresses. * docs(installer): update JSDoc to mention HTTP support in cloneRepo Add HTTP to the cloneRepo method's JSDoc param description. Also fixes minor spacing in empty arrow functions (formatting). * docs(installer): fix JSDoc annotation for cloneRepo param Correct @param backtick escaping in cloneRepo JSDoc. Also documents HTTP as a supported protocol alongside HTTPS and SSH. --------- Co-authored-by: 关惠民 <9155544@qq.com> |
||
|
|
6ff74ba662 |
fix(installer): route community installs through PluginResolver when marketplace.json ships (#2331)
* fix(installer): route community installs through PluginResolver when marketplace.json ships Community-catalog installs ignored .claude-plugin/marketplace.json, so modules that nest module.yaml inside a setup skill's assets/ directory (e.g. Strategy 2 in PluginResolver) ended up half-installed: only module-help.csv and the generated config.yaml landed in _bmad/<code>/, while the actual skill source trees and module.yaml never got copied. The install would silently emit "could not locate module.yaml" warnings and leave .agents/skills/ without the module's skills. The fix wires the existing PluginResolver onto the community path: - CommunityModuleManager.cloneModule now detects marketplace.json after the clone+ref-checkout completes and runs PluginResolver. The resolution is stamped with channel/sha/registryApprovedTag/registryApprovedSha and cached in _pluginResolutions, mirroring the existing _resolutions cache. - OfficialModules.install consults the community plugin resolution and delegates to installFromResolution (the same code path custom-source installs already use). installFromResolution branches on communitySource to write source: 'community' with the registry's approved tag/sha and channel. - resolveInstalledModuleYaml now searches the community-modules cache root in addition to the external-modules cache, and the BMB setup-skill detector walks src/skills/ and skills/ (not just the repo root) so collectAgents FromModuleYaml and writeCentralConfig can find module.yaml in nested marketplace-plugin layouts. Backward compatibility: repos without marketplace.json (e.g. WDS, which declares module_definition: src/module.yaml at the root) continue through the legacy findModuleSource path with no behavior change. Verified against the live zarlor/suno-band-manager community module and a 23-check fixture suite covering Suno-shape, WDS-shape, and bare-repo layouts. * fix(installer): harden community marketplace.json resolution path Address review feedback on the community marketplace.json install path: - Wrap PluginResolver.resolve() in try/catch so a malformed plugin entry falls through to the legacy install path with a warn instead of crashing cloneModule. - Stop mutating the resolver's return object; shallow-clone before stamping community provenance so install state cannot leak back into resolver-owned objects. - Warn when _selectPluginForModule lands on the single-plugin fallback with a name that doesn't match the registry code or module_definition hint, so a misconfigured marketplace.json can't silently install the wrong plugin. - Add CommunityModuleManager.resolveFromCache() and call it from OfficialModules.install() when the in-process plugin cache is empty, so callers that reach install() without pre-cloning still get the marketplace-aware path. Reuses an existing channel resolution when present, otherwise synthesizes a stable-channel stub from the registry entry plus the cached repo's HEAD. - Align installFromResolution()'s returned versionInfo.version with manifestEntry.version precedence (communityVersion || cloneRef || ...) so downstream summaries match what was written to the manifest. Tests: lint, format:check, lint:md, test:install (290), test:channels (83), test:refs (7) all green. |
||
|
|
3d824d4c0f |
feat(installer): channel-based version resolution + interactive channel management (#2305)
* feat(installer): channel-based version resolution for external modules Adds stable/next/pinned channel resolution so external/community modules install at released git tags by default instead of tracking main HEAD. Manifest now records channel, resolved version, and SHA per module for reproducible installs. CLI flags: --channel, --all-stable, --all-next, --next=CODE (repeatable), --pin CODE=TAG (repeatable). Precedence: pin > next > channel > registry default > stable. --yes accepts patch/minor upgrades but refuses majors. Interactive "Ready to install (all stable)?" gate with a per-module picker (stable/next/pin) when declined. Re-install prompts classify tag diffs as patch/minor/major with semver-class-dependent defaults. Legacy version:null manifests get a one-time migration prompt. Custom modules gain an optional @<ref> URL suffix for pinning (https, ssh, /tree/<ref>/subdir forms supported; local paths rejected). Community modules honor --next/--pin overrides with a curator-bypass warning; default path still enforces the approved SHA. Quick-update now reads the manifest's recorded channel per module so pinned installs don't silently roll forward. * feat(installer): interactive channel switch, upgrade refusal, unified docs Builds on the channel-resolution foundation. The installer now lets users flip a module between stable, next, and pinned after install — either interactively via a "Review channel assignments?" gate, or by flag. Quick and modify re-installs classify stable upgrades; under non-interactive flows, patches and minors apply automatically but majors are refused with a pointer to --pin. Fallback behavior for GitHub rate-limit / network failures is now cache- aware: re-installs reuse the recorded ref silently; fresh installs abort with actionable guidance (set GITHUB_TOKEN or use --next/--pin). Bundled modules (core, bmm) warn when targeted by --pin or --next so users aren't left wondering why the flag had no effect. Install summary labels no longer mangle "main" into "vmain"; next-channel entries render as "main @ <short-sha>" instead. Bundled modules are now correctly skipped from all channel prompts and tag-API lookups. Docs consolidated into a single how-to. install-bmad.md now covers the interactive flow, the channel model (stable/next/pinned plus the npm dist-tag axis for core/bmm), the re-install upgrade prompts, the full flag reference, copy-paste recipes, and troubleshooting. The old non-interactive-installation.md is reduced to a redirect stub. * fix(installer): review fixes + unit tests for channel resolution - ui.js: import parseGitHubRepo; fixes ReferenceError in the interactive channel picker's stable-tag pre-resolve path. - community-manager: pinned modules now fetch+checkout the pin tag on cache refresh instead of resetting to origin/HEAD (was silently drifting to main on re-install). - channel-plan: parseChannelOptions returns acceptBypass so --yes auto-confirms the curator-bypass prompt; headless --next/--pin installs of community modules no longer hang. - community-manager: simplify recordedVersion (dead ternary branch). - custom-module-manager: drop "or sha" from the @<ref> comment (git clone --branch rejects raw SHAs); update-path fetches origin <ref> so /tree/<branch>/ URLs work too. - install-bmad.md: rename "Headless / CI installs" to "Headless CI installs" so the stub's #headless-ci-installs anchor resolves. - test/test-installer-channels.js: 83 unit tests for channel-plan and channel-resolver pure modules; wired into npm test as test:channels. * fix(installer): address CodeRabbit review findings - ui.js: skip stable-channel upgrade classification when the user has already declared intent via --pin/--next=/--channel or the review gate. Prevents the decline / major-refused / fetch-error branches from silently overwriting an explicit pin with prev.version. - external-manager.js: short-circuit cloneExternalModule when the requested plan matches an existing in-process resolution and the cache is valid. Avoids redundant resolveChannel() + git fetch on every same-plan lookup in a single install. - installer.js: fall back to CommunityModuleManager.getResolution() when no external resolution exists, so community module result rows carry newChannel/newSha instead of null under --next/--pin. - installer.js: don't label a module as "no change" when its version string is 'main'/'HEAD' — the SHA may have moved and preVersions doesn't track the prior SHA. Show "(refreshed)" instead. - official-modules.js: match versionInfo.version to the manifest's cloneRef || (hasGitClone ? 'main' : version) expression so summary lines report the cloned ref for git-backed custom installs. - install-bmad.md: clarify that sha is only written for git-backed modules and that rerunning the same --modules on another machine does not reproduce stable-channel installs — convert recorded tags into explicit --pin flags for cross-machine reproducibility. |
||
|
|
2395b0e2ed |
fix: bmad tea instal version (#2298)
* fix: bmad tea instal version * fix: addressed review comments |
||
|
|
0dbfae675b |
feat(skills): TOML-based agent and workflow customization (#2284)
* feat(skills): TOML-based agent customization with stdlib Python resolver Re-applies PR #2282's three-layer customization model (skill defaults → team → user) but swaps YAML for TOML and uv for stdlib tomllib. Users no longer need uv, pip, or a virtualenv — plain python3 (3.11+) is sufficient, since tomllib shipped in the standard library. ## Schema changes vs PR #2282 - Flat agent schema: fields live directly under [agent], no nested metadata/persona sub-tables. Easier to author, less indentation. - Non-configurable identity: name and title are declared in customize.toml as source-of-truth metadata (for future skill-manifest generation) but SKILL.md ignores overrides there — identity is hardcoded to preserve brand recognition. - role redefined: now describes what the skill does for the user within its module phase, not a restatement of the title. - persistent_facts replaces the activation-time file-context load AND the old memories concept. Entries can be literal sentences or file: prefixed paths/globs; avoids collision with the upcoming runtime memory sidecar. - activation_steps_prepend / activation_steps_append harmonized across agents and workflows (replaces agent-specific critical_actions). - [workflow] namespace mirrors [agent] for workflow customization. Same four structural rules, same field vocabulary. ## Resolver (src/scripts/resolve_customization.py) Four purely structural merge rules, zero field-name hardcoding: - Scalars: override wins - Tables: deep merge - Arrays of tables where every item has `code` or `id`: merge by that key (matching keys replace, new keys append) - Any other array: append No removal mechanism — overrides cannot delete base items. Fork the skill or override by code with a no-op value to suppress defaults. ## Agents ported (6) All six BMad agents now ship customize.toml + rewritten SKILL.md: analyst (Mary), tech-writer (Paige), pm (John), ux-designer (Sally), architect (Winston), dev (Amelia). Each uses the same 8-step activation template: resolve → execute prepend → adopt persona → load persistent facts → load config → greet (with {agent.icon}) → execute append → dispatch or present menu. Step 8 supports fast-path invocation: "hey Mary, let's brainstorm" dispatches the matching menu item directly after greeting, skipping the menu render when intent is clear. Chat, clarifying questions, and bmad-help remain available when nothing on the menu fits. ## Installer + tooling - _bmad/scripts/ provisioned on install (copies src/scripts/) - _bmad/custom/ seeded with .gitignore for *.user.toml on fresh install - Non-module-dir filter extended to skip _memory, memory, docs, scripts, and custom when scanning for modules - Dead _config/agents/ directory no longer created - metadata.capabilities removed from agent-manifest.csv and schema - eslint config extended to cover src/scripts/** - validate-file-refs.js knows about custom/ as install-only ## Deferred for follow-up - bmad-product-brief workflow port (the pilot that demonstrates [workflow] + on_complete) - Translated docs (cs/fr/vi-vn/zh-cn) — regenerate from English * feat(skills): port bmad-product-brief to TOML workflow customization Completes the customization surface rollout by giving the product-brief workflow the same override model as the six BMad agents, under the [workflow] namespace instead of [agent]. ## customize.toml Mirrors the agent shape under [workflow] with: - activation_steps_prepend / activation_steps_append (harmonized across agents and workflows — same field names, same append semantics) - persistent_facts with the file: convention, seeded with file:{project-root}/**/project-context.md - on_complete scalar (renamed from PR #2282's skill_end for clarity — reads cleaner as "what runs when the workflow completes") ## SKILL.md 7-step workflow activation: 1. Resolve workflow block 2. Execute prepend steps 3. Load persistent facts (file: or literal) 4. Load config 5. Greet if not already 6. Execute append steps 7. Stage 1 — Understand Intent python3 + stdlib tomllib invocation; no uv required. ## Prompt file changes - Path normalization: ../agents/ → agents/, ../resources/ → resources/, bare foo.md → prompts/foo.md. All references now resolve from the skill root (matches the convention documented in SKILL.md). - Paths: meta-line added to each of the 4 prompt files that reference other files, reinforcing "bare paths resolve from skill root" so the LLM doesn't lose the convention when operating two hops into a prompt chain. - finalize.md terminal stage now calls the resolver for workflow.on_complete — non-empty values run as the final step. ## Validation - Resolver output verified: 4 workflow fields returned cleanly. - validate-file-refs.js: 254 files scanned, 139 refs checked, 0 broken. - test:refs: passing. * docs(skills): enterprise customization recipes + workflow template variable Three independent improvements bundled because they share the same surface (workflow/agent customization) and landed from the same design discussion: ## Fallback sentence disambiguated (7 SKILL.md files) The "if the script fails" fallback used to say `{project-root}/_bmad/ custom/{skill-name}.toml` for the team override and then just `{skill- name}.user.toml` for the user override, leaving the user file's location implicit. LLMs could reasonably guess skill root or project root instead. Replaced with an unambiguous numbered list that spells out the full path for every file in the merge chain. ## Product-brief: stage promotion + brief_template variable - Promoted `## Stage 1: Understand Intent` from a nested step inside "On Activation" to a top-level section. The previous "Step 7: Stage 1 — Understand Intent → Proceed to Stage 1 below" was mechanical numbering pretending to be a step. Activation now ends cleanly at Step 6; Stage 1 is a peer section. - Added `brief_template` as a workflow-level scalar customization defaulting to `resources/brief-template.md`. Stage 4 reads `{workflow.brief_template}` instead of the hardcoded path, so orgs can point at their own template under `{project-root}/...` without forking the skill. ## New doc: docs/how-to/extend-bmad-for-your-org.md Four worked recipes that together cover most enterprise scenarios: 1. Shape an agent across every workflow it dispatches (dev agent + Context7 MCP + Linear search — the highest-leverage pattern) 2. Enforce org conventions inside a specific workflow (product-brief + compliance-field persistent_facts) 3. Publish completed outputs to external systems (product-brief + Confluence + Jira via MCP, gated on user confirmation for Jira) 4. Swap in your own output template (product-brief + brief_template variable swap) Opens with the two-layer mental model (agent spans workflows, workflow is local) so readers pick the right granularity before reading any recipe. Closes with a "Combining Recipes" section showing all four composed. Cross-linked from customize-bmad.md. ## Validation - Resolver: workflow.brief_template returns the default cleanly. - validate-file-refs.js: 254 files scanned, 146 refs checked (+7 from this commit), 0 broken. * docs(skills): encourage CLAUDE.md/AGENTS.md reinforcement of critical rules Added a "Reinforce Global Rules in Your IDE's Session File" section to extend-bmad-for-your-org.md. BMad customizations only load when a skill activates, but IDE session files (CLAUDE.md, AGENTS.md, cursor rules, copilot-instructions) load every turn — worth restating the most critical rules there too so they survive ad-hoc chat outside a BMad skill. Includes a one-line example reinforcing the Recipe 1 Context7 rule, plus a scope table that clarifies what each layer is for: - IDE session file: universal, every session, keep succinct - Agent customization: persona-specific, every dispatched workflow - Workflow customization: one workflow run Emphasizes brevity — noise in the session file crowds out signal. * docs(skills): add Named Agents explanation doc New docs/explanation/named-agents.md walking through the three-legged stool (skills + named agents + customization) with the "Hey Mary, let's brainstorm" activation flow as the narrative thread. Covers: - Why named agents vs menu-driven or prompt-driven alternatives - The 8-step activation flow and what each step contributes - How customization scales the model beyond a single developer - Cross-links to the how-to docs for implementation details Sits alongside brainstorming.md, quick-dev.md, party-mode.md in the explanation folder — feature narratives for users who want to understand why BMad is designed the way it is, not just how to use it. * docs(skills): clarify that keyed-merge requires a single identifier key per array Review feedback (PR #2284) flagged that the merge-rules wording was ambiguous: "every item has a `code` or `id` field" could reasonably be read as "each item individually has at least one of the two", allowing arrays to mix `code` and `id` across items. The resolver has always required all items share the *same* identifier key (all `code`, or all `id`). Mixed arrays fall through to append — intentional, because mixing identifier keys within one array is a schema smell and any guess about which key should merge creates a worse trap than the append-fallback. Clarified in three places: - Merge-rules table in customize-bmad.md: "every item shares the **same** identifier field" - `code`/`id` convention paragraph: "pick **one** convention ... and stick with it across the whole array" - Resolver docstring and `_detect_keyed_merge_field` docstring: explicit note that mixed arrays fall through with rationale No behavior change. * docs(skills): address CodeRabbit review — fallback rules, OS claim, headless greeting Three fixes from PR #2284 review feedback: ## 1. Fallback merge wording (7 SKILL.md files) Every SKILL.md told the LLM to merge the three customization files "in priority order (later wins)" when the resolver fails. That reads as shallow last-write-wins — but the resolver does structural merge (scalars override, tables deep-merge, code/id-keyed arrays merge by key, other arrays append). Following the old wording manually would have silently stripped base `principles`, `persistent_facts`, and `menu` items whenever a team override was present. Expanded the fallback sentence to restate the four structural rules explicitly, matching the resolver's behavior. Applied to all 6 agents + bmad-product-brief workflow. ## 2. Python 3.11 / OS shipping claim (customize-bmad.md) The docs claimed "macOS 13+, Ubuntu 22.04+, Debian 12+, Fedora 37+ all ship 3.11 or newer." Inaccurate — Ubuntu 22.04 defaults `python3` to 3.10.6 (3.11 is a separate package), and macOS doesn't really ship Python by default anymore. Replaced with honest guidance: check `python3 --version` and note that macOS without Homebrew and Ubuntu 22.04 default to 3.10 or earlier. ## 3. Autonomous mode greeting gate (bmad-product-brief) Product-brief's activation-mode detection documents autonomous mode as "produce complete brief without interaction" — but Step 5 greeted unconditionally, adding conversational output before the headless artifact. Gated the greeting on `{mode}` != `autonomous`. ## Dismissed (replied on thread) - `.gitignore` migration from *.user.yaml to *.user.toml: YAML installer code was in reverted #2282, never released. No users affected. Same rationale as Augment's earlier thread. Validated: 254 files, 146 refs, 0 broken. test:refs 7/7, test:install 242/242. * docs: rename Extend to Expand throughout customization docs |
||
|
|
e550df2474 |
Revert "feat(skills): YAML-based agent customization with Python resolver (#2282)" (#2283)
This reverts commit
|
||
|
|
bd1c0053d5 |
feat(skills): YAML-based agent customization with Python resolver (#2282)
Three-layer customization (skill defaults → team → user) for BMad agents
and any skill that opts in. Users edit `_bmad/custom/{skill-name}.yaml`
(team, committed) or `{skill-name}.user.yaml` (personal, gitignored);
customizations survive updates.
Resolver is a Python script using PEP 723 inline metadata, invoked via
`uv run` so deps auto-install into a cached isolated env on first call.
This aligns with Anthropic's Agent Skills spec and BMB conventions, and
keeps the dependency declared (scannable by pip-audit/Dependabot) rather
than vendored.
## Design choices
- **Agent identity is hardcoded** in SKILL.md (name, title, Overview prose)
so skills can be invoked reliably by role *or* default name. Brand
recognition is preserved; customization shapes behavior, not identity.
- **Luminary-anchored personas** (e.g. "Channels Martin Fowler's
pragmatism and Werner Vogels's cloud-scale realism") deliver ~55%
token savings per agent while preserving distinctive voice beats.
- **Universal per-field merge rules** with v6.1-compatible agent
semantics: metadata shallow-merge, persona replace, critical_actions
and memories append, menu merge-by-code, all else deep-merge.
- **Workflow customization** shares the same surface — `bmad-product-brief`
pilots `activation_steps_prepend`, `activation_steps_append`, and
`skill_end` hooks that any workflow-style skill can adopt.
## Infrastructure
- `_bmad/scripts/` houses shared Python scripts (resolver + future).
- `_bmad/custom/` is provisioned empty with a seeded `.gitignore` for
`*.user.yaml` on fresh installs.
- Installer filters ensure `scripts/`, `custom/`, and sidecar-generated
`memory/` directories are never treated as modules.
- Dead v6.1 code cleaned up: `_config/agents/` no longer created,
`metadata.capabilities` removed from schema and CSV manifest.
|
||
|
|
d09363b1b2 |
feat(installer): use GitHub API as primary fetch with raw CDN fallback (#2248)
* feat(installer): use GitHub API as primary fetch with raw CDN fallback Corporate proxies commonly block raw.githubusercontent.com while allowing api.github.com. Add fetchGitHubFile() to RegistryClient that tries the GitHub Contents API first, falling back to the raw CDN transparently. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(installer): cap redirect depth and preserve dual-fallback errors Add maxRedirects parameter to fetch() and _fetchWithHeaders() to prevent unbounded redirect recursion. Wrap CDN fallback in try/catch and throw AggregateError with both API and CDN errors for better diagnostics. Extract marketplace repo coordinates into named constants in external-manager. * chore(installer): drop unused fetchJson and fetchGitHubJson Neither method has any callers. Also drop the corresponding test. * refactor(test): fold registry tests into test-installation-components No reason for RegistryClient tests to be a separate runner — the same file already tests the registry consumers in Suite 33. Drop test:registry from package.json scripts and quality gate. * fix(installer): include URL, API message, and rate-limit info in HTTP errors Non-2xx responses previously yielded bare `HTTP 403`. Now surface the request URL, GitHub's JSON error message (or body snippet), X-RateLimit-Reset when quota is exhausted, and Retry-After. Turns a mystery 403 into 'rate limit exhausted; resets at 2026-04-15T18:00:00Z' — the difference between 'try GITHUB_TOKEN' and a wild goose chase. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
a6d075bd0b |
fix(installer): replace fs-extra with native node:fs to prevent file loss
fs-extra routes all operations through graceful-fs, which globally monkey-patches node:fs with a deferred retry queue. During multi-module installs (~500+ file ops), retried unlink operations from one module's remove phase can fire after the next module's copy phase has written files, silently deleting them non-deterministically. Replace fs-extra with a thin fs-native.js wrapper over node:fs/promises and node:fs. All 21 consumers now use native APIs with no global monkey-patching, eliminating the retry-queue race condition entirely. Closes #1779 |
||
|
|
ea99b7ece5 |
chore(installer): remove 1,683 lines of dead code (#2247)
* chore(installer): remove dead code across installer modules
Delete 3 entirely dead files (agent-command-generator, bmad-artifacts,
module-injections) and remove ~50 unused exports from manifest.js,
cli-utils.js, prompts.js, path-utils.js, official-modules.js,
external-manager.js, custom-module-manager.js, and registry-client.js.
Removes corresponding dead tests.
* fix(installer): restore currentProjectDir writes for placeholder expansion
The previous commit removed the three assignments to
OfficialModules.currentProjectDir as dead code, but buildQuestion()
still reads the property to resolve {directory_name} placeholders in
module config defaults during interactive collection. Without the
writes, any module default containing {directory_name} would surface
the literal placeholder to users.
|
||
|
|
97d32405d0 |
feat(installer): universal source support for custom module installs (#2233)
* feat(installer): add plugin resolution strategies for custom URL installs When installing from a custom GitHub URL, the installer now analyzes marketplace.json plugin structures to determine how to locate module registration files (module.yaml, module-help.csv). Five strategies are tried in cascade: 1. Root module files at the common parent of listed skills 2. A -setup skill with registration files in its assets/ 3. Single standalone skill with registration files in assets/ 4. Multiple standalone skills, each with their own registration files 5. Fallback: synthesize registration from marketplace.json metadata and SKILL.md frontmatter Also changes the custom URL flow from confirm-all to multiselect, letting users pick which plugins to install. Already-installed modules are pre-checked for update; new modules are unchecked for opt-in. New file: tools/installer/modules/plugin-resolver.js Modified: custom-module-manager.js, official-modules.js, ui.js * fix(installer): address PR review findings for plugin resolver - Guard against path traversal in plugin-resolver.js: skill paths from unverified marketplace.json are now constrained to the repo root using path.resolve() + startsWith check - Skip npm install during browsing phase: cloneRepo() accepts skipInstall option, used in ui.js before user confirms selection, preventing arbitrary lifecycle script execution from untrusted repos - Add createModuleDirectories() call to installFromResolution() so modules with declarative directory config are fully set up - Fix ESLint: use replaceAll instead of replace with global regex * fix(installer): pass version and repoUrl to manifest for custom plugins installFromResolution was passing empty strings for version and repoUrl, which the manifest stores as null. Now threads the repo URL from ui.js through resolvePlugin into each ResolvedModule, and passes the plugin version and URL to the manifest correctly. * fix(installer): manifest-generator overwrites custom module version/repoUrl ManifestGenerator rebuilds the entire manifest via getModuleVersionInfo for every module. For custom modules, this returned null for version and repoUrl because it only checked _readMarketplaceVersion (which searches for marketplace.json on disk) and hardcoded repoUrl to null. Now checks the resolution cache first to get the correct version and repo URL. * fix(installer): resolve custom modules from disk cache on quick update When the resolution cache is empty (fresh CLI process, e.g. quick update), findModuleSourceByCode only matched plugin.name against the module code. This failed for modules like "sam" and "dw" where the code comes from module.yaml inside a setup/standalone skill, not from the plugin name in marketplace.json. Now runs the PluginResolver on cached repos when the direct name match fails, finding the correct module source and re-populating the cache for the install pipeline. * feat(installer): universal source support for custom modules Replace GitHub-only custom module installation with support for any Git host (GitHub, GitLab, Bitbucket, self-hosted) and local file paths. - Add parseSource() universal input parser (local paths, SSH, HTTPS with deep path/subdir extraction for GitHub, GitLab, Gitea) - Add resolveSource() coordinator: parse -> clone if URL -> detect discovery vs direct mode (marketplace.json present or not) - Clone-first approach eliminates host-specific raw URL fetching - 3-level cache structure (host/owner/repo) with .bmad-source.json metadata for URL reconstruction - Local paths install directly without caching; localPath persisted in manifest for quick-update source lookup - Direct mode scans target directory for SKILL.md when no marketplace.json - Fix version display bug where walk-up found parent repo marketplace.json and reported wrong version for custom modules * fix(installer): harden readMarketplaceJsonFromDisk and hoist require - Add try/catch to readMarketplaceJsonFromDisk so malformed JSON returns null instead of throwing an unhandled parse error - Hoist CustomModuleManager require outside the per-module loop in _installOfficialModules * fix(installer): restore validateGitHubUrl strictness and fix prettier - Restore original GitHub-only regex in deprecated validateGitHubUrl wrapper so existing tests pass (rejects non-GitHub URLs, trailing slashes) - Run prettier to fix formatting in custom-module-manager.js * feat(installer): add --custom-source CLI flag for non-interactive installs Allows installing custom modules from Git URLs or local paths directly from the command line without interactive prompts: npx bmad-method install --custom-source /path/to/module npx bmad-method install --custom-source https://gitlab.com/org/repo npx bmad-method install --custom-source /path/one,https://host/org/repo Works alongside --modules and --yes flags. All discovered modules from each source are auto-selected. * docs: add custom and community module installation guide New how-to page covering community module browsing, custom sources (any Git host, local paths), discovery vs direct mode, local development workflow, and the --custom-source CLI flag. Clarifies that .claude-plugin/ is a cross-tool convention, not Claude-specific. Also updates non-interactive installation docs with the new flag and examples, bumps sidebar ordering, and fixes --custom-source to install only core + custom modules when --modules is not specified. |
||
|
|
b744408783 |
feat(installer): community module browser and custom URL support (#2229)
* feat(installer): add community module browser and custom URL support Three-tier module selection: official, community (category drill-down with featured/search), and custom GitHub URL. - Add RegistryClient shared fetch utility - Add CommunityModuleManager with SHA-pinned cloning (refuses install if approved SHA cannot be reached; uses HEAD when no SHA set) - Add CustomModuleManager for arbitrary GitHub repo installation - Extend findModuleSource chain with community and custom fallthrough - Extend manifest to detect community and custom source types - Add Config.customModulesMeta for custom module metadata * fix: resolve review findings for community/custom module support - Remove redundant CommunityModuleManager instantiation in UI display - Remove dead customModulesMeta field from Config (never populated) - Add 35 unit tests for CustomModuleManager and CommunityModuleManager pure functions: URL validation, normalization, search, featured, categories * fix: preserve installed community/custom modules in modify flow When a user does "Modify Installation" and declines to browse community modules, previously installed community/custom modules are now auto-kept. If the user does browse, their selections are trusted (they can deselect). Also fix stale docs: class doc for SHA pinning, JSDoc return type. * fix: include community and custom modules in quick update Quick update now checks community registry and custom cache so installed community/custom modules are updated instead of skipped. * fix: use defaults for new config fields during quick update When quick update encounters new config fields (e.g., from a newly supported community module), use schema defaults silently instead of prompting the user. Quick update should be non-interactive. * test: add unit tests for SHA pinning, category filtering, and URL edge cases Cover SHA normalization (set vs null/trusted), listByCategory, getModuleByCode, and URL validation edge cases (HTTP, trailing slash, SSH without .git). Total: 243 tests. |
||
|
|
5e038a8ce4 |
feat(installer): remote registry + remove custom content (#2228)
* refactor(installer): remove custom content installation feature Remove the entire local filesystem custom content feature from the installer to make way for marketplace-based plugin installation. Deleted: custom-handler.js, custom-module-cache.js, custom-modules.js Removed: --custom-content CLI flag, interactive custom content prompts, custom module caching, manifest tracking, missing-source resolution, and related test suites. Updated docs across all translations. * fix: address review findings from Augment Fix admonition syntax (remove accidental space in :::note) across 4 translated docs files, and update stale JSDoc on listAvailable(). * feat(installer): fetch module list from marketplace registry Switch module list source of truth from bundled external-official-modules.yaml to the remote marketplace registry (registry/official.yaml) fetched via raw.githubusercontent.com. - Rewrite ExternalModuleManager to fetch from GitHub with local fallback - Simplify selectAllModules/getDefaultModules to use registry as single source - Registry order controls display order; built_in flag prevents cloning - Rename fallback file to registry-fallback.yaml in modules/ - Only show legacy migration message when legacy dirs actually exist |
||
|
|
5dbfb588ee |
refactor(installer): remove custom content installation feature (#2227)
* refactor(installer): remove custom content installation feature Remove the entire local filesystem custom content feature from the installer to make way for marketplace-based plugin installation. Deleted: custom-handler.js, custom-module-cache.js, custom-modules.js Removed: --custom-content CLI flag, interactive custom content prompts, custom module caching, manifest tracking, missing-source resolution, and related test suites. Updated docs across all translations. * fix: address review findings from Augment Fix admonition syntax (remove accidental space in :::note) across 4 translated docs files, and update stale JSDoc on listAvailable(). |
||
|
|
1f99eb0496 |
fix: preserve local custom module sources during quick update (#2172)
* fix: preserve local custom module sources during quick update Keep customModules in the generated main manifest so local custom module source paths survive update runs. Load those preserved source paths during stock quick update before falling back to the custom cache directory. This fixes the case where BMAD would drop customModules, lose the original source path for a local module, and then skip the module or try to re-cache from _bmad/_config/custom/<module>, which could fail with ENOENT after the cache directory was removed. Also adds an installation component regression test to verify customModules and sourcePath are preserved in manifest generation. Fixes #1582 * fix: ensure consistent formatting * refactor: extract quick update custom source assembly Move quick-update custom module source collection out of Installer and into CustomModules as assembleQuickUpdateSources(). This keeps discoverPaths() focused on consuming prepared install inputs while making the quick-update source assembly step explicit and easier to evolve. Also: - preserve customModules metadata in manifest regeneration for installed modules - drop stale customModules entries when modules are no longer installed - cover manifest preservation and manifest-backed quick-update sources in tests |
||
|
|
e0ea6a0500 |
fix: support skills/ folder as module source location (#2149)
The installer now finds module.yaml in both skills/ and src/ directories, including one level deep in subfolders. Updates bmb module-definition to skills/module.yaml to match its actual structure. |
||
|
|
513f440a23 |
refactor(installer): restructure installer with clean separation of concerns (#2129)
* refactor(installer): restructure installer with clean separation of concerns Move tools/cli/ to tools/installer/ with major structural cleanup: - InstallPaths async factory for path resolution and directory creation - Config value object (frozen) replaces mutable config bag - ExistingInstall value object replaces stateful Detector class - OfficialModules + CustomModules + ExternalModuleManager replace monolithic ModuleManager - install() is prompt-free; all user interaction in ui.js - Update state returned explicitly instead of mutating customConfig - Delete dead code: dependency-resolver, _base-ide, IdeConfigManager, platform-codes helpers, npx wrapper, xml-utils - Flatten directory structure: custom/handler → custom-handler, tools/cli/ → tools/installer/, lib/ directories removed - Update all path references in package.json, tests, CI, and docs * fix(installer): guard ExistingInstall.version and surface module.yaml errors Guard ExistingInstall.version access with .installed check in uninstall.js, ui.js, and installer.js to prevent throwing on empty/partial _bmad dirs. Surface invalid module.yaml parse errors as warnings instead of silently returning empty results. |