arcvision 0.2.28 → 0.2.29

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/src/index.js CHANGED
@@ -93,6 +93,16 @@ function analyzeBlastRadius(architectureMap) {
93
93
  };
94
94
  }
95
95
 
96
+ /**
97
+ * Print the PASS 5 Architecture Intelligence Summary to the terminal.
98
+ * All values are derived from actual graph computation in pass5_intelligence.js.
99
+ * This is NOT a template — it reads real data from map.intelligence.
100
+ *
101
+ * @param {Object} map - Full context object with intelligence block attached
102
+ * @param {Object} chalkInstance - chalk instance for colors
103
+ */
104
+
105
+
96
106
  function saveToken(token) {
97
107
  try {
98
108
  // Validate token format before saving
@@ -497,87 +507,103 @@ program
497
507
  .description('Scan the current directory and generate architecture map')
498
508
  .argument('[directory]', 'Directory to scan', '.')
499
509
  .option('-u, --upload', 'Upload to database')
510
+ .option('-o, --output <file>', 'Save context to a specific file')
511
+ .option('--raw', 'Show verbose pass output and structural analysis details')
512
+ .option('--debug', 'Show all internal logs (preflight, plugins, ownership resolution, etc.)')
500
513
  .action(async (directory, options) => {
501
514
  const targetDir = path.resolve(directory);
502
515
 
516
+ // Wire verbosity flags to global so scanner.js can check them
517
+ process.env.ARCVISION_RAW = options.raw ? '1' : '';
518
+ process.env.ARCVISION_DEBUG = options.debug ? '1' : '';
519
+
503
520
  try {
504
- // Pre-flight validation
505
- await cliValidator.preFlightValidation('scan', {
506
- directory: targetDir
507
- });
521
+ // Pre-flight validation (silenced in default mode)
522
+ if (options.raw || options.debug) {
523
+ await cliValidator.preFlightValidation('scan', { directory: targetDir });
524
+ } else {
525
+ // Run validation silently — capture console temporarily
526
+ const origLog = console.log;
527
+ const origWarn = console.warn;
528
+ console.log = () => { };
529
+ console.warn = () => { };
530
+ try { await cliValidator.preFlightValidation('scan', { directory: targetDir }); } catch (e) { /* rethrow after restoring */ console.log = origLog; console.warn = origWarn; throw e; }
531
+ console.log = origLog;
532
+ console.warn = origWarn;
533
+ }
508
534
 
509
535
  // Initialize Artifact Manager
510
536
  const { ArtifactManager } = require('./core/artifact-manager');
511
537
  const artifactManager = new ArtifactManager(targetDir);
512
-
513
- // Ensure all required artifacts exist
514
538
  artifactManager.ensureArtifacts();
515
539
 
516
- console.log(chalk.blue(`Scanning directory: ${targetDir}`));
517
-
518
- const map = await scanner.scan(targetDir);
519
- console.log(chalk.green('Scan complete!'));
520
-
521
- // Analyze and print blast radius insight
522
- const blastRadiusAnalysis = analyzeBlastRadius(map);
523
- if (blastRadiusAnalysis && blastRadiusAnalysis.topFiles && blastRadiusAnalysis.topFiles.length > 0) {
524
- console.log('\n🔍 STRUCTURAL ANALYSIS RESULTS:\n');
525
-
526
- blastRadiusAnalysis.topFiles.forEach((item, index) => {
527
- let warningMessage = '';
528
- if (index === 0) {
529
- warningMessage = 'Changes here may silently propagate across the system.';
530
- } else if (index === 1) {
531
- warningMessage = 'Acts as a coordination layer between components.';
532
- } else {
533
- warningMessage = 'Modifications can cause widespread inconsistencies.';
534
- }
540
+ if (options.raw || options.debug) {
541
+ console.log(chalk.blue(`\nScanning directory: ${targetDir}`));
542
+ }
535
543
 
536
- console.log(`${index + 1}. 📁 ${item.file}`);
537
- console.log(` 🎯 Blast Radius: ${item.blastRadius} files (${item.percentOfGraph}%)`);
538
- console.log(` ⚠️ Risk: ${warningMessage}\n`);
539
- });
544
+ // Run the full 5-pass engine
545
+ // In default mode, suppress the noisy pass-level console output from scanner.js
546
+ let map;
547
+ if (options.raw || options.debug) {
548
+ map = await scanner.scan(targetDir);
540
549
  } else {
541
- console.log('\n✅ No high-impact structural hubs detected in this codebase.');
550
+ // Capture ALL console.log/warn during scan show only our curated summary
551
+ const origLog = console.log;
552
+ const origWarn = console.warn;
553
+ const origError = console.error;
554
+ const capturedLogs = [];
555
+ console.log = (...args) => capturedLogs.push(args.join(' '));
556
+ console.warn = (...args) => capturedLogs.push('[WARN] ' + args.join(' '));
557
+ // Keep errors visible even in default mode (failures matter)
558
+ try {
559
+ map = await scanner.scan(targetDir);
560
+ } finally {
561
+ console.log = origLog;
562
+ console.warn = origWarn;
563
+ console.error = origError;
564
+ }
542
565
  }
543
566
 
544
- // Validate the map before saving or uploading
545
- const { validateContext } = require('./engine/context_validator');
546
- const validation = validateContext(map);
547
-
548
- if (!validation.valid) {
549
- console.warn('⚠️ VALIDATION ISSUES FOUND:');
550
- validation.errors.forEach(e => console.warn(' -', e));
551
- console.warn('⚠️ Proceeding with output despite validation issues to see results');
567
+ // ── PASS 5: ARCHITECTURE INTELLIGENCE SUMMARY (always printed) ──
568
+ printIntelligenceSummary(map, chalk);
569
+
570
+ // ── STRUCTURAL ANALYSIS (blast radius) — only in --raw mode ──
571
+ if (options.raw) {
572
+ const blastRadiusAnalysis = analyzeBlastRadius(map);
573
+ if (blastRadiusAnalysis && blastRadiusAnalysis.topFiles && blastRadiusAnalysis.topFiles.length > 0) {
574
+ console.log(chalk.dim('\n── Blast Radius Analysis ──'));
575
+ blastRadiusAnalysis.topFiles.forEach((item, index) => {
576
+ const messages = [
577
+ 'Changes here may silently propagate across the system.',
578
+ 'Acts as a coordination layer between components.',
579
+ 'Modifications can cause widespread inconsistencies.'
580
+ ];
581
+ console.log(`${index + 1}. 📁 ${item.file}`);
582
+ console.log(` 🎯 Blast Radius: ${item.blastRadius} files (${item.percentOfGraph}%)`);
583
+ console.log(` ⚠️ Risk: ${messages[index] || ''}\n`);
584
+ });
585
+ }
552
586
  }
553
587
 
554
- // Create dedicated arcvision_context directory
588
+ // ── SAVE / UPLOAD ──
555
589
  const arcvisionDir = path.join(targetDir, 'arcvision_context');
556
590
  if (!fs.existsSync(arcvisionDir)) {
557
591
  fs.mkdirSync(arcvisionDir, { recursive: true });
558
- console.log(chalk.green(`📁 Created arcvision_context directory: ${arcvisionDir}`));
559
592
  }
560
593
 
561
- // Upload to database if requested
594
+ const { generateReadme } = require('./core/readme-generator');
595
+
562
596
  if (options.upload) {
563
597
  await uploadToDatabase(map, arcvisionDir);
564
-
565
- // Generate README for system context when uploading
566
- const { generateReadme } = require('./core/readme-generator');
567
- generateReadme(arcvisionDir, version, blastRadiusAnalysis);
598
+ generateReadme(arcvisionDir, version, analyzeBlastRadius(map), map.intelligence);
568
599
  } else {
569
- // Save to file with validation in dedicated directory
570
- const fs = require('fs');
571
- const outputFileName = path.join(arcvisionDir, 'arcvision.context.json');
600
+ const outputFileName = options.output ? path.resolve(options.output) : path.join(arcvisionDir, 'arcvision.context.json');
572
601
  fs.writeFileSync(outputFileName, JSON.stringify(map, null, 2));
573
- console.log(chalk.green(`✅ Structural context saved to ${outputFileName}`));
574
-
575
- // Generate README for system context in dedicated directory
576
- const { generateReadme } = require('./core/readme-generator');
577
- generateReadme(arcvisionDir, version, blastRadiusAnalysis);
578
-
579
- console.log(chalk.dim('\nUse --upload to send to dashboard.'));
602
+ console.log(chalk.green(`\n✅ Context saved ${outputFileName}`));
603
+ generateReadme(arcvisionDir, version, analyzeBlastRadius(map), map.intelligence);
604
+ console.log(chalk.dim('Use --upload to send to dashboard.'));
580
605
  }
606
+
581
607
  } catch (error) {
582
608
  cliErrorHandler.handleFatalError(error, {
583
609
  operation: 'scan',
@@ -592,7 +618,8 @@ program
592
618
  .description('Compare two context artifacts and generate diff summary')
593
619
  .argument('<old-file>', 'Path to the old context artifact')
594
620
  .argument('<new-file>', 'Path to the new context artifact')
595
- .action(async (oldFile, newFile) => {
621
+ .option('-o, --output <file>', 'Save diff summary to a specific file')
622
+ .action(async (oldFile, newFile, options) => {
596
623
  try {
597
624
  // Pre-flight validation
598
625
  await cliValidator.preFlightValidation('diff', {
@@ -619,7 +646,7 @@ program
619
646
  if (!fs.existsSync(arcvisionDir)) {
620
647
  fs.mkdirSync(arcvisionDir, { recursive: true });
621
648
  }
622
- const outputFileName = path.join(arcvisionDir, 'arcvision.context.diff.json');
649
+ const outputFileName = options.output ? path.resolve(options.output) : path.join(arcvisionDir, 'arcvision.context.diff.json');
623
650
  fs.writeFileSync(outputFileName, JSON.stringify(newContext, null, 2));
624
651
 
625
652
  console.log(chalk.green('✅ Structural diff completed!'));
@@ -977,4 +1004,70 @@ program
977
1004
  }
978
1005
  });
979
1006
 
1007
+ /**
1008
+ * Print the Architecture Intelligence Summary from Pass 5
1009
+ * @param {Object} context - The structural context result
1010
+ * @param {Object} chalk - Chalk instance for formatting
1011
+ */
1012
+ function printIntelligenceSummary(context, chalk) {
1013
+ if (!context || !context.intelligence) return;
1014
+
1015
+ const intel = context.intelligence;
1016
+ const sep = '═'.repeat(60);
1017
+
1018
+ console.log(`\n${chalk.bold.cyan('🧠 ARCHITECTURE INTELLIGENCE SUMMARY (Pass 5)')}`);
1019
+ console.log(chalk.cyan(sep));
1020
+
1021
+ // 1. Archetype Classification
1022
+ if (intel.architectural_classification) {
1023
+ const arch = intel.architectural_classification;
1024
+ console.log(`\n${chalk.bold('Architectural Archetype:')}`);
1025
+ console.log(` ${chalk.magenta(arch.type.toUpperCase().replace(/_/g, ' '))}`);
1026
+ console.log(` → ${chalk.dim(arch.description)}`);
1027
+ }
1028
+ // 1. Risk Score
1029
+ const riskColor = intel.risk_assessment.risk_level === 'high' ? chalk.red :
1030
+ intel.risk_assessment.risk_level === 'medium' ? chalk.yellow : chalk.green;
1031
+ console.log(`\n${chalk.bold('Risk Score:')} ${riskColor(intel.risk_assessment.risk_score + '/10')} (${intel.risk_assessment.risk_level.toUpperCase()})`);
1032
+
1033
+ // 1.a Architectural Entropy
1034
+ if (intel.entropy) {
1035
+ const entropyColor = intel.entropy.level === 'critical' ? chalk.red :
1036
+ intel.entropy.level === 'high' ? chalk.red :
1037
+ intel.entropy.level === 'medium' ? chalk.yellow : chalk.green;
1038
+ console.log(`${chalk.bold('Architectural Entropy:')} ${entropyColor(intel.entropy.score)} [${intel.entropy.level.toUpperCase()}]`);
1039
+ }
1040
+
1041
+ // 2. Structural Hotspots
1042
+ console.log(`\n${chalk.bold('Structural Hotspots:')}`);
1043
+ console.log(` • ${chalk.yellow(intel.hotspots.total_cycles)} circular dependency cycles detected`);
1044
+ console.log(` • ${chalk.yellow(intel.hotspots.clusters.length)} dense coupling clusters identified`);
1045
+ if (intel.hotspots.boundary_violations && intel.hotspots.boundary_violations.length > 0) {
1046
+ console.log(` • ${chalk.red(intel.hotspots.boundary_violations.length)} architectural boundary violations detected`);
1047
+ }
1048
+
1049
+ // 3. Architectural Gravity (Centrality)
1050
+ console.log(`\n${chalk.bold('Most Central File (Gravity Hub):')}`);
1051
+ console.log(` • ${chalk.magenta(intel.centrality.most_central || 'None identified')}`);
1052
+
1053
+ // 4. Critical Fragility
1054
+ const highFragility = (intel.fragility.top_fragile_files || []).filter(f => f.score > 2);
1055
+ if (highFragility.length > 0) {
1056
+ console.log(`\n${chalk.bold('Highly Fragile Components:')}`);
1057
+ highFragility.slice(0, 3).forEach(f => {
1058
+ console.log(` • ${chalk.red(f.file)} (fragility: ${f.score})`);
1059
+ });
1060
+ }
1061
+
1062
+ // 5. Recommendations
1063
+ if (intel.recommendations && intel.recommendations.length > 0) {
1064
+ console.log(`\n${chalk.bold.green('AI Recommendations:')}`);
1065
+ intel.recommendations.forEach((rec, idx) => {
1066
+ console.log(` ${idx + 1}. ${rec}`);
1067
+ });
1068
+ }
1069
+
1070
+ console.log(`\n${chalk.cyan('='.repeat(45))}\n`);
1071
+ }
1072
+
980
1073
  program.parse();