arcvision 0.2.12 → 0.2.15
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/ARCVISION_DIRECTORY_STRUCTURE.md +104 -0
- package/CLI_STRUCTURE.md +110 -0
- package/CONFIGURATION.md +119 -0
- package/IMPLEMENTATION_SUMMARY.md +99 -0
- package/README.md +149 -89
- package/architecture.authority.ledger.json +46 -0
- package/arcvision-0.2.3.tgz +0 -0
- package/arcvision-0.2.4.tgz +0 -0
- package/arcvision-0.2.5.tgz +0 -0
- package/arcvision.context.diff.json +2181 -0
- package/arcvision.context.json +1021 -0
- package/arcvision.context.v1.json +2163 -0
- package/arcvision.context.v2.json +2173 -0
- package/arcvision_context/README.md +93 -0
- package/arcvision_context/architecture.authority.ledger.json +83 -0
- package/arcvision_context/arcvision.context.json +6884 -0
- package/debug-cycle-detection.js +56 -0
- package/dist/index.js +1626 -25
- package/docs/ENHANCED_ACCURACY_SAFETY_PROTOCOL.md +172 -0
- package/docs/accuracy-enhancement-artifacts/enhanced-validation-config.json +98 -0
- package/docs/acig-robustness-guide.md +164 -0
- package/docs/authoritative-gate-implementation.md +168 -0
- package/docs/cli-strengthening-summary.md +232 -0
- package/docs/invariant-system-summary.md +100 -0
- package/docs/invariant-system.md +112 -0
- package/generate_large_test.js +42 -0
- package/large_test_repo.json +1 -0
- package/output1.json +2163 -0
- package/output2.json +2163 -0
- package/package.json +46 -36
- package/scan_calcom_report.txt +0 -0
- package/scan_leafmint_report.txt +0 -0
- package/scan_output.txt +0 -0
- package/scan_trigger_report.txt +0 -0
- package/schema/arcvision_context_schema_v1.json +136 -1
- package/src/arcvision-guard.js +433 -0
- package/src/core/authority-core-detector.js +382 -0
- package/src/core/authority-ledger.js +300 -0
- package/src/core/blastRadius.js +299 -0
- package/src/core/call-resolver.js +196 -0
- package/src/core/change-evaluator.js +509 -0
- package/src/core/change-evaluator.js.backup +424 -0
- package/src/core/change-evaluator.ts +285 -0
- package/src/core/chunked-uploader.js +180 -0
- package/src/core/circular-dependency-detector.js +404 -0
- package/src/core/cli-error-handler.js +458 -0
- package/src/core/cli-validator.js +458 -0
- package/src/core/compression.js +64 -0
- package/src/core/context_builder.js +741 -0
- package/src/core/dependency-manager.js +134 -0
- package/src/core/di-detector.js +202 -0
- package/src/core/diff-analyzer.js +76 -0
- package/src/core/example-invariants.js +135 -0
- package/src/core/failure-mode-synthesizer.js +341 -0
- package/src/core/invariant-analyzer.js +294 -0
- package/src/core/invariant-detector.js +548 -0
- package/src/core/invariant-enforcer.js +171 -0
- package/src/core/invariant-evaluation-utils.js +172 -0
- package/src/core/invariant-hooks.js +152 -0
- package/src/core/invariant-integration-example.js +186 -0
- package/src/core/invariant-registry.js +298 -0
- package/src/core/invariant-registry.ts +100 -0
- package/src/core/invariant-types.js +66 -0
- package/src/core/invariants-index.js +88 -0
- package/src/core/method-tracker.js +170 -0
- package/src/core/override-handler.js +304 -0
- package/src/core/ownership-resolver.js +227 -0
- package/src/core/parser-enhanced.js +80 -0
- package/src/core/parser.js +610 -0
- package/src/core/path-resolver.js +240 -0
- package/src/core/pattern-matcher.js +246 -0
- package/src/core/progress-tracker.js +71 -0
- package/src/core/react-nextjs-detector.js +245 -0
- package/src/core/readme-generator.js +167 -0
- package/src/core/retry-handler.js +57 -0
- package/src/core/scanner.js +289 -0
- package/src/core/semantic-analyzer.js +204 -0
- package/src/core/structural-context-owner.js +442 -0
- package/src/core/symbol-indexer.js +164 -0
- package/src/core/tsconfig-utils.js +73 -0
- package/src/core/type-analyzer.js +272 -0
- package/src/core/watcher.js +18 -0
- package/src/core/workspace-scanner.js +88 -0
- package/src/engine/context_builder.js +280 -0
- package/src/engine/context_sorter.js +59 -0
- package/src/engine/context_validator.js +200 -0
- package/src/engine/id-generator.js +16 -0
- package/src/engine/pass1_facts.js +260 -0
- package/src/engine/pass2_semantics.js +333 -0
- package/src/engine/pass3_lifter.js +99 -0
- package/src/engine/pass4_signals.js +201 -0
- package/src/index.js +830 -0
- package/src/plugins/express-plugin.js +48 -0
- package/src/plugins/plugin-manager.js +58 -0
- package/src/plugins/react-plugin.js +54 -0
- package/temp_original.js +0 -0
- package/test/determinism-test.js +83 -0
- package/test-authoritative-context.js +53 -0
- package/test-real-authoritative-context.js +118 -0
- package/test-upload-enhancements.js +111 -0
- package/test_repos/allowed-clean-architecture/.arcvision/invariants.json +57 -0
- package/test_repos/allowed-clean-architecture/adapters/controllers/UserController.js +95 -0
- package/test_repos/allowed-clean-architecture/adapters/http/HttpServer.js +78 -0
- package/test_repos/allowed-clean-architecture/application/dtos/CreateUserRequest.js +37 -0
- package/test_repos/allowed-clean-architecture/application/services/UserService.js +61 -0
- package/test_repos/allowed-clean-architecture/arcvision_context/README.md +93 -0
- package/test_repos/allowed-clean-architecture/arcvision_context/arcvision.context.json +2796 -0
- package/test_repos/allowed-clean-architecture/domain/interfaces/UserRepository.js +25 -0
- package/test_repos/allowed-clean-architecture/domain/models/User.js +39 -0
- package/test_repos/allowed-clean-architecture/index.js +45 -0
- package/test_repos/allowed-clean-architecture/infrastructure/database/DatabaseConnection.js +56 -0
- package/test_repos/allowed-clean-architecture/infrastructure/repositories/InMemoryUserRepository.js +61 -0
- package/test_repos/allowed-clean-architecture/package.json +15 -0
- package/test_repos/blocked-legacy-monolith/.arcvision/invariants.json +78 -0
- package/test_repos/blocked-legacy-monolith/arcvision_context/README.md +93 -0
- package/test_repos/blocked-legacy-monolith/arcvision_context/arcvision.context.json +2882 -0
- package/test_repos/blocked-legacy-monolith/database/dbConnection.js +35 -0
- package/test_repos/blocked-legacy-monolith/index.js +38 -0
- package/test_repos/blocked-legacy-monolith/modules/emailService.js +31 -0
- package/test_repos/blocked-legacy-monolith/modules/paymentProcessor.js +37 -0
- package/test_repos/blocked-legacy-monolith/package.json +15 -0
- package/test_repos/blocked-legacy-monolith/shared/utils.js +19 -0
- package/test_repos/blocked-legacy-monolith/utils/helpers.js +23 -0
- package/test_repos/risky-microservices-concerns/.arcvision/invariants.json +69 -0
- package/test_repos/risky-microservices-concerns/arcvision_context/README.md +93 -0
- package/test_repos/risky-microservices-concerns/arcvision_context/arcvision.context.json +3070 -0
- package/test_repos/risky-microservices-concerns/common/utils.js +77 -0
- package/test_repos/risky-microservices-concerns/gateways/apiGateway.js +84 -0
- package/test_repos/risky-microservices-concerns/index.js +20 -0
- package/test_repos/risky-microservices-concerns/libs/deprecatedHelper.js +36 -0
- package/test_repos/risky-microservices-concerns/package.json +15 -0
- package/test_repos/risky-microservices-concerns/services/orderService.js +42 -0
- package/test_repos/risky-microservices-concerns/services/userService.js +48 -0
- package/verify_engine.js +116 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React/Next.js Pattern Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects framework-specific patterns including:
|
|
5
|
+
* - Component composition (JSX usage)
|
|
6
|
+
* - Server/Client component boundaries
|
|
7
|
+
* - API route dependencies
|
|
8
|
+
* - Middleware dependencies
|
|
9
|
+
* - Next.js specific imports (Image, Link, etc.)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const traverse = require('@babel/traverse').default;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Detect JSX component usage
|
|
16
|
+
* @param {Object} ast - Babel AST
|
|
17
|
+
* @returns {Array} Array of component usages
|
|
18
|
+
*/
|
|
19
|
+
function detectComponentUsage(ast) {
|
|
20
|
+
const componentUsages = [];
|
|
21
|
+
|
|
22
|
+
if (!ast) return componentUsages;
|
|
23
|
+
|
|
24
|
+
traverse(ast, {
|
|
25
|
+
JSXElement(path) {
|
|
26
|
+
const openingElement = path.node.openingElement;
|
|
27
|
+
let componentName = null;
|
|
28
|
+
|
|
29
|
+
// Simple component: <Button />
|
|
30
|
+
if (openingElement.name.type === 'JSXIdentifier') {
|
|
31
|
+
componentName = openingElement.name.name;
|
|
32
|
+
|
|
33
|
+
// Only track components (start with uppercase)
|
|
34
|
+
if (/^[A-Z]/.test(componentName)) {
|
|
35
|
+
componentUsages.push({
|
|
36
|
+
component: componentName,
|
|
37
|
+
type: 'jsx_component',
|
|
38
|
+
loc: path.node.loc
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Member expression: <Icons.Check />
|
|
44
|
+
else if (openingElement.name.type === 'JSXMemberExpression') {
|
|
45
|
+
const object = openingElement.name.object.name;
|
|
46
|
+
const property = openingElement.name.property.name;
|
|
47
|
+
componentName = `${object}.${property}`;
|
|
48
|
+
|
|
49
|
+
componentUsages.push({
|
|
50
|
+
component: componentName,
|
|
51
|
+
type: 'jsx_member_component',
|
|
52
|
+
loc: path.node.loc
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return componentUsages;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Detect server/client component boundaries
|
|
63
|
+
* @param {string} content - File content as string
|
|
64
|
+
* @returns {Object} Boundary markers
|
|
65
|
+
*/
|
|
66
|
+
function detectServerClientBoundaries(content) {
|
|
67
|
+
const boundaries = {
|
|
68
|
+
isClientComponent: false,
|
|
69
|
+
isServerComponent: false,
|
|
70
|
+
isServerAction: false
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (!content) return boundaries;
|
|
74
|
+
|
|
75
|
+
// Check for 'use client' directive
|
|
76
|
+
if (/['"]use client['"]/.test(content)) {
|
|
77
|
+
boundaries.isClientComponent = true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check for 'use server' directive
|
|
81
|
+
if (/['"]use server['"]/.test(content)) {
|
|
82
|
+
boundaries.isServerAction = true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Server components are the default in Next.js App Router
|
|
86
|
+
// If no 'use client', it's a server component
|
|
87
|
+
if (!boundaries.isClientComponent && !boundaries.isServerAction) {
|
|
88
|
+
boundaries.isServerComponent = true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return boundaries;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Detect API route dependencies
|
|
96
|
+
* @param {Object} ast - Babel AST
|
|
97
|
+
* @returns {Array} Array of API route dependencies
|
|
98
|
+
*/
|
|
99
|
+
function detectAPIRouteDependencies(ast) {
|
|
100
|
+
const apiDeps = [];
|
|
101
|
+
|
|
102
|
+
if (!ast) return apiDeps;
|
|
103
|
+
|
|
104
|
+
traverse(ast, {
|
|
105
|
+
// Detect Next.js API route handlers: export async function GET/POST/etc
|
|
106
|
+
ExportNamedDeclaration(path) {
|
|
107
|
+
const node = path.node;
|
|
108
|
+
|
|
109
|
+
if (node.declaration && node.declaration.type === 'FunctionDeclaration') {
|
|
110
|
+
const funcName = node.declaration.id ? node.declaration.id.name : null;
|
|
111
|
+
|
|
112
|
+
// Check if it's a Next.js route handler
|
|
113
|
+
if (['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'].includes(funcName)) {
|
|
114
|
+
apiDeps.push({
|
|
115
|
+
handler: funcName,
|
|
116
|
+
type: 'api_route_handler',
|
|
117
|
+
loc: node.loc
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// Detect fetch calls and database queries within API routes
|
|
124
|
+
CallExpression(path) {
|
|
125
|
+
const callee = path.node.callee;
|
|
126
|
+
|
|
127
|
+
// Database queries
|
|
128
|
+
if (callee.type === 'MemberExpression') {
|
|
129
|
+
const objectName = callee.object.name;
|
|
130
|
+
const methodName = callee.property.name || callee.property.value;
|
|
131
|
+
|
|
132
|
+
// Supabase queries
|
|
133
|
+
if (objectName === 'supabase' || /supabase/i.test(objectName)) {
|
|
134
|
+
apiDeps.push({
|
|
135
|
+
service: 'supabase',
|
|
136
|
+
method: methodName,
|
|
137
|
+
type: 'database_query',
|
|
138
|
+
loc: path.node.loc
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Prisma queries
|
|
143
|
+
if (objectName === 'prisma' || /prisma/i.test(objectName)) {
|
|
144
|
+
apiDeps.push({
|
|
145
|
+
service: 'prisma',
|
|
146
|
+
method: methodName,
|
|
147
|
+
type: 'database_query',
|
|
148
|
+
loc: path.node.loc
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
return apiDeps;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Detect middleware dependencies
|
|
160
|
+
* @param {Object} ast - Babel AST
|
|
161
|
+
* @param {string} filePath - File path to check if it's middleware
|
|
162
|
+
* @returns {Array} Array of middleware dependencies
|
|
163
|
+
*/
|
|
164
|
+
function detectMiddlewareDependencies(ast, filePath = '') {
|
|
165
|
+
const middlewareDeps = [];
|
|
166
|
+
|
|
167
|
+
// Check if this is a middleware file
|
|
168
|
+
const isMiddleware = /middleware\.(ts|js)$/.test(filePath);
|
|
169
|
+
|
|
170
|
+
if (!isMiddleware || !ast) return middlewareDeps;
|
|
171
|
+
|
|
172
|
+
traverse(ast, {
|
|
173
|
+
// Detect middleware function export
|
|
174
|
+
ExportNamedDeclaration(path) {
|
|
175
|
+
const node = path.node;
|
|
176
|
+
|
|
177
|
+
if (node.declaration && node.declaration.type === 'FunctionDeclaration') {
|
|
178
|
+
const funcName = node.declaration.id ? node.declaration.id.name : null;
|
|
179
|
+
|
|
180
|
+
if (funcName === 'middleware') {
|
|
181
|
+
middlewareDeps.push({
|
|
182
|
+
function: funcName,
|
|
183
|
+
type: 'middleware_function',
|
|
184
|
+
loc: node.loc
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
// Detect auth checks and redirects
|
|
191
|
+
CallExpression(path) {
|
|
192
|
+
const callee = path.node.callee;
|
|
193
|
+
|
|
194
|
+
if (callee.type === 'MemberExpression') {
|
|
195
|
+
const methodName = callee.property.name || callee.property.value;
|
|
196
|
+
|
|
197
|
+
// Auth verification
|
|
198
|
+
if (methodName === 'getUser' || methodName === 'getSession') {
|
|
199
|
+
middlewareDeps.push({
|
|
200
|
+
service: 'auth',
|
|
201
|
+
method: methodName,
|
|
202
|
+
type: 'auth_check',
|
|
203
|
+
loc: path.node.loc
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Redirects
|
|
208
|
+
if (methodName === 'redirect' || methodName === 'rewrite') {
|
|
209
|
+
middlewareDeps.push({
|
|
210
|
+
service: 'next',
|
|
211
|
+
method: methodName,
|
|
212
|
+
type: 'middleware_action',
|
|
213
|
+
loc: path.node.loc
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
return middlewareDeps;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Detect all React/Next.js patterns
|
|
225
|
+
* @param {Object} ast - Babel AST
|
|
226
|
+
* @param {string} content - File content
|
|
227
|
+
* @param {string} filePath - File path
|
|
228
|
+
* @returns {Object} All detected patterns
|
|
229
|
+
*/
|
|
230
|
+
function detectReactNextJSPatterns(ast, content = '', filePath = '') {
|
|
231
|
+
return {
|
|
232
|
+
componentUsages: detectComponentUsage(ast),
|
|
233
|
+
boundaries: detectServerClientBoundaries(content),
|
|
234
|
+
apiDependencies: detectAPIRouteDependencies(ast),
|
|
235
|
+
middlewareDependencies: detectMiddlewareDependencies(ast, filePath)
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.exports = {
|
|
240
|
+
detectComponentUsage,
|
|
241
|
+
detectServerClientBoundaries,
|
|
242
|
+
detectAPIRouteDependencies,
|
|
243
|
+
detectMiddlewareDependencies,
|
|
244
|
+
detectReactNextJSPatterns
|
|
245
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { spawnSync } = require('child_process');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get the current git commit hash
|
|
7
|
+
* @returns {string} Commit hash or 'unknown' if git is not available
|
|
8
|
+
*/
|
|
9
|
+
function getCommitHash() {
|
|
10
|
+
try {
|
|
11
|
+
const result = spawnSync('git', ['rev-parse', 'HEAD'], {
|
|
12
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (result.status === 0) {
|
|
16
|
+
return result.stdout.toString().trim();
|
|
17
|
+
}
|
|
18
|
+
return 'unknown';
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return 'unknown';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Generate the README content for the ArcVision system context artifact
|
|
26
|
+
* @param {string} commitHash - Git commit hash
|
|
27
|
+
* @param {string} timestamp - Generation timestamp
|
|
28
|
+
* @param {string} toolVersion - ArcVision tool version
|
|
29
|
+
* @param {Object} blastRadiusData - Blast radius analysis data
|
|
30
|
+
* @returns {string} Formatted README content
|
|
31
|
+
*/
|
|
32
|
+
function generateReadmeContent(commitHash, timestamp, toolVersion, blastRadiusData = null) {
|
|
33
|
+
let content = `# ArcVision System Context Artifact
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## What This Is [arcvision.context.json](./arcvision.context.json)
|
|
37
|
+
|
|
38
|
+
This file is the **canonical structural context** of this codebase.
|
|
39
|
+
It represents how the system actually works — not how it is described.
|
|
40
|
+
|
|
41
|
+
It is generated directly from source code by ArcVision.
|
|
42
|
+
|
|
43
|
+
## What This Replaces
|
|
44
|
+
|
|
45
|
+
This artifact replaces:
|
|
46
|
+
- Manual repository scanning
|
|
47
|
+
- Tribal knowledge held by senior engineers
|
|
48
|
+
- Re-explaining the system to new developers
|
|
49
|
+
- Re-prompting LLMs with partial or incorrect context
|
|
50
|
+
- Guessing blast radius of changes
|
|
51
|
+
|
|
52
|
+
## When You Must Use This
|
|
53
|
+
|
|
54
|
+
Use this artifact when:
|
|
55
|
+
- Onboarding a new developer
|
|
56
|
+
- Prompting an AI assistant about this codebase
|
|
57
|
+
- Making architectural changes
|
|
58
|
+
- Investigating unexpected behavior
|
|
59
|
+
- Assessing risk before modifying core modules
|
|
60
|
+
|
|
61
|
+
## What This Artifact Contains
|
|
62
|
+
|
|
63
|
+
- Canonical module and dependency graph
|
|
64
|
+
- Execution and data flow relationships
|
|
65
|
+
- Structural roles (service, store, boundary, etc.)
|
|
66
|
+
- Invariants inferred from the system
|
|
67
|
+
- Impact metrics (blast radius, coupling)
|
|
68
|
+
- Authority core identification
|
|
69
|
+
- Hidden coupling detection
|
|
70
|
+
- Architectural archetype classification
|
|
71
|
+
- Analysis completeness metrics
|
|
72
|
+
|
|
73
|
+
## Determinism & Trust
|
|
74
|
+
|
|
75
|
+
- Generated from commit: ${commitHash}
|
|
76
|
+
- Generation timestamp: ${timestamp}
|
|
77
|
+
- Tool version: ${toolVersion}
|
|
78
|
+
- Deterministic: same input → same output
|
|
79
|
+
- Explicit assumptions listed inside the artifact
|
|
80
|
+
|
|
81
|
+
If this artifact conflicts with human memory, **trust the artifact**.`;
|
|
82
|
+
|
|
83
|
+
// Add blast radius information if available
|
|
84
|
+
if (blastRadiusData && blastRadiusData.topFiles && blastRadiusData.topFiles.length > 0) {
|
|
85
|
+
content += `
|
|
86
|
+
|
|
87
|
+
## Structural Context Hubs
|
|
88
|
+
|
|
89
|
+
The following files have the highest blast radius and represent critical structural hubs in the system:
|
|
90
|
+
|
|
91
|
+
`;
|
|
92
|
+
|
|
93
|
+
blastRadiusData.topFiles.forEach((item, index) => {
|
|
94
|
+
let warningMessage = '';
|
|
95
|
+
if (index === 0) {
|
|
96
|
+
warningMessage = 'Changes here may silently propagate across the system.';
|
|
97
|
+
} else if (index === 1) {
|
|
98
|
+
warningMessage = 'Acts as a coordination layer between components.';
|
|
99
|
+
} else {
|
|
100
|
+
warningMessage = 'Modifications can cause widespread inconsistencies.';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
content += `- **${item.file}**
|
|
104
|
+
- Blast Radius: ${item.blastRadius} files (${item.percentOfGraph}% of codebase)
|
|
105
|
+
- Risk: ${warningMessage}
|
|
106
|
+
|
|
107
|
+
`;
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
content += `
|
|
111
|
+
|
|
112
|
+
## Structural Context Hubs
|
|
113
|
+
|
|
114
|
+
No high-structure files detected based on import dependencies.`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
content += `
|
|
118
|
+
|
|
119
|
+
## How to Use With AI
|
|
120
|
+
|
|
121
|
+
When prompting AI tools, include this file as system context.
|
|
122
|
+
Do not ask the AI to infer architecture without it.
|
|
123
|
+
|
|
124
|
+
## When to Regenerate
|
|
125
|
+
|
|
126
|
+
Regenerate this artifact when:
|
|
127
|
+
- Core modules change
|
|
128
|
+
- New services are added
|
|
129
|
+
- Dependency structure shifts
|
|
130
|
+
|
|
131
|
+
Run:
|
|
132
|
+
|
|
133
|
+
\`\`\`
|
|
134
|
+
arcvision scan --upload
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
## Source of Truth
|
|
138
|
+
|
|
139
|
+
This artifact is the **source of truth** for system structure.
|
|
140
|
+
All explanations, decisions, and AI reasoning should reference it.
|
|
141
|
+
|
|
142
|
+
Some execution script invocations are dynamically assembled at runtime and may not be statically traceable; such scripts are included
|
|
143
|
+
as execution boundaries without guaranteed call-site resolution`;
|
|
144
|
+
|
|
145
|
+
return content;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Generate and save the README file
|
|
150
|
+
* @param {string} outputDir - Directory to save the README
|
|
151
|
+
* @param {string} toolVersion - ArcVision tool version
|
|
152
|
+
* @param {Object} blastRadiusData - Blast radius analysis data
|
|
153
|
+
*/
|
|
154
|
+
function generateReadme(outputDir, toolVersion, blastRadiusData = null) {
|
|
155
|
+
const commitHash = getCommitHash();
|
|
156
|
+
const timestamp = new Date().toISOString();
|
|
157
|
+
const readmeContent = generateReadmeContent(commitHash, timestamp, toolVersion, blastRadiusData);
|
|
158
|
+
|
|
159
|
+
const readmePath = path.join(outputDir, 'README.md');
|
|
160
|
+
fs.writeFileSync(readmePath, readmeContent);
|
|
161
|
+
|
|
162
|
+
console.log(`✅ System context README generated at ${readmePath}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = { generateReadme, generateReadmeContent, getCommitHash };
|
|
166
|
+
|
|
167
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
|
|
3
|
+
class RetryHandler {
|
|
4
|
+
constructor(maxRetries = 3, baseDelay = 1000, backoffMultiplier = 2) {
|
|
5
|
+
this.maxRetries = maxRetries;
|
|
6
|
+
this.baseDelay = baseDelay;
|
|
7
|
+
this.backoffMultiplier = backoffMultiplier;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async executeWithRetry(operation, context = '') {
|
|
11
|
+
let lastError;
|
|
12
|
+
|
|
13
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
14
|
+
try {
|
|
15
|
+
if (attempt > 0) {
|
|
16
|
+
const delay = this.baseDelay * Math.pow(this.backoffMultiplier, attempt - 1);
|
|
17
|
+
console.log(chalk.yellow(`Retry attempt ${attempt}/${this.maxRetries} for ${context} after ${delay}ms delay...`));
|
|
18
|
+
|
|
19
|
+
// Wait before retrying
|
|
20
|
+
await this.sleep(delay);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const result = await operation(attempt);
|
|
24
|
+
return { success: true, result, attempts: attempt + 1 };
|
|
25
|
+
} catch (error) {
|
|
26
|
+
lastError = error;
|
|
27
|
+
|
|
28
|
+
// Don't log error on final attempt since caller will handle it
|
|
29
|
+
if (attempt < this.maxRetries) {
|
|
30
|
+
console.log(chalk.red(`Attempt ${attempt + 1} failed for ${context}: ${error.message}`));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return { success: false, error: lastError, attempts: this.maxRetries + 1 };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
sleep(ms) {
|
|
39
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Specific retry for network requests
|
|
43
|
+
async executeNetworkRequest(url, options, context = 'network request') {
|
|
44
|
+
return this.executeWithRetry(async (attempt) => {
|
|
45
|
+
const response = await fetch(url, options);
|
|
46
|
+
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
const errorText = await response.text().catch(() => 'Unknown error');
|
|
49
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return await response.json();
|
|
53
|
+
}, context);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = RetryHandler;
|