arcvision 0.2.20 → 0.2.21

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.
@@ -3,3 +3,5 @@
3
3
  {"timestamp":"2026-01-25T02:04:57.719Z","error":{"category":"UNKNOWN","message":"Invalid ledger structure","code":null,"type":"Error"},"context":{"operation":"evaluate","directory":"C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\test-dev-project"},"stack":"Error: Invalid ledger structure\n at AuthorityLedger.readLedger (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:203:15)\n at AuthorityLedger.appendEvent (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:176:27)\n at AuthorityLedger.recordBlocked (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:81:10)\n at Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:662:35)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}
4
4
  {"timestamp":"2026-01-25T02:05:38.566Z","error":{"category":"UNKNOWN","message":"Invalid ledger structure","code":null,"type":"Error"},"context":{"operation":"evaluate","directory":"C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\test-dev-project"},"stack":"Error: Invalid ledger structure\n at AuthorityLedger.readLedger (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:203:15)\n at AuthorityLedger.appendEvent (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:176:27)\n at AuthorityLedger.recordBlocked (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:81:10)\n at Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:662:35)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}
5
5
  {"timestamp":"2026-01-25T03:16:17.596Z","error":{"category":"CONFIGURATION","message":"Invalid or revoked token","code":null,"type":"Error"},"context":{"operation":"standard_upload"},"stack":"Error: Invalid or revoked token\n at C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:330:19\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async RetryHandler.executeWithRetry (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\retry-handler.js:23:24)\n at async uploadToDatabase (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:294:24)\n at async Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:462:9)"}
6
+ {"timestamp":"2026-01-25T10:28:14.750Z","error":{"category":"UNKNOWN","message":"Failed to initiate upload session","code":null,"type":"Error"},"context":{"operation":"chunked_upload"},"stack":"Error: Failed to initiate upload session\n at ChunkedUploader.uploadInChunks (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\chunked-uploader.js:58:13)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:177:18\n at async RetryHandler.executeWithRetry (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\retry-handler.js:23:24)\n at async uploadToDatabase (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:176:24)\n at async Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:473:9)"}
7
+ {"timestamp":"2026-01-25T14:09:23.628Z","error":{"category":"CONFIGURATION","message":"Invalid or revoked token","code":null,"type":"Error"},"context":{"operation":"standard_upload"},"stack":"Error: Invalid or revoked token\n at C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:341:19\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async RetryHandler.executeWithRetry (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\retry-handler.js:23:24)\n at async uploadToDatabase (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:294:24)\n at async Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:473:9)"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcvision",
3
- "version": "0.2.20",
3
+ "version": "0.2.21",
4
4
  "description": "ArcVision CLI - Architectural Governance and Invariant Detection Tool",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -206,11 +206,17 @@ program
206
206
  fs.mkdirSync(tokensDir, { recursive: true });
207
207
  }
208
208
 
209
- // Copy configuration templates
210
- const templateDir = path.join(__dirname, '..', '.arcvision');
211
- if (fs.existsSync(templateDir)) {
212
- copyFile(path.join(templateDir, 'config.json'), path.join(arcDir, 'config.json'));
213
- copyFile(path.join(templateDir, 'invariants.json'), path.join(arcDir, 'invariants.json'));
209
+ // Create default configuration (no longer using separate invariants file as they're stored in context)
210
+ const configPath = path.join(arcDir, 'config.json');
211
+ if (!fs.existsSync(configPath)) {
212
+ const defaultConfig = {
213
+ guard_rules: {
214
+ blast_radius: {
215
+ critical_threshold: 50
216
+ }
217
+ }
218
+ };
219
+ fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
214
220
  console.log(chalk.green('āœ… Configuration files created'));
215
221
  }
216
222
 
@@ -223,7 +229,7 @@ program
223
229
  console.log(chalk.green('\nšŸŽ‰ ArcVision Impact Guard initialized successfully!'));
224
230
  console.log(chalk.yellow('\nNext steps:'));
225
231
  console.log(chalk.yellow('1. Review .arcvision/config.json for project settings'));
226
- console.log(chalk.yellow('2. Customize .arcvision/invariants.json with your architectural rules'));
232
+ console.log(chalk.yellow('2. Auto-detect architectural invariants by running: arcvision scan'));
227
233
  console.log(chalk.yellow('3. Run: arcvision-guard check'));
228
234
  console.log(chalk.yellow('4. For critical changes: arcvision-guard bypass-request --reason "your reason"'));
229
235
  });
@@ -246,17 +252,11 @@ program
246
252
  remediation: "Define appropriate remediation steps"
247
253
  };
248
254
 
249
- const invariantsPath = path.join('.arcvision', 'invariants.json');
250
- if (!fs.existsSync(invariantsPath)) {
251
- console.log(chalk.red('āŒ ArcVision not initialized. Run "arcvision-guard setup" first.'));
252
- process.exit(1);
253
- }
254
-
255
- const invariants = JSON.parse(fs.readFileSync(invariantsPath, 'utf8'));
256
- invariants.project_specific_invariants.push(invariant);
257
-
258
- fs.writeFileSync(invariantsPath, JSON.stringify(invariants, null, 2));
259
- console.log(chalk.green(`āœ… Added invariant: ${name}`));
255
+ // Note: Invariants are now automatically detected by scanning and stored in arcvision.context.json
256
+ console.log(chalk.red('āŒ Custom invariants are now managed differently.'));
257
+ console.log(chalk.yellow('šŸ’” Run "arcvision scan" to auto-detect invariants from your codebase.'));
258
+ console.log(chalk.yellow('šŸ’” Or manually edit the invariants section in arcvision_context/arcvision.context.json if needed.'));
259
+ process.exit(1);
260
260
  });
261
261
 
262
262
  // Helper functions
@@ -4,11 +4,12 @@ const path = require('path');
4
4
  class ArtifactManager {
5
5
  constructor(projectRoot) {
6
6
  this.projectRoot = projectRoot;
7
- this.requiredDirs = ['.arcvision', 'arcvision_context'];
7
+ // Remove .arcvision directory as invariants should be in main context file only
8
+ this.requiredDirs = ['arcvision_context'];
8
9
  this.requiredFiles = {
9
10
  context: 'arcvision_context/arcvision.context.json',
10
- ledger: 'arcvision_context/architecture.authority.ledger.json',
11
- invariants: '.arcvision/invariants.json'
11
+ ledger: 'arcvision_context/architecture.authority.ledger.json'
12
+ // Remove invariants from separate file as they should be in main context per schema
12
13
  };
13
14
  }
14
15
 
@@ -43,19 +44,6 @@ class ArtifactManager {
43
44
  * Creates missing files with default content
44
45
  */
45
46
  createMissingFiles() {
46
- // Create default invariants file if missing
47
- const invariantsPath = path.join(this.projectRoot, this.requiredFiles.invariants);
48
- if (!fs.existsSync(invariantsPath)) {
49
- const defaultInvariants = {
50
- version: '1.0',
51
- project_specific_invariants: [],
52
- generated_at: new Date().toISOString()
53
- };
54
-
55
- fs.writeFileSync(invariantsPath, JSON.stringify(defaultInvariants, null, 2));
56
- this.logCreation(this.requiredFiles.invariants);
57
- }
58
-
59
47
  // Create default ledger if missing
60
48
  const ledgerPath = path.join(this.projectRoot, this.requiredFiles.ledger);
61
49
  if (!fs.existsSync(ledgerPath)) {
@@ -7,13 +7,13 @@ class ConfigValidator {
7
7
  */
8
8
  static validateProjectStructure(projectPath) {
9
9
  const requiredPaths = [
10
- path.join(projectPath, 'arcvision_context'),
11
- path.join(projectPath, '.arcvision')
10
+ path.join(projectPath, 'arcvision_context')
11
+ // Removed .arcvision as invariants are now stored in main context file
12
12
  ];
13
13
 
14
14
  const optionalPaths = [
15
15
  path.join(projectPath, 'arcvision_context', 'arcvision.context.json'),
16
- path.join(projectPath, '.arcvision', 'invariants.json'),
16
+ // Removed .arcvision/invariants.json as invariants are now stored in main context file
17
17
  path.join(projectPath, 'arcvision_context', 'architecture.authority.ledger.json')
18
18
  ];
19
19
 
@@ -174,14 +174,7 @@ class ConfigValidator {
174
174
  isValid: projectValidation.isValid
175
175
  };
176
176
 
177
- // Validate invariants file if it exists
178
- const invariantsPath = path.join(projectPath, '.arcvision', 'invariants.json');
179
- if (fs.existsSync(invariantsPath)) {
180
- configValidation.invariantsFile = this.validateInvariantsFile(invariantsPath);
181
- if (!configValidation.invariantsFile.isValid) {
182
- configValidation.isValid = false;
183
- }
184
- }
177
+ // No longer validating separate invariants file as they are stored in main context file
185
178
 
186
179
  // Validate context file if it exists
187
180
  const contextPath = path.join(projectPath, 'arcvision_context', 'arcvision.context.json');
@@ -190,8 +190,9 @@ function buildContext(fileNodes, edges, symbols, options = {}) {
190
190
  structural_hubs: options.structuralHubs || [],
191
191
  architectural_boundaries: options.architecturalBoundaries || {},
192
192
  structural_invariants: options.structuralInvariants || [],
193
- // Include detected invariants from the current scan
194
- invariants: options.detectedInvariants || [],
193
+ // Include detected invariants from the current scan - these should conform to the schema specification
194
+ invariants: Array.isArray(options.autoDetectedInvariants) ? options.autoDetectedInvariants :
195
+ Array.isArray(options.detectedInvariants) ? options.detectedInvariants : [],
195
196
  // Include invariant analysis results
196
197
  invariant_analysis: options.invariantAnalysis || null,
197
198
  // Include architectural health assessment
@@ -30,9 +30,23 @@ class FeatureManager {
30
30
  * Checks for the presence of key artifacts
31
31
  */
32
32
  static checkArtifacts(projectPath) {
33
+ // Read the context file to check if it contains invariants
34
+ const contextPath = path.join(projectPath, 'arcvision_context', 'arcvision.context.json');
35
+ let invariantsExists = false;
36
+
37
+ if (fs.existsSync(contextPath)) {
38
+ try {
39
+ const contextData = JSON.parse(fs.readFileSync(contextPath, 'utf8'));
40
+ invariantsExists = Array.isArray(contextData.invariants) && contextData.invariants.length > 0;
41
+ } catch (error) {
42
+ // If there's an error parsing, assume no invariants
43
+ invariantsExists = false;
44
+ }
45
+ }
46
+
33
47
  return {
34
- context_exists: fs.existsSync(path.join(projectPath, 'arcvision_context', 'arcvision.context.json')),
35
- invariants_exists: fs.existsSync(path.join(projectPath, '.arcvision', 'invariants.json')),
48
+ context_exists: fs.existsSync(contextPath),
49
+ invariants_exists: invariantsExists,
36
50
  ledger_exists: fs.existsSync(path.join(projectPath, 'arcvision_context', 'architecture.authority.ledger.json')),
37
51
  readme_exists: fs.existsSync(path.join(projectPath, 'arcvision_context', 'README.md')),
38
52
  arcvision_dir_exists: fs.existsSync(path.join(projectPath, '.arcvision')),
@@ -51,9 +65,9 @@ class FeatureManager {
51
65
  recommendations.push({
52
66
  type: 'SETUP',
53
67
  priority: 'HIGH',
54
- message: 'Define architectural invariants for governance',
55
- action: 'arcvision init-invariants',
56
- description: 'Create custom rules to govern your architectural decisions'
68
+ message: 'Auto-detect architectural invariants for governance',
69
+ action: 'arcvision scan',
70
+ description: 'Re-scan your project to auto-detect architectural invariants'
57
71
  });
58
72
  }
59
73
 
@@ -61,16 +61,18 @@ class InvariantDetector {
61
61
  system: 'automatic',
62
62
  statement: invariant.description,
63
63
  description: invariant.description,
64
- severity: invariant.isCritical ? 'block' : 'risk',
65
64
  scope: { files: [nodeId] },
66
65
  critical_path: invariant.isCritical,
67
66
  assertion: `Pattern: ${invariant.pattern}`,
67
+ status: 'suspected',
68
+ confidence: this.calculateConfidenceScore(invariant.pattern, nodeId, content),
69
+ owner: this.determineOwnerFromPath(nodeId),
70
+ violated_by: [],
71
+ severity: invariant.isCritical ? 'block' : 'risk',
68
72
  rule: {
69
73
  type: 'pattern',
70
74
  condition: { pattern: invariant.pattern }
71
75
  },
72
- status: 'suspected',
73
- confidence: this.calculateConfidenceScore(invariant.pattern, nodeId, content),
74
76
  source_file: nodeId,
75
77
  detected_at: new Date().toISOString()
76
78
  });
@@ -96,10 +98,14 @@ class InvariantDetector {
96
98
  system: 'automatic',
97
99
  statement: constraint.description,
98
100
  description: constraint.description,
99
- severity: constraint.critical ? 'block' : 'risk',
100
101
  scope: { files: [constraint.from, constraint.to] },
101
102
  critical_path: constraint.critical,
102
103
  assertion: `Dependency constraint: ${constraint.from} -> ${constraint.to}`,
104
+ status: 'suspected',
105
+ confidence: this.calculateConfidenceScore('dependency_constraint', constraint.from, ''),
106
+ owner: this.determineOwnerFromPath(constraint.from),
107
+ violated_by: [],
108
+ severity: constraint.critical ? 'block' : 'risk',
103
109
  rule: {
104
110
  type: 'dependency',
105
111
  condition: {
@@ -109,8 +115,6 @@ class InvariantDetector {
109
115
  }
110
116
  }
111
117
  },
112
- status: 'suspected',
113
- confidence: this.calculateConfidenceScore('dependency_constraint', constraint.from, ''),
114
118
  source_relationship: `${constraint.from} -> ${constraint.to}`,
115
119
  detected_at: new Date().toISOString()
116
120
  });
@@ -137,16 +141,18 @@ class InvariantDetector {
137
141
  system: 'automatic',
138
142
  statement: `System invariant implemented in ${relativePath}: ${pattern.description}`,
139
143
  description: `System invariant implemented in ${relativePath}: ${pattern.description}`,
140
- severity: 'risk',
141
144
  scope: { files: [relativePath] },
142
145
  critical_path: true, // File specifically for invariants is likely critical
143
146
  assertion: pattern.assertion,
147
+ status: 'suspected',
148
+ confidence: this.calculateConfidenceScore(pattern.type, relativePath, content),
149
+ owner: this.determineOwnerFromPath(relativePath),
150
+ violated_by: [],
151
+ severity: 'risk',
144
152
  rule: {
145
153
  type: 'pattern',
146
154
  condition: { pattern: pattern.type }
147
155
  },
148
- status: 'suspected',
149
- confidence: this.calculateConfidenceScore(pattern.type, relativePath, content),
150
156
  source_file: relativePath,
151
157
  implementation_type: pattern.type,
152
158
  detected_at: new Date().toISOString()
@@ -664,10 +670,14 @@ class InvariantDetector {
664
670
  system: 'architectural',
665
671
  statement: `Layer dependency rule: ${fromLayer} components should not depend on ${toLayer} components`,
666
672
  description: `Prevent ${fromLayer} layer from depending on ${toLayer} layer to maintain separation of concerns`,
667
- severity: 'block',
668
673
  scope: { files: dependencies.map(d => d.from) },
669
674
  critical_path: true,
670
675
  assertion: `Layer dependency rule: ${fromLayer} -> ${toLayer} is forbidden`,
676
+ status: 'detected',
677
+ confidence: 0.9,
678
+ owner: 'architectural-analyzer',
679
+ violated_by: [],
680
+ severity: 'block',
671
681
  rule: {
672
682
  type: 'dependency',
673
683
  condition: {
@@ -677,8 +687,6 @@ class InvariantDetector {
677
687
  }
678
688
  }
679
689
  },
680
- status: 'detected',
681
- confidence: 0.9,
682
690
  detected_at: new Date().toISOString()
683
691
  });
684
692
  }
@@ -707,26 +715,31 @@ class InvariantDetector {
707
715
 
708
716
  // Identify potential architectural bottlenecks
709
717
  for (const [nodeId, degrees] of nodeDegrees.entries()) {
710
- if (degrees.incoming > 10) { // High incoming degree indicates hub
711
- this.detectedInvariants.push({
712
- id: this.generateInvariantId(`hub_protection_${nodeId}`, 'high_degree'),
713
- system: 'architectural',
714
- statement: `Protect high-degree node ${nodeId} from unauthorized modifications`,
715
- description: `Node ${nodeId} has ${degrees.incoming} incoming dependencies, changes here affect many components`,
716
- severity: 'risk',
717
- scope: { files: [nodeId] },
718
- critical_path: true,
719
- assertion: `High-degree node protection: ${nodeId} has ${degrees.incoming} dependencies`,
720
- rule: {
721
- type: 'access_control',
722
- condition: {
723
- mustBeReviewed: true
724
- }
725
- },
726
- status: 'detected',
727
- confidence: 0.8,
728
- detected_at: new Date().toISOString()
729
- });
718
+ // Make sure nodeId is valid before creating invariant
719
+ if (nodeId && nodeId !== 'undefined' && nodeId !== 'null' && nodeId !== 'unknown' && degrees.incoming > 0) {
720
+ if (degrees.incoming > 10) { // High incoming degree indicates hub
721
+ this.detectedInvariants.push({
722
+ id: this.generateInvariantId(`hub_protection_${nodeId}`, 'high_degree'),
723
+ system: 'architectural',
724
+ statement: `Protect high-degree node ${nodeId} from unauthorized modifications`,
725
+ description: `Node ${nodeId} has ${degrees.incoming} incoming dependencies, changes here affect many components`,
726
+ scope: { files: [nodeId] },
727
+ critical_path: true,
728
+ assertion: `High-degree node protection: ${nodeId} has ${degrees.incoming} dependencies`,
729
+ status: 'detected',
730
+ confidence: 0.8,
731
+ owner: this.determineOwnerFromPath(nodeId),
732
+ violated_by: [],
733
+ severity: 'risk',
734
+ rule: {
735
+ type: 'access_control',
736
+ condition: {
737
+ mustBeReviewed: true
738
+ }
739
+ },
740
+ detected_at: new Date().toISOString()
741
+ });
742
+ }
730
743
  }
731
744
  }
732
745
  }
@@ -755,25 +768,30 @@ class InvariantDetector {
755
768
  for (const [coupleKey, edgesList] of couplingMap.entries()) {
756
769
  const [nodeA, nodeB] = coupleKey.split('|');
757
770
 
758
- this.detectedInvariants.push({
759
- id: this.generateInvariantId(`tight_coupling_${nodeA}_${nodeB}`, 'bidirectional'),
760
- system: 'architectural',
761
- statement: `Prevent tight coupling between ${nodeA} and ${nodeB}`,
762
- description: `Bidirectional dependency detected between ${nodeA} and ${nodeB}, indicating tight coupling`,
763
- severity: 'risk',
764
- scope: { files: [nodeA, nodeB] },
765
- critical_path: false,
766
- assertion: `Bidirectional dependency: ${nodeA} <-> ${nodeB}`,
767
- rule: {
768
- type: 'dependency',
769
- condition: {
770
- shouldAvoidBidirectional: true
771
- }
772
- },
773
- status: 'detected',
774
- confidence: 0.7,
775
- detected_at: new Date().toISOString()
776
- });
771
+ // Only create the invariant if both node names are valid and non-empty
772
+ if (nodeA && nodeA.trim() !== '' && nodeB && nodeB.trim() !== '') {
773
+ this.detectedInvariants.push({
774
+ id: this.generateInvariantId(`tight_coupling_${nodeA}_${nodeB}`, 'bidirectional'),
775
+ system: 'architectural',
776
+ statement: `Prevent tight coupling between ${nodeA} and ${nodeB}`,
777
+ description: `Bidirectional dependency detected between ${nodeA} and ${nodeB}, indicating tight coupling`,
778
+ scope: { files: [nodeA, nodeB] },
779
+ critical_path: false,
780
+ assertion: `Bidirectional dependency: ${nodeA} <-> ${nodeB}`,
781
+ status: 'detected',
782
+ confidence: 0.7,
783
+ owner: 'architectural-analyzer',
784
+ violated_by: [],
785
+ severity: 'risk',
786
+ rule: {
787
+ type: 'dependency',
788
+ condition: {
789
+ shouldAvoidBidirectional: true
790
+ }
791
+ },
792
+ detected_at: new Date().toISOString()
793
+ });
794
+ }
777
795
  }
778
796
  }
779
797
  }
@@ -195,8 +195,9 @@ async function scan(directory) {
195
195
  architecturalBoundaries,
196
196
  structuralInvariants,
197
197
  authoritativeContext,
198
- // Include detected invariants
198
+ // Include detected invariants - this will be used in context_builder
199
199
  autoDetectedInvariants: detectedInvariants,
200
+ detectedInvariants: detectedInvariants,
200
201
  // Include invariant analysis results
201
202
  invariantAnalysis,
202
203
  // Include architectural health assessment
package/src/index.js CHANGED
@@ -605,21 +605,48 @@ program
605
605
 
606
606
  console.log(chalk.green(`āœ… Loaded context from: ${contextFile}`));
607
607
 
608
- // Load invariants
608
+ // Load invariants from both sources for backward compatibility
609
609
  const invariantsFile = options.invariantsFile || path.join(targetDir, '.arcvision', 'invariants.json');
610
610
  let loadSuccess = false;
611
611
 
612
+ // First, try to load auto-detected invariants from the main context file
613
+ const contextFilePath = options.contextFile || path.join(targetDir, 'arcvision_context', 'arcvision.context.json');
614
+ if (fs.existsSync(contextFilePath)) {
615
+ try {
616
+ const contextContent = fs.readFileSync(contextFilePath, 'utf8');
617
+ const contextData = JSON.parse(contextContent);
618
+
619
+ // Load auto-detected invariants from the context file if they exist
620
+ if (contextData.invariants && Array.isArray(contextData.invariants) && contextData.invariants.length > 0) {
621
+ console.log(chalk.blue(`Loading ${contextData.invariants.length} auto-detected invariants from context file...`));
622
+
623
+ // Load each invariant individually to the registry
624
+ for (const invariant of contextData.invariants) {
625
+ invariantRegistry.register(invariant);
626
+ }
627
+
628
+ console.log(chalk.green(`āœ… Loaded ${contextData.invariants.length} auto-detected invariants from context file`));
629
+ loadSuccess = true; // Mark as successful if we loaded from context
630
+ } else {
631
+ console.log(chalk.yellow('No auto-detected invariants found in context file'));
632
+ }
633
+ } catch (contextError) {
634
+ console.log(chalk.yellow(`āš ļø Could not load invariants from context file: ${contextError.message}`));
635
+ }
636
+ }
637
+
638
+ // Then, try to load project-specific invariants from the separate file (for backward compatibility)
612
639
  if (fs.existsSync(invariantsFile)) {
613
- loadSuccess = invariantRegistry.loadFromFile(invariantsFile);
614
- if (loadSuccess) {
615
- console.log(chalk.green(`āœ… Loaded invariants from: ${invariantsFile}`));
640
+ // We'll load the separate file to supplement the context file invariants
641
+ const fileLoadSuccess = invariantRegistry.loadFromFile(invariantsFile);
642
+ if (fileLoadSuccess) {
643
+ console.log(chalk.green(`āœ… Loaded project-specific invariants from: ${invariantsFile}`));
644
+ loadSuccess = true;
616
645
  } else {
617
- console.log(chalk.yellow(`āš ļø Failed to load invariants from: ${invariantsFile}`));
618
- console.log(chalk.yellow('Using default invariants...'));
646
+ console.log(chalk.yellow(`āš ļø Failed to load project-specific invariants from: ${invariantsFile}`));
619
647
  }
620
648
  } else {
621
- console.log(chalk.yellow(`āš ļø Invariants file not found: ${invariantsFile}`));
622
- console.log(chalk.yellow('Using default invariants...'));
649
+ console.log(chalk.yellow(`āš ļø No project-specific invariants file found: ${invariantsFile}`));
623
650
  }
624
651
 
625
652
  // If invariants couldn't be loaded or file doesn't exist, use defaults
@@ -808,6 +835,9 @@ program
808
835
  .option('--export <format>', 'Export ledger (json|csv)')
809
836
  .action(async (options) => {
810
837
  try {
838
+ // Initialize Authority Ledger with default path
839
+ const authorityLedger = new AuthorityLedger(path.join(process.cwd(), 'arcvision_context', 'architecture.authority.ledger.json'));
840
+
811
841
  if (options.stats) {
812
842
  const stats = authorityLedger.getStats();
813
843
  console.log(chalk.blue('šŸ“Š Authority Ledger Statistics'));
@@ -845,7 +875,7 @@ program
845
875
  }
846
876
 
847
877
  // Default: show ledger info
848
- console.log(chalk.blue('Authority Ledger Location: ./architecture.authority.ledger.json'));
878
+ console.log(chalk.blue('Authority Ledger Location: ./arcvision_context/architecture.authority.ledger.json'));
849
879
  console.log(chalk.yellow('Use --stats, --recent-blocks, or --export for detailed information'));
850
880
  process.exit(0);
851
881