bmad-plus 0.17.0 → 0.18.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +108 -30
  2. package/README.md +23 -23
  3. package/SECURITY.md +9 -1
  4. package/osint-agent-package/README.md +13 -0
  5. package/osint-agent-package/SETUP_KEYS.md +13 -0
  6. package/package.json +32 -8
  7. package/readme-international/README.de.md +133 -542
  8. package/readme-international/README.es.md +135 -561
  9. package/readme-international/README.fr.md +134 -558
  10. package/src/bmad-plus/agents/agent-shadow/SKILL.md +6 -0
  11. package/src/bmad-plus/packs/pack-memory/README.md +1 -1
  12. package/src/bmad-plus/packs/pack-memory/memory-orchestrator.md +1 -1
  13. package/src/bmad-plus/packs/pack-memory/shared/memory-protocol.md +1 -1
  14. package/src/bmad-plus/packs/pack-shield/README.md +2 -0
  15. package/src/bmad-plus/packs/pack-shield/SKILL.md +2 -0
  16. package/src/bmad-plus/packs/pack-shield/shared/audit-report-template.md +6 -0
  17. package/src/bmad-plus/packs/pack-shield/shield-orchestrator.md +4 -0
  18. package/src/bmad-plus/skills/bmad-plus-uat/SKILL.md +61 -1
  19. package/src/bmad-plus/skills/bmad-plus-uat/ref/uat-results.schema.json +11 -0
  20. package/src/bmad-plus/skills/bmad-plus-uat/template/page.html +455 -137
  21. package/src/bmad-plus/skills/bmad-plus-uat/template/strings.json +230 -20
  22. package/tools/build/adapters.config.js +1 -1
  23. package/tools/build/generate-adapters.js +186 -60
  24. package/tools/build/generate.js +49 -13
  25. package/tools/cli/bmad-plus-cli.js +3 -6
  26. package/tools/cli/commands/autoconfig.js +62 -22
  27. package/tools/cli/commands/install.js +620 -356
  28. package/tools/cli/commands/memory.js +40 -13
  29. package/tools/cli/commands/scan.js +94 -30
  30. package/tools/cli/commands/uat.js +50 -5
  31. package/tools/cli/commands/uninstall.js +65 -16
  32. package/tools/cli/commands/update-check.js +13 -4
  33. package/tools/cli/commands/update-policy.js +14 -5
  34. package/tools/cli/commands/update.js +96 -21
  35. package/tools/cli/i18n.js +120 -68
  36. package/tools/cli/lib/ide-config.js +3 -1
  37. package/tools/cli/lib/install-manifest.js +32 -7
  38. package/tools/cli/lib/installation-health.js +33 -1
  39. package/tools/cli/lib/installed-adapters.js +29 -6
  40. package/tools/cli/lib/memory-init.js +19 -4
  41. package/tools/cli/lib/packs.js +17 -28
  42. package/tools/cli/lib/path-hash.js +5 -1
  43. package/tools/cli/lib/python-provision.js +51 -12
  44. package/tools/cli/lib/stack-detect.js +51 -25
  45. package/tools/cli/lib/uat.js +139 -1
  46. package/tools/cli/lib/update-check.js +132 -34
  47. package/tools/cli/lib/update-dispatch.js +2 -2
  48. package/tools/cli/lib/update-policy.js +57 -19
  49. package/tools/cli/lib/update-transaction.js +439 -85
  50. package/tools/build/README.md +0 -78
  51. package/tools/build/check-counts.js +0 -626
  52. package/tools/build/check-install-contract.js +0 -648
  53. package/tools/build/generated-adapters/.codex/AGENTS.md +0 -134
  54. package/tools/build/generated-adapters/.cursor/rules/bmad-plus.mdc +0 -139
  55. package/tools/build/generated-adapters/.opencode/AGENTS.md +0 -134
  56. package/tools/build/generated-adapters/AGENTS.md +0 -132
  57. package/tools/build/generated-adapters/CLAUDE.md +0 -135
  58. package/tools/build/generated-adapters/CONVENTIONS.md +0 -134
  59. package/tools/build/generated-adapters/GEMINI.md +0 -139
  60. package/tools/build/generated-adapters/README.md +0 -79
  61. package/tools/maintain/upstream-candidate.js +0 -456
  62. package/tools/release/publication-content.js +0 -904
  63. 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') structure.hasTests = true;
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') structure.hasCI = true;
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') structure.directories.push(entry.name);
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 (name === 'Dockerfile' || name === 'docker-compose.yml' || name === 'docker-compose.yaml') structure.hasDocker = true;
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;
@@ -111,7 +119,10 @@ function recommendPacks(stack, structure) {
111
119
  }
112
120
 
113
121
  // SEO — if it looks like a web project
114
- if (stack.framework && ['Next.js', 'Nuxt', 'Angular', 'React', 'Vue.js', 'Svelte'].includes(stack.framework)) {
122
+ if (
123
+ stack.framework &&
124
+ ['Next.js', 'Nuxt', 'Angular', 'React', 'Vue.js', 'Svelte'].includes(stack.framework)
125
+ ) {
115
126
  packs.push('seo');
116
127
  reasons.seo = `${stack.framework} web app detected — SEO audit agents recommended`;
117
128
  }
@@ -123,21 +134,37 @@ function generateRecommendations(stack, structure, health) {
123
134
  const recs = [];
124
135
 
125
136
  if (!structure.hasTests) {
126
- recs.push({ agent: 'Sentinel', action: 'set up a test framework and write initial tests', priority: 'high' });
137
+ recs.push({
138
+ agent: 'Sentinel',
139
+ action: 'set up a test framework and write initial tests',
140
+ priority: 'high',
141
+ });
127
142
  }
128
143
  if (!structure.hasDocs) {
129
- recs.push({ agent: 'Forge', action: 'document the project architecture and API', priority: 'medium' });
144
+ recs.push({
145
+ agent: 'Forge',
146
+ action: 'document the project architecture and API',
147
+ priority: 'medium',
148
+ });
130
149
  }
131
150
  if (!structure.hasCI) {
132
151
  recs.push({ agent: 'Forge', action: 'set up CI/CD pipeline', priority: 'medium' });
133
152
  }
134
153
  if (health.pct < 60) {
135
- recs.push({ agent: 'Sentinel', action: 'review code quality and project health', priority: 'high' });
154
+ recs.push({
155
+ agent: 'Sentinel',
156
+ action: 'review code quality and project health',
157
+ priority: 'high',
158
+ });
136
159
  }
137
160
 
138
161
  // Context-specific
139
162
  if (structure.hasSrc) {
140
- recs.push({ agent: 'Forge', action: 'continue developing the current module', priority: 'normal' });
163
+ recs.push({
164
+ agent: 'Forge',
165
+ action: 'continue developing the current module',
166
+ priority: 'normal',
167
+ });
141
168
  }
142
169
 
143
170
  // Memory
@@ -203,7 +230,11 @@ module.exports = {
203
230
 
204
231
  // Check if directory has content
205
232
  let entries = [];
206
- try { entries = fs.readdirSync(projectDir).filter(e => !e.startsWith('.')); } catch (e) { console.warn('autoconfig: Failed to list directory', e.message); }
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
+ }
207
238
 
208
239
  const isExistingProject = entries.length > 0;
209
240
 
@@ -228,8 +259,11 @@ module.exports = {
228
259
  clack.log.info('');
229
260
 
230
261
  // Stack
231
- const stackLabel = [stack.framework, stack.language, stack.runtime].filter(Boolean).join(' + ') || 'Unknown';
232
- clack.log.info(` Stack: ${pc.cyan(stackLabel)}${stack.packageManager ? pc.dim(` (${stack.packageManager})`) : ''}`);
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
+ );
233
267
 
234
268
  // Structure
235
269
  const structItems = [];
@@ -244,7 +278,8 @@ module.exports = {
244
278
 
245
279
  // Health
246
280
  const healthColor = health.pct >= 80 ? pc.green : health.pct >= 50 ? pc.yellow : pc.red;
247
- const healthBar = '█'.repeat(Math.round(health.pct / 10)) + '░'.repeat(10 - Math.round(health.pct / 10));
281
+ const healthBar =
282
+ '█'.repeat(Math.round(health.pct / 10)) + '░'.repeat(10 - Math.round(health.pct / 10));
248
283
  clack.log.info(` Health: ${healthColor(`${healthBar} ${health.pct}%`)}`);
249
284
 
250
285
  // Existing BMAD+
@@ -252,7 +287,9 @@ module.exports = {
252
287
  clack.log.info(` BMAD+: ${pc.green('✓ already installed')} — will update`);
253
288
  }
254
289
  if (structure.hasIdeConfigs.length > 0) {
255
- clack.log.info(` IDE configs: ${pc.green('✓')} ${structure.hasIdeConfigs.length} found — will preserve`);
290
+ clack.log.info(
291
+ ` IDE configs: ${pc.green('✓')} ${structure.hasIdeConfigs.length} found — will preserve`
292
+ );
256
293
  }
257
294
 
258
295
  clack.log.info('');
@@ -261,7 +298,9 @@ module.exports = {
261
298
  clack.log.info(pc.bold('📦 Recommended Packs'));
262
299
  clack.log.info('');
263
300
  for (const packId of packs) {
264
- clack.log.info(` ${pc.green('✓')} ${pc.bold(packId.padEnd(12))} ${pc.dim(reasons[packId])}`);
301
+ clack.log.info(
302
+ ` ${pc.green('✓')} ${pc.bold(packId.padEnd(12))} ${pc.dim(reasons[packId])}`
303
+ );
265
304
  }
266
305
  clack.log.info('');
267
306
 
@@ -294,7 +333,7 @@ module.exports = {
294
333
  } else {
295
334
  const detectedIDEs = [];
296
335
  for (const [id, ide] of Object.entries(IDE_CONFIGS)) {
297
- if (ide.detect.some(marker => fs.existsSync(path.join(projectDir, marker)))) {
336
+ if (ide.detect.some((marker) => fs.existsSync(path.join(projectDir, marker)))) {
298
337
  detectedIDEs.push(id);
299
338
  }
300
339
  }
@@ -351,15 +390,15 @@ module.exports = {
351
390
  '## Health',
352
391
  '',
353
392
  `- **Score:** ${health.pct}%`,
354
- ...health.checks.map(c => `- ${c.pass ? '✅' : '❌'} ${c.name}`),
393
+ ...health.checks.map((c) => `- ${c.pass ? '✅' : '❌'} ${c.name}`),
355
394
  '',
356
395
  '## Key Directories',
357
396
  '',
358
- ...structure.directories.slice(0, 15).map(d => `- \`${d}/\``),
397
+ ...structure.directories.slice(0, 15).map((d) => `- \`${d}/\``),
359
398
  '',
360
399
  '## Installed Packs',
361
400
  '',
362
- ...packs.map(p => `- ${p}`),
401
+ ...packs.map((p) => `- ${p}`),
363
402
  '',
364
403
  ];
365
404
 
@@ -373,11 +412,12 @@ module.exports = {
373
412
 
374
413
  const priorityIcon = { high: pc.red('‼'), medium: pc.yellow('!'), normal: pc.dim('·') };
375
414
  for (const rec of recs.slice(0, 5)) {
376
- clack.log.info(` ${priorityIcon[rec.priority] || '·'} "${pc.cyan(rec.agent)}, ${rec.action}"`);
415
+ clack.log.info(
416
+ ` ${priorityIcon[rec.priority] || '·'} "${pc.cyan(rec.agent)}, ${rec.action}"`
417
+ );
377
418
  }
378
419
 
379
420
  clack.log.info('');
380
-
381
421
  } else {
382
422
  // ── MODE B: New Project ──
383
423
  clack.log.info(pc.bold('🆕 Empty directory — starting new project wizard'));
@@ -439,7 +479,7 @@ module.exports = {
439
479
  '',
440
480
  '## Installed Packs',
441
481
  '',
442
- ...packs.map(p => `- ${p}`),
482
+ ...packs.map((p) => `- ${p}`),
443
483
  '',
444
484
  ];
445
485