bmad-plus 0.12.1 → 0.13.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/CHANGELOG.md +637 -580
- package/README.md +123 -120
- package/osint-agent-package/agents/osint-investigator.md +12 -0
- package/osint-agent-package/skills/bmad-osint-investigate/osint/SKILL.md +491 -482
- package/osint-agent-package/skills/bmad-osint-investigate/osint/assets/dossier-template.md +126 -126
- package/osint-agent-package/skills/bmad-osint-investigate/osint/assets/lawful-basis-record.md +48 -48
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/content-extraction.md +100 -100
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/gdpr-osint.md +48 -48
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/platforms.md +130 -130
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/psychoprofile.md +69 -69
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/tools.md +281 -281
- package/osint-agent-package/skills/bmad-osint-investigate/osint/scripts/mcp-client.py +136 -136
- package/package.json +106 -91
- package/readme-international/README.de.md +625 -594
- package/readme-international/README.es.md +642 -611
- package/readme-international/README.fr.md +640 -609
- package/src/bmad-plus/agents/agent-orchestrator/SKILL.md +2 -0
- package/src/bmad-plus/agents/agent-shadow/SKILL.md +18 -0
- package/src/bmad-plus/data/role-triggers.yaml +52 -0
- package/src/bmad-plus/module.yaml +333 -283
- package/src/bmad-plus/packs/pack-animated/animated-website-agent.md +325 -325
- package/src/bmad-plus/packs/pack-animated/templates/animated-website-workflow.md +55 -55
- package/src/bmad-plus/packs/pack-backup/backup-agent.md +71 -71
- package/src/bmad-plus/packs/pack-backup/templates/backup-workflow.md +51 -51
- package/src/bmad-plus/packs/pack-dev-studio/README.md +162 -162
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/analyst-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/document-project.md +61 -61
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/domain-research.md +95 -95
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/market-research.md +95 -95
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/prfaq.md +134 -134
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/product-brief.md +80 -80
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/tech-writer-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/technical-research.md +95 -95
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/architect-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/create-architecture.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/create-epics-stories.md +92 -92
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/generate-project-context.md +80 -80
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/implementation-readiness.md +90 -90
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-01-init.md +153 -153
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-01b-continue.md +173 -173
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-02-context.md +224 -224
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-03-starter.md +329 -329
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-04-decisions.md +318 -318
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-05-patterns.md +359 -359
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-06-structure.md +379 -379
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-07-validation.md +361 -361
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-08-complete.md +81 -81
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/checkpoint-preview.md +67 -67
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review-steps/step-01-gather-context.md +85 -85
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review-steps/step-02-review.md +35 -35
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review-steps/step-03-triage.md +49 -49
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review-steps/step-04-present.md +131 -131
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review.md +89 -89
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/correct-course.md +300 -300
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/create-story.md +428 -428
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-story-checklist.md +80 -80
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-story.md +484 -484
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/investigate.md +193 -193
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/qa-e2e-tests.md +175 -175
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/quick-dev.md +110 -110
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/retrospective.md +1511 -1511
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/sprint-planning.md +298 -298
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/sprint-status.md +296 -296
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/create-prd.md +29 -29
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/create-ux-design.md +74 -74
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/edit-prd.md +29 -29
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/pm-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/prd.md +89 -89
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/ux-designer-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/validate-prd.md +29 -29
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/advanced-elicitation.md +141 -141
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/adversarial-review.md +37 -37
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/bmad-help.md +75 -75
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/brainstorming.md +6 -6
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/customize.md +110 -110
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/distillator.md +176 -176
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/edge-case-hunter.md +67 -67
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/editorial-review-prose.md +86 -86
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/editorial-review-structure.md +179 -179
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/index-docs.md +66 -66
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/party-mode.md +127 -127
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/shard-doc.md +105 -105
- package/src/bmad-plus/packs/pack-dev-studio/dev-studio-orchestrator.md +120 -120
- package/src/bmad-plus/packs/pack-dev-studio/shared/architecture-decision-template.md +12 -12
- package/src/bmad-plus/packs/pack-dev-studio/shared/bwml-spec.md +328 -328
- package/src/bmad-plus/packs/pack-dev-studio/shared/module-help.csv +32 -32
- package/src/bmad-plus/packs/pack-dev-studio/upstream-sync.yaml +81 -81
- package/src/bmad-plus/packs/pack-seo/SKILL.md +171 -171
- package/src/bmad-plus/packs/pack-seo/checklist.md +140 -140
- package/src/bmad-plus/packs/pack-seo/pagespeed-playbook.md +320 -320
- package/src/bmad-plus/packs/pack-seo/ref/audit-schema.json +187 -187
- package/src/bmad-plus/packs/pack-seo/ref/cwv-thresholds.md +87 -87
- package/src/bmad-plus/packs/pack-seo/ref/eeat-criteria.md +123 -123
- package/src/bmad-plus/packs/pack-seo/ref/geo-signals.md +167 -167
- package/src/bmad-plus/packs/pack-seo/ref/hreflang-rules.md +153 -153
- package/src/bmad-plus/packs/pack-seo/ref/quality-gates.md +133 -133
- package/src/bmad-plus/packs/pack-seo/ref/schema-catalog.md +91 -91
- package/src/bmad-plus/packs/pack-seo/ref/schema-templates.json +356 -356
- package/src/bmad-plus/packs/pack-seo/requirements.txt +17 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_apis.py +456 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_crawl.py +359 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_fetch.py +303 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_parse.py +255 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_report.py +409 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_screenshot.py +202 -0
- package/src/bmad-plus/packs/pack-seo/seo-chief.md +294 -294
- package/src/bmad-plus/packs/pack-seo/seo-judge.md +241 -241
- package/src/bmad-plus/packs/pack-seo/seo-scout.md +171 -171
- package/src/bmad-plus/packs/pack-seo/templates/seo-audit-workflow.md +241 -241
- package/src/bmad-plus/packs/pack-shield/README.md +6 -6
- package/src/bmad-plus/packs/pack-shield/SKILL.md +2 -2
- package/src/bmad-plus/packs/pack-shield/categories/accessibility-esg/csrd-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/accessibility-esg/section508-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/accessibility-esg/wcag-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/ai-governance/eu-ai-act-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/ai-governance/iso42001-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/ai-governance/nist-ai-rmf-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/cis-controls-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/ism-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/iso27001-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/nis2-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/nist-800-53-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/nist-csf-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/defense-export/cmmc-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/defense-export/ear-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/defense-export/itar-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/defense-export/tsa-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/dora-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/fedramp-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/hipaa-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/pci-dss-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/soc2-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/swift-csp-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/shield-orchestrator.md +1 -1
- package/src/bmad-plus/skills/bmad-plus-autopilot/SKILL.md +1 -1
- package/tools/bmad-plus-npx.js +4 -2
- package/tools/build/adapters.config.js +60 -51
- package/tools/build/check-counts.js +626 -0
- package/tools/build/check-install-contract.js +298 -0
- package/tools/build/generate-adapters.js +252 -56
- package/tools/build/generate.js +187 -10
- package/tools/build/generated-adapters/.codex/AGENTS.md +20 -7
- package/tools/build/generated-adapters/.cursor/rules/bmad-plus.mdc +20 -7
- package/tools/build/generated-adapters/.opencode/AGENTS.md +20 -7
- package/tools/build/generated-adapters/AGENTS.md +20 -7
- package/tools/build/generated-adapters/CLAUDE.md +20 -7
- package/tools/build/generated-adapters/CONVENTIONS.md +20 -7
- package/tools/build/generated-adapters/GEMINI.md +20 -7
- package/tools/build/module.template.yaml +82 -0
- package/tools/cli/bmad-plus-cli.js +16 -1
- package/tools/cli/commands/autoconfig.js +470 -470
- package/tools/cli/commands/doctor.js +205 -233
- package/tools/cli/commands/install.js +543 -501
- package/tools/cli/commands/memory-journal-cmd.js +311 -311
- package/tools/cli/commands/memory.js +195 -195
- package/tools/cli/commands/scan.js +348 -348
- package/tools/cli/commands/uninstall.js +209 -101
- package/tools/cli/commands/update-check.js +31 -0
- package/tools/cli/commands/update-policy.js +39 -0
- package/tools/cli/commands/update.js +123 -134
- package/tools/cli/i18n.js +905 -845
- package/tools/cli/lib/README-memory-journal.md +125 -125
- package/tools/cli/lib/ide-config.js +10 -259
- package/tools/cli/lib/install-manifest.js +17 -0
- package/tools/cli/lib/installed-adapters.js +89 -0
- package/tools/cli/lib/npm-runner.js +177 -0
- package/tools/cli/lib/pack-copy.js +62 -66
- package/tools/cli/lib/packs.js +437 -3
- package/tools/cli/lib/python-provision.js +508 -508
- package/tools/cli/lib/stack-detect.js +102 -102
- package/tools/cli/lib/update-check.js +153 -0
- package/tools/cli/lib/update-dispatch.js +182 -0
- package/tools/cli/lib/update-policy.js +90 -0
- package/tools/cli/lib/update-transaction.js +334 -0
- package/tools/cli/lib/validate.js +50 -50
|
@@ -1,101 +1,209 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BMAD+ Uninstall Command
|
|
3
|
-
* Removes BMAD+
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
1
|
+
/**
|
|
2
|
+
* BMAD+ Uninstall Command
|
|
3
|
+
* Removes identifiable BMAD+ files while preserving project memory and edits.
|
|
4
|
+
* Author: Laurent Rochetta
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('node:path');
|
|
8
|
+
const fs = require('node:fs');
|
|
9
|
+
const clack = require('@clack/prompts');
|
|
10
|
+
const pc = require('picocolors');
|
|
11
|
+
const { t } = require('../i18n');
|
|
12
|
+
const { PACKS, DERIVED } = require('../lib/packs');
|
|
13
|
+
const { readInstallManifest } = require('../lib/install-manifest');
|
|
14
|
+
const { generateUserFiles, USER_CONFIG_MARKER } = require('../../build/generate-adapters');
|
|
15
|
+
const { contentHash } = require('../lib/installed-adapters');
|
|
16
|
+
|
|
17
|
+
// Never follow a junction/symlink in a path used for deletion, including parents.
|
|
18
|
+
function safeStat(projectDir, target) {
|
|
19
|
+
const relative = path.relative(projectDir, target);
|
|
20
|
+
if (!relative || relative === '..' || relative.startsWith('..' + path.sep) || path.isAbsolute(relative)) {
|
|
21
|
+
throw new Error('Path outside the project: ' + target);
|
|
22
|
+
}
|
|
23
|
+
let current = projectDir;
|
|
24
|
+
let stat;
|
|
25
|
+
for (const part of relative.split(path.sep)) {
|
|
26
|
+
current = path.join(current, part);
|
|
27
|
+
try {
|
|
28
|
+
stat = fs.lstatSync(current);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
if (err.code === 'ENOENT') return undefined;
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
if (stat.isSymbolicLink()) {
|
|
34
|
+
const error = new Error('Symbolic link or junction: ' + current);
|
|
35
|
+
error.code = 'BMAD_UNSAFE_LINK';
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return stat;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function removalPlan(projectDir, manifest, manifestPath) {
|
|
43
|
+
const packageRoot = path.join(__dirname, '..', '..', '..');
|
|
44
|
+
const sourceRoot = path.join(packageRoot, 'src', 'bmad-plus');
|
|
45
|
+
const files = new Map();
|
|
46
|
+
const directories = new Set();
|
|
47
|
+
const targetPath = (...parts) => path.join(projectDir, ...parts);
|
|
48
|
+
|
|
49
|
+
// Old manifests contain pack IDs, not file hashes. Match shipped files byte for
|
|
50
|
+
// byte; anything unknown or modified stays, including files inside a pack.
|
|
51
|
+
function matchSource(source, target) {
|
|
52
|
+
const targetStat = safeStat(projectDir, target);
|
|
53
|
+
if (!targetStat || !fs.existsSync(source)) return;
|
|
54
|
+
const sourceStat = fs.lstatSync(source);
|
|
55
|
+
if (sourceStat.isDirectory() && targetStat.isDirectory()) {
|
|
56
|
+
directories.add(target);
|
|
57
|
+
for (const name of fs.readdirSync(source)) matchSource(path.join(source, name), path.join(target, name));
|
|
58
|
+
} else if (sourceStat.isFile() && targetStat.isFile()) {
|
|
59
|
+
const expected = fs.readFileSync(source);
|
|
60
|
+
if (fs.readFileSync(target).equals(expected)) files.set(target, expected);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (const relative of ['.agents', '.agents/skills', '.agents/data', '_bmad', '_bmad-output']) {
|
|
65
|
+
const target = targetPath(relative);
|
|
66
|
+
if (safeStat(projectDir, target)?.isDirectory()) directories.add(target);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (const packId of manifest.packs) {
|
|
70
|
+
if (!Object.hasOwn(PACKS, packId)) throw new Error('Unknown installed pack: ' + packId);
|
|
71
|
+
const pack = PACKS[packId];
|
|
72
|
+
for (const name of pack.agents || []) matchSource(path.join(sourceRoot, 'agents', name), targetPath('.agents', 'skills', name));
|
|
73
|
+
for (const name of pack.skills || []) matchSource(path.join(sourceRoot, 'skills', name), targetPath('.agents', 'skills', name));
|
|
74
|
+
for (const name of pack.data || []) matchSource(path.join(sourceRoot, 'data', name), targetPath('.agents', 'data', name));
|
|
75
|
+
if (pack.packDir) matchSource(path.join(sourceRoot, pack.packSrcDir || 'agents', pack.packDir), targetPath('.agents', 'skills', pack.packDir));
|
|
76
|
+
if (pack.externalPackage) matchSource(path.join(packageRoot, pack.externalPackage, 'skills'), targetPath('.agents', 'skills'));
|
|
77
|
+
}
|
|
78
|
+
for (const name of ['module.yaml', 'module-help.csv']) matchSource(path.join(sourceRoot, name), targetPath('_bmad', name));
|
|
79
|
+
const renderOptions = {
|
|
80
|
+
packs: manifest.packs,
|
|
81
|
+
userName: typeof manifest.user === 'string' ? manifest.user : 'Developer',
|
|
82
|
+
language: typeof manifest.language === 'string' ? manifest.language : 'English',
|
|
83
|
+
};
|
|
84
|
+
const expectedFiles = new Map(generateUserFiles(DERIVED, renderOptions).map(entry => [entry.file, entry.content]));
|
|
85
|
+
const hashes = manifest.adapterHashes && typeof manifest.adapterHashes === 'object' && !Array.isArray(manifest.adapterHashes)
|
|
86
|
+
? manifest.adapterHashes : {};
|
|
87
|
+
// Only registry-declared paths can become deletion candidates, even when the
|
|
88
|
+
// manifest contains arbitrary hash keys. Keep previously owned tool targets.
|
|
89
|
+
const claimed = new Set(Object.keys(hashes).filter(file => expectedFiles.has(file)));
|
|
90
|
+
if (Array.isArray(manifest.ides)) {
|
|
91
|
+
const tools = manifest.ides.filter(id => DERIVED.targets.adapters.some(adapter => adapter.tool === id));
|
|
92
|
+
if (tools.length) {
|
|
93
|
+
for (const entry of generateUserFiles(DERIVED, { ...renderOptions, tools })) {
|
|
94
|
+
claimed.add(entry.file);
|
|
95
|
+
expectedFiles.set(entry.file, entry.content);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const legacyFallback = !Array.isArray(manifest.ides) && Object.keys(hashes).length === 0;
|
|
100
|
+
for (const [file, rendered] of expectedFiles) {
|
|
101
|
+
if (!legacyFallback && !claimed.has(file)) continue;
|
|
102
|
+
const target = targetPath(file);
|
|
103
|
+
let stat;
|
|
104
|
+
try {
|
|
105
|
+
stat = safeStat(projectDir, target);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
// A link with no ownership evidence is user content, not an uninstall target.
|
|
108
|
+
if (legacyFallback && error.code === 'BMAD_UNSAFE_LINK') continue;
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
if (stat?.isFile()) {
|
|
112
|
+
const content = fs.readFileSync(target);
|
|
113
|
+
const text = content.toString('utf8');
|
|
114
|
+
const expectedHash = hashes[file];
|
|
115
|
+
const matches = expectedHash ? contentHash(text) === expectedHash : text === rendered;
|
|
116
|
+
if (text.includes(USER_CONFIG_MARKER) && matches) {
|
|
117
|
+
files.set(target, content);
|
|
118
|
+
let parent = path.dirname(target);
|
|
119
|
+
while (parent !== projectDir) {
|
|
120
|
+
directories.add(parent);
|
|
121
|
+
parent = path.dirname(parent);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Keep config.yaml: it contains the user's settings and has no ownership hash.
|
|
127
|
+
files.set(manifestPath, fs.readFileSync(manifestPath));
|
|
128
|
+
return { files, directories };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = {
|
|
132
|
+
command: 'uninstall',
|
|
133
|
+
description: 'Remove BMAD+ from your project',
|
|
134
|
+
options: [
|
|
135
|
+
['-y, --yes', 'Confirm removal without prompting'],
|
|
136
|
+
['-l, --lang <code>', 'Language code: en, fr, es, de, pt-br, ru, zh, he, ja, it'],
|
|
137
|
+
],
|
|
138
|
+
action: async (options) => {
|
|
139
|
+
const projectDir = fs.realpathSync(process.cwd());
|
|
140
|
+
let i = t(options.lang || 'en');
|
|
141
|
+
clack.intro(pc.bgRed(pc.white(' BMAD+ Uninstaller ')));
|
|
142
|
+
|
|
143
|
+
const manifestPath = path.join(projectDir, '_bmad', '.bmad-plus-install.json');
|
|
144
|
+
let manifest;
|
|
145
|
+
try {
|
|
146
|
+
if (!safeStat(projectDir, manifestPath)) {
|
|
147
|
+
clack.log.warn(i.uninstall_not_installed);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
manifest = readInstallManifest(manifestPath);
|
|
151
|
+
} catch (err) {
|
|
152
|
+
clack.log.error(i.manifest_invalid(err.message));
|
|
153
|
+
clack.outro(pc.red(i.manifest_repair));
|
|
154
|
+
process.exitCode = 1;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
i = t(options.lang || manifest.uiLanguage || 'en');
|
|
158
|
+
if (!options.yes && !process.stdin.isTTY) {
|
|
159
|
+
clack.log.error(i.noninteractive_requires_yes('uninstall'));
|
|
160
|
+
process.exitCode = 1;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let plan;
|
|
165
|
+
try {
|
|
166
|
+
plan = removalPlan(projectDir, manifest, manifestPath);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
clack.log.error(i.uninstall_aborted(err.message));
|
|
169
|
+
process.exitCode = 1;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
clack.log.info('BMAD+ v' + manifest.version + ' (' + i.installed_on + ' ' + manifest.installed.split('T')[0] + ')');
|
|
173
|
+
clack.log.info(i.selected_packs + ': ' + manifest.packs.join(', '));
|
|
174
|
+
if (!options.yes) {
|
|
175
|
+
const confirm = await clack.confirm({ message: i.uninstall_confirm });
|
|
176
|
+
if (!confirm || clack.isCancel(confirm)) {
|
|
177
|
+
clack.cancel(i.cancelled);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const spinner = clack.spinner();
|
|
183
|
+
spinner.start(i.uninstall_removing);
|
|
184
|
+
let removed = 0;
|
|
185
|
+
try {
|
|
186
|
+
// Revalidate after the prompt, before deleting any file.
|
|
187
|
+
for (const target of [...plan.files.keys(), ...plan.directories]) safeStat(projectDir, target);
|
|
188
|
+
for (const [target, expected] of plan.files) {
|
|
189
|
+
if (safeStat(projectDir, target)?.isFile() && fs.readFileSync(target).equals(expected)) {
|
|
190
|
+
fs.unlinkSync(target);
|
|
191
|
+
removed++;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// No recursive deletion: hidden files, nested user content, and memory stay.
|
|
195
|
+
for (const target of [...plan.directories].sort((a, b) => b.length - a.length)) {
|
|
196
|
+
if (safeStat(projectDir, target)?.isDirectory() && fs.readdirSync(target).length === 0) {
|
|
197
|
+
fs.rmdirSync(target);
|
|
198
|
+
removed++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} catch (err) {
|
|
202
|
+
spinner.stop(i.uninstall_aborted(err.message));
|
|
203
|
+
process.exitCode = 1;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
spinner.stop(i.uninstall_done(removed));
|
|
207
|
+
clack.outro(i.uninstall_preserved);
|
|
208
|
+
},
|
|
209
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Report release status without applying updates. */
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
const { checkForUpdate } = require('../lib/update-check');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
command: 'update-check',
|
|
7
|
+
description: 'Check the published BMAD+ release without applying it',
|
|
8
|
+
options: [
|
|
9
|
+
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
10
|
+
['--refresh', 'Bypass the release cache and retry backoff'],
|
|
11
|
+
['--offline', 'Report local state without network access'],
|
|
12
|
+
['--json', 'Print machine-readable JSON'],
|
|
13
|
+
],
|
|
14
|
+
action: async (options = {}) => {
|
|
15
|
+
const result = await checkForUpdate({
|
|
16
|
+
projectDir: path.resolve(options.directory || process.cwd()),
|
|
17
|
+
runningVersion: require('../../../package.json').version,
|
|
18
|
+
refresh: Boolean(options.refresh), offline: Boolean(options.offline),
|
|
19
|
+
checkReadiness: ({ projectDir }) => {
|
|
20
|
+
const { evaluateUpdateReadiness } = require('../lib/update-transaction');
|
|
21
|
+
return evaluateUpdateReadiness({ projectDir });
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
if (result.status.startsWith('invalid-')) process.exitCode = 1;
|
|
25
|
+
if (options.json) console.log(JSON.stringify(result));
|
|
26
|
+
else {
|
|
27
|
+
console.log(`Installed: ${result.installedVersion || 'unknown'}; running: ${result.runningVersion}; channel ${result.channel || 'unknown'}: ${result.targetVersion || 'unknown'}`);
|
|
28
|
+
console.log(`${result.status}: ${result.reason}${result.stale ? ' (cached result is stale)' : ''}`);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Show or explicitly configure the local update policy; never updates packages. */
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
const { readUpdatePolicy, writeUpdatePolicy } = require('../lib/update-policy');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
command: 'update-policy',
|
|
7
|
+
description: 'Show or configure the project update policy',
|
|
8
|
+
options: [
|
|
9
|
+
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
10
|
+
['--mode <mode>', 'off, notify, or auto (auto requires --range)'],
|
|
11
|
+
['--range <range>', 'Explicit semantic-version range for automatic updates'],
|
|
12
|
+
['--channel <tag>', 'npm release tag (default: latest)'],
|
|
13
|
+
['--allow-prerelease', 'Explicitly allow prerelease targets'],
|
|
14
|
+
['--stable-only', 'Disable prerelease targets'],
|
|
15
|
+
['--json', 'Print machine-readable JSON'],
|
|
16
|
+
],
|
|
17
|
+
action: async (options = {}) => {
|
|
18
|
+
try {
|
|
19
|
+
if (options.allowPrerelease && options.stableOnly) throw new Error('Choose --allow-prerelease or --stable-only.');
|
|
20
|
+
if (options.mode === 'auto' && !options.range) throw new Error('--mode auto requires an explicit --range.');
|
|
21
|
+
const projectDir = path.resolve(options.directory || process.cwd());
|
|
22
|
+
const policy = readUpdatePolicy(projectDir);
|
|
23
|
+
const changing = options.mode !== undefined || options.range !== undefined ||
|
|
24
|
+
options.channel !== undefined || options.allowPrerelease || options.stableOnly;
|
|
25
|
+
if (options.mode !== undefined) policy.mode = options.mode;
|
|
26
|
+
if (options.range !== undefined) policy.allowedRange = options.range;
|
|
27
|
+
if (options.channel !== undefined) policy.channel = options.channel;
|
|
28
|
+
if (options.allowPrerelease) policy.allowPrerelease = true;
|
|
29
|
+
if (options.stableOnly) policy.allowPrerelease = false;
|
|
30
|
+
const saved = changing ? writeUpdatePolicy(projectDir, policy) : policy;
|
|
31
|
+
if (options.json) console.log(JSON.stringify({ policy: saved, changed: Boolean(changing) }));
|
|
32
|
+
else console.log(`Update policy${changing ? ' saved' : ''}: ${saved.mode}; channel=${saved.channel}; range=${saved.allowedRange || 'none'}; prereleases=${saved.allowPrerelease}`);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
if (options.json) console.log(JSON.stringify({ error: error.message }));
|
|
36
|
+
else console.error(error.message);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
};
|