mirror of
https://github.com/bmad-code-org/BMAD-METHOD.git
synced 2026-09-19 08:11:52 +08:00
v6.6.0
640 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
91a57499e9 |
feat(installer): add --set and --list-options for non-interactive config (#2354)
Closes #1663. Adds two installer flags so module config options can be set without interactive prompts. Designed for CI scripts, Dockerfiles, and enterprise rollouts where the user wants to bake answers into the install command rather than answer prompts. `--set <module>.<key>=<value>` (repeatable) sets any module config option. `--list-options [module]` lists every key the installer can discover locally — built-in modules (`core`, `bmm`) plus any cached official modules. One flag scales to every module without growing the CLI surface per option. ```bash npx bmad-method install --yes \ --modules bmm --tools claude-code \ --set bmm.project_knowledge=research \ --set bmm.user_skill_level=expert \ --set core.user_name=Brian ``` ## How it works `--set` is a post-install patch. The installer runs its normal flow untouched, then `applySetOverrides` upserts each value into the relevant config files: - `_bmad/config.toml` (team scope, default) - `_bmad/config.user.toml` (user scope, when the key already lives there — so user-scope keys like `core.user_name` and `bmm.user_skill_level` keep their proper file) - `_bmad/<module>/config.yaml` (so declared schema keys carry forward via the existingValue path on the next install) A module without `_bmad/<module>/config.yaml` is skipped silently — no orphan sections in `config.toml` for uninstalled modules. ## Tradeoffs documented in install-bmad.md - **Verbatim values.** `--set bmm.project_knowledge=research` writes `"research"`, not `"{project-root}/research"`. The `result:` template is not applied. Pass it explicitly if you want the rendered form: `--set bmm.project_knowledge='{project-root}/research'`. - **Carry-forward, declared keys.** Free — values land in the per-module `config.yaml`, so the next install reads them as `existingValue` and they become the prompt default (accepted under `--yes`). - **Carry-forward, undeclared keys.** Best-effort. The value lives in `config.toml` for the current install but won't be re-emitted on the next install (the manifest writer's schema-strict partition drops unknown keys). Re-pass `--set` if needed. - **No "key not in schema" validation.** Whatever you assert is written. ## Security Prototype-pollution defense: `--set __proto__.x=1` would otherwise reach `overrides.__proto__[x] = 1` and pollute `Object.prototype`, cascading into every plain-object lookup in the process. Defense-in- depth via parser-level reserved-name rejection (`__proto__`, `prototype`, `constructor`) AND `Object.create(null)` for the override maps. Verified the attack reproduces without the guard and is blocked with it. ## What's intentionally NOT integrated `--set` deliberately does not touch the prompt / template / schema collection flow. No pre-seeding answers, no question filtering, no function-default evaluation, no schema-strict partition exemption. That earlier integration approach was tried and scrapped: it spread state across `Config`, `OfficialModules`, `manifest-generator`, both collection helpers, and required parallel plumbing for quick-update — every bug fix touched a different layer. The post-install patch model covers the actual user need (set a config value from CI) in ~330 lines of `set-overrides.js` without the schema gymnastics. ## Files - `tools/installer/set-overrides.js` (new): parser, prototype-pollution guard, `applySetOverrides` post-install patch, `upsertTomlKey` / `tomlString` / `tomlHasKey` line-based TOML helpers - `tools/installer/list-options.js` (new): module.yaml discovery + formatter for `--list-options` - `tools/installer/commands/install.js`: register `--set` / `--list-options` flags, early validation, `--list-options` exit-code handling (await `stream.write` callback then `process.exitCode` to avoid truncating piped output), thread `setOverrides` through to quick-update - `tools/installer/core/config.js`: carry `setOverrides` field for the post-install patch step - `tools/installer/core/installer.js`: invoke `applySetOverrides` after `writeCentralConfig` (covers regular install + quick-update via the shared install path) - `tools/installer/ui.js`: parse `--set` for early validation, warn about overrides targeting modules not in `--modules`, drop those entries before threading - `docs/how-to/install-bmad.md`, `README.md`: usage, routing rules, carry-forward semantics, tradeoffs ## Test plan Suite 44 (24 cases): parser, prototype-pollution guard, `tomlString` escaping, `upsertTomlKey` across insert/replace/missing-section/ empty-file/preserved-newline cases, `applySetOverrides` happy path + uninstalled-module skip + missing-user-toml-creation + empty-input no-op, `discoverOfficialModuleYamls` / `formatOptionsList` sanity (hermetic via `BMAD_EXTERNAL_MODULES_CACHE` temp dir). 355 total passing. Lint + prettier + markdownlint clean. E2E smoke verified across: - [x] `--set` writes correct files (team toml / user toml / per-module yaml) for declared and undeclared keys - [x] Quick-update without `--set` carries forward declared keys via `existingValue` path - [x] Quick-update WITH `--set` applies cleanly (uniform behavior across action types) - [x] `--set` for unselected module: warned, no orphan section - [x] Prototype pollution: rejected with non-zero exit - [x] `--list-options bmm` exit 0 with full output through pipe; `--list-options nope` exit 1 - [x] Translated docs (`docs/{cs,fr,vi-vn,zh-cn}/`) intentionally not touched — they'll lag behind English until the translation pipeline runs |
||
|
|
48a7ec8bff |
fix: align bmad-help.csv with documented schema and clean up source rows (#2278) (#2349)
* fix(installer): preserve module-help.csv schema in merged bmad-help.csv (#2278) The installer's mergeModuleHelpCatalogs was rewriting the merged catalog under a different schema (module,phase,name,code,sequence,workflow-file,...) than the documented source schema in every module's module-help.csv (module,skill,display-name,menu-code,description,action,args,phase,...). Worse, the parsing assumed the wrong source column order, so column data was scrambled in the merged output. SKILL.md docs the source schema, so the bmad-help skill was navigating a catalog whose actual columns no longer matched its mental model. Drop the transformation and the agent enrichment columns (which had no consumers anywhere in the codebase). Emit rows verbatim in the source schema, padding short rows and filling empty module fields. Sort by module then phase, stable within phase to preserve authored order. Closes #2278 * fix(catalog): normalize module-help.csv rows to documented 13-column schema Many rows in core-skills/module-help.csv and bmm-skills/module-help.csv were missing one column between description and phase, leaving them at 12 fields instead of 13. CSV consumers that read by header position were silently mapping data into the wrong columns (description into action, phase into args, required into before, etc). Inserted an empty cell at column index 5 across all 31 affected rows to restore alignment with the documented header (module,skill,display-name,menu-code,description,action,args,phase, after,before,required,output-location,outputs). |
||
|
|
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. |
||
|
|
7ee5fa313b |
fix(installer): require --tools for fresh --yes installs; remove --tools none (#2346)
* fix(installer): require --tools for fresh --yes installs; remove --tools none (closes #2326) Fresh non-interactive installs without --tools previously produced a config-only install (~35 files vs ~1400 in the manifest) with no warning and a "BMAD is ready to use" success card, leaving slash commands unreachable. --tools none was an explicit opt-in for the same broken state. Now: fresh install + -y without --tools throws a helpful error pointing at --list-tools. --tools none is rejected as an unknown ID. Empty and typo'd tool IDs are also rejected. Existing-install paths (--action update, quick-update, modify) are unchanged - they continue to reuse previously-configured tools when --tools is omitted. Adds --list-tools flag that prints all 42 supported tool IDs (id, name, target_dir, preferred star) sourced from platform-codes.yaml. English docs updated; localized docs (vi-vn, fr, cs, etc.) will sync via the normal translation pass. * fix(installer): address review for #2326 — single source of truth, drop dead code, add tests - Refactor formatPlatformList to use IdeManager so --list-tools and --tools validation see the same set of platforms. Eliminates the drift where suspended platforms appeared in --list-tools but were rejected at validation. - Drop unused getValidPlatformIds export. - Flatten redundant block scope around the throw in the --yes-without-tools branch (refactor leftover). - Drop dead String() defensive cast (Commander always passes a string). - Add Test Suite 42: 8 unit tests covering _parseToolsFlag empty/whitespace/ unknown/typo cases plus an integration check that --list-tools output and --tools validation agree on the ID set. * fix(installer): close --tools "" bypass and drop hardcoded tool count - Replace truthy `if (options.tools)` guard with `!== undefined` in both upgrade and fresh-install branches. Empty string now reaches _parseToolsFlag and produces the specific "passed empty" error instead of falling through to a generic message (fresh-install) or being silently ignored (existing-install). - Drop the hardcoded "42 supported tools" count from the prereqs in install-bmad.md so the doc doesn't drift as platform-codes.yaml changes. Addresses augment / coderabbit review on #2346. |
||
|
|
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. |
||
|
|
350688df67 |
fix(installer): resolve url-source custom modules from custom-modules cache (#2323)
* fix(installer): resolve url-source custom modules from custom-modules cache resolveInstalledModuleYaml previously only searched ~/.bmad/cache/external-modules/, so modules installed via --custom-source <git-url> (cached at ~/.bmad/cache/custom-modules/<host>/<owner>/<repo>/) could not be located on re-install runs. This caused warnings during npx bmad-method install: [warn] collectAgentsFromModuleYaml: could not locate module.yaml for '<name>' [warn] writeCentralConfig: could not locate module.yaml for '<name>' Adds a fallback that walks the custom-modules cache via _findCacheRepoRoots (identifying repo roots by .bmad-source.json or .claude-plugin/, not marketplace.json, so direct-mode modules are also covered), reuses the same searchRoot candidate-path logic, and matches by the discovered yaml's code or name field. Works without needing _resolutionCache to be populated, which fixes the re-install scenario where no --custom-source flag is passed. Closes #2312 * fix(installer): enumerate all module.yamls when walking custom-modules cache A url-source custom-modules repo can host multiple plugins in discovery mode (e.g. skills/module-a/module.yaml and skills/module-b/module.yaml). The previous walk used searchRoot which returned only the first match, so asking for module-b would surface module-a's yaml, fail the code/name check, and skip the repo entirely — never inspecting module-b. Splits the candidate-path traversal into searchRootAll (returns every module.yaml in priority order) and a thin searchRoot wrapper for the existing single-module fallbacks. The custom-modules walk now iterates every yaml per repo and matches each against code or name. |
||
|
|
be85e5b4a0 |
fix(installer): support local custom-source modules in resolveInstalledModuleYaml and TOML key (#2316)
- resolveInstalledModuleYaml: fall back to CustomModuleManager._resolutionCache for local custom-source modules (external cache path doesn't exist for these); refactor candidate-path search into shared searchRoot() helper; add *-setup/assets/module.yaml BMB standard path - manifest-generator: use module code field (not display name) as TOML section key [modules.X] Co-authored-by: cidemaxio <cidemaxio@users.noreply.github.com> |
||
|
|
04cfde1454 |
fix(installer): mirror launch channel as default for external modules (#2321)
* fix(installer): mirror launch channel as default for external modules When the user runs `npx bmad-method@next install`, the installer itself runs from a prerelease, but the interactive channel gate previously hardcoded "(all stable)" — defaulting tea/community modules to stable while bmad-method itself was on next. The bleeding-edge launch did not flow through. Detect the installer's own version via semver.prerelease() and default the gate (and per-module picker) to match — "all next" for prerelease launches, "all stable" for stable. Users keep full control: hit "n" to customize per module, or pass explicit --channel / --pin / --next flags to override. * fix(installer): seed channelOptions before module picker, not gate CodeRabbit caught a label/install mismatch in the previous approach: the module picker resolves version labels via decideChannelForModule, which runs before _interactiveChannelGate. With channelOptions.global still null at picker time, labels rendered from stable tags — then the gate flipped global to 'next' and externals installed from main HEAD. Net effect on @next launches: "tea (v1.6.0)" in the picker, but install pulled HEAD. Move the launch detection up into promptInstall, immediately after parseChannelOptions. Seeding channelOptions.global = 'next' before the picker makes labels resolve from main HEAD (matching the install) and lets the existing gate's haveFlagIntent check skip cleanly — the @next user already declared their intent by typing it. Per-module customization remains available via --pin / --next / --channel flags, same as for any pre-set global. |
||
|
|
7baa30c567 |
fix(publish): advance @next dist-tag after stable release (#2320)
* fix(publish): advance @next dist-tag after stable release When a stable release publishes via workflow_dispatch, @latest can leapfrog the existing @next prerelease (e.g. latest=6.5.0 while next=6.4.1-next.0), turning `npx bmad-method@next install` into a silent downgrade until the next qualifying push to main republishes a fresh -next.0. - publish.yaml: after stable publish, repoint @next at the just-published stable version. The existing derive-prerelease step picks max(latest, next) as its base, so subsequent push-driven prereleases bump from there. - bmad-cli.js: checkForUpdate was querying the @beta dist-tag (which this package does not use). Replace string-matching with semver.prerelease() and query @next for prerelease users. * fix(publish): harden next-tag advance step and broaden path filter - continue-on-error on the dist-tag advance: failure leaves @next stale until the next push-driven prerelease, which is recoverable; failing the job after a successful publish + git tag + GH release is not. - Status echo so release-log triage can confirm the advance ran. - Add removals.txt to the push-trigger path filter. Installer-affecting changes outside src/** (like the post-6.5.0 removals.txt fix) should still trigger a fresh -next.0 publish. |
||
|
|
01cc32540b |
feat(installer): expand to 42 platforms with shared target_dir coordination (#2313)
* 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. |
||
|
|
9ff9d6f8f3 |
feat: add Kimi Code CLI support (#2302)
Adds kimi-code to both platform-codes.yaml files so Kimi Code CLI is available as an install target via the config-driven installer. Skills are installed to .kimi/skills/, which is the project-level skills directory per the official Kimi Code CLI documentation. Closes #1630 Co-authored-by: Brian <bmadcode@gmail.com> |
||
|
|
0533976753 |
fix: installer live version for external modules (#2307)
* resolved merge conflict * fix: addressed PR comments * fix: use git tags for installer module versions |
||
|
|
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 |
||
|
|
914c4edd6b |
fix(installer): resolve external-module agents from cache during manifest write (#2295)
External official modules (bmb, cis, gds, tea, wds) are cloned to ~/.bmad/cache/external-modules/<name>/ and never copied into src/modules/, so collectAgentsFromModuleYaml silently skipped them and their agents never reached config.toml. Swap the hardcoded src/modules lookup for a resolveInstalledModuleYaml() helper that also searches the external cache (handling src/, skills/, nested, and root layouts) and warns instead of silently skipping when a module.yaml can't be found. |
||
|
|
4405b817a9 |
refactor(skills): remove bmad-skill-manifest yaml; introduce central config.toml (#2285)
* refactor: remove bmad-skill-manifest yaml; introduce four-layer central config.toml
- Agent essence moves from per-skill bmad-skill-manifest.yaml files
into each module.yaml's `agents:` block (code, name, title, icon,
description). Per-agent customize.toml remains the deep-behavior
source of truth.
- Installer emits four TOML files:
_bmad/config.toml team install answers + agent roster
_bmad/config.user.toml user install answers
_bmad/custom/config.toml team overrides stub
_bmad/custom/config.user.toml personal overrides stub
Prompts declare scope: user to route answers to config.user.toml.
- resolve_config.py merges four layers: base-team -> base-user ->
custom-team -> custom-user.
- Three consumer skills (party-mode, advanced-elicitation,
retrospective) switched from agent-manifest.csv to the resolver.
- installer.js mergeModuleHelpCatalogs now takes the in-memory
agent list from ManifestGenerator -- no CSV roundtrip.
- Deleted: 6 bmad-skill-manifest.yaml files, agent-manifest.csv
emission, collectAgents/getAgentsFromDirRecursive,
paths.agentManifest().
* fix(installer): strip core-key pollution from [modules.*]; soften config headers
- writeCentralConfig now always strips core-module keys from every
[modules.<code>] bucket, even when the module's schema is not
available in src/ (external / marketplace modules like cis, bmb).
Core values belong in [core] only; workflows read them directly.
- When the module's own schema IS available (built-in modules),
also drop any key it does not declare as a prompt — same
spread-pollution filter as before, now layered on top.
- Section-aware headers on both _bmad/config.toml and
_bmad/config.user.toml: [core] / [modules.*] values are
editable (installer reads them as defaults on next install);
[agents.*] is regenerated from module.yaml and will be wiped —
overrides for agents go in _bmad/custom/config*.toml instead.
* docs: cover central config.toml + Diataxis prose pass across three files
Document the new four-file central configuration surface (_bmad/config.toml,
config.user.toml, and custom/ overrides) alongside the existing per-skill
customize.toml. Make editing rules, scope partitioning, and when-to-use-which
guidance explicit.
- customize-bmad.md: new "Central Configuration" section with editing rules,
three worked examples (rebrand, fictional agent, module settings override),
and a "when to use which surface" table. Converted five h4 headers to
bold paragraph intros per style guide.
- expand-bmad-for-your-org.md: two-layer mental model extended to three;
new Recipe 5 with three variants (rebrand, custom crew, pinned team
settings); reinforcement table extended.
- named-agents.md: noted the dual customization surface — per-skill shapes
behavior, central config shapes roster identity.
Diataxis prose pass applied across all three files: banned vocabulary
check, em-dash cap, hypophora / metanoia / amplificatio / stakes-inflation
cleanup, rhythm and burstiness fixes. Structural conformance verified;
markdownlint and prettier clean.
* test+docs: add central config unit tests; fix stale recipe count
- test: two new suites (35 + 36) covering writeCentralConfig and
ensureCustomConfigStubs. Verifies scope partitioning (user_name
lands only in config.user.toml), core-key pollution stripping
from [modules.*], unknown-schema fallthrough (external modules
survive without schema), agent roster baked into config.toml
[agents.*] only, stub-preservation on re-install. 44 new
assertions.
- docs: fixed four stale "four recipes" references to say "five"
after Recipe 5 (Customize the Agent Roster) was added. Touches
frontmatter, opening paragraph, Combining Recipes paragraph,
and the named-agents cross-link blurb.
* fix: address PR review feedback on central config
- resolve_config.py argparse: three-layer → four-layer description
- SKILL/workflow/explanation docs: document all four layers including
_bmad/config.user.toml (was missing from merge-stack descriptions)
- customize-bmad.md + installer headers: drop the false "direct edits to
config.toml persist" claim; installer reads from per-module config.yaml,
not central TOML, so direct edits get clobbered. Route users to
_bmad/custom/config.toml for durable overrides
- writeCentralConfig: warn loudly when a module.yaml can't be parsed
(previously silent — user-scoped keys could mis-file into team config)
- writeCentralConfig: preserve [agents.*] blocks for modules that didn't
contribute fresh agents this run (e.g. quickUpdate skipping modules
whose source is unavailable) so the roster doesn't silently shrink
- add extractAgentBlocks helper + Test Suite 37 covering preservation
Addresses comments from augmentcode and coderabbitai on PR #2285.
|
||
|
|
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> |
||
|
|
0f958cf713 |
fix(installer): add missing sync and async methods to fs-native wrapper
Closes #2256 |
||
|
|
9ffb5b80ab |
fix(installer): stop skill scanner from recursing into discovered skills
Skills don't nest. Once the manifest generator finds a valid SKILL.md in a directory, it should not recurse into that skill's subdirectories looking for more skills. Template files (like bmb's setup-skill-template) inside a skill's assets/ would be incorrectly scanned and produce spurious errors. |
||
|
|
c6c8301ea1 |
fix(installer): add move() and overwrite support to fs-native
Add missing move() with cross-device fallback (rename → copy+rm on EXDEV), needed by OfficialModules.createModuleDirectories for directory migrations during upgrades. Honor overwrite/errorOnExist options in copy() to match fs-extra behavior for callers that pass these flags. |
||
|
|
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 |
||
|
|
83f374c254 |
fix(installer): source built-in modules locally instead of from registry
Core and BMM modules live in this repo (src/core-skills, src/bmm-skills) but the installer UI sourced them from the remote registry. When the registry was unreachable (VPN, proxy, firewall), the fallback YAML only had the 4 external modules, so core and bmm disappeared from the install list entirely. Now _selectOfficialModules and getDefaultModules always read built-in modules from the local source via OfficialModules.listAvailable(), then append external modules from the registry. Network failures only affect external modules. Closes #2239 |
||
|
|
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.
|
||
|
|
eabcd03f65 |
chore(installer): remove dead template and agent-command pipeline (#2244)
The legacy agent-command-generator, bmad-artifacts helpers, and all 26 IDE template files (combined/ and split/) are unreachable dead code. The installer now uses verbatim SKILL.md directory copying -- no template rendering occurs. The files own TODO comments confirm retirement. |
||
|
|
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. |
||
|
|
59b07c33e2 |
feat(bmad-help): llms.txt support for general questions (#2230)
* feat(bmad-help): add _meta rows and llms.txt support for general questions Register llms.txt URLs in module-help.csv via _meta rows so bmad-help can fetch module documentation when users ask questions that don't map to a specific skill. * refactor(bmad-help): streamline llms.txt docs into existing skill sections |
||
|
|
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(). |
||
|
|
6cecab2626 |
chore(install): stop copying skill prompts to _bmad by default (#2182)
* chore(install): stop copying skill prompts to _bmad by default Flip install_to_bmad default from true to false so skill directories are cleaned from _bmad/ after IDE install. Skills are self-contained in their IDE directories (.claude/skills/, etc.) and no longer need duplicate copies in _bmad/. Two skills (bmad-create-prd, bmad-validate-prd) opt back in via explicit manifests because bmad-edit-prd cross-references their data files. Also fixes broken bmm-skills/ path references and corrects the file-ref validator module-to-source mapping. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(install): make edit-prd self-contained and remove install_to_bmad Give bmad-edit-prd its own copy of prd-purpose.md and replace the cross-skill validation workflow reference with a skill invocation, so all three PRD skills are fully self-contained. With no remaining consumers, remove the install_to_bmad flag from manifests, CSV output, the post-install cleanup loop, and the dedicated test file. * feat(install): clean up skill directories from _bmad after IDE install Skills are self-contained in IDE directories, so _bmad/ only needs module-level files (config.yaml, _config/). After all IDE setups complete, remove skill directories from _bmad/ via skill-manifest.csv. Also cleans up skill dirs left by older installer versions. * test(install): drop stale install_to_bmad column from suite 27 CSV row --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
c46502f640 |
feat(installer): overhaul branding, versioning, and skill cleanup (#2223)
* feat(installer): overhaul branding, versioning, and skill cleanup Logo and branding: - Responsive logo: full "BMAD METHOD" at >=95 cols, "BMAD" for narrower terminals - Color scheme updated from yellow to blue (matching bmadcode.com brand) - Added copyright notice and tagline in white for contrast - Removed version number from logo (individual module versions shown in summary) - Added ™ to both wide and narrow logo variants Installer start message: - Replaced outdated V6 launch announcement with clean welcome - Consolidated redundant module/platform messaging into single intro - Tightened open source manifesto (same spirit, fewer words) - Merged speaking/media into support section with contact email - Added full social links: Website, Discord, YouTube, X, Facebook - Replaced docs.bmad-method.org and changelog links with bmadcode.com hub Install summary improvements: - Module names now show full display names from module.yaml (not abbreviations) - All module versions sourced from .claude-plugin/marketplace.json exclusively - Summary shows version transitions: "v6.2.2 -> v6.3.0", "v6.3.0, no change", or "v6.3.0, installed" for fresh installs - Switched summary from clack note() to box() for full-brightness text - Removed dim/gray styling that was hard to read on dark terminals - Links styled with color.blue instead of color.dim - Get started section leads with actionable steps (launch agent, run bmad-help) - Removed redundant social links (already shown in start message) Version source unification: - All module versions now come from .claude-plugin/marketplace.json only - Removed package.json as version source for core/bmm modules - Updated manifest.js getModuleVersionInfo() to use marketplace.json - Updated installer.js _getMarketplaceVersion() helper - Updated ui.js getMarketplaceVersion() for module selection display - Quick Update menu no longer shows misleading version (was using package.json) - Module selection list now shows versions next to each module name Skill cleanup overhaul: - Replaced blunt-force bmad-* prefix deletion with surgical removal system - Added removals.txt support: optional per-project file listing skills to remove - Created initial removals.txt with all skills removed since v6.2.0 - Install/update: captures previously installed skill IDs from skill-manifest.csv before manifest regeneration, then removes those + removals.txt entries - Uninstall: removes all installed skills via skill-manifest.csv + removals.txt - Deselecting modules now correctly removes their skills from IDE directories - User-created bmad-* skills in IDE directories are no longer destroyed - Legacy directory cleanup retains prefix matching (those dirs are abandoned) Bug fixes: - Fixed duplicate "CORE module already up to date" during quick update - Fixed version display showing package.json version instead of actual module version - Updated test fixture for bmad-os-* preservation test to use skill-manifest.csv * fix(installer): address Augment review findings - Fix plugins[0] fragility: extract highest version across all plugins in marketplace.json instead of assuming first entry (ui.js, installer.js, manifest.js) - Fix _readMarketplaceVersion ignoring moduleSourcePath: custom modules can now source their own marketplace.json by walking up from source path - Hard-exclude bmad-os-* utility skills in both surgical and legacy cleanup modes, preventing accidental deletion if tracked in manifests - Distinguish missing file vs parse error in skill-manifest.csv reading: warn on corrupt CSV instead of silently skipping cleanup * fix(installer): resolve module source before reading marketplace version Move _readMarketplaceVersion call after source type resolution so custom modules use their own source path instead of falling back to the external module cache, which could match a different module with the same code. |
||
|
|
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 |
||
|
|
04513e5953 |
feat(installer): restore KiloCoder support and installer (#2151)
Kilo Code now supports Agent Skills. Remove the suspended flag, restore it in the IDE picker, and replace the suspended test suite with a full native-skills installation test. - Remove suspended message from platform-codes.yaml - Rewrite test suite 22: config, IDE picker, install, skill output, legacy cleanup, and reinstall assertions - Update migration checklist to reflect active status Co-authored-by: Junie <junie@jetbrains.com> Co-authored-by: Brian <bmadcode@gmail.com> |
||
|
|
aae6ddb8c9 |
fix: remove ancestor_conflict_check from all platforms (#2158)
The ancestor directory walk was based on the false premise that IDEs like Claude Code inherit skills from parent directories — they do not. The check blocked legitimate installations when unrelated BMAD skills existed anywhere up the directory tree. |
||
|
|
abfc56bd2c |
feat: add bmad-prfaq skill as alternative analysis path (#2157)
* feat: add bmad-prfaq skill as alternative to product brief Add Working Backwards PRFAQ challenge skill for stress-testing product concepts through Amazon's PRFAQ methodology. Includes press release drafting, customer FAQ, internal FAQ, and verdict stages with subagent support for artifact scanning and web research. - New bmad-prfaq skill with 5-stage interactive gauntlet and headless mode - Subagents for artifact analysis and web research (graceful degradation) - Research-grounded output directive for current market/competitive data - Always produces distillate for downstream PRD consumption - Fix manifest array syntax in both prfaq and product-brief manifests - Drop number prefixes from reference files - Update docs: getting-started, workflow-map, agents, skills reference - Add analysis-phase explainer doc with comparison table and decision guide - Update workflow-map-diagram.html with prfaq card - Add -H and -A args to CSV for both skills - Add unist-util-visit as devDependency (was imported but undeclared) * fix: harden bmad-prfaq for compaction resilience and context efficiency Add coaching persona re-anchors to all stage prompts so the behavioral directive survives context compaction. Add do-not-read guards at resume detection, headless mode, and input gathering to prevent parent agent context bloat. Add Stage 1 coaching notes capture. Adapt template and press release stage for non-commercial concept types. Cap subagent response token budgets. * fix: add config.user.yaml to file-ref validator allowlist Also update PRFAQ config path to use correct _config/bmm/ prefix. |
||
|
|
fa909a8916 |
feat: add Junie platform support (#2142)
* feat: add Junie platform support with .agents/skills target Co-authored-by: Junie <junie@jetbrains.com> * fix: disable ancestor_conflict_check for Junie platform Junie does not traverse ancestor directories looking for skills, so ancestor_conflict_check should be false. Co-authored-by: Junie <junie@jetbrains.com> --------- Co-authored-by: Junie <junie@jetbrains.com> |
||
|
|
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. |
||
|
|
c91db0db4b |
fix: revert bmb module-definition path to src/module.yaml (#2146)
bmad-builder reverted its skills/ directory back to src/ for installer compatibility (bmad-code-org/bmad-builder#40). Update the external modules manifest to match. |
||
|
|
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. |
||
|
|
6dd0a97c1f |
fix: update bmb module-definition path for skills/ restructure (#2126)
bmad-builder moved skills from src/skills/ to skills/ at repo root for Claude Code plugin and Vercel Skills CLI compatibility. |
||
|
|
a04635efe0 |
fix: agent-manifest.csv empty after install — type mismatch + scan path bug (#2115)
Two bugs combined to produce an empty agent-manifest.csv:
1. collectAgents() only scanned {module}/agents/ directories, but agents
live at various paths (bmm/1-analysis/bmad-agent-analyst/,
cis/skills/bmad-cis-agent-*, etc.). Now walks the full module tree.
2. All 9 BMM agent manifests declared type: skill instead of type: agent.
The manifest generator requires type: agent to include a directory in
agent-manifest.csv. CIS, GDS, TEA, and WDS already had the correct type.
Changes:
- Fix 9 BMM bmad-skill-manifest.yaml files: type: skill → type: agent
- Replace collectAgents/getAgentsFromDir with full-tree recursive scan
- Module field from manifest file always takes precedence over directory
- Remove dead skillManifest load (legacy .md agent support removed)
- Add TODO in bmad-artifacts.js documenting legacy agent pipeline as dead code
- Add 10 regression tests covering BMM, CIS, and GDS directory layouts
|
||
|
|
0c245474c4 |
fix: use execFileSync to preserve spaces in CLI arguments (#2088)
Replace execSync with execFileSync in npx wrapper so that argument values containing spaces (e.g. --user-name "CI Bot") are passed as discrete array elements instead of being split by the shell. Fixes #2066 Signed-off-by: majiayu000 <1835304752@qq.com> Co-authored-by: Alex Verkhovsky <alexey.verkhovsky@gmail.com> |
||
|
|
303e7ae290 |
fix: issue 55 config paths (#2113)
* fix: issue 55 config paths * Fix: ci test failure |
||
|
|
e3f935fd6d |
fix(docs): community feedback — typo, locale 404s, llms-full (#2091)
* fix(docs): correct Hasselhoff spelling, add locale-aware 404 redirect Fix "Hasslehoff" → "Hasselhoff" typo in customize-bmad.md across all three locales (en, zh-cn, fr). Add client-side locale detection to 404.astro so GitHub Pages serves the correct localized 404 page instead of always showing English. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(build): exclude translated locales from llms-full.txt llms-full.txt was including zh-cn and fr docs, tripling the content with duplicate information in different languages. Restrict to English only — translations add no value for LLM context consumption. Reduces output from ~393K to ~114K chars (~29k tokens). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(i18n): extract locale config to shared module Move locale definitions from astro.config.mjs into a shared website/src/lib/locales.mjs consumed by astro config, build-docs, and 404.astro. Adding a new locale is now a single-file change. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |