ma-agents 3.15.5 → 3.17.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -4
- package/bin/cli.js +323 -6
- package/lib/agents.js +22 -15
- package/lib/bmad-cache/cache-manifest.json +2 -2
- package/lib/bmad-extension/.claude-plugin/marketplace.json.template +2 -15
- package/lib/bmad-extension/skills/module-help.csv +0 -13
- package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +3 -16
- package/lib/bmad-extension-plugin/skills/module-help.csv +0 -13
- package/lib/bmad.js +116 -1
- package/lib/custom-marketplace.js +507 -0
- package/lib/installer.js +19 -7
- package/lib/knowledge-atlas/dist/atlas.cjs +14651 -14570
- package/lib/knowledge-atlas/src/render/document.ts +100 -10
- package/lib/knowledge-atlas/src/render/site.ts +20 -2
- package/lib/knowledge-atlas/src/render/vendor.ts +43 -0
- package/lib/knowledge-atlas/vendor/drawio-viewer.min.js +7563 -0
- package/lib/knowledge-atlas/vendor/mermaid.min.js +2314 -0
- package/lib/profile.js +201 -0
- package/lib/skill-authoring.js +3 -1
- package/package.json +70 -70
- package/scripts/build-bmad-cache.js +127 -43
- package/lib/bmad-extension/skills/ma-agent-ml/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ma-agent-ml/SKILL.md +0 -59
- package/lib/bmad-extension/skills/ma-agent-ml/bmad-skill-manifest.yaml +0 -11
- package/lib/bmad-extension/skills/ml-advise/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-advise/SKILL.md +0 -76
- package/lib/bmad-extension/skills/ml-advise/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-advise/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-analysis/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-analysis/SKILL.md +0 -60
- package/lib/bmad-extension/skills/ml-analysis/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-analysis/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-architecture/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-architecture/SKILL.md +0 -55
- package/lib/bmad-extension/skills/ml-architecture/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-architecture/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-detailed-design/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-detailed-design/SKILL.md +0 -67
- package/lib/bmad-extension/skills/ml-detailed-design/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-detailed-design/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-eda/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-eda/SKILL.md +0 -56
- package/lib/bmad-extension/skills/ml-eda/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-eda/scripts/baseline_classifier.py +0 -522
- package/lib/bmad-extension/skills/ml-eda/scripts/class_weights_calculator.py +0 -295
- package/lib/bmad-extension/skills/ml-eda/scripts/clustering_explorer.py +0 -383
- package/lib/bmad-extension/skills/ml-eda/scripts/eda_analyzer.py +0 -654
- package/lib/bmad-extension/skills/ml-eda/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-experiment/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-experiment/SKILL.md +0 -74
- package/lib/bmad-extension/skills/ml-experiment/assets/advanced_trainer_configs.py +0 -430
- package/lib/bmad-extension/skills/ml-experiment/assets/quick_trainer_setup.py +0 -233
- package/lib/bmad-extension/skills/ml-experiment/assets/template_datamodule.py +0 -219
- package/lib/bmad-extension/skills/ml-experiment/assets/template_gnn_module.py +0 -341
- package/lib/bmad-extension/skills/ml-experiment/assets/template_lightning_module.py +0 -158
- package/lib/bmad-extension/skills/ml-experiment/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-experiment/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-hparam/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-hparam/SKILL.md +0 -81
- package/lib/bmad-extension/skills/ml-hparam/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-hparam/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-ideation/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-ideation/SKILL.md +0 -50
- package/lib/bmad-extension/skills/ml-ideation/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-ideation/scripts/validate_ml_prd.py +0 -287
- package/lib/bmad-extension/skills/ml-ideation/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-infra/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-infra/SKILL.md +0 -58
- package/lib/bmad-extension/skills/ml-infra/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-infra/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-retrospective/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-retrospective/SKILL.md +0 -63
- package/lib/bmad-extension/skills/ml-retrospective/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-retrospective/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-revision/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-revision/SKILL.md +0 -82
- package/lib/bmad-extension/skills/ml-revision/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-revision/skill.json +0 -7
- package/lib/bmad-extension/skills/ml-techspec/.gitkeep +0 -0
- package/lib/bmad-extension/skills/ml-techspec/SKILL.md +0 -80
- package/lib/bmad-extension/skills/ml-techspec/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension/skills/ml-techspec/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ma-agent-ml/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ma-agent-ml/SKILL.md +0 -59
- package/lib/bmad-extension-plugin/skills/ma-agent-ml/bmad-skill-manifest.yaml +0 -11
- package/lib/bmad-extension-plugin/skills/ml-advise/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-advise/SKILL.md +0 -76
- package/lib/bmad-extension-plugin/skills/ml-advise/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-advise/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-analysis/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-analysis/SKILL.md +0 -60
- package/lib/bmad-extension-plugin/skills/ml-analysis/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-analysis/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-architecture/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-architecture/SKILL.md +0 -55
- package/lib/bmad-extension-plugin/skills/ml-architecture/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-architecture/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-detailed-design/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-detailed-design/SKILL.md +0 -67
- package/lib/bmad-extension-plugin/skills/ml-detailed-design/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-detailed-design/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-eda/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-eda/SKILL.md +0 -56
- package/lib/bmad-extension-plugin/skills/ml-eda/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-eda/scripts/baseline_classifier.py +0 -522
- package/lib/bmad-extension-plugin/skills/ml-eda/scripts/class_weights_calculator.py +0 -295
- package/lib/bmad-extension-plugin/skills/ml-eda/scripts/clustering_explorer.py +0 -383
- package/lib/bmad-extension-plugin/skills/ml-eda/scripts/eda_analyzer.py +0 -654
- package/lib/bmad-extension-plugin/skills/ml-eda/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-experiment/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-experiment/SKILL.md +0 -74
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/advanced_trainer_configs.py +0 -430
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/quick_trainer_setup.py +0 -233
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/template_datamodule.py +0 -219
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/template_gnn_module.py +0 -341
- package/lib/bmad-extension-plugin/skills/ml-experiment/assets/template_lightning_module.py +0 -158
- package/lib/bmad-extension-plugin/skills/ml-experiment/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-experiment/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-hparam/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-hparam/SKILL.md +0 -81
- package/lib/bmad-extension-plugin/skills/ml-hparam/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-hparam/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-ideation/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-ideation/SKILL.md +0 -50
- package/lib/bmad-extension-plugin/skills/ml-ideation/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-ideation/scripts/validate_ml_prd.py +0 -287
- package/lib/bmad-extension-plugin/skills/ml-ideation/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-infra/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-infra/SKILL.md +0 -58
- package/lib/bmad-extension-plugin/skills/ml-infra/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-infra/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-retrospective/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-retrospective/SKILL.md +0 -63
- package/lib/bmad-extension-plugin/skills/ml-retrospective/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-retrospective/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-revision/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-revision/SKILL.md +0 -82
- package/lib/bmad-extension-plugin/skills/ml-revision/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-revision/skill.json +0 -7
- package/lib/bmad-extension-plugin/skills/ml-techspec/.gitkeep +0 -0
- package/lib/bmad-extension-plugin/skills/ml-techspec/SKILL.md +0 -80
- package/lib/bmad-extension-plugin/skills/ml-techspec/bmad-skill-manifest.yaml +0 -3
- package/lib/bmad-extension-plugin/skills/ml-techspec/skill.json +0 -7
package/README.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
A universal NPX tool to install AI coding agent skills. Write skills once, install them across Claude Code, Gemini, Copilot, Cline, Cursor, Kilocode, and Roo Code.
|
|
4
4
|
|
|
5
|
+
## What's New in v3.17.0
|
|
6
|
+
|
|
7
|
+
- **BMAD-METHOD v6.10.0** — bundled bmad-method updated to v6.10.0. The
|
|
8
|
+
offline bundle stays exactly `{tea, bmb, cis, gds, wds}`; the new upstream
|
|
9
|
+
`bmad-loop` module is deliberately excluded (never bundled, never installed
|
|
10
|
+
by default) by a closed-allowlist filter with a two-sided fail-loud guard.
|
|
11
|
+
- **Custom marketplace source (opt-in)** — `--bmad-custom-source
|
|
12
|
+
<path|url>` (or the install-time Y/N prompt) lets you enumerate and install
|
|
13
|
+
a hand-picked subset of extensions from your own BMAD marketplace repo —
|
|
14
|
+
the sanctioned way to add `bmad-loop` or any other excluded module. The
|
|
15
|
+
source and your selection persist in `.ma-agents.json` and re-enumerate on
|
|
16
|
+
every `update`. See "Custom Marketplace Source" below.
|
|
17
|
+
- **Demerzel (ML Scientist) deprecated** — `ma-agent-ml` and its 12 `ml-*`
|
|
18
|
+
skills are no longer installed by default for new projects. Existing
|
|
19
|
+
installs are completely untouched (non-destructive); a one-time notice
|
|
20
|
+
explains how to opt back in via a custom marketplace source.
|
|
21
|
+
|
|
5
22
|
## What's New in v3.12.0
|
|
6
23
|
|
|
7
24
|
- **Cline `.clinerules` directory fix** — `.clinerules` is now correctly created as a directory (matching Cline's native structure), not as a file. This prevents ENOTDIR errors during workflow generation and ensures `.clinerules/workflows/` is always generated correctly. Legacy installs that had `.clinerules` as a file are automatically migrated on the next install or update.
|
|
@@ -316,7 +333,7 @@ Running `ma-agents` on a project where skills are already installed triggers the
|
|
|
316
333
|
- **Cleans up stale tool directories** — if a tool's skill path changed between releases (e.g., Copilot migrated from `.github/copilot/skills/` to `.github/skills/`), the old directory is automatically removed when the new one has content.
|
|
317
334
|
|
|
318
335
|
### BMAD-METHOD Integration
|
|
319
|
-
`ma-agents` bundles [BMAD-METHOD](https://docs.bmad-method.org/) **v6.
|
|
336
|
+
`ma-agents` bundles [BMAD-METHOD](https://docs.bmad-method.org/) **v6.10.0** to provide advanced orchestration and specialized personas.
|
|
320
337
|
|
|
321
338
|
#### Core Features
|
|
322
339
|
- **Auto-Detection**: Recognizes existing BMAD installations and prompts for silent updates.
|
|
@@ -330,16 +347,70 @@ Running `ma-agents` on a project where skills are already installed triggers the
|
|
|
330
347
|
`ma-agents` ships with everything needed to install BMAD without any network access at install time:
|
|
331
348
|
|
|
332
349
|
- **`bmad-method` is a direct npm dependency** — no runtime `npx bmad-method` fetch required. The correct version is pinned and bundled inside `node_modules/` when you `npm install ma-agents`.
|
|
333
|
-
- **External modules pre-bundled** — `lib/bmad-cache/` ships
|
|
350
|
+
- **External modules pre-bundled** — `lib/bmad-cache/` ships exactly 5 optional BMAD modules (`bmb`, `cis`, `gds`, `tea`, `wds`) inside the package itself. They are pre-populated to `~/.bmad/cache/external-modules/` before any install runs, so BMAD never needs to clone them from GitHub. The bundled set is a **closed allowlist** — a build-time guard fails loud if the resolved set is ever smaller (a thin cache) *or* larger (a silent upstream addition) than these five, so a new upstream module can never be force-bundled or installed by default. `bmad-loop` (BMAD's own unattended-dev orchestrator, added upstream at v6.10.0) is deliberately **excluded** from this bundle — see "BMAD-loop and other opt-in modules" below.
|
|
334
351
|
- **Plugin bundle pre-built** — `lib/bmad-extension-plugin/` ships as a deterministic, byte-stable bundle (built from `lib/bmad-extension/` via `scripts/build-plugin.js`). At install time it is staged into `<project>/.ma-agents-plugin-stage/` and consumed by `bmad-method install --custom-source`, so the install never touches the network for plugin assembly.
|
|
335
352
|
- **Deterministic installs** — same `ma-agents` version always produces the same `_bmad/` output, regardless of network conditions (NFR21). Bundle reproducibility is gated by a CI drift check.
|
|
336
353
|
- **Air-gapped friendly** — install from a tarball (`npm install ./ma-agents-x.y.z.tgz`) and run `npx ma-agents install` completely offline. Every PR runs an offline-install gate (`--network none` Docker) to enforce this guarantee (NFR54).
|
|
337
354
|
|
|
338
355
|
```
|
|
339
|
-
npm install ma-agents # bundles bmad-method +
|
|
356
|
+
npm install ma-agents # bundles bmad-method + 5 external modules
|
|
340
357
|
npx ma-agents install --yes # fully offline BMAD install — no network needed
|
|
341
358
|
```
|
|
342
359
|
|
|
360
|
+
#### Custom Marketplace Source (opt-in)
|
|
361
|
+
|
|
362
|
+
After module selection, the installer offers to pull in extensions from **one**
|
|
363
|
+
additional BMAD marketplace repository — a local path or an intra-perimeter
|
|
364
|
+
Git URL (e.g. on-prem GitLab) pointing at a repo with a
|
|
365
|
+
`.claude-plugin/marketplace.json`. This is how a team plugs in extensions
|
|
366
|
+
ma-agents deliberately does not ship by default — including **`bmad-loop`**
|
|
367
|
+
(see below) or an internally-published replacement for a deprecated agent.
|
|
368
|
+
|
|
369
|
+
- **Interactive flow**: `Install additional BMAD extensions from a custom
|
|
370
|
+
source? (y/N)` → if yes, enter the source → ma-agents **enumerates** the
|
|
371
|
+
extensions the source declares (reusing bmad-method's own module
|
|
372
|
+
discovery) → presents them in **ma-agents' own multiselect** (the
|
|
373
|
+
single-wizard principle is preserved; `bmad-method` itself still runs
|
|
374
|
+
non-interactively) → installs only the codes you picked.
|
|
375
|
+
- **Non-interactive equivalent**: `--bmad-custom-source <local-path-or-url>`.
|
|
376
|
+
Under `--yes`, every declared extension is selected automatically (matching
|
|
377
|
+
how `--bmad-modules`/skill selection behave under `--yes`).
|
|
378
|
+
- **Persistence + reconcile on update**: the marketplace source and your
|
|
379
|
+
selected extension codes are saved in `.ma-agents.json`. On the next
|
|
380
|
+
`update`, ma-agents automatically re-resolves the source and re-enumerates
|
|
381
|
+
it, reporting anything newly published (not auto-installed — re-run the
|
|
382
|
+
custom-source flow to add it) or no longer available (dropped from the
|
|
383
|
+
installed selection) — it never silently changes what you already have.
|
|
384
|
+
- **Authentication**: ambient git only — your existing SSH keys or credential
|
|
385
|
+
helper. ma-agents performs zero token handling and never stores or logs a
|
|
386
|
+
credential.
|
|
387
|
+
- **On-prem posture**: no public-internet egress is required (an on-prem
|
|
388
|
+
GitLab over SSH works with no extra configuration), but custom-source
|
|
389
|
+
content is explicitly **outside** the sealed offline-bundle guarantee above
|
|
390
|
+
— you are responsible for that source's own offline self-containment. The
|
|
391
|
+
installer prints a one-line warning before you can select anything from it.
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
npx ma-agents install --yes --bmad-custom-source ./org-marketplace
|
|
395
|
+
npx ma-agents install --bmad-custom-source git@git.intra.example:team/bmad-marketplace.git
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
#### `bmad-loop` and other opt-in modules
|
|
399
|
+
|
|
400
|
+
BMAD-METHOD v6.10.0 added `bmad-loop`, an unattended Python/tmux/hooks
|
|
401
|
+
development-orchestrator module that requires a separate `bmad-loop-setup`
|
|
402
|
+
step and vendor-API sessions. It is **air-gap-hostile as a default** and
|
|
403
|
+
functionally overlaps ma-agents' own `bmad-dev-epic` orchestrator, so
|
|
404
|
+
`bmad-loop` is **never bundled and never installed by default** — it is
|
|
405
|
+
excluded by the same closed-allowlist guard described above. `bmad-dev-epic`
|
|
406
|
+
remains ma-agents' default air-gapped epic orchestrator.
|
|
407
|
+
|
|
408
|
+
`bmad-loop` (or any other module ma-agents excludes) can still be installed
|
|
409
|
+
as a deliberate, explicit opt-in through a **custom marketplace source** (see
|
|
410
|
+
above) — for example a locally-published copy of `bmad-loop` in your org's
|
|
411
|
+
marketplace repo. This is the sanctioned path for teams that want it; nothing
|
|
412
|
+
in the default install pulls it in silently.
|
|
413
|
+
|
|
343
414
|
#### Specialized BMAD Agents
|
|
344
415
|
1. **SRE Agent (Alex)**:
|
|
345
416
|
- **Focus**: High availability, Kubernetes, Docker, and Podman.
|
|
@@ -353,10 +424,20 @@ npx ma-agents install --yes # fully offline BMAD install — no network neede
|
|
|
353
424
|
- **Focus**: Cyber immunity, security auditing, and vulnerability management.
|
|
354
425
|
- **Capabilities**: Immunity estimation (scoring), Vault secret management, and PKI automation.
|
|
355
426
|
- **Integration**: Orchestrates ma-agents security skills for deep scans.
|
|
356
|
-
4. **Demerzel (ML Scientist)**:
|
|
427
|
+
4. **Demerzel (ML Scientist)** — **DEPRECATED, no longer installed by default (v3.17.0+)**:
|
|
357
428
|
- **Focus**: Hypothesis-driven machine learning lifecycle with scientific rigor.
|
|
358
429
|
- **Capabilities**: EDA, architecture design, locked TechSpec contracts, experiment execution, failure-cost analysis.
|
|
359
430
|
- **Workflows**: 12-stage ML lifecycle from ideation through retrospective, with mandatory review gates.
|
|
431
|
+
- **Status**: `ma-agent-ml` and its 12 `ml-*` workflow skills are no longer
|
|
432
|
+
part of the default bundle for **new** installs. This is **non-destructive**
|
|
433
|
+
for everyone else — an **existing** install's `ma-agent-ml`/`ml-*` content
|
|
434
|
+
(and anything you produced with it) is left completely untouched on update;
|
|
435
|
+
there is no auto-removal and no prompt. You'll see a one-time notice the
|
|
436
|
+
first time you install or update after upgrading ma-agents, and that's it.
|
|
437
|
+
There is no in-tool migration path — if your team still needs ML
|
|
438
|
+
workflows, install a replacement from your organization's own BMAD
|
|
439
|
+
marketplace via the **custom marketplace source** described above
|
|
440
|
+
(`--bmad-custom-source`).
|
|
360
441
|
5. **Gadi (SQA & Standards Expert)**:
|
|
361
442
|
- **Focus**: Software quality assurance and defense documentation standards — a unified persona covering SQA auditing and MIL-STD-498 document generation.
|
|
362
443
|
- **SQA Capabilities**: Multi-dimensional project quality audits, IEEE/ISO/IEC 12207:2017 compliance assessments (23 process areas, 4 groups), requirements evaluation against 14 established quality criteria (scope-selectable: PRD FRs, NFRs, epics, stories).
|
package/bin/cli.js
CHANGED
|
@@ -34,11 +34,12 @@ const path = require('path');
|
|
|
34
34
|
const fs = require('fs');
|
|
35
35
|
const { execFileSync } = require('child_process');
|
|
36
36
|
const { installSkill, uninstallSkill, getStatus, listSkills, listAgents, updateProjectContextRepoLayout, migrateRetiredSkills, reconcileAgentsSharedSkills } = require('../lib/installer');
|
|
37
|
-
const { getProfile, setProfile, resolveProfile, getBmadModules, setBmadModules } = require('../lib/profile');
|
|
37
|
+
const { getProfile, setProfile, resolveProfile, getBmadModules, setBmadModules, showDemerzelDeprecationNoticeOnce, getCustomMarketplaceSelection } = require('../lib/profile');
|
|
38
38
|
const { reconfigure: runReconfigure, ReconfigureYesRejectedError, ManifestNotFoundError, RoomodesSlugDivergenceError } = require('../lib/reconfigure');
|
|
39
39
|
const { uninstallProfileArtifacts } = require('../lib/uninstall');
|
|
40
40
|
const bmad = require('../lib/bmad');
|
|
41
41
|
const { getBmadPlatformCode } = require('../lib/agents');
|
|
42
|
+
const { enumerateCustomSource, NFR71_WARNING, CustomMarketplaceError, reconcileCustomMarketplaceSelection } = require('../lib/custom-marketplace');
|
|
42
43
|
const { handleCreateSkill, handleValidateSkill, handleSetMandatory, handleCustomizeAgent, handleCreateAgent } = require('../lib/skill-authoring');
|
|
43
44
|
|
|
44
45
|
const PKG = require('../package.json');
|
|
@@ -119,6 +120,13 @@ ${chalk.bold('Install options:')}
|
|
|
119
120
|
With CSV: install exactly those (e.g. tea,bmb)
|
|
120
121
|
Omitted: install every non-retired module (default)
|
|
121
122
|
'bmm' is always force-included.
|
|
123
|
+
${chalk.cyan('--bmad-custom-source <ref>')} Enumerate extensions from ONE custom
|
|
124
|
+
marketplace repo (local path or Git URL containing
|
|
125
|
+
.claude-plugin/marketplace.json) and offer them in
|
|
126
|
+
ma-agents' own multiselect. Non-interactive equivalent
|
|
127
|
+
of the "Install additional BMAD extensions from a
|
|
128
|
+
custom source?" prompt. Ambient git credentials only —
|
|
129
|
+
no token handling.
|
|
122
130
|
${chalk.cyan('--log')} Log all console output to install_<datetime>.log
|
|
123
131
|
|
|
124
132
|
${chalk.bold('Reconfigure options:')}
|
|
@@ -142,6 +150,8 @@ ${chalk.bold('Examples:')}
|
|
|
142
150
|
npx ${NAME} install --yes --global
|
|
143
151
|
npx ${NAME} install --yes --bmad-modules bmm,tea,bmb
|
|
144
152
|
npx ${NAME} install --bmad-modules # prompt for modules
|
|
153
|
+
npx ${NAME} install --yes --bmad-custom-source ./org-marketplace
|
|
154
|
+
npx ${NAME} install --bmad-custom-source git@git.intra.example:team/bmad-marketplace.git
|
|
145
155
|
npx ${NAME} uninstall code-review claude-code
|
|
146
156
|
npx ${NAME} status
|
|
147
157
|
npx ${NAME} status --global
|
|
@@ -270,6 +280,23 @@ function parseFlags(args) {
|
|
|
270
280
|
}
|
|
271
281
|
}
|
|
272
282
|
|
|
283
|
+
// --bmad-custom-source <ref> — Story 30.6a. Requires an explicit value (a
|
|
284
|
+
// path or Git URL); unlike --bmad-modules there is no "bare = prompt" form
|
|
285
|
+
// because the underlying Y/N wizard prompt already exists for interactive
|
|
286
|
+
// runs. A missing value is an error, not a silent no-op, to avoid a typo'd
|
|
287
|
+
// invocation silently skipping the intended custom source.
|
|
288
|
+
let bmadCustomSourceFlag = '';
|
|
289
|
+
const bmadCustomSourceIdx = positional.indexOf('--bmad-custom-source');
|
|
290
|
+
if (bmadCustomSourceIdx !== -1) {
|
|
291
|
+
const value = positional[bmadCustomSourceIdx + 1];
|
|
292
|
+
if (!value || value.startsWith('--')) {
|
|
293
|
+
console.error(chalk.red('Error: --bmad-custom-source requires a path or Git URL'));
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
bmadCustomSourceFlag = value;
|
|
297
|
+
positional.splice(bmadCustomSourceIdx, 2);
|
|
298
|
+
}
|
|
299
|
+
|
|
273
300
|
return {
|
|
274
301
|
globalFlag,
|
|
275
302
|
forceFlag,
|
|
@@ -278,6 +305,7 @@ function parseFlags(args) {
|
|
|
278
305
|
customPath,
|
|
279
306
|
bmadModulesFlag,
|
|
280
307
|
bmadModulesPrompt,
|
|
308
|
+
bmadCustomSourceFlag,
|
|
281
309
|
scope: globalFlag ? 'global' : 'project',
|
|
282
310
|
positional
|
|
283
311
|
};
|
|
@@ -918,9 +946,212 @@ async function selectBmadModules({ bmadModulesFlag, bmadModulesPrompt, projectRo
|
|
|
918
946
|
return persist(installable.map(m => m.id));
|
|
919
947
|
}
|
|
920
948
|
|
|
949
|
+
// --- Custom marketplace source (Story 30.6a) ---
|
|
950
|
+
|
|
951
|
+
/**
|
|
952
|
+
* Story 30.6b AC 6 — single source of truth for whether the base BMAD
|
|
953
|
+
* install/update step (Step 3.5) left a usable installation for the
|
|
954
|
+
* custom-marketplace subset install (Step 3.5b) to layer `--custom-source`
|
|
955
|
+
* onto. Pure function, exported for direct unit testing (no need to drive
|
|
956
|
+
* the full wizard to exercise this policy):
|
|
957
|
+
*
|
|
958
|
+
* - not attempted (user declined, or --yes short-circuited before any
|
|
959
|
+
* call): usable only if BMAD was ALREADY installed from a prior run —
|
|
960
|
+
* there is no `_bmad/` tree to layer onto for a declined FRESH install.
|
|
961
|
+
* - attempted: usable iff the install/update call itself reported success.
|
|
962
|
+
*
|
|
963
|
+
* @param {Object} ctx
|
|
964
|
+
* @param {boolean} ctx.bmadInstalled - Was BMAD already installed before this step?
|
|
965
|
+
* @param {boolean} ctx.attempted - Was `installBmad`/`updateBmad` actually invoked?
|
|
966
|
+
* @param {boolean} [ctx.success] - That call's return value (ignored if `attempted` is false).
|
|
967
|
+
* @returns {boolean}
|
|
968
|
+
*/
|
|
969
|
+
function resolveBaseBmadOk({ bmadInstalled, attempted, success }) {
|
|
970
|
+
if (!attempted) return Boolean(bmadInstalled);
|
|
971
|
+
return Boolean(success);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* FR239-FR241 — after BMAD module selection, offer to enumerate ONE custom
|
|
976
|
+
* marketplace source and let the user pick which of its declared extensions
|
|
977
|
+
* to install. This function does the Y/N prompt (or its `--bmad-custom-source`
|
|
978
|
+
* non-interactive equivalent), the enumerate call, the NFR71 warning, and
|
|
979
|
+
* ma-agents' OWN multiselect (FR240) — and stops there.
|
|
980
|
+
*
|
|
981
|
+
* Scope boundary (Story 30.6a vs 30.6b): this returns the user's selection —
|
|
982
|
+
* `{ source, mode, selectedCodes, plugins, rootDir, sourceUrl }` (the last two
|
|
983
|
+
* added by 30.6b — additive, existing 30.6a consumers only read the first
|
|
984
|
+
* four fields) — for Story 30.6b to consume for prune-and-stage. NO pruning,
|
|
985
|
+
* staging, or `bmad-method` invocation happens here or anywhere in this
|
|
986
|
+
* function. Returns `null` when the feature is not engaged (no flag, and
|
|
987
|
+
* either --yes with no flag, or the user answered "N") — this is the
|
|
988
|
+
* byte-identical-to-baseline "off" path required by NFR70.
|
|
989
|
+
*
|
|
990
|
+
* @param {Object} ctx
|
|
991
|
+
* @param {string} [ctx.bmadCustomSourceFlag] - `--bmad-custom-source <ref>` value
|
|
992
|
+
* @param {boolean} [ctx.yesFlag] - non-interactive run
|
|
993
|
+
* @returns {Promise<null|{ source: string, mode: 'discovery'|'direct', selectedCodes: string[],
|
|
994
|
+
* plugins: Array<Object>, rootDir: string, sourceUrl: string|null }>}
|
|
995
|
+
*/
|
|
996
|
+
async function promptCustomMarketplace({ bmadCustomSourceFlag = '', yesFlag = false } = {}) {
|
|
997
|
+
let source = bmadCustomSourceFlag;
|
|
998
|
+
|
|
999
|
+
if (!source) {
|
|
1000
|
+
if (yesFlag) {
|
|
1001
|
+
// Non-interactive run with no flag — feature stays off (NFR70: a
|
|
1002
|
+
// no-source install is byte-identical to baseline). There is no
|
|
1003
|
+
// "bare = prompt" fallback for --yes, matching how other install-time
|
|
1004
|
+
// Y/N prompts behave under --yes.
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
const { wantsCustomSource } = await prompts({
|
|
1008
|
+
type: 'confirm',
|
|
1009
|
+
name: 'wantsCustomSource',
|
|
1010
|
+
message: 'Install additional BMAD extensions from a custom source? (y/N)',
|
|
1011
|
+
initial: false,
|
|
1012
|
+
});
|
|
1013
|
+
if (!wantsCustomSource) return null;
|
|
1014
|
+
|
|
1015
|
+
const { sourceInput } = await prompts({
|
|
1016
|
+
type: 'text',
|
|
1017
|
+
name: 'sourceInput',
|
|
1018
|
+
message: 'Custom marketplace source (local path or Git URL):',
|
|
1019
|
+
});
|
|
1020
|
+
if (!sourceInput || !sourceInput.trim()) {
|
|
1021
|
+
console.log(chalk.yellow(' No source entered — skipping custom marketplace source.'));
|
|
1022
|
+
return null;
|
|
1023
|
+
}
|
|
1024
|
+
source = sourceInput.trim();
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
let enumerated;
|
|
1028
|
+
try {
|
|
1029
|
+
enumerated = await enumerateCustomSource(source);
|
|
1030
|
+
} catch (err) {
|
|
1031
|
+
// Fail clean (spike §3 contract) — a short, human-readable message only.
|
|
1032
|
+
// Never print err.stack here: an unreachable/unauthorized custom source
|
|
1033
|
+
// must not dump a raw upstream stack, and must never touch the base
|
|
1034
|
+
// install (the rest of installWizard proceeds unaffected).
|
|
1035
|
+
const message = err instanceof CustomMarketplaceError ? err.message : `Custom marketplace source error: ${err.message}`;
|
|
1036
|
+
console.log(chalk.red(`\n ${message}`));
|
|
1037
|
+
console.log(chalk.gray(' Skipping custom marketplace source; the rest of the install is unaffected.'));
|
|
1038
|
+
return null;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
const { plugins, mode, rootDir, sourceUrl } = enumerated;
|
|
1042
|
+
if (!plugins || plugins.length === 0) {
|
|
1043
|
+
console.log(chalk.yellow(` Custom marketplace source "${source}" declared no plugins — nothing to select.`));
|
|
1044
|
+
return { source, mode, selectedCodes: [], plugins: [], rootDir, sourceUrl };
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// NFR71 — shown before the user can select/install anything from the source.
|
|
1048
|
+
console.log(chalk.yellow(`\n Warning: ${NFR71_WARNING}`));
|
|
1049
|
+
|
|
1050
|
+
if (yesFlag) {
|
|
1051
|
+
// --yes + --bmad-custom-source: select every declared plugin, matching
|
|
1052
|
+
// the "select all" default used elsewhere in --yes mode (bmad modules,
|
|
1053
|
+
// skills). The user asked for this source explicitly via the flag.
|
|
1054
|
+
const selectedCodes = plugins.map((p) => p.code);
|
|
1055
|
+
console.log(chalk.cyan(` Custom marketplace: selected all ${selectedCodes.length} extension(s) from "${source}".`));
|
|
1056
|
+
return { source, mode, selectedCodes, plugins, rootDir, sourceUrl };
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
const { chosenCodes } = await prompts({
|
|
1060
|
+
type: 'multiselect',
|
|
1061
|
+
name: 'chosenCodes',
|
|
1062
|
+
message: `Select extensions to install from "${source}":`,
|
|
1063
|
+
choices: plugins.map((p) => ({
|
|
1064
|
+
title: chalk.white(p.code) + chalk.gray(p.description ? ` — ${p.description}` : ''),
|
|
1065
|
+
value: p.code,
|
|
1066
|
+
selected: true,
|
|
1067
|
+
})),
|
|
1068
|
+
instructions: chalk.gray(' Use space to toggle, enter to confirm.'),
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
if (chosenCodes === undefined) {
|
|
1072
|
+
console.log(chalk.gray(' Custom marketplace selection cancelled.'));
|
|
1073
|
+
return null;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
return { source, mode, selectedCodes: chosenCodes, plugins, rootDir, sourceUrl };
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* Story 30.7 (FR242) — on `update`, re-enumerate a PERSISTED custom
|
|
1081
|
+
* marketplace source instead of asking the plain Y/N prompt again, and
|
|
1082
|
+
* reconcile the fresh plugin list against the persisted `selectedCodes`.
|
|
1083
|
+
* Newly-appeared plugins are reported ONLY — never added to the returned
|
|
1084
|
+
* selection. A code that is no longer declared is dropped and reported.
|
|
1085
|
+
*
|
|
1086
|
+
* Fail-loud contract: if the persisted source cannot be re-enumerated
|
|
1087
|
+
* (unreachable, removed, drifted adapter surface), this prints a clear,
|
|
1088
|
+
* visible error and returns `null` WITHOUT writing anything to
|
|
1089
|
+
* `.ma-agents.json` — the persisted selection is left exactly as it was so a
|
|
1090
|
+
* later successful `update` picks up where the user left off. This function
|
|
1091
|
+
* never calls `setCustomMarketplaceSelection` itself; persistence only ever
|
|
1092
|
+
* happens after a REAL install, in `lib/bmad.js#installCustomMarketplaceSubset`.
|
|
1093
|
+
*
|
|
1094
|
+
* @param {Object} ctx
|
|
1095
|
+
* @param {string} ctx.projectRoot
|
|
1096
|
+
* @returns {Promise<undefined|null|{ source: string, mode: 'discovery'|'direct',
|
|
1097
|
+
* selectedCodes: string[], plugins: Array<Object>, rootDir: string, sourceUrl: string|null }>}
|
|
1098
|
+
* `undefined` — nothing persisted; caller should fall back to `promptCustomMarketplace()`.
|
|
1099
|
+
* `null` — persisted source exists but could not be re-enumerated (fail-loud; skip this run).
|
|
1100
|
+
* selection object — reconciled; `selectedCodes` is the persisted set minus any `removed`.
|
|
1101
|
+
*/
|
|
1102
|
+
async function reconcileCustomMarketplaceOnUpdate({ projectRoot }) {
|
|
1103
|
+
const persisted = getCustomMarketplaceSelection(projectRoot);
|
|
1104
|
+
if (!persisted) return undefined;
|
|
1105
|
+
|
|
1106
|
+
let enumerated;
|
|
1107
|
+
try {
|
|
1108
|
+
enumerated = await enumerateCustomSource(persisted.source);
|
|
1109
|
+
} catch (err) {
|
|
1110
|
+
const message = err instanceof CustomMarketplaceError ? err.message : `Custom marketplace source error: ${err.message}`;
|
|
1111
|
+
console.log(chalk.red(`\n Custom marketplace update FAILED: ${message}`));
|
|
1112
|
+
console.log(
|
|
1113
|
+
chalk.red(
|
|
1114
|
+
` The persisted selection (${persisted.selectedCodes.join(', ') || '(none)'}) from ` +
|
|
1115
|
+
`"${persisted.source}" is UNCHANGED — it will be retried on the next update.`
|
|
1116
|
+
)
|
|
1117
|
+
);
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
const { plugins, mode, rootDir, sourceUrl } = enumerated;
|
|
1122
|
+
const { added, removed, stillPresent } = reconcileCustomMarketplaceSelection({
|
|
1123
|
+
persistedSelectedCodes: persisted.selectedCodes,
|
|
1124
|
+
enumeratedPlugins: plugins,
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
console.log(chalk.cyan(`\n Custom marketplace source "${persisted.source}" re-enumerated:`));
|
|
1128
|
+
if (persisted.sha) {
|
|
1129
|
+
// The persisted SHA is the last-installed commit, INFORMATIONAL only.
|
|
1130
|
+
// Updates deliberately float to remote HEAD (FR242/NFR72) to surface
|
|
1131
|
+
// newly-published extensions — we report the last-installed SHA rather
|
|
1132
|
+
// than pin to it, so the float-to-HEAD behavior is explicit, not silent.
|
|
1133
|
+
console.log(chalk.gray(` (last installed at ${persisted.sha.slice(0, 12)}; update re-enumerates at the source's current HEAD, not this pin)`));
|
|
1134
|
+
}
|
|
1135
|
+
if (added.length > 0) {
|
|
1136
|
+
console.log(chalk.gray(` + newly available (not auto-installed; re-run the custom-source flow to add): ${added.join(', ')}`));
|
|
1137
|
+
}
|
|
1138
|
+
if (removed.length > 0) {
|
|
1139
|
+
console.log(chalk.yellow(` - no longer available (dropped from the installed selection): ${removed.join(', ')}`));
|
|
1140
|
+
}
|
|
1141
|
+
if (added.length === 0 && removed.length === 0) {
|
|
1142
|
+
console.log(chalk.gray(' No changes vs. the persisted selection.'));
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
if (stillPresent.length === 0) {
|
|
1146
|
+
console.log(chalk.yellow(' None of the previously-selected extensions are declared by this source anymore — nothing to reinstall from it.'));
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
return { source: persisted.source, mode, selectedCodes: stillPresent, plugins, rootDir, sourceUrl };
|
|
1150
|
+
}
|
|
1151
|
+
|
|
921
1152
|
// --- Install wizard ---
|
|
922
1153
|
|
|
923
|
-
async function installWizard(preselectedSkill, preselectedAgents, customPath, forceFlag, yesFlag = false, cliScope, bmadModulesFlag = '', bmadModulesPrompt = false) {
|
|
1154
|
+
async function installWizard(preselectedSkill, preselectedAgents, customPath, forceFlag, yesFlag = false, cliScope, bmadModulesFlag = '', bmadModulesPrompt = false, bmadCustomSourceFlag = '') {
|
|
924
1155
|
const skills = listSkills();
|
|
925
1156
|
const agents = listAgents();
|
|
926
1157
|
|
|
@@ -1209,10 +1440,16 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
1209
1440
|
projectRoot: process.cwd(),
|
|
1210
1441
|
});
|
|
1211
1442
|
|
|
1443
|
+
// Story 30.6b AC 6 — tracks whether the base BMAD install/update step
|
|
1444
|
+
// left a usable installation for the custom-marketplace subset install
|
|
1445
|
+
// (Step 3.5b) to layer onto. See resolveBaseBmadOk() for the policy.
|
|
1446
|
+
let baseBmadOk = resolveBaseBmadOk({ bmadInstalled, attempted: false });
|
|
1447
|
+
|
|
1212
1448
|
if (!bmadInstalled) {
|
|
1213
1449
|
if (yesFlag) {
|
|
1214
1450
|
console.log(chalk.cyan(`\n Installing BMAD-METHOD (modules: ${bmadModules.join(', ')})...`));
|
|
1215
1451
|
const success = await bmad.installBmad(bmadModules, bmadTools);
|
|
1452
|
+
baseBmadOk = resolveBaseBmadOk({ bmadInstalled, attempted: true, success });
|
|
1216
1453
|
if (success) {
|
|
1217
1454
|
console.log(chalk.green(' BMAD-METHOD installed successfully!'));
|
|
1218
1455
|
}
|
|
@@ -1227,15 +1464,19 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
1227
1464
|
if (installBmad) {
|
|
1228
1465
|
console.log(chalk.cyan(`\n Installing BMAD-METHOD (modules: ${bmadModules.join(', ')})...`));
|
|
1229
1466
|
const success = await bmad.installBmad(bmadModules, bmadTools);
|
|
1467
|
+
baseBmadOk = resolveBaseBmadOk({ bmadInstalled, attempted: true, success });
|
|
1230
1468
|
if (success) {
|
|
1231
1469
|
console.log(chalk.green(' BMAD-METHOD installed successfully!'));
|
|
1232
1470
|
}
|
|
1471
|
+
} else {
|
|
1472
|
+
baseBmadOk = resolveBaseBmadOk({ bmadInstalled, attempted: false });
|
|
1233
1473
|
}
|
|
1234
1474
|
}
|
|
1235
1475
|
} else {
|
|
1236
1476
|
if (yesFlag) {
|
|
1237
1477
|
console.log(chalk.cyan(`\n Updating BMAD-METHOD (modules: ${bmadModules.join(', ')})...`));
|
|
1238
1478
|
const success = await bmad.updateBmad(bmadModules, bmadTools);
|
|
1479
|
+
baseBmadOk = resolveBaseBmadOk({ bmadInstalled, attempted: true, success });
|
|
1239
1480
|
if (success) {
|
|
1240
1481
|
console.log(chalk.green(' BMAD-METHOD updated successfully!'));
|
|
1241
1482
|
}
|
|
@@ -1250,10 +1491,70 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
1250
1491
|
if (updateBmad) {
|
|
1251
1492
|
console.log(chalk.cyan(`\n Updating BMAD-METHOD (modules: ${bmadModules.join(', ')})...`));
|
|
1252
1493
|
const success = await bmad.updateBmad(bmadModules, bmadTools);
|
|
1494
|
+
baseBmadOk = resolveBaseBmadOk({ bmadInstalled, attempted: true, success });
|
|
1253
1495
|
if (success) {
|
|
1254
1496
|
console.log(chalk.green(' BMAD-METHOD updated successfully!'));
|
|
1255
1497
|
}
|
|
1256
1498
|
}
|
|
1499
|
+
// else: update declined, but BMAD was already installed from a
|
|
1500
|
+
// prior run — resolveBaseBmadOk({attempted:false}) is `bmadInstalled`,
|
|
1501
|
+
// i.e. still true (there IS a usable base).
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
// Step 3.5b: Custom marketplace source (Story 30.6a enumerate + wizard;
|
|
1506
|
+
// Story 30.6b prune + stage + install-the-subset; Story 30.7 persist +
|
|
1507
|
+
// re-enumerate/reconcile on update, FR240/FR242).
|
|
1508
|
+
let customMarketplaceSelection = null;
|
|
1509
|
+
// Story 30.7 — on a BMAD-METHOD *update* (i.e. `bmadInstalled` was
|
|
1510
|
+
// already true before this run, so bmad.updateBmad() ran above — this
|
|
1511
|
+
// is the FR242 "on update" case, and is DELIBERATELY independent of
|
|
1512
|
+
// `isUpdate`, which only tracks ma-agents' own "Update (add/remove
|
|
1513
|
+
// skills)" wizard choice and stays false under `--yes` reruns) with NO
|
|
1514
|
+
// explicit `--bmad-custom-source` override, prefer re-enumerating a
|
|
1515
|
+
// PERSISTED source over asking the plain Y/N prompt again. An explicit
|
|
1516
|
+
// flag always wins (fresh engagement via the normal prompt path below).
|
|
1517
|
+
// `undefined` means nothing was persisted — fall through unchanged.
|
|
1518
|
+
let usedPersistedReconcile = false;
|
|
1519
|
+
if (bmadInstalled && !bmadCustomSourceFlag) {
|
|
1520
|
+
const reconciled = await reconcileCustomMarketplaceOnUpdate({ projectRoot: process.cwd() });
|
|
1521
|
+
if (reconciled !== undefined) {
|
|
1522
|
+
usedPersistedReconcile = true;
|
|
1523
|
+
customMarketplaceSelection = reconciled; // null (fail-loud skip) or a reconciled selection
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
if (!usedPersistedReconcile) {
|
|
1527
|
+
try {
|
|
1528
|
+
customMarketplaceSelection = await promptCustomMarketplace({ bmadCustomSourceFlag, yesFlag });
|
|
1529
|
+
} catch (err) {
|
|
1530
|
+
console.log(chalk.yellow(`\n Custom marketplace source skipped: ${err.message}`));
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
if (customMarketplaceSelection && customMarketplaceSelection.selectedCodes.length > 0) {
|
|
1534
|
+
if (!baseBmadOk) {
|
|
1535
|
+
// AC 6 (30.6b) — never layer --custom-source onto a project with no
|
|
1536
|
+
// (or a broken) base BMAD install. The rest of the install is
|
|
1537
|
+
// otherwise unaffected.
|
|
1538
|
+
console.log(
|
|
1539
|
+
chalk.yellow(
|
|
1540
|
+
'\n Skipping custom marketplace install — the base BMAD install/update did not ' +
|
|
1541
|
+
'complete successfully, so there is no BMAD installation to add it to.'
|
|
1542
|
+
)
|
|
1543
|
+
);
|
|
1544
|
+
} else {
|
|
1545
|
+
try {
|
|
1546
|
+
const success = await bmad.installCustomMarketplaceSubset({
|
|
1547
|
+
projectRoot: process.cwd(),
|
|
1548
|
+
modules: bmadModules,
|
|
1549
|
+
tools: bmadTools,
|
|
1550
|
+
selection: customMarketplaceSelection,
|
|
1551
|
+
});
|
|
1552
|
+
if (success) {
|
|
1553
|
+
console.log(chalk.green(' Custom marketplace subset installed successfully!'));
|
|
1554
|
+
}
|
|
1555
|
+
} catch (err) {
|
|
1556
|
+
console.log(chalk.red(`\n Custom marketplace install failed: ${err.message}`));
|
|
1557
|
+
}
|
|
1257
1558
|
}
|
|
1258
1559
|
}
|
|
1259
1560
|
}
|
|
@@ -1341,6 +1642,14 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
1341
1642
|
console.log(chalk.yellow(`\n Retired-skill migration skipped: ${err.message}`));
|
|
1342
1643
|
}
|
|
1343
1644
|
|
|
1645
|
+
// Story 30.4 (FR245/FR246) — idempotent one-time Demerzel deprecation
|
|
1646
|
+
// notice. No-op after the first time it has ever printed for this project.
|
|
1647
|
+
try {
|
|
1648
|
+
showDemerzelDeprecationNoticeOnce(process.cwd());
|
|
1649
|
+
} catch (err) {
|
|
1650
|
+
console.log(chalk.yellow(`\n Deprecation notice skipped: ${err.message}`));
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1344
1653
|
// Install requested skills
|
|
1345
1654
|
const batchState = {};
|
|
1346
1655
|
if (yesFlag) {
|
|
@@ -1424,7 +1733,7 @@ async function installWizard(preselectedSkill, preselectedAgents, customPath, fo
|
|
|
1424
1733
|
// --- Command handlers ---
|
|
1425
1734
|
|
|
1426
1735
|
async function handleInstall(args) {
|
|
1427
|
-
const { globalFlag, forceFlag, yesFlag, agentFlag, customPath, bmadModulesFlag, bmadModulesPrompt, scope, positional } = parseFlags(args);
|
|
1736
|
+
const { globalFlag, forceFlag, yesFlag, agentFlag, customPath, bmadModulesFlag, bmadModulesPrompt, bmadCustomSourceFlag, scope, positional } = parseFlags(args);
|
|
1428
1737
|
|
|
1429
1738
|
// Task 3.2: Validate agentFlag against known agents
|
|
1430
1739
|
if (agentFlag) {
|
|
@@ -1443,13 +1752,13 @@ async function handleInstall(args) {
|
|
|
1443
1752
|
|
|
1444
1753
|
// No skill → launch wizard (Task 3.3, 3.4)
|
|
1445
1754
|
if (!skillId) {
|
|
1446
|
-
await installWizard(null, preselectedAgents, customPath, forceFlag, yesFlag, scope, bmadModulesFlag, bmadModulesPrompt);
|
|
1755
|
+
await installWizard(null, preselectedAgents, customPath, forceFlag, yesFlag, scope, bmadModulesFlag, bmadModulesPrompt, bmadCustomSourceFlag);
|
|
1447
1756
|
return;
|
|
1448
1757
|
}
|
|
1449
1758
|
|
|
1450
1759
|
// Skill but no agents (and no agentFlag) → wizard with skill preselected
|
|
1451
1760
|
if (!agentFlag && agentIds.length === 0) {
|
|
1452
|
-
await installWizard(skillId, null, customPath, forceFlag, yesFlag, scope, bmadModulesFlag, bmadModulesPrompt);
|
|
1761
|
+
await installWizard(skillId, null, customPath, forceFlag, yesFlag, scope, bmadModulesFlag, bmadModulesPrompt, bmadCustomSourceFlag);
|
|
1453
1762
|
return;
|
|
1454
1763
|
}
|
|
1455
1764
|
|
|
@@ -1506,6 +1815,14 @@ async function handleInstall(args) {
|
|
|
1506
1815
|
console.log(chalk.yellow(`\n Retired-skill migration skipped: ${err.message}`));
|
|
1507
1816
|
}
|
|
1508
1817
|
|
|
1818
|
+
// Story 30.4 (FR245/FR246) — idempotent one-time Demerzel deprecation
|
|
1819
|
+
// notice. No-op after the first time it has ever printed for this project.
|
|
1820
|
+
try {
|
|
1821
|
+
showDemerzelDeprecationNoticeOnce(process.cwd());
|
|
1822
|
+
} catch (err) {
|
|
1823
|
+
console.log(chalk.yellow(`\n Deprecation notice skipped: ${err.message}`));
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1509
1826
|
try {
|
|
1510
1827
|
await installSkill(skillId, targetAgents, customPath, scope, { force: forceFlag, yes: yesFlag });
|
|
1511
1828
|
console.log(chalk.bold.green('\n Installation complete!\n'));
|
|
@@ -1772,4 +2089,4 @@ if (require.main === module) {
|
|
|
1772
2089
|
});
|
|
1773
2090
|
}
|
|
1774
2091
|
|
|
1775
|
-
module.exports = { parseFlags, selectBmadModules, collectRepoLayout, readExistingLayout, writeRepoLayoutConfig, writeProjectLayoutYaml, writeConfigField, normalizePath, toPortablePath, resolveStoredPath, ciCloneIfNeeded, showCurrentLayout, handleConfigLayout, yamlEscapeValue };
|
|
2092
|
+
module.exports = { parseFlags, selectBmadModules, promptCustomMarketplace, reconcileCustomMarketplaceOnUpdate, resolveBaseBmadOk, collectRepoLayout, readExistingLayout, writeRepoLayoutConfig, writeProjectLayoutYaml, writeConfigField, normalizePath, toPortablePath, resolveStoredPath, ciCloneIfNeeded, showCurrentLayout, handleConfigLayout, yamlEscapeValue };
|
package/lib/agents.js
CHANGED
|
@@ -151,7 +151,20 @@ const agents = [
|
|
|
151
151
|
'assets': 'templates'
|
|
152
152
|
},
|
|
153
153
|
instructionFiles: ['.cline/clinerules.md'],
|
|
154
|
-
|
|
154
|
+
// Story 30.9 — registry-driven capability flags replace the previous
|
|
155
|
+
// `agent.id === 'cline'` literal checks in lib/installer.js.
|
|
156
|
+
// `dualFileDriftCheck` opts this agent into the legacy
|
|
157
|
+
// `.cline/clinerules.md` vs `.clinerules`-file drift guard (Story 21.5
|
|
158
|
+
// AC #6). `framingTemplate` names the fresh-file framing template
|
|
159
|
+
// (relative to lib/templates/) used when creating the instruction file
|
|
160
|
+
// from scratch (Story 21.5 AC #1/#2). Both are absent (falsy) on every
|
|
161
|
+
// other agent — installer.js treats that as "skip this behavior".
|
|
162
|
+
injectionStrategy: {
|
|
163
|
+
position: 'top',
|
|
164
|
+
skipPatterns: ['---'],
|
|
165
|
+
dualFileDriftCheck: true,
|
|
166
|
+
framingTemplate: 'clinerules.template.md'
|
|
167
|
+
}
|
|
155
168
|
},
|
|
156
169
|
{
|
|
157
170
|
id: 'roo-code',
|
|
@@ -326,20 +339,14 @@ const agents = [
|
|
|
326
339
|
instructionFiles: ['_bmad/bmm/agents/qa.md'],
|
|
327
340
|
injectionStrategy: { position: 'top', skipPatterns: ['---'] }
|
|
328
341
|
},
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
getGlobalPath: () => null,
|
|
338
|
-
fileExtension: '.md',
|
|
339
|
-
template: 'generic',
|
|
340
|
-
instructionFiles: ['_bmad/bmm/agents/demerzel.md'],
|
|
341
|
-
injectionStrategy: { position: 'top', skipPatterns: ['---'] }
|
|
342
|
-
}
|
|
342
|
+
// Story 30.4 / Decision P5-8, FR244-FR247: the 'bmm-demerzel' (ML Scientist)
|
|
343
|
+
// agent registration is REMOVED for new installs — Demerzel is deprecated
|
|
344
|
+
// and its ma-agent-ml + 12 ml-* skills no longer ship in the BMAD-extension
|
|
345
|
+
// plugin (lib/bmad-extension/skills/). Existing installs that already have
|
|
346
|
+
// this content deployed are left untouched (NFR49) — see
|
|
347
|
+
// lib/profile.js#showDemerzelDeprecationNoticeOnce for the one-time notice.
|
|
348
|
+
// Supersedes FR193 (the deferred Demerzel -> Memory-agent conversion is
|
|
349
|
+
// cancelled).
|
|
343
350
|
// DEFERRED (Story 28.3 / Decision P5-6(d), FR214): BMAD v6.9.0 adds two new
|
|
344
351
|
// installer platform targets — `hermes` (Hermes Agent) and `codewhale`
|
|
345
352
|
// (CodeWhale). They are intentionally NOT added to this registry. Passthrough
|