bmad-fh 6.0.0-alpha.23.50b728f9 → 6.0.0-alpha.23.599980af

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.
@@ -9,6 +9,7 @@ const { select, text, confirm, isCancel } = require('../lib/prompts');
9
9
  const { ScopeManager } = require('../../../src/core/lib/scope/scope-manager');
10
10
  const { ScopeInitializer } = require('../../../src/core/lib/scope/scope-initializer');
11
11
  const { ScopeValidator } = require('../../../src/core/lib/scope/scope-validator');
12
+ const { ScopeSync } = require('../../../src/core/lib/scope/scope-sync');
12
13
 
13
14
  /**
14
15
  * Format a date string for display
@@ -27,7 +28,7 @@ function formatDate(dateStr) {
27
28
  */
28
29
  function displayScopeList(scopes) {
29
30
  if (scopes.length === 0) {
30
- console.log(chalk.yellow('\nNo scopes found. Create one with: bmad scope create <id>\n'));
31
+ console.log(chalk.yellow('\nNo scopes found. Create one with: npx bmad-fh@multi-artifact scope create <id>\n'));
31
32
  return;
32
33
  }
33
34
 
@@ -113,6 +114,16 @@ function displayScopeInfo(scope, paths, tree) {
113
114
  */
114
115
  async function handleList(projectRoot, options) {
115
116
  const manager = new ScopeManager({ projectRoot });
117
+ const initializer = new ScopeInitializer({ projectRoot });
118
+
119
+ // Check if system is initialized before trying to list
120
+ const isInitialized = await initializer.isSystemInitialized();
121
+ const configExists = await fs.pathExists(path.join(projectRoot, '_bmad', '_config', 'scopes.yaml'));
122
+
123
+ if (!isInitialized || !configExists) {
124
+ console.log(chalk.yellow('\nScope system not initialized. Run: npx bmad-fh@multi-artifact scope init\n'));
125
+ return;
126
+ }
116
127
 
117
128
  try {
118
129
  await manager.initialize();
@@ -120,7 +131,7 @@ async function handleList(projectRoot, options) {
120
131
  displayScopeList(scopes);
121
132
  } catch (error) {
122
133
  if (error.message.includes('does not exist')) {
123
- console.log(chalk.yellow('\nScope system not initialized. Run: bmad scope init\n'));
134
+ console.log(chalk.yellow('\nScope system not initialized. Run: npx bmad-fh@multi-artifact scope init\n'));
124
135
  } else {
125
136
  throw error;
126
137
  }
@@ -176,9 +187,9 @@ async function handleCreate(projectRoot, scopeId, options) {
176
187
  name = inputName;
177
188
  }
178
189
 
179
- // Get description if not provided
190
+ // Get description if not provided (check for undefined specifically since empty string is valid)
180
191
  let description = options.description;
181
- if (!description) {
192
+ if (description === undefined) {
182
193
  const inputDesc = await text({
183
194
  message: 'Enter scope description (optional):',
184
195
  placeholder: 'Brief description of this scope',
@@ -203,27 +214,25 @@ async function handleCreate(projectRoot, scopeId, options) {
203
214
  await initializer.initializeScopeSystem();
204
215
  }
205
216
 
206
- // Create scope in configuration
217
+ // Create scope in configuration and directory structure
218
+ // Note: manager.createScope() now also calls initializer.initializeScope() internally
207
219
  const scope = await manager.createScope(scopeId, {
208
220
  name,
209
221
  description,
210
222
  dependencies: options.dependencies ? options.dependencies.split(',').map((d) => d.trim()) : [],
211
- });
212
-
213
- // Create scope directory structure
214
- const paths = await initializer.initializeScope(scopeId, {
215
- name,
216
- description,
217
223
  createContext: options.context,
218
224
  });
219
225
 
226
+ // Get paths for display
227
+ const paths = initializer.getScopePaths(scopeId);
228
+
220
229
  console.log(chalk.green(`\n✓ Scope '${scopeId}' created successfully!\n`));
221
230
  console.log(chalk.dim(' Directories created:'));
222
231
  console.log(` ${paths.planning}`);
223
232
  console.log(` ${paths.implementation}`);
224
233
  console.log(` ${paths.tests}`);
225
234
  console.log();
226
- console.log(chalk.cyan(` Use with: bmad workflow --scope ${scopeId}`));
235
+ console.log(chalk.cyan(` Use with workflows by setting .bmad-scope or using BMAD_SCOPE=${scopeId}`));
227
236
  console.log();
228
237
  }
229
238
 
@@ -232,7 +241,7 @@ async function handleCreate(projectRoot, scopeId, options) {
232
241
  */
233
242
  async function handleInfo(projectRoot, scopeId) {
234
243
  if (!scopeId) {
235
- console.error(chalk.red('Error: Scope ID is required. Usage: bmad scope info <scope-id>'));
244
+ console.error(chalk.red('Error: Scope ID is required. Usage: npx bmad-fh@multi-artifact scope info <scope-id>'));
236
245
  process.exit(1);
237
246
  }
238
247
 
@@ -257,7 +266,7 @@ async function handleInfo(projectRoot, scopeId) {
257
266
  */
258
267
  async function handleRemove(projectRoot, scopeId, options) {
259
268
  if (!scopeId) {
260
- console.error(chalk.red('Error: Scope ID is required. Usage: bmad scope remove <scope-id>'));
269
+ console.error(chalk.red('Error: Scope ID is required. Usage: npx bmad-fh@multi-artifact scope remove <scope-id>'));
261
270
  process.exit(1);
262
271
  }
263
272
 
@@ -288,13 +297,15 @@ async function handleRemove(projectRoot, scopeId, options) {
288
297
  console.log(chalk.blue('\nRemoving scope...'));
289
298
 
290
299
  // Remove scope directory (with backup)
291
- await initializer.removeScope(scopeId, { backup: !options.noBackup });
300
+ // Note: Commander.js sets options.backup to false when --no-backup is passed
301
+ const shouldBackup = options.backup !== false;
302
+ await initializer.removeScope(scopeId, { backup: shouldBackup });
292
303
 
293
304
  // Remove from configuration
294
305
  await manager.removeScope(scopeId, { force: true });
295
306
 
296
307
  console.log(chalk.green(`\n✓ Scope '${scopeId}' removed successfully!`));
297
- if (!options.noBackup) {
308
+ if (shouldBackup) {
298
309
  console.log(chalk.dim(' A backup was created in _bmad-output/'));
299
310
  }
300
311
  console.log();
@@ -318,7 +329,7 @@ async function handleInit(projectRoot) {
318
329
  console.log(` ${chalk.cyan('_bmad-output/_shared/')} - Shared knowledge layer`);
319
330
  console.log(` ${chalk.cyan('_bmad/_events/')} - Event system`);
320
331
  console.log();
321
- console.log(chalk.cyan(' Next: bmad scope create <scope-id>'));
332
+ console.log(chalk.cyan(' Next: npx bmad-fh@multi-artifact scope create <scope-id>'));
322
333
  console.log();
323
334
  }
324
335
 
@@ -327,7 +338,7 @@ async function handleInit(projectRoot) {
327
338
  */
328
339
  async function handleArchive(projectRoot, scopeId) {
329
340
  if (!scopeId) {
330
- console.error(chalk.red('Error: Scope ID is required. Usage: bmad scope archive <scope-id>'));
341
+ console.error(chalk.red('Error: Scope ID is required. Usage: npx bmad-fh@multi-artifact scope archive <scope-id>'));
331
342
  process.exit(1);
332
343
  }
333
344
 
@@ -344,7 +355,7 @@ async function handleArchive(projectRoot, scopeId) {
344
355
  */
345
356
  async function handleActivate(projectRoot, scopeId) {
346
357
  if (!scopeId) {
347
- console.error(chalk.red('Error: Scope ID is required. Usage: bmad scope activate <scope-id>'));
358
+ console.error(chalk.red('Error: Scope ID is required. Usage: npx bmad-fh@multi-artifact scope activate <scope-id>'));
348
359
  process.exit(1);
349
360
  }
350
361
 
@@ -357,34 +368,1080 @@ async function handleActivate(projectRoot, scopeId) {
357
368
  }
358
369
 
359
370
  /**
360
- * Show help for scope command
371
+ * Handle 'sync-up' subcommand - Promote scope artifacts to shared layer
372
+ */
373
+ async function handleSyncUp(projectRoot, scopeId, options) {
374
+ if (!scopeId) {
375
+ console.error(chalk.red('Error: Scope ID is required. Usage: npx bmad-fh@multi-artifact scope sync-up <scope-id>'));
376
+ process.exit(1);
377
+ }
378
+
379
+ const manager = new ScopeManager({ projectRoot });
380
+ const sync = new ScopeSync({ projectRoot });
381
+
382
+ await manager.initialize();
383
+
384
+ // Verify scope exists
385
+ const scope = await manager.getScope(scopeId);
386
+ if (!scope) {
387
+ console.error(chalk.red(`Error: Scope '${scopeId}' not found.`));
388
+ process.exit(1);
389
+ }
390
+
391
+ // Handle dry-run mode
392
+ if (options.dryRun) {
393
+ console.log(chalk.blue(`\n[Dry Run] Analyzing artifacts in '${scopeId}' for promotion...`));
394
+
395
+ // Get sync status to show what would be promoted
396
+ const scopePath = path.join(projectRoot, '_bmad-output', scopeId);
397
+ const promotablePatterns = ['architecture/*.md', 'contracts/*.md', 'principles/*.md', 'project-context.md'];
398
+
399
+ console.log(chalk.yellow('\n Would promote files matching these patterns:\n'));
400
+ for (const pattern of promotablePatterns) {
401
+ console.log(` ${chalk.cyan('•')} ${pattern}`);
402
+ }
403
+
404
+ try {
405
+ const status = await sync.getSyncStatus(scopeId);
406
+ if (status.promotedCount > 0) {
407
+ console.log(chalk.dim(`\n Previously promoted: ${status.promotedCount} files`));
408
+ for (const file of status.promotedFiles) {
409
+ console.log(` ${chalk.dim('✓')} ${file}`);
410
+ }
411
+ }
412
+ } catch {
413
+ // Ignore errors getting status
414
+ }
415
+
416
+ console.log(chalk.dim('\n Run without --dry-run to execute.\n'));
417
+ return;
418
+ }
419
+
420
+ console.log(chalk.blue(`\nPromoting artifacts from '${scopeId}' to shared layer...`));
421
+
422
+ try {
423
+ // syncUp signature: syncUp(scopeId, files = null, options = {})
424
+ const syncOptions = {
425
+ force: options.resolution === 'keep-local' ? false : true,
426
+ };
427
+ const result = await sync.syncUp(scopeId, null, syncOptions);
428
+
429
+ if (result.success) {
430
+ console.log(chalk.green('\n✓ Sync-up complete!\n'));
431
+ } else {
432
+ console.log(chalk.yellow('\n⚠ Sync-up completed with issues.\n'));
433
+ }
434
+
435
+ // Handle promoted files - result.promoted is array of { file, target }
436
+ if (result.promoted && result.promoted.length > 0) {
437
+ console.log(chalk.dim(' Promoted files:'));
438
+ for (const item of result.promoted) {
439
+ const displayFile = typeof item === 'string' ? item : item.file;
440
+ console.log(` ${chalk.cyan('→')} ${displayFile}`);
441
+ }
442
+ } else {
443
+ console.log(chalk.dim(' No files to promote (already in sync or no promotable artifacts).'));
444
+ }
445
+
446
+ // Handle skipped files - result.skipped is array of { file, reason }
447
+ if (result.skipped && result.skipped.length > 0) {
448
+ console.log(chalk.dim('\n Skipped files:'));
449
+ for (const item of result.skipped) {
450
+ const file = typeof item === 'string' ? item : item.file;
451
+ const reason = typeof item === 'object' ? item.reason : 'unknown';
452
+ console.log(` ${chalk.yellow('○')} ${file} - ${reason}`);
453
+ }
454
+ }
455
+
456
+ // Handle conflicts - result.conflicts is array of { file, source, target, resolution }
457
+ if (result.conflicts && result.conflicts.length > 0) {
458
+ console.log(chalk.yellow('\n Conflicts detected:'));
459
+ for (const conflict of result.conflicts) {
460
+ const file = typeof conflict === 'string' ? conflict : conflict.file;
461
+ console.log(` ${chalk.yellow('!')} ${file}`);
462
+
463
+ // Attempt to resolve conflict if resolution strategy provided
464
+ if (options.resolution && options.resolution !== 'prompt') {
465
+ const resolveResult = await sync.resolveConflict(conflict, options.resolution);
466
+ if (resolveResult.success) {
467
+ console.log(` ${chalk.green('✓')} Resolved: ${resolveResult.action}`);
468
+ } else {
469
+ console.log(` ${chalk.red('✗')} Failed: ${resolveResult.error}`);
470
+ }
471
+ } else {
472
+ console.log(` ${chalk.dim('Use --resolution to auto-resolve')}`);
473
+ }
474
+ }
475
+ }
476
+
477
+ // Handle errors - result.errors is array of { file, error } or { error }
478
+ if (result.errors && result.errors.length > 0) {
479
+ console.log(chalk.red('\n Errors:'));
480
+ for (const err of result.errors) {
481
+ if (err.file) {
482
+ console.log(` ${chalk.red('✗')} ${err.file}: ${err.error}`);
483
+ } else {
484
+ console.log(` ${chalk.red('✗')} ${err.error}`);
485
+ }
486
+ }
487
+ }
488
+
489
+ console.log();
490
+ } catch (error) {
491
+ console.error(chalk.red(`\nSync-up failed: ${error.message}`));
492
+ if (process.env.DEBUG) {
493
+ console.error(chalk.dim(error.stack));
494
+ }
495
+ process.exit(1);
496
+ }
497
+ }
498
+
499
+ /**
500
+ * Handle 'sync-down' subcommand - Pull shared layer updates into scope
501
+ */
502
+ async function handleSyncDown(projectRoot, scopeId, options) {
503
+ if (!scopeId) {
504
+ console.error(chalk.red('Error: Scope ID is required. Usage: npx bmad-fh@multi-artifact scope sync-down <scope-id>'));
505
+ process.exit(1);
506
+ }
507
+
508
+ const manager = new ScopeManager({ projectRoot });
509
+ const sync = new ScopeSync({ projectRoot });
510
+
511
+ await manager.initialize();
512
+
513
+ // Verify scope exists
514
+ const scope = await manager.getScope(scopeId);
515
+ if (!scope) {
516
+ console.error(chalk.red(`Error: Scope '${scopeId}' not found.`));
517
+ process.exit(1);
518
+ }
519
+
520
+ // Handle dry-run mode
521
+ if (options.dryRun) {
522
+ console.log(chalk.blue(`\n[Dry Run] Analyzing shared layer for updates to '${scopeId}'...`));
523
+
524
+ try {
525
+ const status = await sync.getSyncStatus(scopeId);
526
+ console.log(chalk.dim(`\n Last sync-down: ${status.lastSyncDown || 'Never'}`));
527
+ if (status.pulledCount > 0) {
528
+ console.log(chalk.dim(` Previously pulled: ${status.pulledCount} files`));
529
+ for (const file of status.pulledFiles) {
530
+ console.log(` ${chalk.dim('✓')} ${file}`);
531
+ }
532
+ }
533
+ } catch {
534
+ // Ignore errors getting status
535
+ }
536
+
537
+ console.log(chalk.dim('\n Run without --dry-run to execute.\n'));
538
+ return;
539
+ }
540
+
541
+ console.log(chalk.blue(`\nPulling shared layer updates into '${scopeId}'...`));
542
+
543
+ try {
544
+ // syncDown signature: syncDown(scopeId, options = {})
545
+ const syncOptions = {
546
+ force: options.resolution === 'keep-shared',
547
+ resolution: options.resolution || 'keep-local',
548
+ };
549
+ const result = await sync.syncDown(scopeId, syncOptions);
550
+
551
+ if (result.success) {
552
+ console.log(chalk.green('\n✓ Sync-down complete!\n'));
553
+ } else {
554
+ console.log(chalk.yellow('\n⚠ Sync-down completed with issues.\n'));
555
+ }
556
+
557
+ // Handle pulled files - result.pulled is array of { file, scope, target }
558
+ if (result.pulled && result.pulled.length > 0) {
559
+ console.log(chalk.dim(' Pulled files:'));
560
+ for (const item of result.pulled) {
561
+ const displayFile = typeof item === 'string' ? item : `${item.scope}/${item.file}`;
562
+ console.log(` ${chalk.cyan('←')} ${displayFile}`);
563
+ }
564
+ } else {
565
+ console.log(chalk.dim(' No new files to pull.'));
566
+ }
567
+
568
+ // Handle up-to-date files - result.upToDate is array of { file, scope }
569
+ if (result.upToDate && result.upToDate.length > 0) {
570
+ console.log(chalk.dim('\n Already up-to-date:'));
571
+ for (const item of result.upToDate) {
572
+ const displayFile = typeof item === 'string' ? item : `${item.scope}/${item.file}`;
573
+ console.log(` ${chalk.green('✓')} ${displayFile}`);
574
+ }
575
+ }
576
+
577
+ // Handle conflicts - result.conflicts is array of { file, scope, local, shared, resolution }
578
+ if (result.conflicts && result.conflicts.length > 0) {
579
+ console.log(chalk.yellow('\n Conflicts detected:'));
580
+ for (const conflict of result.conflicts) {
581
+ const file = typeof conflict === 'string' ? conflict : `${conflict.scope}/${conflict.file}`;
582
+ console.log(` ${chalk.yellow('!')} ${file}`);
583
+
584
+ // Attempt to resolve conflict if resolution strategy provided
585
+ if (options.resolution && options.resolution !== 'prompt') {
586
+ const resolveResult = await sync.resolveConflict(conflict, options.resolution);
587
+ if (resolveResult.success) {
588
+ console.log(` ${chalk.green('✓')} Resolved: ${resolveResult.action}`);
589
+ } else {
590
+ console.log(` ${chalk.red('✗')} Failed: ${resolveResult.error}`);
591
+ }
592
+ } else {
593
+ console.log(` ${chalk.dim('Use --resolution to auto-resolve')}`);
594
+ }
595
+ }
596
+ }
597
+
598
+ // Handle errors - result.errors is array of { file, error } or { error }
599
+ if (result.errors && result.errors.length > 0) {
600
+ console.log(chalk.red('\n Errors:'));
601
+ for (const err of result.errors) {
602
+ if (err.file) {
603
+ console.log(` ${chalk.red('✗')} ${err.file}: ${err.error}`);
604
+ } else {
605
+ console.log(` ${chalk.red('✗')} ${err.error}`);
606
+ }
607
+ }
608
+ }
609
+
610
+ console.log();
611
+ } catch (error) {
612
+ console.error(chalk.red(`\nSync-down failed: ${error.message}`));
613
+ if (process.env.DEBUG) {
614
+ console.error(chalk.dim(error.stack));
615
+ }
616
+ process.exit(1);
617
+ }
618
+ }
619
+
620
+ /**
621
+ * Handle 'set' subcommand - Set the active scope for the session
622
+ */
623
+ async function handleSet(projectRoot, scopeId, options) {
624
+ const manager = new ScopeManager({ projectRoot });
625
+ const scopeFilePath = path.join(projectRoot, '.bmad-scope');
626
+
627
+ // If no scopeId provided, show current scope or prompt
628
+ if (!scopeId) {
629
+ // Check if there's a current scope
630
+ try {
631
+ if (await fs.pathExists(scopeFilePath)) {
632
+ const content = await fs.readFile(scopeFilePath, 'utf8');
633
+ const match = content.match(/active_scope:\s*(\S+)/);
634
+ if (match) {
635
+ console.log(chalk.blue(`\nCurrent active scope: ${chalk.cyan(match[1])}\n`));
636
+
637
+ // Offer to change
638
+ const scopes = await manager.listScopes({ status: 'active' });
639
+ if (scopes.length === 0) {
640
+ console.log(chalk.yellow('No active scopes available. Create one with: npx bmad-fh@multi-artifact scope create <id>\n'));
641
+ return;
642
+ }
643
+
644
+ const choices = scopes.map((s) => ({ value: s.id, label: `${s.id} - ${s.name || 'No name'}` }));
645
+ choices.push({ value: '__clear__', label: 'Clear active scope' });
646
+
647
+ const selected = await select({
648
+ message: 'Select scope to activate:',
649
+ options: choices,
650
+ });
651
+
652
+ if (isCancel(selected)) {
653
+ console.log(chalk.yellow('Cancelled.'));
654
+ return;
655
+ }
656
+
657
+ if (selected === '__clear__') {
658
+ await fs.remove(scopeFilePath);
659
+ console.log(chalk.green('\n✓ Active scope cleared.\n'));
660
+ return;
661
+ }
662
+
663
+ scopeId = selected;
664
+ }
665
+ } else {
666
+ // No current scope, prompt to select
667
+ await manager.initialize();
668
+ const scopes = await manager.listScopes({ status: 'active' });
669
+
670
+ if (scopes.length === 0) {
671
+ console.log(chalk.yellow('\nNo scopes available. Create one first:\n'));
672
+ console.log(` ${chalk.cyan('npx bmad-fh@multi-artifact scope create <id>')}\n`);
673
+ return;
674
+ }
675
+
676
+ const choices = scopes.map((s) => ({ value: s.id, label: `${s.id} - ${s.name || 'No name'}` }));
677
+
678
+ const selected = await select({
679
+ message: 'Select scope to activate:',
680
+ options: choices,
681
+ });
682
+
683
+ if (isCancel(selected)) {
684
+ console.log(chalk.yellow('Cancelled.'));
685
+ return;
686
+ }
687
+
688
+ scopeId = selected;
689
+ }
690
+ } catch (error) {
691
+ if (error.message.includes('does not exist')) {
692
+ console.log(chalk.yellow('\nScope system not initialized. Run: npx bmad-fh@multi-artifact scope init\n'));
693
+ return;
694
+ }
695
+ throw error;
696
+ }
697
+ }
698
+
699
+ // Validate scope exists
700
+ try {
701
+ await manager.initialize();
702
+ const scope = await manager.getScope(scopeId);
703
+
704
+ if (!scope) {
705
+ console.error(chalk.red(`\nError: Scope '${scopeId}' not found.`));
706
+ console.log(chalk.dim('Available scopes:'));
707
+ const scopes = await manager.listScopes({ status: 'active' });
708
+ for (const s of scopes) {
709
+ console.log(` ${chalk.cyan(s.id)} - ${s.name || 'No name'}`);
710
+ }
711
+ console.log();
712
+ process.exit(1);
713
+ }
714
+
715
+ if (scope.status === 'archived') {
716
+ console.error(chalk.yellow(`\nWarning: Scope '${scopeId}' is archived. Activate it first with:`));
717
+ console.log(` ${chalk.cyan(`npx bmad-fh@multi-artifact scope activate ${scopeId}`)}\n`);
718
+
719
+ const proceed = await confirm({
720
+ message: 'Set as active scope anyway?',
721
+ initialValue: false,
722
+ });
723
+
724
+ if (isCancel(proceed) || !proceed) {
725
+ console.log(chalk.yellow('Cancelled.'));
726
+ return;
727
+ }
728
+ }
729
+ } catch (error) {
730
+ if (error.message.includes('does not exist')) {
731
+ console.log(chalk.yellow('\nScope system not initialized. Run: npx bmad-fh@multi-artifact scope init\n'));
732
+ return;
733
+ }
734
+ throw error;
735
+ }
736
+
737
+ // Write .bmad-scope file
738
+ const scopeContent = `# BMAD Active Scope Configuration
739
+ # This file is auto-generated. Do not edit manually.
740
+ # To change: npx bmad-fh@multi-artifact scope set <scope-id>
741
+
742
+ active_scope: ${scopeId}
743
+ set_at: "${new Date().toISOString()}"
744
+ `;
745
+
746
+ await fs.writeFile(scopeFilePath, scopeContent, 'utf8');
747
+
748
+ console.log(chalk.green(`\n✓ Active scope set to '${scopeId}'`));
749
+ console.log(chalk.dim(` File: ${scopeFilePath}`));
750
+ console.log(chalk.dim('\n Workflows will now use this scope automatically.'));
751
+ console.log(chalk.dim(' You can also use BMAD_SCOPE environment variable to override.\n'));
752
+ }
753
+
754
+ /**
755
+ * Handle 'unset' subcommand - Clear the active scope
756
+ */
757
+ async function handleUnset(projectRoot) {
758
+ const scopeFilePath = path.join(projectRoot, '.bmad-scope');
759
+
760
+ if (await fs.pathExists(scopeFilePath)) {
761
+ await fs.remove(scopeFilePath);
762
+ console.log(chalk.green('\n✓ Active scope cleared.\n'));
763
+ console.log(chalk.dim(' Workflows will now prompt for scope selection.\n'));
764
+ } else {
765
+ console.log(chalk.yellow('\n No active scope is set.\n'));
766
+ }
767
+ }
768
+
769
+ /**
770
+ * Show comprehensive help for scope command
361
771
  */
362
772
  function showHelp() {
363
- console.log(chalk.bold('\n BMAD Scope Management\n'));
364
- console.log(' Manage isolated artifact scopes for parallel development.\n');
365
- console.log(chalk.bold(' Commands:'));
366
- console.log(` ${chalk.cyan('init')} Initialize scope system`);
367
- console.log(` ${chalk.cyan('list')} List all scopes`);
368
- console.log(` ${chalk.cyan('create')} ${chalk.dim('[id]')} Create a new scope`);
369
- console.log(` ${chalk.cyan('info')} ${chalk.dim('<id>')} Show scope details`);
370
- console.log(` ${chalk.cyan('remove')} ${chalk.dim('<id>')} Remove a scope`);
371
- console.log(` ${chalk.cyan('archive')} ${chalk.dim('<id>')} Archive a scope`);
372
- console.log(` ${chalk.cyan('activate')} ${chalk.dim('<id>')} Activate an archived scope`);
773
+ console.log(chalk.bold('\n BMAD Scope Management'));
774
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
775
+
776
+ // Overview
777
+ console.log(chalk.bold(' OVERVIEW\n'));
778
+ console.log(' The scope system enables parallel development by isolating artifacts into');
779
+ console.log(' separate workspaces. Each scope maintains its own planning artifacts,');
780
+ console.log(' implementation artifacts, tests, and optionally a scope-specific context.\n');
781
+
782
+ console.log(chalk.dim(' Key Benefits:'));
783
+ console.log(' • Run multiple workflows in parallel across different terminal sessions');
784
+ console.log(' • Isolated artifacts prevent cross-contamination between features/services');
785
+ console.log(' • Shared knowledge layer for cross-cutting concerns and contracts');
786
+ console.log(' • Event system notifies dependent scopes of changes');
787
+ console.log(' • Session-sticky scope context for seamless workflow integration\n');
788
+
789
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
790
+
791
+ // Commands
792
+ console.log(chalk.bold(' COMMANDS\n'));
793
+ console.log(` ${chalk.cyan('init')} Initialize scope system in current project`);
794
+ console.log(` ${chalk.cyan('list')} ${chalk.dim('[options]')} List all scopes (aliases: ls)`);
795
+ console.log(` ${chalk.cyan('create')} ${chalk.dim('[id] [opts]')} Create a new scope (aliases: new)`);
796
+ console.log(` ${chalk.cyan('info')} ${chalk.dim('<id>')} Show detailed scope information (aliases: show)`);
797
+ console.log(` ${chalk.cyan('remove')} ${chalk.dim('<id> [opts]')} Remove a scope and its artifacts (aliases: rm, delete)`);
798
+ console.log(` ${chalk.cyan('archive')} ${chalk.dim('<id>')} Archive a scope (preserves artifacts, excludes from list)`);
799
+ console.log(` ${chalk.cyan('activate')} ${chalk.dim('<id>')} Reactivate an archived scope`);
800
+ console.log(` ${chalk.cyan('set')} ${chalk.dim('[id]')} Set active scope for session (alias: use)`);
801
+ console.log(` ${chalk.cyan('unset')} Clear active scope (alias: clear)`);
802
+ console.log(` ${chalk.cyan('sync-up')} ${chalk.dim('<id> [opts]')} Promote scope artifacts to shared layer (alias: syncup)`);
803
+ console.log(` ${chalk.cyan('sync-down')} ${chalk.dim('<id> [opts]')} Pull shared layer updates into scope (alias: syncdown)`);
804
+ console.log(` ${chalk.cyan('help')} ${chalk.dim('[command]')} Show help (add command name for detailed help)`);
373
805
  console.log();
374
- console.log(chalk.bold(' Options:'));
375
- console.log(` ${chalk.cyan('-n, --name')} ${chalk.dim('<name>')} Scope name for create`);
376
- console.log(` ${chalk.cyan('-d, --description')} ${chalk.dim('<desc>')} Scope description`);
377
- console.log(` ${chalk.cyan('-f, --force')} Force removal without confirmation`);
378
- console.log(` ${chalk.cyan('--no-backup')} Don't create backup on remove`);
379
- console.log(` ${chalk.cyan('--context')} Create scope-specific project-context.md`);
806
+
807
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
808
+
809
+ // Options
810
+ console.log(chalk.bold(' OPTIONS\n'));
811
+ console.log(chalk.dim(' Create options:'));
812
+ console.log(` ${chalk.cyan('-n, --name')} ${chalk.dim('<name>')} Human-readable scope name`);
813
+ console.log(` ${chalk.cyan('-d, --description')} ${chalk.dim('<text>')} Brief description of scope purpose`);
814
+ console.log(` ${chalk.cyan('--deps')} ${chalk.dim('<ids>')} Comma-separated dependency scope IDs`);
815
+ console.log(` ${chalk.cyan('--context')} Create scope-specific project-context.md\n`);
816
+
817
+ console.log(chalk.dim(' Remove options:'));
818
+ console.log(` ${chalk.cyan('-f, --force')} Skip confirmation prompt`);
819
+ console.log(` ${chalk.cyan('--no-backup')} Don't create backup before removal\n`);
820
+
821
+ console.log(chalk.dim(' List options:'));
822
+ console.log(` ${chalk.cyan('-s, --status')} ${chalk.dim('<status>')} Filter by status (active|archived)\n`);
823
+
824
+ console.log(chalk.dim(' Sync options:'));
825
+ console.log(` ${chalk.cyan('--dry-run')} Show what would be synced without changes`);
826
+ console.log(
827
+ ` ${chalk.cyan('--resolution')} ${chalk.dim('<strategy>')} Conflict resolution: keep-local|keep-shared|backup-and-update\n`,
828
+ );
829
+
830
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
831
+
832
+ // Quick Start
833
+ console.log(chalk.bold(' QUICK START\n'));
834
+ console.log(chalk.dim(' 1. Initialize the scope system:'));
835
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope init\n`);
836
+ console.log(chalk.dim(' 2. Create your first scope:'));
837
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope create auth --name "Authentication Service"\n`);
838
+ console.log(chalk.dim(' 3. Set the active scope for your session:'));
839
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope set auth\n`);
840
+ console.log(chalk.dim(' 4. Run workflows - artifacts go to scope directory:'));
841
+ console.log(` Workflows automatically detect scope from .bmad-scope`);
842
+ console.log(` Your PRD, architecture, etc. are isolated in _bmad-output/auth/\n`);
843
+ console.log(chalk.dim(' Alternative: Use BMAD_SCOPE environment variable to override:\n'));
844
+ console.log(` ${chalk.green('$')} BMAD_SCOPE=auth npx bmad-fh@multi-artifact ...\n`);
845
+
846
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
847
+
848
+ // Examples
849
+ console.log(chalk.bold(' EXAMPLES\n'));
850
+ console.log(chalk.dim(' Basic workflow:'));
851
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope init`);
852
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope create auth --name "Auth" --description "User authentication"`);
853
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope create payments --name "Payments" --deps auth`);
854
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope list\n`);
855
+
856
+ console.log(chalk.dim(' Parallel development (two terminals):'));
857
+ console.log(` ${chalk.green('# Terminal 1:')} ${chalk.green('# Terminal 2:')}`);
858
+ console.log(
859
+ ` ${chalk.dim('$')} npx bmad-fh@multi-artifact scope create auth ${chalk.dim('$')} npx bmad-fh@multi-artifact scope create payments`,
860
+ );
861
+ console.log(` ${chalk.dim('# Run PRD workflow for auth')} ${chalk.dim('# Run PRD workflow for payments')}\n`);
862
+
863
+ console.log(chalk.dim(' Sharing artifacts between scopes:'));
864
+ console.log(
865
+ ` ${chalk.green('$')} npx bmad-fh@multi-artifact scope sync-up auth ${chalk.dim('# Promote auth artifacts to _shared/')}`,
866
+ );
867
+ console.log(
868
+ ` ${chalk.green('$')} npx bmad-fh@multi-artifact scope sync-down payments ${chalk.dim('# Pull shared updates into payments')}\n`,
869
+ );
870
+
871
+ console.log(chalk.dim(' Lifecycle management:'));
872
+ console.log(
873
+ ` ${chalk.green('$')} npx bmad-fh@multi-artifact scope archive auth ${chalk.dim('# Archive when feature is complete')}`,
874
+ );
875
+ console.log(
876
+ ` ${chalk.green('$')} npx bmad-fh@multi-artifact scope activate auth ${chalk.dim('# Reactivate if needed later')}`,
877
+ );
878
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope remove auth ${chalk.dim('# Remove with backup')}`);
879
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope remove auth --force --no-backup ${chalk.dim('# Force remove')}\n`);
880
+
881
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
882
+
883
+ // Directory Structure
884
+ console.log(chalk.bold(' DIRECTORY STRUCTURE\n'));
885
+ console.log(chalk.dim(' After initialization and scope creation:'));
380
886
  console.log();
381
- console.log(chalk.bold(' Examples:'));
382
- console.log(` ${chalk.dim('$')} bmad scope init`);
383
- console.log(` ${chalk.dim('$')} bmad scope create auth --name "Authentication"`);
384
- console.log(` ${chalk.dim('$')} bmad scope list`);
385
- console.log(` ${chalk.dim('$')} bmad scope info auth`);
386
- console.log(` ${chalk.dim('$')} bmad scope remove auth --force`);
887
+ console.log(' project-root/');
888
+ console.log(' ├── _bmad/');
889
+ console.log(' │ ├── _config/');
890
+ console.log(` │ │ └── ${chalk.cyan('scopes.yaml')} ${chalk.dim('# Scope registry and settings')}`);
891
+ console.log(' │ └── _events/');
892
+ console.log(` │ ├── ${chalk.cyan('event-log.yaml')} ${chalk.dim('# Event history')}`);
893
+ console.log(` │ └── ${chalk.cyan('subscriptions.yaml')} ${chalk.dim('# Cross-scope subscriptions')}`);
894
+ console.log(' │');
895
+ console.log(' ├── _bmad-output/');
896
+ console.log(` │ ├── ${chalk.yellow('_shared/')} ${chalk.dim('# Shared knowledge layer')}`);
897
+ console.log(` │ │ ├── ${chalk.cyan('project-context.md')} ${chalk.dim('# Global project context')}`);
898
+ console.log(` │ │ ├── contracts/ ${chalk.dim('# Integration contracts')}`);
899
+ console.log(` │ │ └── principles/ ${chalk.dim('# Architecture principles')}`);
900
+ console.log(' │ │');
901
+ console.log(` │ ├── ${chalk.green('auth/')} ${chalk.dim('# Auth scope artifacts')}`);
902
+ console.log(' │ │ ├── planning-artifacts/');
903
+ console.log(' │ │ ├── implementation-artifacts/');
904
+ console.log(' │ │ ├── tests/');
905
+ console.log(` │ │ └── ${chalk.cyan('project-context.md')} ${chalk.dim('# Scope-specific context (optional)')}`);
906
+ console.log(' │ │');
907
+ console.log(` │ └── ${chalk.green('payments/')} ${chalk.dim('# Payments scope artifacts')}`);
908
+ console.log(' │ └── ...');
909
+ console.log(' │');
910
+ console.log(` └── ${chalk.cyan('.bmad-scope')} ${chalk.dim('# Session-sticky active scope (gitignored)')}`);
387
911
  console.log();
912
+
913
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
914
+
915
+ // Access Model
916
+ console.log(chalk.bold(' ACCESS MODEL\n'));
917
+ console.log(' Scopes follow a "read-any, write-own" isolation model:\n');
918
+ console.log(' ┌─────────────┬─────────────────┬─────────────────┬─────────────┐');
919
+ console.log(' │ Operation │ Own Scope │ Other Scopes │ _shared/ │');
920
+ console.log(' ├─────────────┼─────────────────┼─────────────────┼─────────────┤');
921
+ console.log(
922
+ ` │ ${chalk.green('Read')} │ ${chalk.green('✓ Allowed')} │ ${chalk.green('✓ Allowed')} │ ${chalk.green('✓ Allowed')} │`,
923
+ );
924
+ console.log(
925
+ ` │ ${chalk.red('Write')} │ ${chalk.green('✓ Allowed')} │ ${chalk.red('✗ Blocked')} │ ${chalk.yellow('via sync-up')} │`,
926
+ );
927
+ console.log(' └─────────────┴─────────────────┴─────────────────┴─────────────┘\n');
928
+
929
+ console.log(chalk.dim(' Isolation modes (configure in scopes.yaml):'));
930
+ console.log(` • ${chalk.cyan('strict')} - Block cross-scope writes (default, recommended)`);
931
+ console.log(` • ${chalk.cyan('warn')} - Allow with warnings`);
932
+ console.log(` • ${chalk.cyan('permissive')} - Allow all (not recommended)\n`);
933
+
934
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
935
+
936
+ // Workflow Integration
937
+ console.log(chalk.bold(' WORKFLOW INTEGRATION\n'));
938
+ console.log(' Workflows automatically detect and use scope context:\n');
939
+ console.log(chalk.dim(' Resolution order:'));
940
+ console.log(' 1. Explicit --scope flag in workflow command');
941
+ console.log(' 2. Session context from .bmad-scope file');
942
+ console.log(' 3. BMAD_SCOPE environment variable');
943
+ console.log(' 4. Prompt user to select or create scope\n');
944
+
945
+ console.log(chalk.dim(' Scope-aware path variables in workflows:'));
946
+ console.log(` • ${chalk.cyan('{scope}')} → Scope ID (e.g., "auth")`);
947
+ console.log(` • ${chalk.cyan('{scope_path}')} → _bmad-output/auth`);
948
+ console.log(` • ${chalk.cyan('{scope_planning}')} → _bmad-output/auth/planning-artifacts`);
949
+ console.log(` • ${chalk.cyan('{scope_implementation}')} → _bmad-output/auth/implementation-artifacts`);
950
+ console.log(` • ${chalk.cyan('{scope_tests}')} → _bmad-output/auth/tests\n`);
951
+
952
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
953
+
954
+ // Use Cases
955
+ console.log(chalk.bold(' USE CASES\n'));
956
+ console.log(chalk.dim(' Multi-team projects:'));
957
+ console.log(' Each team creates their own scope. Shared contracts and architecture');
958
+ console.log(' principles live in _shared/ and are synced as needed.\n');
959
+
960
+ console.log(chalk.dim(' Microservices architecture:'));
961
+ console.log(' One scope per service. Use dependencies to track service relationships.');
962
+ console.log(' Contracts define APIs between services.\n');
963
+
964
+ console.log(chalk.dim(' Parallel feature development:'));
965
+ console.log(' Create scope per major feature. Develop PRD, architecture, and stories');
966
+ console.log(' independently, then merge to main codebase.\n');
967
+
968
+ console.log(chalk.dim(' Experimentation/Spikes:'));
969
+ console.log(' Create a scope for experiments. Archive or remove when done.\n');
970
+
971
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
972
+
973
+ // Troubleshooting
974
+ console.log(chalk.bold(' TROUBLESHOOTING\n'));
975
+ console.log(chalk.dim(' "Scope system not initialized":'));
976
+ console.log(` Run: ${chalk.cyan('npx bmad-fh@multi-artifact scope init')}\n`);
977
+
978
+ console.log(chalk.dim(' "Cannot write to scope X while in scope Y":'));
979
+ console.log(' You are in strict isolation mode. Either:');
980
+ console.log(' • Switch to the correct scope');
981
+ console.log(' • Use sync-up to promote artifacts to _shared/');
982
+ console.log(' • Change isolation_mode in scopes.yaml (not recommended)\n');
983
+
984
+ console.log(chalk.dim(' "No scope set" when running workflow:'));
985
+ console.log(` • Create and use a scope: ${chalk.cyan('npx bmad-fh@multi-artifact scope create myfeature')}`);
986
+ console.log(' • Or run workflow with --scope flag\n');
987
+
988
+ console.log(chalk.dim(' "Circular dependency detected":'));
989
+ console.log(' Scope A depends on B which depends on A. Remove one dependency.\n');
990
+
991
+ console.log(chalk.dim(' Debug mode:'));
992
+ console.log(` Set ${chalk.cyan('DEBUG=true')} environment variable for verbose output.\n`);
993
+
994
+ console.log(chalk.dim(' ─────────────────────────────────────────────────────────────────────────────\n'));
995
+
996
+ // More Help
997
+ console.log(chalk.bold(' MORE HELP\n'));
998
+ console.log(` ${chalk.cyan('npx bmad-fh@multi-artifact scope help init')} ${chalk.dim('# Detailed help for init command')}`);
999
+ console.log(` ${chalk.cyan('npx bmad-fh@multi-artifact scope help create')} ${chalk.dim('# Detailed help for create command')}`);
1000
+ console.log(
1001
+ ` ${chalk.cyan('npx bmad-fh@multi-artifact scope help sync-up')} ${chalk.dim('# Detailed help for sync operations')}\n`,
1002
+ );
1003
+
1004
+ console.log(chalk.dim(' Documentation:'));
1005
+ console.log(` • Multi-Scope Guide: ${chalk.cyan('docs/multi-scope-guide.md')}`);
1006
+ console.log(` • Full docs: ${chalk.cyan('http://docs.bmad-method.org')}\n`);
1007
+ }
1008
+
1009
+ /**
1010
+ * Show detailed help for 'init' subcommand
1011
+ */
1012
+ function showHelpInit() {
1013
+ console.log(chalk.bold('\n bmad scope init'));
1014
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1015
+
1016
+ console.log(chalk.bold(' DESCRIPTION\n'));
1017
+ console.log(' Initialize the multi-scope system in your project. This command creates the');
1018
+ console.log(' necessary configuration files and directory structure for scope management.\n');
1019
+
1020
+ console.log(chalk.bold(' USAGE\n'));
1021
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope init\n`);
1022
+
1023
+ console.log(chalk.bold(' WHAT IT CREATES\n'));
1024
+ console.log(` ${chalk.cyan('_bmad/_config/scopes.yaml')} Configuration file with scope registry`);
1025
+ console.log(` ${chalk.cyan('_bmad/_events/')} Event system directory`);
1026
+ console.log(` ${chalk.cyan('_bmad-output/_shared/')} Shared knowledge layer\n`);
1027
+
1028
+ console.log(chalk.bold(' NOTES\n'));
1029
+ console.log(' • Safe to run multiple times - will not overwrite existing config');
1030
+ console.log(' • Required before creating any scopes');
1031
+ console.log(' • Automatically run by "scope create" if not initialized\n');
1032
+
1033
+ console.log(chalk.bold(' EXAMPLE\n'));
1034
+ console.log(` ${chalk.green('$')} cd my-project`);
1035
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope init`);
1036
+ console.log(` ${chalk.dim('✓ Scope system initialized successfully!')}\n`);
1037
+ }
1038
+
1039
+ /**
1040
+ * Show detailed help for 'create' subcommand
1041
+ */
1042
+ function showHelpCreate() {
1043
+ console.log(chalk.bold('\n bmad scope create'));
1044
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1045
+
1046
+ console.log(chalk.bold(' DESCRIPTION\n'));
1047
+ console.log(' Create a new isolated scope for parallel development. Each scope has its own');
1048
+ console.log(' directory structure for artifacts and can optionally declare dependencies on');
1049
+ console.log(' other scopes.\n');
1050
+
1051
+ console.log(chalk.bold(' USAGE\n'));
1052
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope create [id] [options]\n`);
1053
+
1054
+ console.log(chalk.bold(' ARGUMENTS\n'));
1055
+ console.log(` ${chalk.cyan('id')} Scope identifier (lowercase letters, numbers, hyphens)`);
1056
+ console.log(' If omitted, you will be prompted interactively\n');
1057
+
1058
+ console.log(chalk.bold(' OPTIONS\n'));
1059
+ console.log(` ${chalk.cyan('-n, --name')} ${chalk.dim('<name>')}`);
1060
+ console.log(' Human-readable name for the scope');
1061
+ console.log(' Example: --name "Authentication Service"\n');
1062
+
1063
+ console.log(` ${chalk.cyan('-d, --description')} ${chalk.dim('<text>')}`);
1064
+ console.log(' Brief description of the scope purpose');
1065
+ console.log(' Example: --description "Handles user auth, SSO, and sessions"\n');
1066
+
1067
+ console.log(` ${chalk.cyan('--deps, --dependencies')} ${chalk.dim('<ids>')}`);
1068
+ console.log(' Comma-separated list of scope IDs this scope depends on');
1069
+ console.log(' Example: --deps auth,users,notifications\n');
1070
+
1071
+ console.log(` ${chalk.cyan('--context')}`);
1072
+ console.log(' Create a scope-specific project-context.md file');
1073
+ console.log(' Useful when scope needs its own context extending global\n');
1074
+
1075
+ console.log(chalk.bold(' SCOPE ID RULES\n'));
1076
+ console.log(' • Lowercase letters, numbers, and hyphens only');
1077
+ console.log(' • Must start with a letter');
1078
+ console.log(' • Cannot use reserved names: _shared, _backup, _config, _events');
1079
+ console.log(' • Maximum 50 characters\n');
1080
+
1081
+ console.log(chalk.bold(' EXAMPLES\n'));
1082
+ console.log(chalk.dim(' Interactive mode (prompts for all fields):'));
1083
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope create\n`);
1084
+
1085
+ console.log(chalk.dim(' Quick create with ID only:'));
1086
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope create auth\n`);
1087
+
1088
+ console.log(chalk.dim(' Full specification:'));
1089
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope create payments \\`);
1090
+ console.log(` --name "Payment Processing" \\`);
1091
+ console.log(` --description "Stripe integration, invoicing, subscriptions" \\`);
1092
+ console.log(` --deps auth,users \\`);
1093
+ console.log(` --context\n`);
1094
+
1095
+ console.log(chalk.bold(' WHAT IT CREATES\n'));
1096
+ console.log(' _bmad-output/{scope-id}/');
1097
+ console.log(' ├── planning-artifacts/ # PRDs, architecture docs');
1098
+ console.log(' ├── implementation-artifacts/ # Sprint status, stories');
1099
+ console.log(' ├── tests/ # Test artifacts');
1100
+ console.log(' └── project-context.md # If --context specified\n');
1101
+ }
1102
+
1103
+ /**
1104
+ * Show detailed help for 'list' subcommand
1105
+ */
1106
+ function showHelpList() {
1107
+ console.log(chalk.bold('\n bmad scope list'));
1108
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1109
+
1110
+ console.log(chalk.bold(' DESCRIPTION\n'));
1111
+ console.log(' List all scopes in the project with their status and metadata.\n');
1112
+
1113
+ console.log(chalk.bold(' USAGE\n'));
1114
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope list [options]`);
1115
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope ls [options] ${chalk.dim('# alias')}\n`);
1116
+
1117
+ console.log(chalk.bold(' OPTIONS\n'));
1118
+ console.log(` ${chalk.cyan('-s, --status')} ${chalk.dim('<status>')}`);
1119
+ console.log(' Filter by scope status');
1120
+ console.log(' Values: active, archived\n');
1121
+
1122
+ console.log(chalk.bold(' OUTPUT COLUMNS\n'));
1123
+ console.log(` ${chalk.cyan('ID')} Scope identifier`);
1124
+ console.log(` ${chalk.cyan('Name')} Human-readable name`);
1125
+ console.log(` ${chalk.cyan('Status')} active or archived`);
1126
+ console.log(` ${chalk.cyan('Created')} Creation date\n`);
1127
+
1128
+ console.log(chalk.bold(' EXAMPLES\n'));
1129
+ console.log(chalk.dim(' List all scopes:'));
1130
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope list\n`);
1131
+
1132
+ console.log(chalk.dim(' List only active scopes:'));
1133
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope list --status active\n`);
1134
+
1135
+ console.log(chalk.dim(' List archived scopes:'));
1136
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope ls -s archived\n`);
1137
+ }
1138
+
1139
+ /**
1140
+ * Show detailed help for 'info' subcommand
1141
+ */
1142
+ function showHelpInfo() {
1143
+ console.log(chalk.bold('\n bmad scope info'));
1144
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1145
+
1146
+ console.log(chalk.bold(' DESCRIPTION\n'));
1147
+ console.log(' Display detailed information about a specific scope including paths,');
1148
+ console.log(' dependencies, dependents, and metadata.\n');
1149
+
1150
+ console.log(chalk.bold(' USAGE\n'));
1151
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope info <id>`);
1152
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope show <id> ${chalk.dim('# alias')}`);
1153
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope <id> ${chalk.dim('# shorthand')}\n`);
1154
+
1155
+ console.log(chalk.bold(' ARGUMENTS\n'));
1156
+ console.log(` ${chalk.cyan('id')} Scope identifier (required)\n`);
1157
+
1158
+ console.log(chalk.bold(' DISPLAYED INFORMATION\n'));
1159
+ console.log(' • Basic info: ID, name, description, status');
1160
+ console.log(' • Timestamps: Created, last activity');
1161
+ console.log(' • Metrics: Artifact count');
1162
+ console.log(' • Paths: Planning, implementation, tests directories');
1163
+ console.log(' • Dependencies: Scopes this scope depends on');
1164
+ console.log(' • Dependents: Scopes that depend on this scope\n');
1165
+
1166
+ console.log(chalk.bold(' EXAMPLES\n'));
1167
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope info auth`);
1168
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope auth ${chalk.dim('# shorthand')}\n`);
1169
+ }
1170
+
1171
+ /**
1172
+ * Show detailed help for 'remove' subcommand
1173
+ */
1174
+ function showHelpRemove() {
1175
+ console.log(chalk.bold('\n bmad scope remove'));
1176
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1177
+
1178
+ console.log(chalk.bold(' DESCRIPTION\n'));
1179
+ console.log(' Remove a scope and optionally its artifacts. By default, creates a backup');
1180
+ console.log(' before removal and prompts for confirmation.\n');
1181
+
1182
+ console.log(chalk.bold(' USAGE\n'));
1183
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope remove <id> [options]`);
1184
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope rm <id> ${chalk.dim('# alias')}`);
1185
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope delete <id> ${chalk.dim('# alias')}\n`);
1186
+
1187
+ console.log(chalk.bold(' ARGUMENTS\n'));
1188
+ console.log(` ${chalk.cyan('id')} Scope identifier to remove (required)\n`);
1189
+
1190
+ console.log(chalk.bold(' OPTIONS\n'));
1191
+ console.log(` ${chalk.cyan('-f, --force')}`);
1192
+ console.log(' Skip confirmation prompt\n');
1193
+
1194
+ console.log(` ${chalk.cyan('--no-backup')}`);
1195
+ console.log(' Do not create backup before removal');
1196
+ console.log(` ${chalk.red('Warning: Artifacts will be permanently deleted!')}\n`);
1197
+
1198
+ console.log(chalk.bold(' BACKUP LOCATION\n'));
1199
+ console.log(' Backups are created at: _bmad-output/_backup_{id}_{timestamp}/\n');
1200
+
1201
+ console.log(chalk.bold(' EXAMPLES\n'));
1202
+ console.log(chalk.dim(' Safe removal (prompts, creates backup):'));
1203
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope remove auth\n`);
1204
+
1205
+ console.log(chalk.dim(' Force removal without prompt (still creates backup):'));
1206
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope rm auth --force\n`);
1207
+
1208
+ console.log(chalk.dim(' Permanent removal (no backup, no prompt):'));
1209
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope delete auth --force --no-backup\n`);
1210
+
1211
+ console.log(chalk.bold(' CONSIDERATIONS\n'));
1212
+ console.log(' • Check dependents first: scopes depending on this will have broken deps');
1213
+ console.log(' • Consider archiving instead if you might need artifacts later');
1214
+ console.log(' • Backup includes all scope artifacts but not _shared/ content\n');
1215
+ }
1216
+
1217
+ /**
1218
+ * Show detailed help for 'archive' subcommand
1219
+ */
1220
+ function showHelpArchive() {
1221
+ console.log(chalk.bold('\n bmad scope archive'));
1222
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1223
+
1224
+ console.log(chalk.bold(' DESCRIPTION\n'));
1225
+ console.log(' Archive a scope. Archived scopes are excluded from default listings but');
1226
+ console.log(' retain all artifacts. Use this for completed features or paused work.\n');
1227
+
1228
+ console.log(chalk.bold(' USAGE\n'));
1229
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope archive <id>\n`);
1230
+
1231
+ console.log(chalk.bold(' ARGUMENTS\n'));
1232
+ console.log(` ${chalk.cyan('id')} Scope identifier to archive (required)\n`);
1233
+
1234
+ console.log(chalk.bold(' BEHAVIOR\n'));
1235
+ console.log(' • Scope status changes to "archived"');
1236
+ console.log(' • Artifacts remain intact');
1237
+ console.log(' • Excluded from "scope list" (use --status archived to see)');
1238
+ console.log(' • Can be reactivated with "scope activate"\n');
1239
+
1240
+ console.log(chalk.bold(' EXAMPLES\n'));
1241
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope archive auth`);
1242
+ console.log(` ${chalk.dim("✓ Scope 'auth' archived.")}\n`);
1243
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope list --status archived`);
1244
+ console.log(` ${chalk.dim('# Shows auth in archived list')}\n`);
1245
+ }
1246
+
1247
+ /**
1248
+ * Show detailed help for 'activate' subcommand
1249
+ */
1250
+ function showHelpActivate() {
1251
+ console.log(chalk.bold('\n bmad scope activate'));
1252
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1253
+
1254
+ console.log(chalk.bold(' DESCRIPTION\n'));
1255
+ console.log(' Reactivate an archived scope. The scope will appear in default listings');
1256
+ console.log(' and can be used for workflows again.\n');
1257
+
1258
+ console.log(chalk.bold(' USAGE\n'));
1259
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope activate <id>\n`);
1260
+
1261
+ console.log(chalk.bold(' ARGUMENTS\n'));
1262
+ console.log(` ${chalk.cyan('id')} Scope identifier to activate (required)\n`);
1263
+
1264
+ console.log(chalk.bold(' EXAMPLE\n'));
1265
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope activate auth`);
1266
+ console.log(` ${chalk.dim("✓ Scope 'auth' activated.")}\n`);
1267
+ }
1268
+
1269
+ /**
1270
+ * Show detailed help for 'sync-up' subcommand
1271
+ */
1272
+ function showHelpSyncUp() {
1273
+ console.log(chalk.bold('\n bmad scope sync-up'));
1274
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1275
+
1276
+ console.log(chalk.bold(' DESCRIPTION\n'));
1277
+ console.log(' Promote scope artifacts to the shared knowledge layer (_shared/). Use this');
1278
+ console.log(' to share mature artifacts like architecture decisions, contracts, and');
1279
+ console.log(' principles with other scopes.\n');
1280
+
1281
+ console.log(chalk.bold(' USAGE\n'));
1282
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope sync-up <id> [options]\n`);
1283
+
1284
+ console.log(chalk.bold(' ARGUMENTS\n'));
1285
+ console.log(` ${chalk.cyan('id')} Scope identifier to sync from (required)\n`);
1286
+
1287
+ console.log(chalk.bold(' WHAT GETS PROMOTED\n'));
1288
+ console.log(' • architecture/*.md → _shared/architecture/');
1289
+ console.log(' • contracts/*.md → _shared/contracts/');
1290
+ console.log(' • principles/*.md → _shared/principles/');
1291
+ console.log(' • project-context.md → Merged into _shared/project-context.md\n');
1292
+
1293
+ console.log(chalk.bold(' OPTIONS\n'));
1294
+ console.log(` ${chalk.cyan('--dry-run')}`);
1295
+ console.log(' Show what would be promoted without making changes\n');
1296
+
1297
+ console.log(` ${chalk.cyan('--resolution')} ${chalk.dim('<strategy>')}`);
1298
+ console.log(' How to handle conflicts:');
1299
+ console.log(' • keep-local - Keep scope version');
1300
+ console.log(' • keep-shared - Keep shared version');
1301
+ console.log(' • backup-and-update - Backup shared, use scope version\n');
1302
+
1303
+ console.log(chalk.bold(' EXAMPLE\n'));
1304
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope sync-up auth`);
1305
+ console.log(` ${chalk.dim('Promoted 3 files to _shared/')}`);
1306
+ console.log(` ${chalk.dim(' architecture/auth-design.md')}`);
1307
+ console.log(` ${chalk.dim(' contracts/auth-api.md')}`);
1308
+ console.log(` ${chalk.dim(' principles/security.md')}\n`);
1309
+ }
1310
+
1311
+ /**
1312
+ * Show detailed help for 'sync-down' subcommand
1313
+ */
1314
+ function showHelpSyncDown() {
1315
+ console.log(chalk.bold('\n bmad scope sync-down'));
1316
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1317
+
1318
+ console.log(chalk.bold(' DESCRIPTION\n'));
1319
+ console.log(' Pull updates from the shared knowledge layer into a scope. Use this to get');
1320
+ console.log(' the latest shared architecture, contracts, and context into your scope.\n');
1321
+
1322
+ console.log(chalk.bold(' USAGE\n'));
1323
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope sync-down <id> [options]\n`);
1324
+
1325
+ console.log(chalk.bold(' ARGUMENTS\n'));
1326
+ console.log(` ${chalk.cyan('id')} Scope identifier to sync to (required)\n`);
1327
+
1328
+ console.log(chalk.bold(' OPTIONS\n'));
1329
+ console.log(` ${chalk.cyan('--dry-run')}`);
1330
+ console.log(' Show what would be pulled without making changes\n');
1331
+
1332
+ console.log(` ${chalk.cyan('--resolution')} ${chalk.dim('<strategy>')}`);
1333
+ console.log(' How to handle conflicts:');
1334
+ console.log(' • keep-local - Keep scope version (default)');
1335
+ console.log(' • keep-shared - Overwrite with shared version');
1336
+ console.log(' • backup-and-update - Backup scope, use shared version\n');
1337
+
1338
+ console.log(chalk.bold(' EXAMPLE\n'));
1339
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope sync-down payments`);
1340
+ console.log(` ${chalk.dim('Pulled 2 updates from _shared/')}`);
1341
+ console.log(` ${chalk.dim(' contracts/auth-api.md (new)')}`);
1342
+ console.log(` ${chalk.dim(' project-context.md (merged)')}\n`);
1343
+ }
1344
+
1345
+ /**
1346
+ * Show detailed help for 'set' subcommand
1347
+ */
1348
+ function showHelpSet() {
1349
+ console.log(chalk.bold('\n bmad scope set'));
1350
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1351
+
1352
+ console.log(chalk.bold(' DESCRIPTION\n'));
1353
+ console.log(' Set the active scope for your session. This creates a .bmad-scope file in');
1354
+ console.log(' your project root that workflows automatically detect and use.\n');
1355
+
1356
+ console.log(chalk.bold(' USAGE\n'));
1357
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope set [id]`);
1358
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope use [id] ${chalk.dim('# alias')}\n`);
1359
+
1360
+ console.log(chalk.bold(' ARGUMENTS\n'));
1361
+ console.log(` ${chalk.cyan('id')} Scope identifier to set as active (optional)`);
1362
+ console.log(' If omitted, shows current scope and prompts to select\n');
1363
+
1364
+ console.log(chalk.bold(' BEHAVIOR\n'));
1365
+ console.log(' • Creates/updates .bmad-scope file in project root');
1366
+ console.log(' • .bmad-scope should be added to .gitignore (session-specific)');
1367
+ console.log(' • Workflows automatically detect scope from this file');
1368
+ console.log(' • BMAD_SCOPE environment variable can override\n');
1369
+
1370
+ console.log(chalk.bold(' EXAMPLES\n'));
1371
+ console.log(chalk.dim(' Set a specific scope:'));
1372
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope set auth\n`);
1373
+
1374
+ console.log(chalk.dim(' Interactive selection (shows current and prompts):'));
1375
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope set\n`);
1376
+
1377
+ console.log(chalk.dim(' Override with environment variable:'));
1378
+ console.log(` ${chalk.green('$')} BMAD_SCOPE=payments npx bmad-fh@multi-artifact ...\n`);
1379
+
1380
+ console.log(chalk.bold(' FILE FORMAT\n'));
1381
+ console.log(' The .bmad-scope file contains:');
1382
+ console.log(chalk.dim(' active_scope: auth'));
1383
+ console.log(chalk.dim(' set_at: "2026-01-22T10:00:00Z"\n'));
1384
+ }
1385
+
1386
+ /**
1387
+ * Show detailed help for 'unset' subcommand
1388
+ */
1389
+ function showHelpUnset() {
1390
+ console.log(chalk.bold('\n bmad scope unset'));
1391
+ console.log(chalk.dim(' ═══════════════════════════════════════════════════════════════════════════\n'));
1392
+
1393
+ console.log(chalk.bold(' DESCRIPTION\n'));
1394
+ console.log(' Clear the active scope by removing the .bmad-scope file. After this,');
1395
+ console.log(' workflows will prompt for scope selection.\n');
1396
+
1397
+ console.log(chalk.bold(' USAGE\n'));
1398
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope unset`);
1399
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope clear ${chalk.dim('# alias')}\n`);
1400
+
1401
+ console.log(chalk.bold(' BEHAVIOR\n'));
1402
+ console.log(' • Removes .bmad-scope file from project root');
1403
+ console.log(' • Workflows will prompt for scope selection');
1404
+ console.log(' • Does nothing if no scope is currently set\n');
1405
+
1406
+ console.log(chalk.bold(' EXAMPLE\n'));
1407
+ console.log(` ${chalk.green('$')} npx bmad-fh@multi-artifact scope unset`);
1408
+ console.log(` ${chalk.dim('✓ Active scope cleared.')}\n`);
1409
+ }
1410
+
1411
+ /**
1412
+ * Router for subcommand-specific help
1413
+ * @param {string} subcommand - The subcommand to show help for
1414
+ */
1415
+ function showSubcommandHelp(subcommand) {
1416
+ const helpFunctions = {
1417
+ init: showHelpInit,
1418
+ create: showHelpCreate,
1419
+ new: showHelpCreate,
1420
+ list: showHelpList,
1421
+ ls: showHelpList,
1422
+ info: showHelpInfo,
1423
+ show: showHelpInfo,
1424
+ remove: showHelpRemove,
1425
+ rm: showHelpRemove,
1426
+ delete: showHelpRemove,
1427
+ archive: showHelpArchive,
1428
+ activate: showHelpActivate,
1429
+ set: showHelpSet,
1430
+ use: showHelpSet,
1431
+ unset: showHelpUnset,
1432
+ clear: showHelpUnset,
1433
+ 'sync-up': showHelpSyncUp,
1434
+ syncup: showHelpSyncUp,
1435
+ 'sync-down': showHelpSyncDown,
1436
+ syncdown: showHelpSyncDown,
1437
+ };
1438
+
1439
+ if (helpFunctions[subcommand]) {
1440
+ helpFunctions[subcommand]();
1441
+ } else {
1442
+ console.log(chalk.red(`\n Unknown command: ${subcommand}\n`));
1443
+ console.log(` Run ${chalk.cyan('npx bmad-fh@multi-artifact scope help')} to see available commands.\n`);
1444
+ }
388
1445
  }
389
1446
 
390
1447
  module.exports = {
@@ -398,6 +1455,8 @@ module.exports = {
398
1455
  ['--no-backup', 'Skip backup on remove'],
399
1456
  ['--context', 'Create scope-specific project-context.md'],
400
1457
  ['-s, --status <status>', 'Filter by status (active/archived)'],
1458
+ ['--dry-run', 'Show what would be synced without making changes'],
1459
+ ['--resolution <strategy>', 'Conflict resolution: keep-local|keep-shared|backup-and-update'],
401
1460
  ],
402
1461
  action: async (subcommand, id, options) => {
403
1462
  try {
@@ -446,7 +1505,40 @@ module.exports = {
446
1505
  break;
447
1506
  }
448
1507
 
449
- case 'help':
1508
+ case 'sync-up':
1509
+ case 'syncup': {
1510
+ await handleSyncUp(projectRoot, id, options);
1511
+ break;
1512
+ }
1513
+
1514
+ case 'sync-down':
1515
+ case 'syncdown': {
1516
+ await handleSyncDown(projectRoot, id, options);
1517
+ break;
1518
+ }
1519
+
1520
+ case 'set':
1521
+ case 'use': {
1522
+ await handleSet(projectRoot, id, options);
1523
+ break;
1524
+ }
1525
+
1526
+ case 'unset':
1527
+ case 'clear': {
1528
+ await handleUnset(projectRoot);
1529
+ break;
1530
+ }
1531
+
1532
+ case 'help': {
1533
+ // Check if a subcommand was provided for detailed help
1534
+ if (id) {
1535
+ showSubcommandHelp(id);
1536
+ } else {
1537
+ showHelp();
1538
+ }
1539
+ break;
1540
+ }
1541
+
450
1542
  case undefined: {
451
1543
  showHelp();
452
1544
  break;