bmad-plus 0.16.0 → 0.17.1
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 +114 -29
- package/README.md +45 -27
- package/SECURITY.md +9 -1
- package/osint-agent-package/README.md +13 -0
- package/osint-agent-package/SETUP_KEYS.md +13 -0
- package/package.json +32 -8
- package/readme-international/README.de.md +134 -537
- package/readme-international/README.es.md +136 -556
- package/readme-international/README.fr.md +135 -553
- package/src/bmad-plus/agents/agent-shadow/SKILL.md +6 -0
- package/src/bmad-plus/packs/pack-memory/README.md +1 -1
- package/src/bmad-plus/packs/pack-memory/memory-orchestrator.md +1 -1
- package/src/bmad-plus/packs/pack-memory/shared/memory-protocol.md +1 -1
- package/src/bmad-plus/packs/pack-shield/README.md +2 -0
- package/src/bmad-plus/packs/pack-shield/SKILL.md +2 -0
- package/src/bmad-plus/packs/pack-shield/shared/audit-report-template.md +6 -0
- package/src/bmad-plus/packs/pack-shield/shield-orchestrator.md +4 -0
- package/src/bmad-plus/skills/bmad-plus-uat/SKILL.md +18 -4
- package/src/bmad-plus/skills/bmad-plus-uat/template/page.html +95 -19
- package/src/bmad-plus/skills/bmad-plus-uat/template/strings.json +90 -10
- package/src/bmad-plus/skills/bmad-plus-uat/templates/README.md +63 -0
- package/src/bmad-plus/skills/bmad-plus-uat/templates/example-uat-spec.json +95 -0
- package/src/bmad-plus/skills/bmad-plus-uat/templates/uat-release-gate.mjs +127 -0
- package/src/bmad-plus/skills/bmad-plus-uat/templates/uat-spec-present.mjs +77 -0
- package/tools/build/adapters.config.js +1 -1
- package/tools/build/generate-adapters.js +186 -60
- package/tools/build/generate.js +49 -13
- package/tools/cli/bmad-plus-cli.js +3 -6
- package/tools/cli/commands/autoconfig.js +66 -24
- package/tools/cli/commands/install.js +620 -356
- package/tools/cli/commands/memory.js +40 -13
- package/tools/cli/commands/scan.js +94 -30
- package/tools/cli/commands/uat.js +21 -5
- package/tools/cli/commands/uninstall.js +65 -16
- package/tools/cli/commands/update-check.js +8 -3
- package/tools/cli/commands/update-policy.js +14 -5
- package/tools/cli/commands/update.js +89 -20
- package/tools/cli/i18n.js +128 -66
- package/tools/cli/lib/ide-config.js +3 -1
- package/tools/cli/lib/install-manifest.js +13 -6
- package/tools/cli/lib/installation-health.js +33 -1
- package/tools/cli/lib/installed-adapters.js +29 -6
- package/tools/cli/lib/memory-init.js +19 -4
- package/tools/cli/lib/packs.js +17 -28
- package/tools/cli/lib/path-hash.js +5 -1
- package/tools/cli/lib/python-provision.js +51 -12
- package/tools/cli/lib/stack-detect.js +51 -25
- package/tools/cli/lib/uat.js +18 -0
- package/tools/cli/lib/update-check.js +132 -34
- package/tools/cli/lib/update-dispatch.js +2 -2
- package/tools/cli/lib/update-policy.js +57 -19
- package/tools/cli/lib/update-transaction.js +439 -85
- package/tools/build/README.md +0 -78
- package/tools/build/check-counts.js +0 -626
- package/tools/build/check-install-contract.js +0 -648
- package/tools/build/generated-adapters/.codex/AGENTS.md +0 -134
- package/tools/build/generated-adapters/.cursor/rules/bmad-plus.mdc +0 -139
- package/tools/build/generated-adapters/.opencode/AGENTS.md +0 -134
- package/tools/build/generated-adapters/AGENTS.md +0 -132
- package/tools/build/generated-adapters/CLAUDE.md +0 -135
- package/tools/build/generated-adapters/CONVENTIONS.md +0 -134
- package/tools/build/generated-adapters/GEMINI.md +0 -139
- package/tools/build/generated-adapters/README.md +0 -79
- package/tools/maintain/upstream-candidate.js +0 -456
- package/tools/release/publication-content.js +0 -903
- package/tools/release/supply-chain.js +0 -282
|
@@ -40,15 +40,23 @@ function analyzeStructure(dir) {
|
|
|
40
40
|
if (entry.isDirectory()) {
|
|
41
41
|
const name = entry.name.toLowerCase();
|
|
42
42
|
if (name === 'src' || name === 'lib' || name === 'app') structure.hasSrc = true;
|
|
43
|
-
if (name === 'tests' || name === 'test' || name === '__tests__' || name === 'spec')
|
|
43
|
+
if (name === 'tests' || name === 'test' || name === '__tests__' || name === 'spec')
|
|
44
|
+
structure.hasTests = true;
|
|
44
45
|
if (name === 'docs' || name === 'doc' || name === 'documentation') structure.hasDocs = true;
|
|
45
|
-
if (name === '.github' || name === '.gitlab-ci' || name === '.circleci')
|
|
46
|
+
if (name === '.github' || name === '.gitlab-ci' || name === '.circleci')
|
|
47
|
+
structure.hasCI = true;
|
|
46
48
|
if (name === '.agents' || name === '_bmad') structure.hasBmad = true;
|
|
47
|
-
if (!name.startsWith('.') && name !== 'node_modules')
|
|
49
|
+
if (!name.startsWith('.') && name !== 'node_modules')
|
|
50
|
+
structure.directories.push(entry.name);
|
|
48
51
|
} else {
|
|
49
52
|
structure.fileCount++;
|
|
50
53
|
const name = entry.name;
|
|
51
|
-
if (
|
|
54
|
+
if (
|
|
55
|
+
name === 'Dockerfile' ||
|
|
56
|
+
name === 'docker-compose.yml' ||
|
|
57
|
+
name === 'docker-compose.yaml'
|
|
58
|
+
)
|
|
59
|
+
structure.hasDocker = true;
|
|
52
60
|
if (name === 'LICENSE' || name === 'LICENSE.md') structure.hasLicense = true;
|
|
53
61
|
if (name === 'README.md' || name === 'readme.md') structure.hasReadme = true;
|
|
54
62
|
if (name === '.env' || name === '.env.local') structure.hasEnv = true;
|
|
@@ -87,7 +95,9 @@ function calculateHealth(structure) {
|
|
|
87
95
|
return { pct, checks };
|
|
88
96
|
}
|
|
89
97
|
|
|
90
|
-
|
|
98
|
+
// `health` is measured elsewhere and does not change the recommendation: a project
|
|
99
|
+
// with failing checks needs the same packs as a healthy one.
|
|
100
|
+
function recommendPacks(stack, structure) {
|
|
91
101
|
const packs = ['core', 'memory']; // Always
|
|
92
102
|
const reasons = {
|
|
93
103
|
core: 'Essential multi-role agents (Atlas, Forge, Sentinel, Nexus)',
|
|
@@ -109,7 +119,10 @@ function recommendPacks(stack, structure, health) {
|
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
// SEO — if it looks like a web project
|
|
112
|
-
if (
|
|
122
|
+
if (
|
|
123
|
+
stack.framework &&
|
|
124
|
+
['Next.js', 'Nuxt', 'Angular', 'React', 'Vue.js', 'Svelte'].includes(stack.framework)
|
|
125
|
+
) {
|
|
113
126
|
packs.push('seo');
|
|
114
127
|
reasons.seo = `${stack.framework} web app detected — SEO audit agents recommended`;
|
|
115
128
|
}
|
|
@@ -121,21 +134,37 @@ function generateRecommendations(stack, structure, health) {
|
|
|
121
134
|
const recs = [];
|
|
122
135
|
|
|
123
136
|
if (!structure.hasTests) {
|
|
124
|
-
recs.push({
|
|
137
|
+
recs.push({
|
|
138
|
+
agent: 'Sentinel',
|
|
139
|
+
action: 'set up a test framework and write initial tests',
|
|
140
|
+
priority: 'high',
|
|
141
|
+
});
|
|
125
142
|
}
|
|
126
143
|
if (!structure.hasDocs) {
|
|
127
|
-
recs.push({
|
|
144
|
+
recs.push({
|
|
145
|
+
agent: 'Forge',
|
|
146
|
+
action: 'document the project architecture and API',
|
|
147
|
+
priority: 'medium',
|
|
148
|
+
});
|
|
128
149
|
}
|
|
129
150
|
if (!structure.hasCI) {
|
|
130
151
|
recs.push({ agent: 'Forge', action: 'set up CI/CD pipeline', priority: 'medium' });
|
|
131
152
|
}
|
|
132
153
|
if (health.pct < 60) {
|
|
133
|
-
recs.push({
|
|
154
|
+
recs.push({
|
|
155
|
+
agent: 'Sentinel',
|
|
156
|
+
action: 'review code quality and project health',
|
|
157
|
+
priority: 'high',
|
|
158
|
+
});
|
|
134
159
|
}
|
|
135
160
|
|
|
136
161
|
// Context-specific
|
|
137
162
|
if (structure.hasSrc) {
|
|
138
|
-
recs.push({
|
|
163
|
+
recs.push({
|
|
164
|
+
agent: 'Forge',
|
|
165
|
+
action: 'continue developing the current module',
|
|
166
|
+
priority: 'normal',
|
|
167
|
+
});
|
|
139
168
|
}
|
|
140
169
|
|
|
141
170
|
// Memory
|
|
@@ -201,7 +230,11 @@ module.exports = {
|
|
|
201
230
|
|
|
202
231
|
// Check if directory has content
|
|
203
232
|
let entries = [];
|
|
204
|
-
try {
|
|
233
|
+
try {
|
|
234
|
+
entries = fs.readdirSync(projectDir).filter((e) => !e.startsWith('.'));
|
|
235
|
+
} catch (e) {
|
|
236
|
+
console.warn('autoconfig: Failed to list directory', e.message);
|
|
237
|
+
}
|
|
205
238
|
|
|
206
239
|
const isExistingProject = entries.length > 0;
|
|
207
240
|
|
|
@@ -215,7 +248,7 @@ module.exports = {
|
|
|
215
248
|
const stack = detectStack(projectDir);
|
|
216
249
|
const structure = analyzeStructure(projectDir);
|
|
217
250
|
const health = calculateHealth(structure);
|
|
218
|
-
const { packs, reasons } = recommendPacks(stack, structure
|
|
251
|
+
const { packs, reasons } = recommendPacks(stack, structure);
|
|
219
252
|
const recs = generateRecommendations(stack, structure, health);
|
|
220
253
|
|
|
221
254
|
spinner.stop('Analysis complete');
|
|
@@ -226,8 +259,11 @@ module.exports = {
|
|
|
226
259
|
clack.log.info('');
|
|
227
260
|
|
|
228
261
|
// Stack
|
|
229
|
-
const stackLabel =
|
|
230
|
-
|
|
262
|
+
const stackLabel =
|
|
263
|
+
[stack.framework, stack.language, stack.runtime].filter(Boolean).join(' + ') || 'Unknown';
|
|
264
|
+
clack.log.info(
|
|
265
|
+
` Stack: ${pc.cyan(stackLabel)}${stack.packageManager ? pc.dim(` (${stack.packageManager})`) : ''}`
|
|
266
|
+
);
|
|
231
267
|
|
|
232
268
|
// Structure
|
|
233
269
|
const structItems = [];
|
|
@@ -242,7 +278,8 @@ module.exports = {
|
|
|
242
278
|
|
|
243
279
|
// Health
|
|
244
280
|
const healthColor = health.pct >= 80 ? pc.green : health.pct >= 50 ? pc.yellow : pc.red;
|
|
245
|
-
const healthBar =
|
|
281
|
+
const healthBar =
|
|
282
|
+
'█'.repeat(Math.round(health.pct / 10)) + '░'.repeat(10 - Math.round(health.pct / 10));
|
|
246
283
|
clack.log.info(` Health: ${healthColor(`${healthBar} ${health.pct}%`)}`);
|
|
247
284
|
|
|
248
285
|
// Existing BMAD+
|
|
@@ -250,7 +287,9 @@ module.exports = {
|
|
|
250
287
|
clack.log.info(` BMAD+: ${pc.green('✓ already installed')} — will update`);
|
|
251
288
|
}
|
|
252
289
|
if (structure.hasIdeConfigs.length > 0) {
|
|
253
|
-
clack.log.info(
|
|
290
|
+
clack.log.info(
|
|
291
|
+
` IDE configs: ${pc.green('✓')} ${structure.hasIdeConfigs.length} found — will preserve`
|
|
292
|
+
);
|
|
254
293
|
}
|
|
255
294
|
|
|
256
295
|
clack.log.info('');
|
|
@@ -259,7 +298,9 @@ module.exports = {
|
|
|
259
298
|
clack.log.info(pc.bold('📦 Recommended Packs'));
|
|
260
299
|
clack.log.info('');
|
|
261
300
|
for (const packId of packs) {
|
|
262
|
-
clack.log.info(
|
|
301
|
+
clack.log.info(
|
|
302
|
+
` ${pc.green('✓')} ${pc.bold(packId.padEnd(12))} ${pc.dim(reasons[packId])}`
|
|
303
|
+
);
|
|
263
304
|
}
|
|
264
305
|
clack.log.info('');
|
|
265
306
|
|
|
@@ -292,7 +333,7 @@ module.exports = {
|
|
|
292
333
|
} else {
|
|
293
334
|
const detectedIDEs = [];
|
|
294
335
|
for (const [id, ide] of Object.entries(IDE_CONFIGS)) {
|
|
295
|
-
if (ide.detect.some(marker => fs.existsSync(path.join(projectDir, marker)))) {
|
|
336
|
+
if (ide.detect.some((marker) => fs.existsSync(path.join(projectDir, marker)))) {
|
|
296
337
|
detectedIDEs.push(id);
|
|
297
338
|
}
|
|
298
339
|
}
|
|
@@ -349,15 +390,15 @@ module.exports = {
|
|
|
349
390
|
'## Health',
|
|
350
391
|
'',
|
|
351
392
|
`- **Score:** ${health.pct}%`,
|
|
352
|
-
...health.checks.map(c => `- ${c.pass ? '✅' : '❌'} ${c.name}`),
|
|
393
|
+
...health.checks.map((c) => `- ${c.pass ? '✅' : '❌'} ${c.name}`),
|
|
353
394
|
'',
|
|
354
395
|
'## Key Directories',
|
|
355
396
|
'',
|
|
356
|
-
...structure.directories.slice(0, 15).map(d => `- \`${d}/\``),
|
|
397
|
+
...structure.directories.slice(0, 15).map((d) => `- \`${d}/\``),
|
|
357
398
|
'',
|
|
358
399
|
'## Installed Packs',
|
|
359
400
|
'',
|
|
360
|
-
...packs.map(p => `- ${p}`),
|
|
401
|
+
...packs.map((p) => `- ${p}`),
|
|
361
402
|
'',
|
|
362
403
|
];
|
|
363
404
|
|
|
@@ -371,11 +412,12 @@ module.exports = {
|
|
|
371
412
|
|
|
372
413
|
const priorityIcon = { high: pc.red('‼'), medium: pc.yellow('!'), normal: pc.dim('·') };
|
|
373
414
|
for (const rec of recs.slice(0, 5)) {
|
|
374
|
-
clack.log.info(
|
|
415
|
+
clack.log.info(
|
|
416
|
+
` ${priorityIcon[rec.priority] || '·'} "${pc.cyan(rec.agent)}, ${rec.action}"`
|
|
417
|
+
);
|
|
375
418
|
}
|
|
376
419
|
|
|
377
420
|
clack.log.info('');
|
|
378
|
-
|
|
379
421
|
} else {
|
|
380
422
|
// ── MODE B: New Project ──
|
|
381
423
|
clack.log.info(pc.bold('🆕 Empty directory — starting new project wizard'));
|
|
@@ -437,7 +479,7 @@ module.exports = {
|
|
|
437
479
|
'',
|
|
438
480
|
'## Installed Packs',
|
|
439
481
|
'',
|
|
440
|
-
...packs.map(p => `- ${p}`),
|
|
482
|
+
...packs.map((p) => `- ${p}`),
|
|
441
483
|
'',
|
|
442
484
|
];
|
|
443
485
|
|