bmad-method 6.5.1-next.6 → 6.5.1-next.7

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "bmad-method",
4
- "version": "6.5.1-next.6",
4
+ "version": "6.5.1-next.7",
5
5
  "description": "Breakthrough Method of Agile AI-driven Development",
6
6
  "keywords": [
7
7
  "agile",
@@ -15,8 +15,9 @@ module.exports = {
15
15
  ['--modules <modules>', 'Comma-separated list of module IDs to install (e.g., "bmm,bmb")'],
16
16
  [
17
17
  '--tools <tools>',
18
- 'Comma-separated list of tool/IDE IDs to configure (e.g., "claude-code,cursor"). Use "none" to skip tool configuration.',
18
+ 'Comma-separated list of tool/IDE IDs to configure (e.g., "claude-code,cursor"). Required for fresh non-interactive (--yes) installs. Run with --list-tools to see all valid IDs.',
19
19
  ],
20
+ ['--list-tools', 'Print all supported tool/IDE IDs (with target directories) and exit.'],
20
21
  ['--action <type>', 'Action type for existing installations: install, update, or quick-update'],
21
22
  ['--user-name <name>', 'Name for agents to use (default: system username)'],
22
23
  ['--communication-language <lang>', 'Language for agent communication (default: English)'],
@@ -40,6 +41,12 @@ module.exports = {
40
41
  ],
41
42
  action: async (options) => {
42
43
  try {
44
+ if (options.listTools) {
45
+ const { formatPlatformList } = require('../ide/platform-codes');
46
+ process.stdout.write((await formatPlatformList()) + '\n');
47
+ process.exit(0);
48
+ }
49
+
43
50
  // Set debug flag as environment variable for all components
44
51
  if (options.debug) {
45
52
  process.env.BMAD_DEBUG_MANIFEST = 'true';
@@ -81,7 +88,7 @@ module.exports = {
81
88
  } else {
82
89
  await prompts.log.error(`Installation failed: ${error.message}`);
83
90
  }
84
- if (error.stack) {
91
+ if (error.stack && !error.expected) {
85
92
  await prompts.log.message(error.stack);
86
93
  }
87
94
  } catch {
@@ -31,7 +31,50 @@ function clearCache() {
31
31
  _cachedPlatformCodes = null;
32
32
  }
33
33
 
34
+ /**
35
+ * Format the installable platform list for human-readable output (used by --list-tools).
36
+ * Sourced from IdeManager so this view matches what --tools accepts at install time
37
+ * (suspended platforms excluded).
38
+ * @returns {Promise<string>} Formatted multi-line string with id, name, target_dir, preferred flag.
39
+ */
40
+ async function formatPlatformList() {
41
+ const { IdeManager } = require('./manager');
42
+ const ideManager = new IdeManager();
43
+ await ideManager.ensureInitialized();
44
+
45
+ const entries = ideManager.getAvailableIdes().map((ide) => {
46
+ const handler = ideManager.handlers.get(ide.value);
47
+ return {
48
+ id: ide.value,
49
+ name: ide.name,
50
+ targetDir: handler?.installerConfig?.target_dir || '',
51
+ preferred: ide.preferred,
52
+ };
53
+ });
54
+
55
+ const idWidth = Math.max(...entries.map((e) => e.id.length), 'ID'.length);
56
+ const nameWidth = Math.max(...entries.map((e) => e.name.length), 'Name'.length);
57
+
58
+ const pad = (s, w) => s + ' '.repeat(Math.max(0, w - s.length));
59
+ const lines = [
60
+ `Supported tool IDs (pass via --tools <id>[,<id>...]):`,
61
+ '',
62
+ ` ${pad('ID', idWidth)} ${pad('Name', nameWidth)} Target dir`,
63
+ ` ${pad('-'.repeat(idWidth), idWidth)} ${pad('-'.repeat(nameWidth), nameWidth)} ${'-'.repeat(10)}`,
64
+ ];
65
+
66
+ for (const e of entries) {
67
+ const star = e.preferred ? ' *' : ' ';
68
+ lines.push(`${star}${pad(e.id, idWidth)} ${pad(e.name, nameWidth)} ${e.targetDir}`);
69
+ }
70
+
71
+ lines.push('', '* = recommended / preferred', '', 'Example: bmad-method install --modules bmm --tools claude-code');
72
+
73
+ return lines.join('\n');
74
+ }
75
+
34
76
  module.exports = {
35
77
  loadPlatformCodes,
36
78
  clearCache,
79
+ formatPlatformList,
37
80
  };
@@ -404,6 +404,37 @@ class UI {
404
404
  * @param {Object} options - Command-line options
405
405
  * @returns {Object} Tool configuration
406
406
  */
407
+ _parseToolsFlag(toolsArg, allKnownValues) {
408
+ const selectedIdes = toolsArg
409
+ .split(',')
410
+ .map((t) => t.trim())
411
+ .filter(Boolean);
412
+
413
+ if (selectedIdes.length === 0) {
414
+ const err = new Error(
415
+ '--tools was passed empty. Provide at least one tool ID (e.g. --tools claude-code) or run with --list-tools to see valid IDs.',
416
+ );
417
+ err.expected = true;
418
+ throw err;
419
+ }
420
+
421
+ const unknown = selectedIdes.filter((id) => !allKnownValues.has(id));
422
+ if (unknown.length > 0) {
423
+ const err = new Error(
424
+ [
425
+ `Unknown tool ID${unknown.length === 1 ? '' : 's'}: ${unknown.join(', ')}`,
426
+ '',
427
+ 'Run with --list-tools to see all valid IDs.',
428
+ 'Common: claude-code, cursor, copilot, windsurf, cline',
429
+ ].join('\n'),
430
+ );
431
+ err.expected = true;
432
+ throw err;
433
+ }
434
+
435
+ return selectedIdes;
436
+ }
437
+
407
438
  async promptToolSelection(projectDir, options = {}) {
408
439
  const { ExistingInstall } = require('./core/existing-install');
409
440
  const { Installer } = require('./core/installer');
@@ -438,15 +469,10 @@ class UI {
438
469
  const allTools = [...preferredIdes, ...otherIdes];
439
470
 
440
471
  // Non-interactive: handle --tools and --yes flags before interactive prompt
441
- if (options.tools) {
442
- if (options.tools.toLowerCase() === 'none') {
443
- await prompts.log.info('Skipping tool configuration (--tools none)');
444
- return { ides: [], skipIde: true };
445
- }
446
- const selectedIdes = options.tools
447
- .split(',')
448
- .map((t) => t.trim())
449
- .filter(Boolean);
472
+ // Use !== undefined so an explicit --tools "" falls through to _parseToolsFlag and
473
+ // gets a specific "passed empty" error instead of being silently ignored.
474
+ if (options.tools !== undefined) {
475
+ const selectedIdes = this._parseToolsFlag(options.tools, allKnownValues);
450
476
  await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`);
451
477
  await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
452
478
  return { ides: selectedIdes, skipIde: false };
@@ -522,21 +548,13 @@ class UI {
522
548
 
523
549
  let selectedIdes = [];
524
550
 
525
- // Check if tools are provided via command-line
526
- if (options.tools) {
527
- // Check for explicit "none" value to skip tool installation
528
- if (options.tools.toLowerCase() === 'none') {
529
- await prompts.log.info('Skipping tool configuration (--tools none)');
530
- return { ides: [], skipIde: true };
531
- } else {
532
- selectedIdes = options.tools
533
- .split(',')
534
- .map((t) => t.trim())
535
- .filter(Boolean);
536
- await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`);
537
- await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
538
- return { ides: selectedIdes, skipIde: false };
539
- }
551
+ // Check if tools are provided via command-line.
552
+ // Use !== undefined so an explicit --tools "" still hits _parseToolsFlag's empty-value error.
553
+ if (options.tools !== undefined) {
554
+ selectedIdes = this._parseToolsFlag(options.tools, allKnownValues);
555
+ await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`);
556
+ await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
557
+ return { ides: selectedIdes, skipIde: false };
540
558
  } else if (options.yes) {
541
559
  // If --yes flag is set, skip tool prompt and use previously configured tools or empty
542
560
  if (configuredIdes.length > 0) {
@@ -544,8 +562,18 @@ class UI {
544
562
  await this.displaySelectedTools(configuredIdes, preferredIdes, allTools);
545
563
  return { ides: configuredIdes, skipIde: false };
546
564
  } else {
547
- await prompts.log.info('Skipping tool configuration (--yes flag, no previous tools)');
548
- return { ides: [], skipIde: true };
565
+ const err = new Error(
566
+ [
567
+ '--tools is required for non-interactive install (--yes / -y) when no tools are previously configured.',
568
+ '',
569
+ 'Common: claude-code, cursor, copilot, windsurf, cline',
570
+ 'See all supported tools: bmad-method install --list-tools',
571
+ '',
572
+ 'Example: bmad-method install --modules bmm --tools claude-code -y',
573
+ ].join('\n'),
574
+ );
575
+ err.expected = true;
576
+ throw err;
549
577
  }
550
578
  }
551
579