arcvision 0.2.14 → 0.2.16

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 (134) hide show
  1. package/ARCVISION_DIRECTORY_STRUCTURE.md +104 -0
  2. package/CLI_STRUCTURE.md +110 -0
  3. package/CONFIGURATION.md +119 -0
  4. package/IMPLEMENTATION_SUMMARY.md +99 -0
  5. package/README.md +149 -89
  6. package/architecture.authority.ledger.json +46 -0
  7. package/arcvision-0.2.3.tgz +0 -0
  8. package/arcvision-0.2.4.tgz +0 -0
  9. package/arcvision-0.2.5.tgz +0 -0
  10. package/arcvision.context.diff.json +2181 -0
  11. package/arcvision.context.json +1021 -0
  12. package/arcvision.context.v1.json +2163 -0
  13. package/arcvision.context.v2.json +2173 -0
  14. package/arcvision_context/README.md +93 -0
  15. package/arcvision_context/architecture.authority.ledger.json +83 -0
  16. package/arcvision_context/arcvision.context.json +6884 -0
  17. package/debug-cycle-detection.js +56 -0
  18. package/dist/index.js +1626 -25
  19. package/docs/ENHANCED_ACCURACY_SAFETY_PROTOCOL.md +172 -0
  20. package/docs/accuracy-enhancement-artifacts/enhanced-validation-config.json +98 -0
  21. package/docs/acig-robustness-guide.md +164 -0
  22. package/docs/authoritative-gate-implementation.md +168 -0
  23. package/docs/cli-strengthening-summary.md +232 -0
  24. package/docs/invariant-system-summary.md +100 -0
  25. package/docs/invariant-system.md +112 -0
  26. package/generate_large_test.js +42 -0
  27. package/large_test_repo.json +1 -0
  28. package/output1.json +2163 -0
  29. package/output2.json +2163 -0
  30. package/package.json +46 -36
  31. package/scan_calcom_report.txt +0 -0
  32. package/scan_leafmint_report.txt +0 -0
  33. package/scan_output.txt +0 -0
  34. package/scan_trigger_report.txt +0 -0
  35. package/schema/arcvision_context_schema_v1.json +136 -1
  36. package/src/arcvision-guard.js +433 -0
  37. package/src/core/authority-core-detector.js +382 -0
  38. package/src/core/authority-ledger.js +300 -0
  39. package/src/core/blastRadius.js +299 -0
  40. package/src/core/call-resolver.js +196 -0
  41. package/src/core/change-evaluator.js +509 -0
  42. package/src/core/change-evaluator.js.backup +424 -0
  43. package/src/core/change-evaluator.ts +285 -0
  44. package/src/core/chunked-uploader.js +180 -0
  45. package/src/core/circular-dependency-detector.js +404 -0
  46. package/src/core/cli-error-handler.js +458 -0
  47. package/src/core/cli-validator.js +458 -0
  48. package/src/core/compression.js +64 -0
  49. package/src/core/context_builder.js +741 -0
  50. package/src/core/dependency-manager.js +134 -0
  51. package/src/core/di-detector.js +202 -0
  52. package/src/core/diff-analyzer.js +76 -0
  53. package/src/core/example-invariants.js +135 -0
  54. package/src/core/failure-mode-synthesizer.js +341 -0
  55. package/src/core/invariant-analyzer.js +294 -0
  56. package/src/core/invariant-detector.js +548 -0
  57. package/src/core/invariant-enforcer.js +171 -0
  58. package/src/core/invariant-evaluation-utils.js +172 -0
  59. package/src/core/invariant-hooks.js +152 -0
  60. package/src/core/invariant-integration-example.js +186 -0
  61. package/src/core/invariant-registry.js +298 -0
  62. package/src/core/invariant-registry.ts +100 -0
  63. package/src/core/invariant-types.js +66 -0
  64. package/src/core/invariants-index.js +88 -0
  65. package/src/core/method-tracker.js +170 -0
  66. package/src/core/override-handler.js +304 -0
  67. package/src/core/ownership-resolver.js +227 -0
  68. package/src/core/parser-enhanced.js +80 -0
  69. package/src/core/parser.js +610 -0
  70. package/src/core/path-resolver.js +240 -0
  71. package/src/core/pattern-matcher.js +246 -0
  72. package/src/core/progress-tracker.js +71 -0
  73. package/src/core/react-nextjs-detector.js +245 -0
  74. package/src/core/readme-generator.js +167 -0
  75. package/src/core/retry-handler.js +57 -0
  76. package/src/core/scanner.js +289 -0
  77. package/src/core/semantic-analyzer.js +204 -0
  78. package/src/core/structural-context-owner.js +442 -0
  79. package/src/core/symbol-indexer.js +164 -0
  80. package/src/core/tsconfig-utils.js +73 -0
  81. package/src/core/type-analyzer.js +272 -0
  82. package/src/core/watcher.js +18 -0
  83. package/src/core/workspace-scanner.js +88 -0
  84. package/src/engine/context_builder.js +280 -0
  85. package/src/engine/context_sorter.js +59 -0
  86. package/src/engine/context_validator.js +200 -0
  87. package/src/engine/id-generator.js +16 -0
  88. package/src/engine/pass1_facts.js +260 -0
  89. package/src/engine/pass2_semantics.js +333 -0
  90. package/src/engine/pass3_lifter.js +99 -0
  91. package/src/engine/pass4_signals.js +201 -0
  92. package/src/index.js +830 -0
  93. package/src/plugins/express-plugin.js +48 -0
  94. package/src/plugins/plugin-manager.js +58 -0
  95. package/src/plugins/react-plugin.js +54 -0
  96. package/temp_original.js +0 -0
  97. package/test/determinism-test.js +83 -0
  98. package/test-authoritative-context.js +53 -0
  99. package/test-real-authoritative-context.js +118 -0
  100. package/test-upload-enhancements.js +111 -0
  101. package/test_repos/allowed-clean-architecture/.arcvision/invariants.json +57 -0
  102. package/test_repos/allowed-clean-architecture/adapters/controllers/UserController.js +95 -0
  103. package/test_repos/allowed-clean-architecture/adapters/http/HttpServer.js +78 -0
  104. package/test_repos/allowed-clean-architecture/application/dtos/CreateUserRequest.js +37 -0
  105. package/test_repos/allowed-clean-architecture/application/services/UserService.js +61 -0
  106. package/test_repos/allowed-clean-architecture/arcvision_context/README.md +93 -0
  107. package/test_repos/allowed-clean-architecture/arcvision_context/arcvision.context.json +2796 -0
  108. package/test_repos/allowed-clean-architecture/domain/interfaces/UserRepository.js +25 -0
  109. package/test_repos/allowed-clean-architecture/domain/models/User.js +39 -0
  110. package/test_repos/allowed-clean-architecture/index.js +45 -0
  111. package/test_repos/allowed-clean-architecture/infrastructure/database/DatabaseConnection.js +56 -0
  112. package/test_repos/allowed-clean-architecture/infrastructure/repositories/InMemoryUserRepository.js +61 -0
  113. package/test_repos/allowed-clean-architecture/package.json +15 -0
  114. package/test_repos/blocked-legacy-monolith/.arcvision/invariants.json +78 -0
  115. package/test_repos/blocked-legacy-monolith/arcvision_context/README.md +93 -0
  116. package/test_repos/blocked-legacy-monolith/arcvision_context/arcvision.context.json +2882 -0
  117. package/test_repos/blocked-legacy-monolith/database/dbConnection.js +35 -0
  118. package/test_repos/blocked-legacy-monolith/index.js +38 -0
  119. package/test_repos/blocked-legacy-monolith/modules/emailService.js +31 -0
  120. package/test_repos/blocked-legacy-monolith/modules/paymentProcessor.js +37 -0
  121. package/test_repos/blocked-legacy-monolith/package.json +15 -0
  122. package/test_repos/blocked-legacy-monolith/shared/utils.js +19 -0
  123. package/test_repos/blocked-legacy-monolith/utils/helpers.js +23 -0
  124. package/test_repos/risky-microservices-concerns/.arcvision/invariants.json +69 -0
  125. package/test_repos/risky-microservices-concerns/arcvision_context/README.md +93 -0
  126. package/test_repos/risky-microservices-concerns/arcvision_context/arcvision.context.json +3070 -0
  127. package/test_repos/risky-microservices-concerns/common/utils.js +77 -0
  128. package/test_repos/risky-microservices-concerns/gateways/apiGateway.js +84 -0
  129. package/test_repos/risky-microservices-concerns/index.js +20 -0
  130. package/test_repos/risky-microservices-concerns/libs/deprecatedHelper.js +36 -0
  131. package/test_repos/risky-microservices-concerns/package.json +15 -0
  132. package/test_repos/risky-microservices-concerns/services/orderService.js +42 -0
  133. package/test_repos/risky-microservices-concerns/services/userService.js +48 -0
  134. package/verify_engine.js +116 -0
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Type Dependency Analyzer
3
+ *
4
+ * Tracks TypeScript type-only dependencies including:
5
+ * - Type-only imports
6
+ * - Interface extensions
7
+ * - Interface implementations
8
+ * - Generic type parameters
9
+ * - Return type dependencies
10
+ */
11
+
12
+ const traverse = require('@babel/traverse').default;
13
+
14
+ /**
15
+ * Extract type-only imports from AST
16
+ * @param {Object} ast - Babel AST
17
+ * @returns {Array} Array of type imports
18
+ */
19
+ function extractTypeImports(ast) {
20
+ const typeImports = [];
21
+
22
+ if (!ast) return typeImports;
23
+
24
+ traverse(ast, {
25
+ ImportDeclaration(path) {
26
+ const node = path.node;
27
+
28
+ // Check if it's a type-only import: import type { ... }
29
+ if (node.importKind === 'type') {
30
+ const specifiers = [];
31
+ node.specifiers.forEach(spec => {
32
+ if (spec.imported) {
33
+ specifiers.push({
34
+ imported: spec.imported.name || spec.imported.value,
35
+ local: spec.local.name
36
+ });
37
+ }
38
+ });
39
+
40
+ typeImports.push({
41
+ source: node.source.value,
42
+ specifiers,
43
+ importKind: 'type',
44
+ loc: node.loc
45
+ });
46
+ }
47
+
48
+ // Check for individual type specifiers: import { type User } from '...'
49
+ else {
50
+ const typeSpecifiers = [];
51
+ node.specifiers.forEach(spec => {
52
+ if (spec.importKind === 'type' && spec.imported) {
53
+ typeSpecifiers.push({
54
+ imported: spec.imported.name || spec.imported.value,
55
+ local: spec.local.name
56
+ });
57
+ }
58
+ });
59
+
60
+ if (typeSpecifiers.length > 0) {
61
+ typeImports.push({
62
+ source: node.source.value,
63
+ specifiers: typeSpecifiers,
64
+ importKind: 'mixed',
65
+ loc: node.loc
66
+ });
67
+ }
68
+ }
69
+ }
70
+ });
71
+
72
+ return typeImports;
73
+ }
74
+
75
+ /**
76
+ * Extract interface dependencies (extends, implements)
77
+ * @param {Object} ast - Babel AST
78
+ * @returns {Array} Array of interface dependencies
79
+ */
80
+ function extractInterfaceDependencies(ast) {
81
+ const interfaceDeps = [];
82
+
83
+ if (!ast) return interfaceDeps;
84
+
85
+ traverse(ast, {
86
+ // Interface extends
87
+ TSInterfaceDeclaration(path) {
88
+ const node = path.node;
89
+ const interfaceName = node.id.name;
90
+
91
+ if (node.extends && node.extends.length > 0) {
92
+ node.extends.forEach(ext => {
93
+ const extendedInterface = extractTypeName(ext.expression);
94
+ if (extendedInterface) {
95
+ interfaceDeps.push({
96
+ interface: interfaceName,
97
+ extends: extendedInterface,
98
+ type: 'interface_extends',
99
+ loc: node.loc
100
+ });
101
+ }
102
+ });
103
+ }
104
+ },
105
+
106
+ // Class implements
107
+ ClassDeclaration(path) {
108
+ const node = path.node;
109
+ const className = node.id ? node.id.name : 'Anonymous';
110
+
111
+ if (node.implements && node.implements.length > 0) {
112
+ node.implements.forEach(impl => {
113
+ const implementedInterface = extractTypeName(impl.expression);
114
+ if (implementedInterface) {
115
+ interfaceDeps.push({
116
+ class: className,
117
+ implements: implementedInterface,
118
+ type: 'class_implements',
119
+ loc: node.loc
120
+ });
121
+ }
122
+ });
123
+ }
124
+ }
125
+ });
126
+
127
+ return interfaceDeps;
128
+ }
129
+
130
+ /**
131
+ * Extract generic type dependencies
132
+ * @param {Object} ast - Babel AST
133
+ * @returns {Array} Array of generic type usages
134
+ */
135
+ function extractGenericDependencies(ast) {
136
+ const genericDeps = [];
137
+
138
+ if (!ast) return genericDeps;
139
+
140
+ traverse(ast, {
141
+ // Function return types
142
+ FunctionDeclaration(path) {
143
+ const node = path.node;
144
+ const functionName = node.id ? node.id.name : 'anonymous';
145
+
146
+ if (node.returnType) {
147
+ const returnTypeName = extractComplexTypeName(node.returnType.typeAnnotation);
148
+ if (returnTypeName) {
149
+ genericDeps.push({
150
+ function: functionName,
151
+ returnType: returnTypeName,
152
+ type: 'return_type',
153
+ loc: node.loc
154
+ });
155
+ }
156
+ }
157
+ },
158
+
159
+ // Arrow function return types
160
+ ArrowFunctionExpression(path) {
161
+ const node = path.node;
162
+
163
+ if (node.returnType) {
164
+ const returnTypeName = extractComplexTypeName(node.returnType.typeAnnotation);
165
+ if (returnTypeName) {
166
+ genericDeps.push({
167
+ function: 'arrow_function',
168
+ returnType: returnTypeName,
169
+ type: 'return_type',
170
+ loc: node.loc
171
+ });
172
+ }
173
+ }
174
+ },
175
+
176
+ // Variable type annotations
177
+ VariableDeclarator(path) {
178
+ const node = path.node;
179
+ const varName = node.id.name;
180
+
181
+ if (node.id.typeAnnotation) {
182
+ const typeName = extractComplexTypeName(node.id.typeAnnotation.typeAnnotation);
183
+ if (typeName) {
184
+ genericDeps.push({
185
+ variable: varName,
186
+ type: typeName,
187
+ kind: 'variable_type',
188
+ loc: node.loc
189
+ });
190
+ }
191
+ }
192
+ }
193
+ });
194
+
195
+ return genericDeps;
196
+ }
197
+
198
+ /**
199
+ * Analyze all type dependencies in a file
200
+ * @param {Object} ast - Babel AST
201
+ * @returns {Object} All type dependencies
202
+ */
203
+ function analyzeTypeDependencies(ast) {
204
+ if (!ast) {
205
+ return {
206
+ typeImports: [],
207
+ interfaceDependencies: [],
208
+ genericDependencies: []
209
+ };
210
+ }
211
+
212
+ return {
213
+ typeImports: extractTypeImports(ast),
214
+ interfaceDependencies: extractInterfaceDependencies(ast),
215
+ genericDependencies: extractGenericDependencies(ast)
216
+ };
217
+ }
218
+
219
+ /**
220
+ * Helper: Extract type name from TypeScript type node
221
+ */
222
+ function extractTypeName(node) {
223
+ if (!node) return null;
224
+
225
+ if (node.type === 'Identifier') {
226
+ return node.name;
227
+ } else if (node.type === 'TSTypeReference' && node.typeName) {
228
+ if (node.typeName.type === 'Identifier') {
229
+ return node.typeName.name;
230
+ }
231
+ }
232
+
233
+ return null;
234
+ }
235
+
236
+ /**
237
+ * Helper: Extract complex type names (including generics)
238
+ */
239
+ function extractComplexTypeName(node) {
240
+ if (!node) return null;
241
+
242
+ if (node.type === 'TSTypeReference' && node.typeName) {
243
+ let baseName = extractTypeName(node);
244
+
245
+ // Handle generic parameters
246
+ if (node.typeParameters && node.typeParameters.params) {
247
+ const params = node.typeParameters.params
248
+ .map(p => extractComplexTypeName(p))
249
+ .filter(Boolean)
250
+ .join(', ');
251
+ if (params) {
252
+ baseName += `<${params}>`;
253
+ }
254
+ }
255
+
256
+ return baseName;
257
+ } else if (node.type === 'Identifier') {
258
+ return node.name;
259
+ } else if (node.type === 'TSArrayType') {
260
+ const elementType = extractComplexTypeName(node.elementType);
261
+ return elementType ? `${elementType}[]` : null;
262
+ }
263
+
264
+ return null;
265
+ }
266
+
267
+ module.exports = {
268
+ extractTypeImports,
269
+ extractInterfaceDependencies,
270
+ extractGenericDependencies,
271
+ analyzeTypeDependencies
272
+ };
@@ -0,0 +1,18 @@
1
+ const chokidar = require('chokidar');
2
+
3
+ function watch(directory, callback) {
4
+ const watcher = chokidar.watch(directory, {
5
+ ignored: [/(^|[\/\\])\../, '**/node_modules/**'], // ignore dotfiles
6
+ persistent: true,
7
+ ignoreInitial: true
8
+ });
9
+
10
+ watcher
11
+ .on('add', path => callback('add', path))
12
+ .on('change', path => callback('change', path))
13
+ .on('unlink', path => callback('unlink', path));
14
+
15
+ return watcher;
16
+ }
17
+
18
+ module.exports = { watch };
@@ -0,0 +1,88 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { loadTSConfig } = require('./tsconfig-utils');
4
+
5
+ /**
6
+ * Scans the workspace to build a map of package names to their locations
7
+ * and loads tsconfig configurations.
8
+ */
9
+ class WorkspaceScanner {
10
+ constructor(rootPath) {
11
+ this.rootPath = path.resolve(rootPath);
12
+ this.workspaceMap = new Map(); // packageName -> absolutePath
13
+ this.tsconfigMap = new Map(); // workspaceRoot -> tsconfig object
14
+ }
15
+
16
+ /**
17
+ * Performs the scan and returns the context.
18
+ * @returns {Object} { workspaceMap, tsconfigMap }
19
+ */
20
+ scan() {
21
+ console.log(`Starting workspace scan at ${this.rootPath}`);
22
+ this._scanRecursively(this.rootPath);
23
+
24
+ // Sort maps for determinism in output/debugging
25
+ const sortedWorkspaceMap = new Map([...this.workspaceMap.entries()].sort());
26
+ const sortedTsconfigMap = new Map([...this.tsconfigMap.entries()].sort());
27
+
28
+ console.log(`Workspace scan complete. Found ${sortedWorkspaceMap.size} packages.`);
29
+ return {
30
+ workspaceMap: sortedWorkspaceMap,
31
+ tsconfigMap: sortedTsconfigMap
32
+ };
33
+ }
34
+
35
+ _scanRecursively(currentPath) {
36
+ let entries;
37
+ try {
38
+ entries = fs.readdirSync(currentPath, { withFileTypes: true });
39
+ } catch (e) {
40
+ console.error(`Failed to read directory ${currentPath}: ${e.message}`);
41
+ return;
42
+ }
43
+
44
+ // Sort entries for deterministic scanning order
45
+ entries.sort((a, b) => a.name.localeCompare(b.name));
46
+
47
+ // Check for tsconfig in this directory
48
+ // We check this for every directory we visit.
49
+ const tsConfig = loadTSConfig(currentPath);
50
+ if (tsConfig) {
51
+ this.tsconfigMap.set(currentPath, tsConfig);
52
+ }
53
+
54
+ for (const entry of entries) {
55
+ const fullPath = path.join(currentPath, entry.name);
56
+
57
+ if (entry.isDirectory()) {
58
+ // Skip node_modules and hidden directories (starting with .)
59
+ if (entry.name === 'node_modules' || entry.name.startsWith('.')) {
60
+ continue;
61
+ }
62
+ this._scanRecursively(fullPath);
63
+ } else if (entry.name === 'package.json') {
64
+ this._processPackageJson(fullPath);
65
+ }
66
+ }
67
+ }
68
+
69
+ _processPackageJson(packageJsonPath) {
70
+ try {
71
+ const content = fs.readFileSync(packageJsonPath, 'utf-8');
72
+ const pkg = JSON.parse(content);
73
+
74
+ if (pkg.name) {
75
+ if (this.workspaceMap.has(pkg.name)) {
76
+ // console.warn(`Duplicate package name found: ${pkg.name} at ${packageJsonPath}. Keeping ${this.workspaceMap.get(pkg.name)}`);
77
+ } else {
78
+ this.workspaceMap.set(pkg.name, path.dirname(packageJsonPath));
79
+ }
80
+ }
81
+ } catch (e) {
82
+ // Failures logged, never fatal
83
+ console.warn(`Failed to parse package.json at ${packageJsonPath}: ${e.message}`);
84
+ }
85
+ }
86
+ }
87
+
88
+ module.exports = { WorkspaceScanner };
@@ -0,0 +1,280 @@
1
+ const path = require('path');
2
+ const crypto = require('crypto');
3
+ const { stableId } = require('./id-generator');
4
+
5
+ /**
6
+ * Generate integrity hash for the context
7
+ * @param {Array} nodes - List of nodes
8
+ * @param {Array} edges - List of edges
9
+ * @returns {string} SHA256 hash
10
+ */
11
+ function generateIntegrityHash(nodes, edges) {
12
+ const content = JSON.stringify({
13
+ nodes: nodes.map(n => ({
14
+ id: n.id,
15
+ path: n.path,
16
+ role: n.role
17
+ })).sort((a, b) => a.id.localeCompare(b.id)),
18
+ edges: edges.map(e => ({
19
+ from: e.from,
20
+ to: e.to,
21
+ relation: e.relation
22
+ })).sort((a, b) => {
23
+ if (a.from !== b.from) return a.from.localeCompare(b.from);
24
+ return a.to.localeCompare(b.to);
25
+ })
26
+ });
27
+
28
+ return crypto.createHash('sha256').update(content).digest('hex');
29
+ }
30
+
31
+ /**
32
+ * Build the context object that conforms to the Arcvision schema
33
+ * @param {Array} files - List of files from scanner
34
+ * @param {Array} edges - List of edges from scanner
35
+ * @param {Object} options - Options including directory path and project name
36
+ * @returns {Object} - Context object conforming to schema
37
+ */
38
+ function buildContext(files, edges, options = {}) {
39
+ const {
40
+ directory = '.',
41
+ projectName = 'arcvision',
42
+ language = 'javascript'
43
+ } = options;
44
+
45
+ // Build nodes from files
46
+ const nodes = files.map(file => {
47
+ // Use the node's id field which is already the normalized relative path
48
+ const normalizedPath = file.id;
49
+
50
+ // Determine role based on multiple factors for better accuracy
51
+ const hasFunctions = file.metadata.functions && file.metadata.functions.length > 0;
52
+ const hasClasses = file.metadata.classes && file.metadata.classes.length > 0;
53
+ const hasExports = file.metadata.exports && file.metadata.exports.length > 0;
54
+ const hasApiCalls = file.metadata.apiCalls && file.metadata.apiCalls.length > 0;
55
+
56
+ let role = 'Structure';
57
+ if (hasFunctions || hasClasses || hasApiCalls) {
58
+ role = 'Implementation';
59
+ } else if (hasExports) {
60
+ role = 'Interface';
61
+ }
62
+
63
+ // Extract dependencies more accurately and remove duplicates
64
+ const dependencies = [];
65
+ const uniqueDeps = new Set();
66
+ if (file.metadata.imports && Array.isArray(file.metadata.imports)) {
67
+ file.metadata.imports.forEach(imp => {
68
+ if (imp.source && typeof imp.source === 'string') {
69
+ // Only add unique dependencies
70
+ if (!uniqueDeps.has(imp.source)) {
71
+ uniqueDeps.add(imp.source);
72
+ dependencies.push(imp.source);
73
+ }
74
+ }
75
+ });
76
+ }
77
+
78
+ return {
79
+ id: stableId(normalizedPath),
80
+ type: 'file',
81
+ path: normalizedPath,
82
+ role: role,
83
+ dependencies: dependencies,
84
+ blast_radius: file.metadata.blast_radius || 0
85
+ };
86
+ });
87
+
88
+ // Build edges from dependencies
89
+ const schemaEdges = [];
90
+ for (const edge of edges) {
91
+ // Find source and target nodes to get their stable IDs
92
+ const sourceNode = nodes.find(n => n.path === edge.source);
93
+ const targetNode = nodes.find(n => n.path === edge.target);
94
+
95
+ // Include edges where source exists (even if target doesn't exist as a node)
96
+ if (sourceNode) {
97
+ // Normalize the edge type to fit the schema
98
+ let relationType = 'imports';
99
+
100
+ // Handle import-related types
101
+ if (edge.type === 'imports' || edge.type === 'require' || edge.type === 'export-from' ||
102
+ edge.type === 'export-all' || edge.type === 'dynamic-import' || edge.type === 'require-assignment') {
103
+ relationType = 'imports';
104
+ }
105
+ // Handle call-related types (NEW)
106
+ else if (edge.type === 'function_call' || edge.type === 'method_call') {
107
+ relationType = 'calls';
108
+ }
109
+ // Handle constructor calls (NEW) - map to calls for schema compliance
110
+ else if (edge.type === 'constructor_call') {
111
+ relationType = 'calls';
112
+ }
113
+ // Handle component usage (NEW) - map to imports for schema compliance
114
+ else if (edge.type === 'component_usage' || edge.type === 'jsx_component' || edge.type === 'jsx_member_component') {
115
+ relationType = 'imports';
116
+ }
117
+ // Handle existing types
118
+ else if (edge.type === 'calls') {
119
+ relationType = 'calls';
120
+ } else if (edge.type === 'owns') {
121
+ relationType = 'owns';
122
+ } else if (edge.type === 'depends_on') {
123
+ relationType = 'depends_on';
124
+ } else {
125
+ // Default to 'imports' for any unknown edge types to ensure schema compliance
126
+ relationType = 'imports';
127
+ }
128
+
129
+ if (targetNode) {
130
+ // Both source and target nodes exist
131
+ schemaEdges.push({
132
+ from: sourceNode.id,
133
+ to: targetNode.id,
134
+ relation: relationType
135
+ });
136
+ } else {
137
+ // Source exists but target doesn't (external dependency like node_modules)
138
+ // We'll still include the edge to preserve the relationship
139
+ // However, since the schema requires valid node IDs, we'll only add if the target is a known node
140
+ // For now, we'll skip edges to non-existent targets to maintain schema compliance
141
+ }
142
+ }
143
+ }
144
+
145
+ // Calculate metrics
146
+ const metrics = {
147
+ total_files: nodes.length,
148
+ total_nodes: nodes.length,
149
+ total_edges: schemaEdges.length,
150
+ total_imports: schemaEdges.filter(edge => edge.relation === 'imports').length,
151
+ total_calls: schemaEdges.filter(edge => edge.relation === 'calls').length,
152
+ total_owns: schemaEdges.filter(edge => edge.relation === 'owns').length,
153
+ total_depends_on: schemaEdges.filter(edge => edge.relation === 'depends_on').length,
154
+ files_with_functions: nodes.filter(n => n.role === 'Implementation').length
155
+ };
156
+
157
+ // Build and return the context object
158
+ const context = {
159
+ schema_version: '1.0.0',
160
+ generated_at: new Date().toISOString(),
161
+ system: {
162
+ name: projectName,
163
+ root_path: path.resolve(directory),
164
+ language: language,
165
+ archetype: options.archetype || {
166
+ type: 'general_purpose',
167
+ confidence: 'low',
168
+ description: 'General purpose application',
169
+ authorityPattern: 'distributed_authority'
170
+ }
171
+ },
172
+ nodes,
173
+ edges: schemaEdges,
174
+ symbols: options.symbols || [],
175
+ metrics,
176
+ contextSurface: options.contextSurface || {},
177
+
178
+ // Authority core detection results
179
+ authority_cores: options.authorityCores || [],
180
+ hidden_coupling: options.hiddenCoupling || [],
181
+
182
+ // Completeness metrics
183
+ completeness_metrics: options.completenessMetrics || {
184
+ totalFilesFound: nodes.length,
185
+ filesAnalyzed: nodes.length,
186
+ coveragePercentage: 100,
187
+ missingCriticalFiles: []
188
+ },
189
+
190
+ // Assumptions about analysis limitations
191
+ assumptions: [
192
+ 'Analysis excludes node_modules and build artifacts',
193
+ 'TypeScript declaration files (.d.ts) are excluded from analysis',
194
+ 'Circular dependencies may not be fully detected',
195
+ 'Dynamic imports may not be fully resolved'
196
+ ],
197
+
198
+ // Source repository information
199
+ source: {
200
+ repo: options.rootPath || path.resolve(directory),
201
+ commit: options.commitHash || 'unknown',
202
+ generated_at: new Date().toISOString(),
203
+ arcvision_version: options.arcvisionVersion || '1.0.0'
204
+ },
205
+
206
+ // Integrity hash
207
+ integrity: {
208
+ sha256: generateIntegrityHash(nodes, edges)
209
+ },
210
+
211
+ // Structural layers analysis
212
+ structural_layers: {
213
+ runtime_code: {
214
+ status: 'included',
215
+ description: 'JavaScript/TypeScript source files'
216
+ },
217
+ execution_scripts: {
218
+ status: 'included',
219
+ description: 'Lua execution scripts'
220
+ },
221
+ infrastructure_scripts: {
222
+ status: 'excluded',
223
+ description: 'Infrastructure scripts (bash, shell, etc.)'
224
+ },
225
+ configuration: {
226
+ status: 'included',
227
+ description: 'Configuration files (JSON, YAML, etc.)'
228
+ },
229
+ documentation: {
230
+ status: 'excluded',
231
+ description: 'Documentation files'
232
+ },
233
+ assets: {
234
+ status: 'excluded',
235
+ description: 'Asset files (images, fonts, etc.)'
236
+ }
237
+ },
238
+
239
+ // Project envelope
240
+ project_envelope: {
241
+ configuration_files: nodes
242
+ .filter(n => n.path && (n.path.endsWith('.json') || n.path.endsWith('.yaml') || n.path.endsWith('.yml') || n.path.includes('config')))
243
+ .map(n => ({
244
+ path: n.path,
245
+ role: 'configuration'
246
+ })),
247
+ documentation: [],
248
+ build_tools: []
249
+ },
250
+
251
+ // Diff summary placeholder
252
+ diff_summary: null
253
+ };
254
+
255
+ // Add additional computed metrics
256
+ context.metrics.files_with_functions = nodes.filter(n => n.role === 'Implementation').length;
257
+ context.metrics.files_with_high_blast_radius = nodes.filter(n => n.blast_radius > 5).length;
258
+ context.metrics.total_dependencies = schemaEdges.length;
259
+
260
+ // Add new canonical sections if provided in options
261
+ if (options.invariants !== undefined) {
262
+ context.invariants = options.invariants;
263
+ }
264
+
265
+ if (options.ownership !== undefined) {
266
+ context.ownership = options.ownership;
267
+ }
268
+
269
+ if (options.failure_modes !== undefined) {
270
+ context.failure_modes = options.failure_modes;
271
+ }
272
+
273
+ if (options.decision_guidance !== undefined) {
274
+ context.decision_guidance = options.decision_guidance;
275
+ }
276
+
277
+ return context;
278
+ }
279
+
280
+ module.exports = { buildContext };