musubi-sdd 3.0.1 → 3.5.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.
Files changed (49) hide show
  1. package/bin/musubi-change.js +623 -10
  2. package/bin/musubi-orchestrate.js +456 -0
  3. package/bin/musubi-trace.js +393 -0
  4. package/package.json +3 -2
  5. package/src/analyzers/impact-analyzer.js +682 -0
  6. package/src/integrations/cicd.js +782 -0
  7. package/src/integrations/documentation.js +740 -0
  8. package/src/integrations/examples.js +789 -0
  9. package/src/integrations/index.js +23 -0
  10. package/src/integrations/platforms.js +929 -0
  11. package/src/managers/delta-spec.js +484 -0
  12. package/src/monitoring/incident-manager.js +890 -0
  13. package/src/monitoring/index.js +633 -0
  14. package/src/monitoring/observability.js +938 -0
  15. package/src/monitoring/release-manager.js +622 -0
  16. package/src/orchestration/index.js +168 -0
  17. package/src/orchestration/orchestration-engine.js +409 -0
  18. package/src/orchestration/pattern-registry.js +319 -0
  19. package/src/orchestration/patterns/auto.js +386 -0
  20. package/src/orchestration/patterns/group-chat.js +395 -0
  21. package/src/orchestration/patterns/human-in-loop.js +506 -0
  22. package/src/orchestration/patterns/nested.js +322 -0
  23. package/src/orchestration/patterns/sequential.js +278 -0
  24. package/src/orchestration/patterns/swarm.js +395 -0
  25. package/src/orchestration/workflow-orchestrator.js +738 -0
  26. package/src/reporters/coverage-report.js +452 -0
  27. package/src/reporters/traceability-matrix-report.js +684 -0
  28. package/src/steering/advanced-validation.js +812 -0
  29. package/src/steering/auto-updater.js +670 -0
  30. package/src/steering/index.js +119 -0
  31. package/src/steering/quality-metrics.js +650 -0
  32. package/src/steering/template-constraints.js +789 -0
  33. package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +22 -0
  34. package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +21 -0
  35. package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +90 -28
  36. package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +32 -0
  37. package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +27 -0
  38. package/src/templates/agents/claude-code/skills/steering/SKILL.md +30 -0
  39. package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +21 -0
  40. package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +27 -0
  41. package/src/templates/agents/codex/AGENTS.md +36 -1
  42. package/src/templates/agents/cursor/AGENTS.md +36 -1
  43. package/src/templates/agents/gemini-cli/GEMINI.md +36 -1
  44. package/src/templates/agents/github-copilot/AGENTS.md +65 -1
  45. package/src/templates/agents/qwen-code/QWEN.md +36 -1
  46. package/src/templates/agents/windsurf/AGENTS.md +36 -1
  47. package/src/templates/shared/delta-spec-template.md +246 -0
  48. package/src/validators/delta-format.js +474 -0
  49. package/src/validators/traceability-validator.js +561 -0
@@ -12,11 +12,18 @@
12
12
  * musubi-change archive <change-id> # Archive completed change
13
13
  * musubi-change list # List all changes
14
14
  * musubi-change validate <change-id> # Validate delta format
15
+ * musubi-change show <change-id> # Show change details
16
+ * musubi-change impact <change-id> # Show impact analysis
17
+ * musubi-change approve <change-id> # Approve change proposal
18
+ * musubi-change reject <change-id> # Reject change proposal
15
19
  */
16
20
 
17
21
  const { Command } = require('commander');
18
22
  const chalk = require('chalk');
19
23
  const ChangeManager = require('../src/managers/change.js');
24
+ const { DeltaSpecManager, DeltaType } = require('../src/managers/delta-spec.js');
25
+ const { DeltaFormatValidator } = require('../src/validators/delta-format.js');
26
+ const { ImpactAnalyzer } = require('../src/analyzers/impact-analyzer.js');
20
27
 
21
28
  const program = new Command();
22
29
 
@@ -117,23 +124,49 @@ program
117
124
  .description('Archive completed change to specs/')
118
125
  .option('--changes <dir>', 'Changes directory', 'storage/changes')
119
126
  .option('--specs <dir>', 'Specs archive directory', 'specs')
127
+ .option('--force', 'Force archive even if not in implemented status')
120
128
  .action(async (changeId, options) => {
121
129
  try {
122
130
  const workspaceRoot = process.cwd();
123
- const manager = new ChangeManager(workspaceRoot);
131
+ const deltaManager = new DeltaSpecManager(workspaceRoot);
132
+ const changeManager = new ChangeManager(workspaceRoot);
124
133
 
125
134
  console.log(chalk.blue('📦 Archiving change...'));
126
135
 
127
- const result = await manager.archiveChange(changeId, {
128
- changesDir: options.changes,
129
- specsDir: options.specs,
130
- });
136
+ // Try DeltaSpecManager first (new workflow)
137
+ const delta = deltaManager.load(changeId);
138
+
139
+ if (delta) {
140
+ // Check status
141
+ if (delta.status !== 'implemented' && !options.force) {
142
+ console.log(chalk.yellow(`⚠ Change ${changeId} is in "${delta.status}" status.`));
143
+ console.log(chalk.dim('Use --force to archive anyway, or update status first:'));
144
+ console.log(chalk.dim(` musubi-change approve ${changeId}`));
145
+ console.log(chalk.dim(` # implement the change`));
146
+ console.log(chalk.dim(` musubi-change apply ${changeId}`));
147
+ process.exit(1);
148
+ }
131
149
 
132
- console.log(chalk.green('✓ Change archived successfully'));
133
- console.log(chalk.dim(`Source: ${result.source}`));
134
- console.log(chalk.dim(`Archive: ${result.archive}`));
135
- console.log();
136
- console.log(chalk.yellow('Delta merged to canonical specification'));
150
+ const result = deltaManager.archive(changeId);
151
+
152
+ console.log(chalk.green('✓ Change archived successfully'));
153
+ console.log(chalk.dim(`Merged to: ${result.mergedTo}`));
154
+ console.log(chalk.dim(`Archive: ${result.archivePath}`));
155
+ console.log();
156
+ console.log(chalk.yellow('Delta merged to canonical specification'));
157
+ } else {
158
+ // Fall back to ChangeManager (legacy workflow)
159
+ const result = await changeManager.archiveChange(changeId, {
160
+ changesDir: options.changes,
161
+ specsDir: options.specs,
162
+ });
163
+
164
+ console.log(chalk.green('✓ Change archived successfully'));
165
+ console.log(chalk.dim(`Source: ${result.source}`));
166
+ console.log(chalk.dim(`Archive: ${result.archive}`));
167
+ console.log();
168
+ console.log(chalk.yellow('Delta merged to canonical specification'));
169
+ }
137
170
  } catch (error) {
138
171
  console.error(chalk.red('✗ Failed to archive change'));
139
172
  console.error(chalk.dim(error.message));
@@ -248,4 +281,584 @@ program
248
281
  }
249
282
  });
250
283
 
284
+ // Show change details
285
+ program
286
+ .command('show <change-id>')
287
+ .description('Show detailed information about a change')
288
+ .option('--changes <dir>', 'Changes directory', 'storage/changes')
289
+ .option('--format <format>', 'Output format (text|json)', 'text')
290
+ .action(async (changeId, options) => {
291
+ try {
292
+ const workspaceRoot = process.cwd();
293
+ const deltaManager = new DeltaSpecManager(workspaceRoot);
294
+
295
+ const delta = deltaManager.load(changeId);
296
+ if (!delta) {
297
+ console.error(chalk.red(`✗ Change not found: ${changeId}`));
298
+ process.exit(1);
299
+ }
300
+
301
+ if (options.format === 'json') {
302
+ console.log(JSON.stringify(delta, null, 2));
303
+ return;
304
+ }
305
+
306
+ // Text format
307
+ console.log();
308
+ console.log(chalk.bold.blue(`Delta Specification: ${delta.id}`));
309
+ console.log(chalk.dim('─'.repeat(50)));
310
+ console.log();
311
+
312
+ const typeColors = {
313
+ ADDED: chalk.green,
314
+ MODIFIED: chalk.blue,
315
+ REMOVED: chalk.red,
316
+ RENAMED: chalk.yellow
317
+ };
318
+ const typeColor = typeColors[delta.type] || chalk.white;
319
+
320
+ console.log(`${chalk.bold('Type:')} ${typeColor(delta.type)}`);
321
+ console.log(`${chalk.bold('Target:')} ${delta.target}`);
322
+ console.log(`${chalk.bold('Status:')} ${delta.status}`);
323
+ console.log(`${chalk.bold('Created:')} ${delta.createdAt}`);
324
+ console.log(`${chalk.bold('Updated:')} ${delta.updatedAt}`);
325
+ console.log();
326
+ console.log(chalk.bold('Description:'));
327
+ console.log(chalk.dim(delta.description));
328
+
329
+ if (delta.rationale) {
330
+ console.log();
331
+ console.log(chalk.bold('Rationale:'));
332
+ console.log(chalk.dim(delta.rationale));
333
+ }
334
+
335
+ if (delta.impactedAreas && delta.impactedAreas.length > 0) {
336
+ console.log();
337
+ console.log(chalk.bold('Impacted Areas:'));
338
+ delta.impactedAreas.forEach(area => {
339
+ console.log(chalk.dim(` • ${area}`));
340
+ });
341
+ }
342
+
343
+ if (delta.before) {
344
+ console.log();
345
+ console.log(chalk.bold('Before State:'));
346
+ console.log(chalk.dim(typeof delta.before === 'object'
347
+ ? JSON.stringify(delta.before, null, 2)
348
+ : delta.before));
349
+ }
350
+
351
+ if (delta.after) {
352
+ console.log();
353
+ console.log(chalk.bold('After State:'));
354
+ console.log(chalk.dim(typeof delta.after === 'object'
355
+ ? JSON.stringify(delta.after, null, 2)
356
+ : delta.after));
357
+ }
358
+
359
+ console.log();
360
+ } catch (error) {
361
+ console.error(chalk.red('✗ Failed to show change'));
362
+ console.error(chalk.dim(error.message));
363
+ process.exit(1);
364
+ }
365
+ });
366
+
367
+ // Impact analysis
368
+ program
369
+ .command('impact <change-id>')
370
+ .description('Show detailed impact analysis for a change')
371
+ .option('--changes <dir>', 'Changes directory', 'storage/changes')
372
+ .option('--full', 'Show full impact report with affected files')
373
+ .option('--format <format>', 'Output format (text|json|markdown)', 'text')
374
+ .action(async (changeId, options) => {
375
+ try {
376
+ const workspaceRoot = process.cwd();
377
+ const deltaManager = new DeltaSpecManager(workspaceRoot);
378
+ const impactAnalyzer = new ImpactAnalyzer(workspaceRoot);
379
+
380
+ console.log(chalk.blue('🔍 Analyzing impact...'));
381
+ console.log();
382
+
383
+ // Load delta
384
+ const delta = deltaManager.load(changeId);
385
+ if (!delta) {
386
+ console.error(chalk.red(`✗ Change not found: ${changeId}`));
387
+ process.exit(1);
388
+ }
389
+
390
+ // Run full impact analysis
391
+ const report = await impactAnalyzer.analyzeImpact(delta);
392
+
393
+ if (options.format === 'json') {
394
+ console.log(JSON.stringify(report, null, 2));
395
+ return;
396
+ }
397
+
398
+ if (options.format === 'markdown') {
399
+ console.log(impactAnalyzer.generateSummary(report));
400
+ return;
401
+ }
402
+
403
+ // Text format
404
+ console.log(chalk.bold.blue(`Impact Report: ${report.id}`));
405
+ console.log(chalk.dim('─'.repeat(50)));
406
+ console.log();
407
+
408
+ console.log(`${chalk.bold('Type:')} ${report.type}`);
409
+ console.log(`${chalk.bold('Target:')} ${report.target}`);
410
+ console.log(`${chalk.bold('Analyzed:')} ${report.timestamp}`);
411
+ console.log();
412
+
413
+ // Summary
414
+ console.log(chalk.bold('Summary:'));
415
+ console.log(` Total Affected: ${report.summary.totalAffected}`);
416
+ console.log();
417
+
418
+ // Impact by level
419
+ const levelColors = {
420
+ critical: chalk.red,
421
+ high: chalk.yellow,
422
+ medium: chalk.blue,
423
+ low: chalk.green,
424
+ info: chalk.dim
425
+ };
426
+
427
+ console.log(chalk.bold('Impact Levels:'));
428
+ Object.entries(report.summary.byLevel).forEach(([level, count]) => {
429
+ if (count > 0) {
430
+ const color = levelColors[level] || chalk.white;
431
+ console.log(` ${color(`${level}: ${count}`)}`);
432
+ }
433
+ });
434
+ console.log();
435
+
436
+ // Impact by category
437
+ console.log(chalk.bold('Categories:'));
438
+ Object.entries(report.summary.byCategory).forEach(([category, count]) => {
439
+ if (count > 0) {
440
+ console.log(` ${category}: ${count}`);
441
+ }
442
+ });
443
+ console.log();
444
+
445
+ // Show affected items if --full
446
+ if (options.full && report.affectedItems.length > 0) {
447
+ console.log(chalk.bold('Affected Items:'));
448
+ report.affectedItems.slice(0, 20).forEach(item => {
449
+ const levelColor = levelColors[item.level] || chalk.white;
450
+ console.log(` ${levelColor('●')} ${item.path}`);
451
+ console.log(chalk.dim(` ${item.reason}`));
452
+ });
453
+ if (report.affectedItems.length > 20) {
454
+ console.log(chalk.dim(` ... and ${report.affectedItems.length - 20} more`));
455
+ }
456
+ console.log();
457
+ }
458
+
459
+ // Risks
460
+ if (report.risks.length > 0) {
461
+ console.log(chalk.bold.red('Risks:'));
462
+ report.risks.forEach(risk => {
463
+ const riskColor = risk.level === 'high' ? chalk.red : chalk.yellow;
464
+ console.log(riskColor(` ⚠ ${risk.description}`));
465
+ console.log(chalk.dim(` Mitigation: ${risk.mitigation}`));
466
+ });
467
+ console.log();
468
+ }
469
+
470
+ // Recommendations
471
+ if (report.recommendations.length > 0) {
472
+ console.log(chalk.bold('Recommendations:'));
473
+ report.recommendations.forEach(rec => {
474
+ const emoji = {
475
+ critical: '🔴',
476
+ high: '🟠',
477
+ medium: '🟡',
478
+ info: 'ℹ️'
479
+ }[rec.priority] || '•';
480
+ console.log(` ${emoji} ${rec.message}`);
481
+ });
482
+ console.log();
483
+ }
484
+ } catch (error) {
485
+ console.error(chalk.red('✗ Failed to analyze impact'));
486
+ console.error(chalk.dim(error.message));
487
+ process.exit(1);
488
+ }
489
+ });
490
+
491
+ // Approve change
492
+ program
493
+ .command('approve <change-id>')
494
+ .description('Approve a change proposal')
495
+ .option('--changes <dir>', 'Changes directory', 'storage/changes')
496
+ .action(async (changeId, options) => {
497
+ try {
498
+ const workspaceRoot = process.cwd();
499
+ const deltaManager = new DeltaSpecManager(workspaceRoot);
500
+
501
+ const delta = deltaManager.updateStatus(changeId, 'approved');
502
+
503
+ console.log(chalk.green(`✓ Change ${changeId} approved`));
504
+ console.log(chalk.dim(`Status updated to: approved`));
505
+ console.log();
506
+ console.log(chalk.yellow('Next steps:'));
507
+ console.log(chalk.dim(`1. Implement the change`));
508
+ console.log(chalk.dim(`2. Run: musubi-change apply ${changeId}`));
509
+ } catch (error) {
510
+ console.error(chalk.red('✗ Failed to approve change'));
511
+ console.error(chalk.dim(error.message));
512
+ process.exit(1);
513
+ }
514
+ });
515
+
516
+ // Reject change
517
+ program
518
+ .command('reject <change-id>')
519
+ .description('Reject a change proposal')
520
+ .option('--reason <reason>', 'Rejection reason')
521
+ .option('--changes <dir>', 'Changes directory', 'storage/changes')
522
+ .action(async (changeId, options) => {
523
+ try {
524
+ const workspaceRoot = process.cwd();
525
+ const deltaManager = new DeltaSpecManager(workspaceRoot);
526
+
527
+ const delta = deltaManager.updateStatus(changeId, 'rejected');
528
+
529
+ console.log(chalk.red(`✗ Change ${changeId} rejected`));
530
+ if (options.reason) {
531
+ console.log(chalk.dim(`Reason: ${options.reason}`));
532
+ }
533
+ console.log(chalk.dim(`Status updated to: rejected`));
534
+ } catch (error) {
535
+ console.error(chalk.red('✗ Failed to reject change'));
536
+ console.error(chalk.dim(error.message));
537
+ process.exit(1);
538
+ }
539
+ });
540
+
541
+ // Create delta (new, using DeltaSpecManager)
542
+ program
543
+ .command('create')
544
+ .description('Create a new delta specification interactively')
545
+ .option('-i, --id <id>', 'Delta ID (e.g., DELTA-AUTH-001)')
546
+ .option('-t, --type <type>', 'Delta type (ADDED, MODIFIED, REMOVED, RENAMED)')
547
+ .option('--target <target>', 'Target requirement or component')
548
+ .option('-d, --description <description>', 'Change description')
549
+ .option('-r, --rationale <rationale>', 'Reason for change')
550
+ .option('--impact <areas>', 'Comma-separated impacted areas')
551
+ .action(async (options) => {
552
+ try {
553
+ const workspaceRoot = process.cwd();
554
+ const deltaManager = new DeltaSpecManager(workspaceRoot);
555
+ const validator = new DeltaFormatValidator();
556
+
557
+ // Validate inputs
558
+ if (!options.id) {
559
+ console.error(chalk.red('✗ Delta ID is required (--id)'));
560
+ process.exit(1);
561
+ }
562
+ if (!options.type) {
563
+ console.error(chalk.red('✗ Delta type is required (--type)'));
564
+ console.log(chalk.dim('Valid types: ADDED, MODIFIED, REMOVED, RENAMED'));
565
+ process.exit(1);
566
+ }
567
+ if (!options.target) {
568
+ console.error(chalk.red('✗ Target is required (--target)'));
569
+ process.exit(1);
570
+ }
571
+ if (!options.description) {
572
+ console.error(chalk.red('✗ Description is required (--description)'));
573
+ process.exit(1);
574
+ }
575
+
576
+ const impactedAreas = options.impact
577
+ ? options.impact.split(',').map(a => a.trim())
578
+ : [];
579
+
580
+ const delta = deltaManager.create({
581
+ id: options.id,
582
+ type: options.type.toUpperCase(),
583
+ target: options.target,
584
+ description: options.description,
585
+ rationale: options.rationale || '',
586
+ impactedAreas
587
+ });
588
+
589
+ // Validate the created delta
590
+ const validation = validator.validate(delta);
591
+
592
+ console.log(chalk.green(`✓ Delta specification created: ${delta.id}`));
593
+ console.log(chalk.dim(`Location: storage/changes/${delta.id}/`));
594
+
595
+ if (validation.warnings.length > 0) {
596
+ console.log();
597
+ console.log(chalk.yellow('Warnings:'));
598
+ validation.warnings.forEach(w => {
599
+ console.log(chalk.dim(` • ${w.message}`));
600
+ });
601
+ }
602
+
603
+ console.log();
604
+ console.log(chalk.yellow('Next steps:'));
605
+ console.log(chalk.dim(`1. Review: musubi-change show ${delta.id}`));
606
+ console.log(chalk.dim(`2. Approve: musubi-change approve ${delta.id}`));
607
+ console.log(chalk.dim(`3. Apply: musubi-change apply ${delta.id}`));
608
+ } catch (error) {
609
+ console.error(chalk.red('✗ Failed to create delta'));
610
+ console.error(chalk.dim(error.message));
611
+ process.exit(1);
612
+ }
613
+ });
614
+
615
+ // Validate all changes
616
+ program
617
+ .command('validate-all')
618
+ .description('Validate all delta specifications in the changes directory')
619
+ .option('--changes <dir>', 'Changes directory', 'storage/changes')
620
+ .option('--strict', 'Enable strict validation mode')
621
+ .action(async (options) => {
622
+ try {
623
+ const workspaceRoot = process.cwd();
624
+ const path = require('path');
625
+ const changesDir = path.join(workspaceRoot, options.changes);
626
+ const validator = new DeltaFormatValidator({ strict: options.strict });
627
+
628
+ console.log(chalk.blue('🔍 Validating all delta specifications...'));
629
+ console.log();
630
+
631
+ const result = validator.validateDirectory(changesDir);
632
+
633
+ if (result.summary.total === 0) {
634
+ console.log(chalk.dim('No delta specifications found.'));
635
+ return;
636
+ }
637
+
638
+ result.results.forEach(r => {
639
+ if (r.valid) {
640
+ console.log(chalk.green(`✓ ${r.id}`));
641
+ } else {
642
+ console.log(chalk.red(`✗ ${r.id}`));
643
+ r.errors.forEach(e => {
644
+ console.log(chalk.dim(` ${e.message}`));
645
+ });
646
+ }
647
+ });
648
+
649
+ console.log();
650
+ console.log(chalk.bold('Summary:'));
651
+ console.log(` Total: ${result.summary.total}`);
652
+ console.log(chalk.green(` Valid: ${result.summary.valid}`));
653
+ console.log(chalk.red(` Invalid: ${result.summary.invalid}`));
654
+
655
+ if (!result.valid) {
656
+ process.exit(1);
657
+ }
658
+ } catch (error) {
659
+ console.error(chalk.red('✗ Failed to validate'));
660
+ console.error(chalk.dim(error.message));
661
+ process.exit(1);
662
+ }
663
+ });
664
+
665
+ // Diff command - show before/after comparison
666
+ program
667
+ .command('diff <change-id>')
668
+ .description('Show before/after diff for a change')
669
+ .option('--changes <dir>', 'Changes directory', 'storage/changes')
670
+ .option('--context <lines>', 'Lines of context to show', '3')
671
+ .action(async (changeId, options) => {
672
+ try {
673
+ const workspaceRoot = process.cwd();
674
+ const deltaManager = new DeltaSpecManager(workspaceRoot);
675
+
676
+ const delta = deltaManager.load(changeId);
677
+ if (!delta) {
678
+ console.error(chalk.red(`✗ Change not found: ${changeId}`));
679
+ process.exit(1);
680
+ }
681
+
682
+ console.log();
683
+ console.log(chalk.bold.blue(`Diff: ${delta.id}`));
684
+ console.log(chalk.dim('─'.repeat(50)));
685
+ console.log();
686
+
687
+ const typeColors = {
688
+ ADDED: chalk.green,
689
+ MODIFIED: chalk.yellow,
690
+ REMOVED: chalk.red,
691
+ RENAMED: chalk.cyan
692
+ };
693
+ const typeColor = typeColors[delta.type] || chalk.white;
694
+
695
+ console.log(`${chalk.bold('Type:')} ${typeColor(delta.type)}`);
696
+ console.log(`${chalk.bold('Target:')} ${delta.target}`);
697
+ console.log();
698
+
699
+ switch (delta.type) {
700
+ case 'ADDED':
701
+ console.log(chalk.green('+ New Component'));
702
+ console.log(chalk.dim('─'.repeat(40)));
703
+ if (delta.after) {
704
+ if (typeof delta.after === 'object') {
705
+ console.log(chalk.green(JSON.stringify(delta.after, null, 2)));
706
+ } else {
707
+ console.log(chalk.green(delta.after));
708
+ }
709
+ } else {
710
+ console.log(chalk.green(delta.description));
711
+ }
712
+ break;
713
+
714
+ case 'REMOVED':
715
+ console.log(chalk.red('- Removed Component'));
716
+ console.log(chalk.dim('─'.repeat(40)));
717
+ if (delta.before) {
718
+ if (typeof delta.before === 'object') {
719
+ console.log(chalk.red(JSON.stringify(delta.before, null, 2)));
720
+ } else {
721
+ console.log(chalk.red(delta.before));
722
+ }
723
+ } else {
724
+ console.log(chalk.red(`Removing: ${delta.target}`));
725
+ }
726
+ break;
727
+
728
+ case 'MODIFIED':
729
+ console.log(chalk.yellow('~ Modified Component'));
730
+ console.log(chalk.dim('─'.repeat(40)));
731
+ console.log();
732
+ console.log(chalk.red.bold('BEFORE:'));
733
+ if (delta.before) {
734
+ if (typeof delta.before === 'object') {
735
+ Object.entries(delta.before).forEach(([key, value]) => {
736
+ console.log(chalk.red(`- ${key}: ${JSON.stringify(value)}`));
737
+ });
738
+ } else {
739
+ console.log(chalk.red(`- ${delta.before}`));
740
+ }
741
+ }
742
+ console.log();
743
+ console.log(chalk.green.bold('AFTER:'));
744
+ if (delta.after) {
745
+ if (typeof delta.after === 'object') {
746
+ Object.entries(delta.after).forEach(([key, value]) => {
747
+ console.log(chalk.green(`+ ${key}: ${JSON.stringify(value)}`));
748
+ });
749
+ } else {
750
+ console.log(chalk.green(`+ ${delta.after}`));
751
+ }
752
+ }
753
+ break;
754
+
755
+ case 'RENAMED':
756
+ console.log(chalk.cyan('⇒ Renamed Component'));
757
+ console.log(chalk.dim('─'.repeat(40)));
758
+ console.log(chalk.red(`- ${delta.before || delta.target}`));
759
+ console.log(chalk.green(`+ ${delta.after || 'new name'}`));
760
+ break;
761
+
762
+ default:
763
+ console.log(chalk.dim('No diff information available.'));
764
+ }
765
+
766
+ console.log();
767
+ console.log(chalk.bold('Description:'));
768
+ console.log(chalk.dim(delta.description));
769
+
770
+ if (delta.rationale) {
771
+ console.log();
772
+ console.log(chalk.bold('Rationale:'));
773
+ console.log(chalk.dim(delta.rationale));
774
+ }
775
+
776
+ console.log();
777
+ } catch (error) {
778
+ console.error(chalk.red('✗ Failed to show diff'));
779
+ console.error(chalk.dim(error.message));
780
+ process.exit(1);
781
+ }
782
+ });
783
+
784
+ // Status command - show workflow status summary
785
+ program
786
+ .command('status')
787
+ .description('Show status summary of all changes')
788
+ .option('--changes <dir>', 'Changes directory', 'storage/changes')
789
+ .action(async (options) => {
790
+ try {
791
+ const workspaceRoot = process.cwd();
792
+ const deltaManager = new DeltaSpecManager(workspaceRoot);
793
+
794
+ const deltas = deltaManager.list();
795
+
796
+ if (deltas.length === 0) {
797
+ console.log(chalk.dim('No delta specifications found.'));
798
+ return;
799
+ }
800
+
801
+ const statusCounts = {
802
+ proposed: 0,
803
+ approved: 0,
804
+ rejected: 0,
805
+ implemented: 0,
806
+ archived: 0
807
+ };
808
+
809
+ const typeCounts = {
810
+ ADDED: 0,
811
+ MODIFIED: 0,
812
+ REMOVED: 0,
813
+ RENAMED: 0
814
+ };
815
+
816
+ deltas.forEach(d => {
817
+ statusCounts[d.status] = (statusCounts[d.status] || 0) + 1;
818
+ typeCounts[d.type] = (typeCounts[d.type] || 0) + 1;
819
+ });
820
+
821
+ console.log();
822
+ console.log(chalk.bold.blue('Change Status Summary'));
823
+ console.log(chalk.dim('─'.repeat(40)));
824
+ console.log();
825
+
826
+ console.log(chalk.bold('By Status:'));
827
+ console.log(` ${chalk.yellow('●')} Proposed: ${statusCounts.proposed}`);
828
+ console.log(` ${chalk.blue('●')} Approved: ${statusCounts.approved}`);
829
+ console.log(` ${chalk.red('●')} Rejected: ${statusCounts.rejected}`);
830
+ console.log(` ${chalk.cyan('●')} Implemented: ${statusCounts.implemented}`);
831
+ console.log(` ${chalk.green('●')} Archived: ${statusCounts.archived}`);
832
+ console.log();
833
+
834
+ console.log(chalk.bold('By Type:'));
835
+ console.log(` ${chalk.green('+')} ADDED: ${typeCounts.ADDED}`);
836
+ console.log(` ${chalk.yellow('~')} MODIFIED: ${typeCounts.MODIFIED}`);
837
+ console.log(` ${chalk.red('-')} REMOVED: ${typeCounts.REMOVED}`);
838
+ console.log(` ${chalk.cyan('⇒')} RENAMED: ${typeCounts.RENAMED}`);
839
+ console.log();
840
+
841
+ console.log(`${chalk.bold('Total:')} ${deltas.length} delta(s)`);
842
+ console.log();
843
+
844
+ // Show pending items
845
+ const pending = deltas.filter(d =>
846
+ d.status === 'proposed' || d.status === 'approved'
847
+ );
848
+
849
+ if (pending.length > 0) {
850
+ console.log(chalk.bold('Pending Actions:'));
851
+ pending.forEach(d => {
852
+ const statusColor = d.status === 'proposed' ? chalk.yellow : chalk.blue;
853
+ console.log(` ${statusColor('●')} ${d.id} (${d.status})`);
854
+ });
855
+ console.log();
856
+ }
857
+ } catch (error) {
858
+ console.error(chalk.red('✗ Failed to get status'));
859
+ console.error(chalk.dim(error.message));
860
+ process.exit(1);
861
+ }
862
+ });
863
+
251
864
  program.parse();