bmad-plus 0.12.1 → 0.12.2
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 +612 -580
- package/README.md +90 -115
- 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 +104 -91
- package/readme-international/README.de.md +596 -594
- package/readme-international/README.es.md +613 -611
- package/readme-international/README.fr.md +611 -609
- 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 +283 -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 +304 -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 +410 -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/tools/build/check-counts.js +628 -0
- package/tools/build/generated-adapters/.codex/AGENTS.md +1 -1
- package/tools/build/generated-adapters/.cursor/rules/bmad-plus.mdc +1 -1
- package/tools/build/generated-adapters/.opencode/AGENTS.md +1 -1
- package/tools/build/generated-adapters/AGENTS.md +1 -1
- package/tools/build/generated-adapters/CLAUDE.md +1 -1
- package/tools/build/generated-adapters/CONVENTIONS.md +1 -1
- package/tools/build/generated-adapters/GEMINI.md +1 -1
- package/tools/cli/commands/autoconfig.js +470 -470
- package/tools/cli/commands/doctor.js +233 -233
- package/tools/cli/commands/install.js +598 -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 +101 -101
- package/tools/cli/commands/update.js +134 -134
- package/tools/cli/i18n.js +845 -845
- package/tools/cli/lib/README-memory-journal.md +125 -125
- package/tools/cli/lib/ide-config.js +267 -259
- package/tools/cli/lib/python-provision.js +508 -508
- package/tools/cli/lib/stack-detect.js +102 -102
- package/tools/cli/lib/validate.js +50 -50
|
@@ -1,233 +1,233 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BMAD+ Doctor Command
|
|
3
|
-
* Checks installation integrity and reports issues
|
|
4
|
-
*
|
|
5
|
-
* Author: Laurent Rochetta
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const path = require('node:path');
|
|
9
|
-
const fs = require('node:fs');
|
|
10
|
-
const clack = require('@clack/prompts');
|
|
11
|
-
const pc = require('picocolors');
|
|
12
|
-
const { t } = require('../i18n');
|
|
13
|
-
const { PACKS, EXPECTED_AGENTS } = require('../lib/packs');
|
|
14
|
-
|
|
15
|
-
module.exports = {
|
|
16
|
-
command: 'doctor',
|
|
17
|
-
description: 'Check BMAD+ installation integrity',
|
|
18
|
-
options: [
|
|
19
|
-
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
20
|
-
['-l, --lang <code>', 'Language code: en, fr, es, de, pt-br, ru, zh, he, ja, it'],
|
|
21
|
-
],
|
|
22
|
-
action: async (options) => {
|
|
23
|
-
const projectDir = path.resolve(options.directory || process.cwd());
|
|
24
|
-
const packageJson = require('../../../package.json');
|
|
25
|
-
|
|
26
|
-
clack.intro(pc.bgBlue(pc.white(` BMAD+ Doctor v${packageJson.version} `)));
|
|
27
|
-
|
|
28
|
-
let checks = 0;
|
|
29
|
-
let passed = 0;
|
|
30
|
-
let warnings = 0;
|
|
31
|
-
let errors = 0;
|
|
32
|
-
|
|
33
|
-
// ── Check 1: Installation manifest ──
|
|
34
|
-
checks++;
|
|
35
|
-
const manifestPath = path.join(projectDir, '_bmad', '.bmad-plus-install.json');
|
|
36
|
-
if (!fs.existsSync(manifestPath)) {
|
|
37
|
-
clack.log.error('❌ BMAD+ is not installed in this directory');
|
|
38
|
-
clack.outro(pc.red('Run `npx bmad-plus install` first.'));
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
43
|
-
const lang = options.lang || manifest.uiLanguage || 'en';
|
|
44
|
-
clack.log.success(`✅ Manifest found — v${manifest.version}`);
|
|
45
|
-
passed++;
|
|
46
|
-
|
|
47
|
-
// ── Check 2: Version comparison ──
|
|
48
|
-
checks++;
|
|
49
|
-
if (manifest.version === packageJson.version) {
|
|
50
|
-
clack.log.success(`✅ Version up to date (v${manifest.version})`);
|
|
51
|
-
passed++;
|
|
52
|
-
} else {
|
|
53
|
-
clack.log.warn(`⚠️ Version mismatch: installed v${manifest.version} → latest v${packageJson.version}`);
|
|
54
|
-
clack.log.info(' Run `npx bmad-plus update` to upgrade');
|
|
55
|
-
warnings++;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// ── Check 3: Agent files ──
|
|
59
|
-
checks++;
|
|
60
|
-
const agentsDir = path.join(projectDir, '.agents', 'skills');
|
|
61
|
-
if (fs.existsSync(agentsDir)) {
|
|
62
|
-
const agentDirs = fs.readdirSync(agentsDir, { withFileTypes: true })
|
|
63
|
-
.filter(d => d.isDirectory())
|
|
64
|
-
.map(d => d.name);
|
|
65
|
-
clack.log.success(`✅ ${agentDirs.length} agent/skill directories found`);
|
|
66
|
-
passed++;
|
|
67
|
-
|
|
68
|
-
// Check each expected agent from manifest packs using shared EXPECTED_AGENTS module
|
|
69
|
-
for (const pack of (manifest.packs || ['core'])) {
|
|
70
|
-
const entry = EXPECTED_AGENTS[pack];
|
|
71
|
-
if (!entry) continue;
|
|
72
|
-
|
|
73
|
-
// Check individual agent directories
|
|
74
|
-
for (const agent of (entry.agents || [])) {
|
|
75
|
-
checks++;
|
|
76
|
-
const agentPath = path.join(agentsDir, agent);
|
|
77
|
-
if (fs.existsSync(agentPath)) {
|
|
78
|
-
passed++;
|
|
79
|
-
} else {
|
|
80
|
-
clack.log.warn(`⚠️ Missing agent: ${agent} (pack: ${pack})`);
|
|
81
|
-
warnings++;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Check pack directory if applicable
|
|
86
|
-
if (entry.packDir) {
|
|
87
|
-
checks++;
|
|
88
|
-
const packPath = path.join(agentsDir, entry.packDir);
|
|
89
|
-
if (fs.existsSync(packPath)) {
|
|
90
|
-
passed++;
|
|
91
|
-
|
|
92
|
-
// These packs bundle their agents as files inside packDir — verify
|
|
93
|
-
// them there (not as loose directories, which would falsely warn).
|
|
94
|
-
for (const agentFile of (entry.packAgents || [])) {
|
|
95
|
-
checks++;
|
|
96
|
-
if (fs.existsSync(path.join(packPath, agentFile))) {
|
|
97
|
-
passed++;
|
|
98
|
-
} else {
|
|
99
|
-
clack.log.warn(`⚠️ Missing agent: ${agentFile} (pack: ${pack})`);
|
|
100
|
-
warnings++;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
clack.log.warn(`⚠️ Missing pack directory: ${entry.packDir} (pack: ${pack})`);
|
|
105
|
-
warnings++;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
} else {
|
|
110
|
-
clack.log.error('❌ No .agents/skills/ directory found');
|
|
111
|
-
errors++;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ── Check 4: Config files ──
|
|
115
|
-
checks++;
|
|
116
|
-
const configPath = path.join(projectDir, '_bmad', 'config.yaml');
|
|
117
|
-
if (fs.existsSync(configPath)) {
|
|
118
|
-
clack.log.success('✅ config.yaml present');
|
|
119
|
-
passed++;
|
|
120
|
-
} else {
|
|
121
|
-
clack.log.error('❌ config.yaml missing');
|
|
122
|
-
errors++;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// ── Check 5: Module config ──
|
|
126
|
-
checks++;
|
|
127
|
-
const moduleYaml = path.join(projectDir, '_bmad', 'module.yaml');
|
|
128
|
-
if (fs.existsSync(moduleYaml)) {
|
|
129
|
-
clack.log.success('✅ module.yaml present');
|
|
130
|
-
passed++;
|
|
131
|
-
} else {
|
|
132
|
-
clack.log.warn('⚠️ module.yaml missing');
|
|
133
|
-
warnings++;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// ── Check 6: IDE configs ──
|
|
137
|
-
checks++;
|
|
138
|
-
const ideFiles = ['CLAUDE.md', 'GEMINI.md', 'AGENTS.md'].filter(f =>
|
|
139
|
-
fs.existsSync(path.join(projectDir, f))
|
|
140
|
-
);
|
|
141
|
-
if (ideFiles.length > 0) {
|
|
142
|
-
clack.log.success(`✅ ${ideFiles.length} IDE config(s): ${ideFiles.join(', ')}`);
|
|
143
|
-
passed++;
|
|
144
|
-
} else {
|
|
145
|
-
clack.log.warn('⚠️ No IDE config files found');
|
|
146
|
-
warnings++;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// ── Check 7: Output directories ──
|
|
150
|
-
checks++;
|
|
151
|
-
const outputDir = path.join(projectDir, '_bmad-output');
|
|
152
|
-
if (fs.existsSync(outputDir)) {
|
|
153
|
-
clack.log.success('✅ _bmad-output/ directory exists');
|
|
154
|
-
passed++;
|
|
155
|
-
} else {
|
|
156
|
-
clack.log.warn('⚠️ _bmad-output/ not found');
|
|
157
|
-
warnings++;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// ── Check 8: Skills integrity (SKILL.md exists in pack dirs) ──
|
|
161
|
-
if (manifest.packs && manifest.packs.includes('seo')) {
|
|
162
|
-
checks++;
|
|
163
|
-
const seoSkill = path.join(agentsDir, 'pack-seo', 'SKILL.md');
|
|
164
|
-
if (fs.existsSync(seoSkill)) {
|
|
165
|
-
clack.log.success('✅ SEO Engine SKILL.md present');
|
|
166
|
-
passed++;
|
|
167
|
-
} else {
|
|
168
|
-
clack.log.error('❌ SEO Engine SKILL.md missing — /seo audit will not work');
|
|
169
|
-
errors++;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// ── Check 9: PACKS ↔ module.yaml sync ──
|
|
174
|
-
checks++;
|
|
175
|
-
try {
|
|
176
|
-
const yaml = require('js-yaml');
|
|
177
|
-
const moduleYamlSrc = path.join(__dirname, '..', '..', '..', 'src', 'bmad-plus', 'module.yaml');
|
|
178
|
-
if (fs.existsSync(moduleYamlSrc)) {
|
|
179
|
-
const moduleContent = yaml.load(fs.readFileSync(moduleYamlSrc, 'utf8'));
|
|
180
|
-
const modulePackIds = Object.keys(moduleContent.packs || {});
|
|
181
|
-
|
|
182
|
-
// Use shared PACKS module instead of fragile regex on install.js source
|
|
183
|
-
const cliPackIds = Object.keys(PACKS);
|
|
184
|
-
|
|
185
|
-
// Find mismatches
|
|
186
|
-
const missingInCLI = modulePackIds.filter(p => !cliPackIds.includes(p));
|
|
187
|
-
const missingInModule = cliPackIds.filter(p => !modulePackIds.includes(p));
|
|
188
|
-
|
|
189
|
-
if (missingInCLI.length === 0 && missingInModule.length === 0) {
|
|
190
|
-
clack.log.success(`✅ PACKS ↔ module.yaml in sync (${modulePackIds.length} packs)`);
|
|
191
|
-
passed++;
|
|
192
|
-
} else {
|
|
193
|
-
if (missingInCLI.length > 0) {
|
|
194
|
-
clack.log.warn(`⚠️ Packs in module.yaml but missing from CLI PACKS: ${missingInCLI.join(', ')}`);
|
|
195
|
-
}
|
|
196
|
-
if (missingInModule.length > 0) {
|
|
197
|
-
clack.log.warn(`⚠️ Packs in CLI PACKS but missing from module.yaml: ${missingInModule.join(', ')}`);
|
|
198
|
-
}
|
|
199
|
-
warnings++;
|
|
200
|
-
}
|
|
201
|
-
} else {
|
|
202
|
-
clack.log.info(pc.dim('ℹ️ PACKS↔module.yaml check skipped (source not available in npx context)'));
|
|
203
|
-
passed++; // Not a failure — just unavailable
|
|
204
|
-
}
|
|
205
|
-
} catch (e) {
|
|
206
|
-
clack.log.info(pc.dim(`ℹ️ PACKS↔module.yaml check skipped: ${e.message}`));
|
|
207
|
-
passed++; // Graceful skip
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// ── Summary ──
|
|
211
|
-
const summaryColor = errors > 0 ? pc.red : warnings > 0 ? pc.yellow : pc.green;
|
|
212
|
-
const summaryIcon = errors > 0 ? '❌' : warnings > 0 ? '⚠️' : '✅';
|
|
213
|
-
|
|
214
|
-
clack.note([
|
|
215
|
-
`${summaryIcon} ${passed}/${checks} checks passed`,
|
|
216
|
-
errors > 0 ? `❌ ${errors} error(s)` : null,
|
|
217
|
-
warnings > 0 ? `⚠️ ${warnings} warning(s)` : null,
|
|
218
|
-
'',
|
|
219
|
-
`📦 Version: v${manifest.version}`,
|
|
220
|
-
`📅 Installed: ${manifest.installed.split('T')[0]}`,
|
|
221
|
-
`🗣️ Language: ${manifest.language || 'N/A'}`,
|
|
222
|
-
`📦 Packs: ${(manifest.packs || ['core']).join(', ')}`,
|
|
223
|
-
].filter(Boolean).join('\n'), '🩺 BMAD+ Health Report');
|
|
224
|
-
|
|
225
|
-
clack.outro(summaryColor(
|
|
226
|
-
errors > 0
|
|
227
|
-
? 'Issues found — run `npx bmad-plus install` to fix'
|
|
228
|
-
: warnings > 0
|
|
229
|
-
? 'Minor issues found — consider running `npx bmad-plus update`'
|
|
230
|
-
: 'Everything looks great! 🎉'
|
|
231
|
-
));
|
|
232
|
-
},
|
|
233
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* BMAD+ Doctor Command
|
|
3
|
+
* Checks installation integrity and reports issues
|
|
4
|
+
*
|
|
5
|
+
* Author: Laurent Rochetta
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const fs = require('node:fs');
|
|
10
|
+
const clack = require('@clack/prompts');
|
|
11
|
+
const pc = require('picocolors');
|
|
12
|
+
const { t } = require('../i18n');
|
|
13
|
+
const { PACKS, EXPECTED_AGENTS } = require('../lib/packs');
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
command: 'doctor',
|
|
17
|
+
description: 'Check BMAD+ installation integrity',
|
|
18
|
+
options: [
|
|
19
|
+
['-d, --directory <path>', 'Project directory (default: current directory)'],
|
|
20
|
+
['-l, --lang <code>', 'Language code: en, fr, es, de, pt-br, ru, zh, he, ja, it'],
|
|
21
|
+
],
|
|
22
|
+
action: async (options) => {
|
|
23
|
+
const projectDir = path.resolve(options.directory || process.cwd());
|
|
24
|
+
const packageJson = require('../../../package.json');
|
|
25
|
+
|
|
26
|
+
clack.intro(pc.bgBlue(pc.white(` BMAD+ Doctor v${packageJson.version} `)));
|
|
27
|
+
|
|
28
|
+
let checks = 0;
|
|
29
|
+
let passed = 0;
|
|
30
|
+
let warnings = 0;
|
|
31
|
+
let errors = 0;
|
|
32
|
+
|
|
33
|
+
// ── Check 1: Installation manifest ──
|
|
34
|
+
checks++;
|
|
35
|
+
const manifestPath = path.join(projectDir, '_bmad', '.bmad-plus-install.json');
|
|
36
|
+
if (!fs.existsSync(manifestPath)) {
|
|
37
|
+
clack.log.error('❌ BMAD+ is not installed in this directory');
|
|
38
|
+
clack.outro(pc.red('Run `npx bmad-plus install` first.'));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
43
|
+
const lang = options.lang || manifest.uiLanguage || 'en';
|
|
44
|
+
clack.log.success(`✅ Manifest found — v${manifest.version}`);
|
|
45
|
+
passed++;
|
|
46
|
+
|
|
47
|
+
// ── Check 2: Version comparison ──
|
|
48
|
+
checks++;
|
|
49
|
+
if (manifest.version === packageJson.version) {
|
|
50
|
+
clack.log.success(`✅ Version up to date (v${manifest.version})`);
|
|
51
|
+
passed++;
|
|
52
|
+
} else {
|
|
53
|
+
clack.log.warn(`⚠️ Version mismatch: installed v${manifest.version} → latest v${packageJson.version}`);
|
|
54
|
+
clack.log.info(' Run `npx bmad-plus update` to upgrade');
|
|
55
|
+
warnings++;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── Check 3: Agent files ──
|
|
59
|
+
checks++;
|
|
60
|
+
const agentsDir = path.join(projectDir, '.agents', 'skills');
|
|
61
|
+
if (fs.existsSync(agentsDir)) {
|
|
62
|
+
const agentDirs = fs.readdirSync(agentsDir, { withFileTypes: true })
|
|
63
|
+
.filter(d => d.isDirectory())
|
|
64
|
+
.map(d => d.name);
|
|
65
|
+
clack.log.success(`✅ ${agentDirs.length} agent/skill directories found`);
|
|
66
|
+
passed++;
|
|
67
|
+
|
|
68
|
+
// Check each expected agent from manifest packs using shared EXPECTED_AGENTS module
|
|
69
|
+
for (const pack of (manifest.packs || ['core'])) {
|
|
70
|
+
const entry = EXPECTED_AGENTS[pack];
|
|
71
|
+
if (!entry) continue;
|
|
72
|
+
|
|
73
|
+
// Check individual agent directories
|
|
74
|
+
for (const agent of (entry.agents || [])) {
|
|
75
|
+
checks++;
|
|
76
|
+
const agentPath = path.join(agentsDir, agent);
|
|
77
|
+
if (fs.existsSync(agentPath)) {
|
|
78
|
+
passed++;
|
|
79
|
+
} else {
|
|
80
|
+
clack.log.warn(`⚠️ Missing agent: ${agent} (pack: ${pack})`);
|
|
81
|
+
warnings++;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Check pack directory if applicable
|
|
86
|
+
if (entry.packDir) {
|
|
87
|
+
checks++;
|
|
88
|
+
const packPath = path.join(agentsDir, entry.packDir);
|
|
89
|
+
if (fs.existsSync(packPath)) {
|
|
90
|
+
passed++;
|
|
91
|
+
|
|
92
|
+
// These packs bundle their agents as files inside packDir — verify
|
|
93
|
+
// them there (not as loose directories, which would falsely warn).
|
|
94
|
+
for (const agentFile of (entry.packAgents || [])) {
|
|
95
|
+
checks++;
|
|
96
|
+
if (fs.existsSync(path.join(packPath, agentFile))) {
|
|
97
|
+
passed++;
|
|
98
|
+
} else {
|
|
99
|
+
clack.log.warn(`⚠️ Missing agent: ${agentFile} (pack: ${pack})`);
|
|
100
|
+
warnings++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
clack.log.warn(`⚠️ Missing pack directory: ${entry.packDir} (pack: ${pack})`);
|
|
105
|
+
warnings++;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
clack.log.error('❌ No .agents/skills/ directory found');
|
|
111
|
+
errors++;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ── Check 4: Config files ──
|
|
115
|
+
checks++;
|
|
116
|
+
const configPath = path.join(projectDir, '_bmad', 'config.yaml');
|
|
117
|
+
if (fs.existsSync(configPath)) {
|
|
118
|
+
clack.log.success('✅ config.yaml present');
|
|
119
|
+
passed++;
|
|
120
|
+
} else {
|
|
121
|
+
clack.log.error('❌ config.yaml missing');
|
|
122
|
+
errors++;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── Check 5: Module config ──
|
|
126
|
+
checks++;
|
|
127
|
+
const moduleYaml = path.join(projectDir, '_bmad', 'module.yaml');
|
|
128
|
+
if (fs.existsSync(moduleYaml)) {
|
|
129
|
+
clack.log.success('✅ module.yaml present');
|
|
130
|
+
passed++;
|
|
131
|
+
} else {
|
|
132
|
+
clack.log.warn('⚠️ module.yaml missing');
|
|
133
|
+
warnings++;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ── Check 6: IDE configs ──
|
|
137
|
+
checks++;
|
|
138
|
+
const ideFiles = ['CLAUDE.md', 'GEMINI.md', 'AGENTS.md'].filter(f =>
|
|
139
|
+
fs.existsSync(path.join(projectDir, f))
|
|
140
|
+
);
|
|
141
|
+
if (ideFiles.length > 0) {
|
|
142
|
+
clack.log.success(`✅ ${ideFiles.length} IDE config(s): ${ideFiles.join(', ')}`);
|
|
143
|
+
passed++;
|
|
144
|
+
} else {
|
|
145
|
+
clack.log.warn('⚠️ No IDE config files found');
|
|
146
|
+
warnings++;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ── Check 7: Output directories ──
|
|
150
|
+
checks++;
|
|
151
|
+
const outputDir = path.join(projectDir, '_bmad-output');
|
|
152
|
+
if (fs.existsSync(outputDir)) {
|
|
153
|
+
clack.log.success('✅ _bmad-output/ directory exists');
|
|
154
|
+
passed++;
|
|
155
|
+
} else {
|
|
156
|
+
clack.log.warn('⚠️ _bmad-output/ not found');
|
|
157
|
+
warnings++;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ── Check 8: Skills integrity (SKILL.md exists in pack dirs) ──
|
|
161
|
+
if (manifest.packs && manifest.packs.includes('seo')) {
|
|
162
|
+
checks++;
|
|
163
|
+
const seoSkill = path.join(agentsDir, 'pack-seo', 'SKILL.md');
|
|
164
|
+
if (fs.existsSync(seoSkill)) {
|
|
165
|
+
clack.log.success('✅ SEO Engine SKILL.md present');
|
|
166
|
+
passed++;
|
|
167
|
+
} else {
|
|
168
|
+
clack.log.error('❌ SEO Engine SKILL.md missing — /seo audit will not work');
|
|
169
|
+
errors++;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ── Check 9: PACKS ↔ module.yaml sync ──
|
|
174
|
+
checks++;
|
|
175
|
+
try {
|
|
176
|
+
const yaml = require('js-yaml');
|
|
177
|
+
const moduleYamlSrc = path.join(__dirname, '..', '..', '..', 'src', 'bmad-plus', 'module.yaml');
|
|
178
|
+
if (fs.existsSync(moduleYamlSrc)) {
|
|
179
|
+
const moduleContent = yaml.load(fs.readFileSync(moduleYamlSrc, 'utf8'));
|
|
180
|
+
const modulePackIds = Object.keys(moduleContent.packs || {});
|
|
181
|
+
|
|
182
|
+
// Use shared PACKS module instead of fragile regex on install.js source
|
|
183
|
+
const cliPackIds = Object.keys(PACKS);
|
|
184
|
+
|
|
185
|
+
// Find mismatches
|
|
186
|
+
const missingInCLI = modulePackIds.filter(p => !cliPackIds.includes(p));
|
|
187
|
+
const missingInModule = cliPackIds.filter(p => !modulePackIds.includes(p));
|
|
188
|
+
|
|
189
|
+
if (missingInCLI.length === 0 && missingInModule.length === 0) {
|
|
190
|
+
clack.log.success(`✅ PACKS ↔ module.yaml in sync (${modulePackIds.length} packs)`);
|
|
191
|
+
passed++;
|
|
192
|
+
} else {
|
|
193
|
+
if (missingInCLI.length > 0) {
|
|
194
|
+
clack.log.warn(`⚠️ Packs in module.yaml but missing from CLI PACKS: ${missingInCLI.join(', ')}`);
|
|
195
|
+
}
|
|
196
|
+
if (missingInModule.length > 0) {
|
|
197
|
+
clack.log.warn(`⚠️ Packs in CLI PACKS but missing from module.yaml: ${missingInModule.join(', ')}`);
|
|
198
|
+
}
|
|
199
|
+
warnings++;
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
clack.log.info(pc.dim('ℹ️ PACKS↔module.yaml check skipped (source not available in npx context)'));
|
|
203
|
+
passed++; // Not a failure — just unavailable
|
|
204
|
+
}
|
|
205
|
+
} catch (e) {
|
|
206
|
+
clack.log.info(pc.dim(`ℹ️ PACKS↔module.yaml check skipped: ${e.message}`));
|
|
207
|
+
passed++; // Graceful skip
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ── Summary ──
|
|
211
|
+
const summaryColor = errors > 0 ? pc.red : warnings > 0 ? pc.yellow : pc.green;
|
|
212
|
+
const summaryIcon = errors > 0 ? '❌' : warnings > 0 ? '⚠️' : '✅';
|
|
213
|
+
|
|
214
|
+
clack.note([
|
|
215
|
+
`${summaryIcon} ${passed}/${checks} checks passed`,
|
|
216
|
+
errors > 0 ? `❌ ${errors} error(s)` : null,
|
|
217
|
+
warnings > 0 ? `⚠️ ${warnings} warning(s)` : null,
|
|
218
|
+
'',
|
|
219
|
+
`📦 Version: v${manifest.version}`,
|
|
220
|
+
`📅 Installed: ${manifest.installed.split('T')[0]}`,
|
|
221
|
+
`🗣️ Language: ${manifest.language || 'N/A'}`,
|
|
222
|
+
`📦 Packs: ${(manifest.packs || ['core']).join(', ')}`,
|
|
223
|
+
].filter(Boolean).join('\n'), '🩺 BMAD+ Health Report');
|
|
224
|
+
|
|
225
|
+
clack.outro(summaryColor(
|
|
226
|
+
errors > 0
|
|
227
|
+
? 'Issues found — run `npx bmad-plus install` to fix'
|
|
228
|
+
: warnings > 0
|
|
229
|
+
? 'Minor issues found — consider running `npx bmad-plus update`'
|
|
230
|
+
: 'Everything looks great! 🎉'
|
|
231
|
+
));
|
|
232
|
+
},
|
|
233
|
+
};
|