arcvision 0.2.5 → 0.2.7
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/README.md +85 -74
- package/dist/index.js +778 -8
- package/package.json +1 -1
- package/schema/arcvision_context_schema_v1.json +138 -1
- package/dist/schema/arcvision_context_schema_v1.json +0 -84
package/README.md
CHANGED
|
@@ -1,74 +1,85 @@
|
|
|
1
|
-
# ArcVision
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
##
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
- **
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
1
|
+
# ArcVision System Context Artifact
|
|
2
|
+
|
|
3
|
+
## What This Is
|
|
4
|
+
|
|
5
|
+
This file is the **canonical structural context** of this codebase.
|
|
6
|
+
It represents how the system actually works — not how it is described.
|
|
7
|
+
|
|
8
|
+
It is generated directly from source code by ArcVision.
|
|
9
|
+
|
|
10
|
+
## What This Replaces
|
|
11
|
+
|
|
12
|
+
This artifact replaces:
|
|
13
|
+
- Manual repository scanning
|
|
14
|
+
- Tribal knowledge held by senior engineers
|
|
15
|
+
- Re-explaining the system to new developers
|
|
16
|
+
- Re-prompting LLMs with partial or incorrect context
|
|
17
|
+
- Guessing blast radius of changes
|
|
18
|
+
|
|
19
|
+
## When You Must Use This
|
|
20
|
+
|
|
21
|
+
Use this artifact when:
|
|
22
|
+
- Onboarding a new developer
|
|
23
|
+
- Prompting an AI assistant about this codebase
|
|
24
|
+
- Making architectural changes
|
|
25
|
+
- Investigating unexpected behavior
|
|
26
|
+
- Assessing risk before modifying core modules
|
|
27
|
+
|
|
28
|
+
## What This Artifact Contains
|
|
29
|
+
|
|
30
|
+
- Canonical module and dependency graph
|
|
31
|
+
- Execution and data flow relationships
|
|
32
|
+
- Structural roles (service, store, boundary, etc.)
|
|
33
|
+
- Invariants inferred from the system
|
|
34
|
+
- Impact metrics (blast radius, coupling)
|
|
35
|
+
|
|
36
|
+
## Determinism & Trust
|
|
37
|
+
|
|
38
|
+
- Generated from commit: b63e62db4aedf6ffb21055dd88d13c8a947a7422
|
|
39
|
+
- Generation timestamp: 2026-01-13T03:50:34.571Z
|
|
40
|
+
- Tool version: 0.2.5
|
|
41
|
+
- Deterministic: same input → same output
|
|
42
|
+
- Explicit assumptions listed inside the artifact
|
|
43
|
+
|
|
44
|
+
If this artifact conflicts with human memory, **trust the artifact**.
|
|
45
|
+
|
|
46
|
+
## Structural Context Hubs
|
|
47
|
+
|
|
48
|
+
The following files have the highest blast radius and represent critical structural hubs in the system:
|
|
49
|
+
|
|
50
|
+
- **src/lib/utils.ts**
|
|
51
|
+
- Blast Radius: 62 files (14.73% of codebase)
|
|
52
|
+
- Risk: Changes here may silently propagate across the system.
|
|
53
|
+
|
|
54
|
+
- **src/components/ui/button.tsx**
|
|
55
|
+
- Blast Radius: 49 files (11.64% of codebase)
|
|
56
|
+
- Risk: Acts as a coordination layer between components.
|
|
57
|
+
|
|
58
|
+
- **src/lib/supabase/client.ts**
|
|
59
|
+
- Blast Radius: 45 files (10.69% of codebase)
|
|
60
|
+
- Risk: Modifications can cause widespread inconsistencies.
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
## How to Use With AI
|
|
65
|
+
|
|
66
|
+
When prompting AI tools, include this file as system context.
|
|
67
|
+
Do not ask the AI to infer architecture without it.
|
|
68
|
+
|
|
69
|
+
## When to Regenerate
|
|
70
|
+
|
|
71
|
+
Regenerate this artifact when:
|
|
72
|
+
- Core modules change
|
|
73
|
+
- New services are added
|
|
74
|
+
- Dependency structure shifts
|
|
75
|
+
|
|
76
|
+
Run:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
arcvision scan --upload
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Source of Truth
|
|
83
|
+
|
|
84
|
+
This artifact is the **source of truth** for system structure.
|
|
85
|
+
All explanations, decisions, and AI reasoning should reference it.
|
package/dist/index.js
CHANGED
|
@@ -57524,7 +57524,7 @@ var require_pass1_facts = __commonJS({
|
|
|
57524
57524
|
if (fs2.existsSync(pluginDir)) {
|
|
57525
57525
|
pluginManager.loadPluginsFromDirectory(pluginDir);
|
|
57526
57526
|
}
|
|
57527
|
-
const files = await glob("**/*.{js,jsx,ts,tsx,json}", {
|
|
57527
|
+
const files = await glob("**/*.{js,jsx,ts,tsx,json,lua}", {
|
|
57528
57528
|
...scanOptions,
|
|
57529
57529
|
ignore: [...scanOptions.ignore, "**/*.d.ts", "**/.next/**", "**/coverage/**", "**/arcvision.context.json"]
|
|
57530
57530
|
});
|
|
@@ -57545,14 +57545,27 @@ var require_pass1_facts = __commonJS({
|
|
|
57545
57545
|
isJson: true,
|
|
57546
57546
|
raw: content
|
|
57547
57547
|
};
|
|
57548
|
+
} else if (file.endsWith(".lua")) {
|
|
57549
|
+
const content = fs2.readFileSync(file, "utf-8");
|
|
57550
|
+
metadata = {
|
|
57551
|
+
id: file,
|
|
57552
|
+
isLua: true,
|
|
57553
|
+
raw: content,
|
|
57554
|
+
// Extract potential invocations from Lua content
|
|
57555
|
+
potentialInvocations: extractLuaInvocations(content)
|
|
57556
|
+
};
|
|
57548
57557
|
} else {
|
|
57549
57558
|
metadata = parser.parseFile(file);
|
|
57550
57559
|
}
|
|
57551
57560
|
metadata = await pluginManager.processFile(file, metadata);
|
|
57561
|
+
const isLuaFile = file.endsWith(".lua");
|
|
57562
|
+
const nodeType = isLuaFile ? "execution_script" : "file";
|
|
57563
|
+
const nodeRole = isLuaFile ? "atomic_redis_operation" : "Structure";
|
|
57552
57564
|
const node = {
|
|
57553
57565
|
id: normalizedRelativePath,
|
|
57554
57566
|
filePath: file,
|
|
57555
|
-
type:
|
|
57567
|
+
type: nodeType,
|
|
57568
|
+
role: nodeRole,
|
|
57556
57569
|
facts: {
|
|
57557
57570
|
imports: metadata.imports || [],
|
|
57558
57571
|
exports: metadata.exports || [],
|
|
@@ -57574,9 +57587,14 @@ var require_pass1_facts = __commonJS({
|
|
|
57574
57587
|
hooks: metadata.hookDependencies || [],
|
|
57575
57588
|
context: metadata.contextUsages || []
|
|
57576
57589
|
},
|
|
57577
|
-
react: metadata.componentUsage || []
|
|
57590
|
+
react: metadata.componentUsage || [],
|
|
57591
|
+
potentialInvocations: metadata.potentialInvocations || []
|
|
57578
57592
|
}
|
|
57579
57593
|
};
|
|
57594
|
+
if (isLuaFile) {
|
|
57595
|
+
node.language = "lua";
|
|
57596
|
+
node.execution_boundary = "redis";
|
|
57597
|
+
}
|
|
57580
57598
|
return { node, factCount: (metadata.imports?.length || 0) + (metadata.functionCalls?.length || 0) };
|
|
57581
57599
|
} catch (e) {
|
|
57582
57600
|
console.warn(`\u26A0\uFE0F Pass 1 failed for ${file}: ${e.message}`);
|
|
@@ -57596,6 +57614,22 @@ var require_pass1_facts = __commonJS({
|
|
|
57596
57614
|
console.log(` \u2713 Extracted ${totalFacts} raw syntactic facts`);
|
|
57597
57615
|
return rawNodes;
|
|
57598
57616
|
}
|
|
57617
|
+
function extractLuaInvocations(content) {
|
|
57618
|
+
const invocations = [];
|
|
57619
|
+
const patterns = [
|
|
57620
|
+
/readFileSync\(['"].*\.lua['"].*\)/gi,
|
|
57621
|
+
/defineCommand\(\s*\{\s*lua\s*:.*\}/gi,
|
|
57622
|
+
/redis\.call\(['"].*['"].*\)/gi,
|
|
57623
|
+
/redis\.pcall\(['"].*['"].*\)/gi
|
|
57624
|
+
];
|
|
57625
|
+
patterns.forEach((pattern) => {
|
|
57626
|
+
let match;
|
|
57627
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
57628
|
+
invocations.push(match[0]);
|
|
57629
|
+
}
|
|
57630
|
+
});
|
|
57631
|
+
return invocations;
|
|
57632
|
+
}
|
|
57599
57633
|
module2.exports = { executePass1 };
|
|
57600
57634
|
}
|
|
57601
57635
|
});
|
|
@@ -58165,6 +58199,69 @@ var require_pass2_semantics = __commonJS({
|
|
|
58165
58199
|
}
|
|
58166
58200
|
}
|
|
58167
58201
|
console.log(` \u2713 Resolved ${resolvedCalls} semantic call edges`);
|
|
58202
|
+
let luaInvocationCount = 0;
|
|
58203
|
+
for (const node of rawNodes) {
|
|
58204
|
+
if (!node.facts.potentialInvocations || node.facts.potentialInvocations.length === 0)
|
|
58205
|
+
continue;
|
|
58206
|
+
const content = node.filePath && require("fs").readFileSync(node.filePath, "utf-8");
|
|
58207
|
+
if (!content)
|
|
58208
|
+
continue;
|
|
58209
|
+
const luaInvocationPatterns = [
|
|
58210
|
+
/readFileSync\(['"].*\.lua['"].*\)/gi,
|
|
58211
|
+
/defineCommand\(\s*[^,]*,\s*\{[^}]*lua\s*:.+?\}/gi,
|
|
58212
|
+
// Matches defineCommand(commandName, { ... lua: ... })
|
|
58213
|
+
/defineCommand\(\s*\{\s*lua\s*:.*?\}/gi,
|
|
58214
|
+
// Original pattern
|
|
58215
|
+
/require\(['"].*\.lua['"].*\)/gi,
|
|
58216
|
+
/fs\.readFileSync\(['"].*\.lua['"].*\)/gi,
|
|
58217
|
+
/import\s+.*?from\s+['"].*\.lua['"].*\)?/gi,
|
|
58218
|
+
/import\(['"].*\.lua['"].*\)/gi,
|
|
58219
|
+
/loadScript\(['"].*\.lua['"].*\)/gi,
|
|
58220
|
+
/loadLua\(['"].*\.lua['"].*\)/gi,
|
|
58221
|
+
/load\(['"].*\.lua['"].*\)/gi
|
|
58222
|
+
];
|
|
58223
|
+
for (const pattern of luaInvocationPatterns) {
|
|
58224
|
+
let match;
|
|
58225
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
58226
|
+
const luaFileMatch = match[0].match(/['"].*?\.lua['"]/);
|
|
58227
|
+
if (luaFileMatch) {
|
|
58228
|
+
let luaFilePath = luaFileMatch[0].slice(1, -1);
|
|
58229
|
+
if (luaFilePath.startsWith("./") || luaFilePath.startsWith("../")) {
|
|
58230
|
+
luaFilePath = path2.resolve(path2.dirname(node.filePath), luaFilePath);
|
|
58231
|
+
luaFilePath = normalize(path2.relative(rootDir, luaFilePath));
|
|
58232
|
+
} else if (luaFilePath.startsWith("/")) {
|
|
58233
|
+
luaFilePath = normalize(path2.relative(rootDir, path2.join(rootDir, luaFilePath)));
|
|
58234
|
+
} else {
|
|
58235
|
+
const commonLuaDirs = ["src", "scripts", "commands", "lua", "lib"];
|
|
58236
|
+
let foundPath = null;
|
|
58237
|
+
for (const dir of commonLuaDirs) {
|
|
58238
|
+
const candidatePath = normalize(path2.join(dir, luaFilePath));
|
|
58239
|
+
if (fileSet.has(candidatePath)) {
|
|
58240
|
+
foundPath = candidatePath;
|
|
58241
|
+
break;
|
|
58242
|
+
}
|
|
58243
|
+
}
|
|
58244
|
+
if (foundPath) {
|
|
58245
|
+
luaFilePath = foundPath;
|
|
58246
|
+
} else {
|
|
58247
|
+
const nodeDir = path2.dirname(node.id);
|
|
58248
|
+
luaFilePath = normalize(path2.join(nodeDir, luaFilePath));
|
|
58249
|
+
}
|
|
58250
|
+
}
|
|
58251
|
+
if (fileSet.has(luaFilePath)) {
|
|
58252
|
+
addEdge(node.id, luaFilePath, "invokes_execution_script", 1, {
|
|
58253
|
+
type: "lua_invocation",
|
|
58254
|
+
invocation_pattern: match[0],
|
|
58255
|
+
original_match: match[0],
|
|
58256
|
+
resolved_path: luaFilePath
|
|
58257
|
+
});
|
|
58258
|
+
luaInvocationCount++;
|
|
58259
|
+
}
|
|
58260
|
+
}
|
|
58261
|
+
}
|
|
58262
|
+
}
|
|
58263
|
+
}
|
|
58264
|
+
console.log(` \u2713 Detected ${luaInvocationCount} Lua script invocations`);
|
|
58168
58265
|
let typeEdgesCount = 0;
|
|
58169
58266
|
for (const node of rawNodes) {
|
|
58170
58267
|
if (!node.facts.typeAnalysis)
|
|
@@ -58522,6 +58619,8 @@ var require_id_generator = __commonJS({
|
|
|
58522
58619
|
var require_context_builder = __commonJS({
|
|
58523
58620
|
"src/core/context_builder.js"(exports2, module2) {
|
|
58524
58621
|
var path2 = require("path");
|
|
58622
|
+
var { spawnSync } = require("child_process");
|
|
58623
|
+
var crypto = require("crypto");
|
|
58525
58624
|
var { stableId } = require_id_generator();
|
|
58526
58625
|
function buildContext(fileNodes, edges, symbols, options = {}) {
|
|
58527
58626
|
const {
|
|
@@ -58619,9 +58718,11 @@ var require_context_builder = __commonJS({
|
|
|
58619
58718
|
total_dependencies: schemaEdges.length,
|
|
58620
58719
|
files_with_high_blast_radius: nodes.filter((n) => n.blast_radius > 5).length
|
|
58621
58720
|
};
|
|
58721
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
58722
|
+
const dateOnly = timestamp.split("T")[0];
|
|
58622
58723
|
const context = {
|
|
58623
58724
|
schema_version: "1.0.0",
|
|
58624
|
-
generated_at:
|
|
58725
|
+
generated_at: timestamp,
|
|
58625
58726
|
system: {
|
|
58626
58727
|
name: projectName,
|
|
58627
58728
|
root_path: path2.resolve(directory),
|
|
@@ -58631,11 +58732,453 @@ var require_context_builder = __commonJS({
|
|
|
58631
58732
|
edges: schemaEdges,
|
|
58632
58733
|
symbols: symbols || [],
|
|
58633
58734
|
metrics,
|
|
58634
|
-
contextSurface: options.contextSurface || []
|
|
58735
|
+
contextSurface: options.contextSurface || [],
|
|
58736
|
+
// Phase 2 requirement: Explicit Assumptions Section
|
|
58737
|
+
assumptions: generateAssumptions(),
|
|
58738
|
+
// Phase 2 requirement: Embed Commit Identity
|
|
58739
|
+
source: {
|
|
58740
|
+
repo: getGitInfo().repo,
|
|
58741
|
+
commit: getGitInfo().commit,
|
|
58742
|
+
generated_at: dateOnly,
|
|
58743
|
+
// Use date only to avoid time variations
|
|
58744
|
+
arcvision_version: options.arcvisionVersion || "0.1.0"
|
|
58745
|
+
},
|
|
58746
|
+
// Phase 3 requirement: Structural layers definition
|
|
58747
|
+
structural_layers: generateAdaptiveStructuralLayers(directory),
|
|
58748
|
+
// Phase 3 requirement: Project envelope
|
|
58749
|
+
project_envelope: generateProjectEnvelope(directory)
|
|
58750
|
+
};
|
|
58751
|
+
const contextWithoutIntegrity = { ...context };
|
|
58752
|
+
delete contextWithoutIntegrity.integrity;
|
|
58753
|
+
const hash = crypto.createHash("sha256").update(JSON.stringify(contextWithoutIntegrity)).digest("hex");
|
|
58754
|
+
context.integrity = {
|
|
58755
|
+
sha256: hash
|
|
58635
58756
|
};
|
|
58636
58757
|
return context;
|
|
58637
58758
|
}
|
|
58638
|
-
|
|
58759
|
+
function getGitInfo() {
|
|
58760
|
+
try {
|
|
58761
|
+
const originResult = spawnSync("git", ["remote", "get-url", "origin"], {
|
|
58762
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
58763
|
+
});
|
|
58764
|
+
let repoUrl = "unknown";
|
|
58765
|
+
if (originResult.status === 0) {
|
|
58766
|
+
let url = originResult.stdout.toString().trim();
|
|
58767
|
+
if (url.startsWith("git@")) {
|
|
58768
|
+
url = url.replace(/^git@(.*?):/, "https://$1/");
|
|
58769
|
+
url = url.replace(/\.git$/, "");
|
|
58770
|
+
} else if (url.endsWith(".git")) {
|
|
58771
|
+
url = url.replace(/\.git$/, "");
|
|
58772
|
+
}
|
|
58773
|
+
repoUrl = url;
|
|
58774
|
+
}
|
|
58775
|
+
const commitResult = spawnSync("git", ["rev-parse", "HEAD"], {
|
|
58776
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
58777
|
+
});
|
|
58778
|
+
let commitHash = "unknown";
|
|
58779
|
+
if (commitResult.status === 0) {
|
|
58780
|
+
commitHash = commitResult.stdout.toString().trim();
|
|
58781
|
+
}
|
|
58782
|
+
return {
|
|
58783
|
+
repo: repoUrl,
|
|
58784
|
+
commit: commitHash
|
|
58785
|
+
};
|
|
58786
|
+
} catch (error) {
|
|
58787
|
+
return {
|
|
58788
|
+
repo: "unknown",
|
|
58789
|
+
commit: "unknown"
|
|
58790
|
+
};
|
|
58791
|
+
}
|
|
58792
|
+
}
|
|
58793
|
+
function calculateIntegrityHash(obj) {
|
|
58794
|
+
try {
|
|
58795
|
+
const objCopy = JSON.parse(JSON.stringify(obj));
|
|
58796
|
+
if (objCopy.integrity) {
|
|
58797
|
+
delete objCopy.integrity;
|
|
58798
|
+
}
|
|
58799
|
+
const jsonString = JSON.stringify(objCopy);
|
|
58800
|
+
return crypto.createHash("sha256").update(jsonString).digest("hex");
|
|
58801
|
+
} catch (error) {
|
|
58802
|
+
return "calculation_error";
|
|
58803
|
+
}
|
|
58804
|
+
}
|
|
58805
|
+
function generateStructuralLayers() {
|
|
58806
|
+
return {
|
|
58807
|
+
"runtime_code": {
|
|
58808
|
+
"status": "included",
|
|
58809
|
+
"description": "Source files that directly participate in runtime execution and system behavior"
|
|
58810
|
+
},
|
|
58811
|
+
"execution_scripts": {
|
|
58812
|
+
"status": "included",
|
|
58813
|
+
"description": "Scripts invoked by runtime code to perform atomic or system-critical operations"
|
|
58814
|
+
},
|
|
58815
|
+
"infrastructure_scripts": {
|
|
58816
|
+
"status": "included",
|
|
58817
|
+
"description": "Scripts that manage infrastructure-level behavior (queues, databases, orchestration)"
|
|
58818
|
+
},
|
|
58819
|
+
"configuration": {
|
|
58820
|
+
"status": "optional",
|
|
58821
|
+
"description": "Project configuration files represented as metadata, not execution graph nodes"
|
|
58822
|
+
},
|
|
58823
|
+
"documentation": {
|
|
58824
|
+
"status": "optional",
|
|
58825
|
+
"description": "Documentation files represented as metadata only"
|
|
58826
|
+
},
|
|
58827
|
+
"assets": {
|
|
58828
|
+
"status": "excluded",
|
|
58829
|
+
"description": "Static assets with no effect on execution semantics"
|
|
58830
|
+
}
|
|
58831
|
+
};
|
|
58832
|
+
}
|
|
58833
|
+
function generateAdaptiveStructuralLayers(directory) {
|
|
58834
|
+
const fs2 = require("fs");
|
|
58835
|
+
const path3 = require("path");
|
|
58836
|
+
const hasPackageJson = fs2.existsSync(path3.join(directory, "package.json"));
|
|
58837
|
+
const hasConfigFiles = fs2.existsSync(path3.join(directory, "tsconfig.json")) || fs2.existsSync(path3.join(directory, "config")) || fs2.existsSync(path3.join(directory, "webpack.config.js"));
|
|
58838
|
+
const hasSrcDir = fs2.existsSync(path3.join(directory, "src"));
|
|
58839
|
+
const hasTestDir = fs2.existsSync(path3.join(directory, "test")) || fs2.existsSync(path3.join(directory, "tests"));
|
|
58840
|
+
const hasDocsDir = fs2.existsSync(path3.join(directory, "docs"));
|
|
58841
|
+
let totalFiles = 0;
|
|
58842
|
+
let jsFiles = 0;
|
|
58843
|
+
let tsFiles = 0;
|
|
58844
|
+
let luaFiles = 0;
|
|
58845
|
+
let configFiles = 0;
|
|
58846
|
+
function walk(dir, depth = 0) {
|
|
58847
|
+
if (depth > 3)
|
|
58848
|
+
return;
|
|
58849
|
+
if (!fs2.existsSync(dir))
|
|
58850
|
+
return;
|
|
58851
|
+
const items = fs2.readdirSync(dir, { withFileTypes: true });
|
|
58852
|
+
for (const item of items) {
|
|
58853
|
+
const fullPath = path3.join(dir, item.name);
|
|
58854
|
+
if (item.isDirectory()) {
|
|
58855
|
+
if (!item.name.startsWith(".") && item.name !== "node_modules" && item.name !== "dist" && item.name !== "build" && item.name !== ".git") {
|
|
58856
|
+
walk(fullPath, depth + 1);
|
|
58857
|
+
}
|
|
58858
|
+
} else {
|
|
58859
|
+
totalFiles++;
|
|
58860
|
+
if (item.name.endsWith(".js"))
|
|
58861
|
+
jsFiles++;
|
|
58862
|
+
if (item.name.endsWith(".ts"))
|
|
58863
|
+
tsFiles++;
|
|
58864
|
+
if (item.name.endsWith(".lua"))
|
|
58865
|
+
luaFiles++;
|
|
58866
|
+
if ([".json", ".yaml", ".yml", ".toml", ".config.js", ".config.ts", ".rc"].some((ext) => item.name.endsWith(ext)))
|
|
58867
|
+
configFiles++;
|
|
58868
|
+
}
|
|
58869
|
+
}
|
|
58870
|
+
}
|
|
58871
|
+
walk(directory);
|
|
58872
|
+
const isLuaProject = luaFiles > 0 && luaFiles / totalFiles > 0.1;
|
|
58873
|
+
const isLargeProject = totalFiles > 1e3;
|
|
58874
|
+
const layers = {
|
|
58875
|
+
"runtime_code": {
|
|
58876
|
+
"status": "included",
|
|
58877
|
+
"description": "Source files that directly participate in runtime execution and system behavior",
|
|
58878
|
+
"project_characteristics": {
|
|
58879
|
+
"has_package_json": hasPackageJson,
|
|
58880
|
+
"has_src_directory": hasSrcDir,
|
|
58881
|
+
"total_files": totalFiles,
|
|
58882
|
+
"javascript_files": jsFiles,
|
|
58883
|
+
"typescript_files": tsFiles,
|
|
58884
|
+
"lua_files": luaFiles
|
|
58885
|
+
}
|
|
58886
|
+
},
|
|
58887
|
+
"execution_scripts": {
|
|
58888
|
+
"status": isLuaProject ? "included" : "included",
|
|
58889
|
+
"description": "Scripts invoked by runtime code to perform atomic or system-critical operations",
|
|
58890
|
+
"project_characteristics": {
|
|
58891
|
+
"lua_files_count": luaFiles,
|
|
58892
|
+
"is_lua_project": isLuaProject
|
|
58893
|
+
}
|
|
58894
|
+
},
|
|
58895
|
+
"infrastructure_scripts": {
|
|
58896
|
+
"status": "included",
|
|
58897
|
+
"description": "Scripts that manage infrastructure-level behavior (queues, databases, orchestration)"
|
|
58898
|
+
},
|
|
58899
|
+
"configuration": {
|
|
58900
|
+
"status": hasConfigFiles ? "optional" : "excluded",
|
|
58901
|
+
"description": "Project configuration files represented as metadata, not execution graph nodes"
|
|
58902
|
+
},
|
|
58903
|
+
"documentation": {
|
|
58904
|
+
"status": hasDocsDir || hasPackageJson ? "optional" : "excluded",
|
|
58905
|
+
"description": "Documentation files represented as metadata only"
|
|
58906
|
+
},
|
|
58907
|
+
"assets": {
|
|
58908
|
+
"status": "excluded",
|
|
58909
|
+
"description": "Static assets with no effect on execution semantics"
|
|
58910
|
+
}
|
|
58911
|
+
};
|
|
58912
|
+
layers.project_metadata = {
|
|
58913
|
+
"size_category": isLargeProject ? "large" : totalFiles > 100 ? "medium" : "small",
|
|
58914
|
+
"file_count": totalFiles,
|
|
58915
|
+
"language_mix": {
|
|
58916
|
+
"javascript": jsFiles,
|
|
58917
|
+
"typescript": tsFiles,
|
|
58918
|
+
"lua": luaFiles,
|
|
58919
|
+
"config": configFiles
|
|
58920
|
+
},
|
|
58921
|
+
"has_package_management": hasPackageJson,
|
|
58922
|
+
"has_standard_structure": hasSrcDir,
|
|
58923
|
+
"has_tests": hasTestDir,
|
|
58924
|
+
"is_lua_intensive": isLuaProject
|
|
58925
|
+
};
|
|
58926
|
+
return layers;
|
|
58927
|
+
}
|
|
58928
|
+
function generateProjectEnvelope(directory) {
|
|
58929
|
+
const fs2 = require("fs");
|
|
58930
|
+
const path3 = require("path");
|
|
58931
|
+
const envelope = {
|
|
58932
|
+
configuration_files: [],
|
|
58933
|
+
documentation: [],
|
|
58934
|
+
build_tools: []
|
|
58935
|
+
};
|
|
58936
|
+
const configFiles = [
|
|
58937
|
+
"package.json",
|
|
58938
|
+
"tsconfig.json",
|
|
58939
|
+
"jsconfig.json",
|
|
58940
|
+
"webpack.config.js",
|
|
58941
|
+
"webpack.config.ts",
|
|
58942
|
+
"vite.config.js",
|
|
58943
|
+
"vite.config.ts",
|
|
58944
|
+
"rollup.config.js",
|
|
58945
|
+
"rollup.config.ts",
|
|
58946
|
+
"babel.config.js",
|
|
58947
|
+
"babel.config.ts",
|
|
58948
|
+
".babelrc",
|
|
58949
|
+
".babelrc.js",
|
|
58950
|
+
"eslint.config.mjs",
|
|
58951
|
+
"eslint.config.js",
|
|
58952
|
+
".eslintrc",
|
|
58953
|
+
".eslintrc.js",
|
|
58954
|
+
".eslintrc.json",
|
|
58955
|
+
"jest.config.js",
|
|
58956
|
+
"jest.config.ts",
|
|
58957
|
+
"jest.config.json",
|
|
58958
|
+
"mocha.opts",
|
|
58959
|
+
"nodemon.json",
|
|
58960
|
+
"nodemon.js",
|
|
58961
|
+
"next.config.ts",
|
|
58962
|
+
"next.config.js",
|
|
58963
|
+
"nuxt.config.js",
|
|
58964
|
+
"nuxt.config.ts",
|
|
58965
|
+
"postcss.config.mjs",
|
|
58966
|
+
"postcss.config.js",
|
|
58967
|
+
"tailwind.config.js",
|
|
58968
|
+
"tailwind.config.ts",
|
|
58969
|
+
"supabase/config.toml",
|
|
58970
|
+
"pnpm-workspace.yaml",
|
|
58971
|
+
"yarn.lock",
|
|
58972
|
+
"package-lock.json",
|
|
58973
|
+
"tsconfig.base.json",
|
|
58974
|
+
"tsconfig.node.json",
|
|
58975
|
+
"tsconfig.app.json",
|
|
58976
|
+
"turbo.json",
|
|
58977
|
+
"biome.json",
|
|
58978
|
+
"biome.jsonc",
|
|
58979
|
+
"angular.json",
|
|
58980
|
+
"nest-cli.json",
|
|
58981
|
+
"remix.config.js",
|
|
58982
|
+
"remix.config.ts"
|
|
58983
|
+
];
|
|
58984
|
+
const docFiles = [
|
|
58985
|
+
"README.md",
|
|
58986
|
+
"README.txt",
|
|
58987
|
+
"readme.md",
|
|
58988
|
+
"Readme.md",
|
|
58989
|
+
"CHANGELOG.md",
|
|
58990
|
+
"CHANGELOG.txt",
|
|
58991
|
+
"LICENSE",
|
|
58992
|
+
"LICENSE.md",
|
|
58993
|
+
"CONTRIBUTING.md",
|
|
58994
|
+
"NOTICE",
|
|
58995
|
+
"NOTICE.md",
|
|
58996
|
+
"SECURITY.md",
|
|
58997
|
+
"CODE_OF_CONDUCT.md",
|
|
58998
|
+
"PULL_REQUEST_TEMPLATE.md",
|
|
58999
|
+
"ISSUE_TEMPLATE.md",
|
|
59000
|
+
"HISTORY.md",
|
|
59001
|
+
"AUTHORS",
|
|
59002
|
+
"THANKS",
|
|
59003
|
+
"CITATION.cff",
|
|
59004
|
+
"CITATION.bib"
|
|
59005
|
+
];
|
|
59006
|
+
const buildToolFiles = [
|
|
59007
|
+
"typedoc.config.cjs",
|
|
59008
|
+
"typedoc.json",
|
|
59009
|
+
"typedoc.config.js",
|
|
59010
|
+
"typedoc.config.ts",
|
|
59011
|
+
"documentation.config.js",
|
|
59012
|
+
"docs.config.js",
|
|
59013
|
+
"api-extractor.json",
|
|
59014
|
+
"api-documenter.json",
|
|
59015
|
+
"jsdoc.json",
|
|
59016
|
+
"jsdoc.config.json",
|
|
59017
|
+
"compodoc.json",
|
|
59018
|
+
"documentation.yml"
|
|
59019
|
+
];
|
|
59020
|
+
function findFilesRecursively(dir, fileNames, results, maxDepth = 3, currentDepth = 0) {
|
|
59021
|
+
if (currentDepth > maxDepth)
|
|
59022
|
+
return;
|
|
59023
|
+
if (!fs2.existsSync(dir))
|
|
59024
|
+
return;
|
|
59025
|
+
const items = fs2.readdirSync(dir, { withFileTypes: true });
|
|
59026
|
+
for (const item of items) {
|
|
59027
|
+
const fullPath = path3.join(dir, item.name);
|
|
59028
|
+
if (item.isDirectory()) {
|
|
59029
|
+
if (!item.name.startsWith(".") && item.name !== "node_modules" && item.name !== "dist" && item.name !== "build") {
|
|
59030
|
+
findFilesRecursively(fullPath, fileNames, results, maxDepth, currentDepth + 1);
|
|
59031
|
+
}
|
|
59032
|
+
} else {
|
|
59033
|
+
if (fileNames.includes(item.name)) {
|
|
59034
|
+
const relativePath = path3.relative(directory, fullPath);
|
|
59035
|
+
results.push({
|
|
59036
|
+
path: relativePath,
|
|
59037
|
+
name: item.name
|
|
59038
|
+
});
|
|
59039
|
+
}
|
|
59040
|
+
}
|
|
59041
|
+
}
|
|
59042
|
+
}
|
|
59043
|
+
const foundConfigFiles = [];
|
|
59044
|
+
findFilesRecursively(directory, configFiles, foundConfigFiles);
|
|
59045
|
+
foundConfigFiles.forEach((fileObj) => {
|
|
59046
|
+
envelope.configuration_files.push({
|
|
59047
|
+
path: fileObj.path,
|
|
59048
|
+
role: getRoleForConfigFile(fileObj.name)
|
|
59049
|
+
});
|
|
59050
|
+
});
|
|
59051
|
+
const foundDocFiles = [];
|
|
59052
|
+
findFilesRecursively(directory, docFiles, foundDocFiles);
|
|
59053
|
+
foundDocFiles.forEach((fileObj) => {
|
|
59054
|
+
envelope.documentation.push({
|
|
59055
|
+
path: fileObj.path,
|
|
59056
|
+
role: getRoleForDocFile(fileObj.name)
|
|
59057
|
+
});
|
|
59058
|
+
});
|
|
59059
|
+
const foundBuildToolFiles = [];
|
|
59060
|
+
findFilesRecursively(directory, buildToolFiles, foundBuildToolFiles);
|
|
59061
|
+
foundBuildToolFiles.forEach((fileObj) => {
|
|
59062
|
+
envelope.build_tools.push({
|
|
59063
|
+
path: fileObj.path,
|
|
59064
|
+
role: getRoleForBuildToolFile(fileObj.name)
|
|
59065
|
+
});
|
|
59066
|
+
});
|
|
59067
|
+
envelope.configuration_files = envelope.configuration_files.filter(
|
|
59068
|
+
(file, index, self2) => index === self2.findIndex((f) => f.path === file.path)
|
|
59069
|
+
);
|
|
59070
|
+
envelope.documentation = envelope.documentation.filter(
|
|
59071
|
+
(file, index, self2) => index === self2.findIndex((f) => f.path === file.path)
|
|
59072
|
+
);
|
|
59073
|
+
envelope.build_tools = envelope.build_tools.filter(
|
|
59074
|
+
(file, index, self2) => index === self2.findIndex((f) => f.path === file.path)
|
|
59075
|
+
);
|
|
59076
|
+
return envelope;
|
|
59077
|
+
}
|
|
59078
|
+
function getRoleForConfigFile(fileName) {
|
|
59079
|
+
const roles = {
|
|
59080
|
+
"package.json": "dependency_manifest",
|
|
59081
|
+
"tsconfig.json": "compiler_configuration",
|
|
59082
|
+
"jsconfig.json": "compiler_configuration",
|
|
59083
|
+
"webpack.config.js": "bundler_configuration",
|
|
59084
|
+
"webpack.config.ts": "bundler_configuration",
|
|
59085
|
+
"vite.config.js": "bundler_configuration",
|
|
59086
|
+
"vite.config.ts": "bundler_configuration",
|
|
59087
|
+
"rollup.config.js": "bundler_configuration",
|
|
59088
|
+
"rollup.config.ts": "bundler_configuration",
|
|
59089
|
+
"babel.config.js": "transpiler_configuration",
|
|
59090
|
+
"babel.config.ts": "transpiler_configuration",
|
|
59091
|
+
".babelrc": "transpiler_configuration",
|
|
59092
|
+
".babelrc.js": "transpiler_configuration",
|
|
59093
|
+
"eslint.config.mjs": "linting_configuration",
|
|
59094
|
+
"eslint.config.js": "linting_configuration",
|
|
59095
|
+
".eslintrc": "linting_configuration",
|
|
59096
|
+
".eslintrc.js": "linting_configuration",
|
|
59097
|
+
".eslintrc.json": "linting_configuration",
|
|
59098
|
+
"jest.config.js": "testing_configuration",
|
|
59099
|
+
"jest.config.ts": "testing_configuration",
|
|
59100
|
+
"jest.config.json": "testing_configuration",
|
|
59101
|
+
"mocha.opts": "testing_configuration",
|
|
59102
|
+
"nodemon.json": "development_configuration",
|
|
59103
|
+
"nodemon.js": "development_configuration",
|
|
59104
|
+
"next.config.ts": "framework_configuration",
|
|
59105
|
+
"next.config.js": "framework_configuration",
|
|
59106
|
+
"nuxt.config.js": "framework_configuration",
|
|
59107
|
+
"nuxt.config.ts": "framework_configuration",
|
|
59108
|
+
"postcss.config.mjs": "css_processing_configuration",
|
|
59109
|
+
"postcss.config.js": "css_processing_configuration",
|
|
59110
|
+
"tailwind.config.js": "css_framework_configuration",
|
|
59111
|
+
"tailwind.config.ts": "css_framework_configuration",
|
|
59112
|
+
"supabase/config.toml": "database_service_configuration",
|
|
59113
|
+
"pnpm-workspace.yaml": "package_manager_configuration",
|
|
59114
|
+
"yarn.lock": "dependency_lockfile",
|
|
59115
|
+
"package-lock.json": "dependency_lockfile",
|
|
59116
|
+
"tsconfig.base.json": "compiler_base_configuration",
|
|
59117
|
+
"tsconfig.node.json": "compiler_node_configuration",
|
|
59118
|
+
"tsconfig.app.json": "compiler_app_configuration",
|
|
59119
|
+
"turbo.json": "build_system_configuration",
|
|
59120
|
+
"biome.json": "formatter_linter_configuration",
|
|
59121
|
+
"biome.jsonc": "formatter_linter_configuration",
|
|
59122
|
+
"angular.json": "framework_configuration",
|
|
59123
|
+
"nest-cli.json": "framework_configuration",
|
|
59124
|
+
"remix.config.js": "framework_configuration",
|
|
59125
|
+
"remix.config.ts": "framework_configuration"
|
|
59126
|
+
};
|
|
59127
|
+
return roles[fileName] || "general_configuration";
|
|
59128
|
+
}
|
|
59129
|
+
function getRoleForDocFile(fileName) {
|
|
59130
|
+
const roles = {
|
|
59131
|
+
"README.md": "system_overview",
|
|
59132
|
+
"README.txt": "system_overview",
|
|
59133
|
+
"readme.md": "system_overview",
|
|
59134
|
+
"Readme.md": "system_overview",
|
|
59135
|
+
"CHANGELOG.md": "change_history",
|
|
59136
|
+
"CHANGELOG.txt": "change_history",
|
|
59137
|
+
"LICENSE": "license_terms",
|
|
59138
|
+
"LICENSE.md": "license_terms",
|
|
59139
|
+
"CONTRIBUTING.md": "contribution_guidelines",
|
|
59140
|
+
"NOTICE": "legal_notice",
|
|
59141
|
+
"NOTICE.md": "legal_notice",
|
|
59142
|
+
"SECURITY.md": "security_policy",
|
|
59143
|
+
"CODE_OF_CONDUCT.md": "code_of_conduct",
|
|
59144
|
+
"PULL_REQUEST_TEMPLATE.md": "pull_request_guidelines",
|
|
59145
|
+
"ISSUE_TEMPLATE.md": "issue_reporting_guidelines",
|
|
59146
|
+
"HISTORY.md": "project_history",
|
|
59147
|
+
"AUTHORS": "authorship_information",
|
|
59148
|
+
"THANKS": "acknowledgements",
|
|
59149
|
+
"CITATION.cff": "citation_information",
|
|
59150
|
+
"CITATION.bib": "citation_information"
|
|
59151
|
+
};
|
|
59152
|
+
return roles[fileName] || "documentation";
|
|
59153
|
+
}
|
|
59154
|
+
function getRoleForBuildToolFile(fileName) {
|
|
59155
|
+
const roles = {
|
|
59156
|
+
"typedoc.config.cjs": "documentation_generator",
|
|
59157
|
+
"typedoc.json": "documentation_generator",
|
|
59158
|
+
"typedoc.config.js": "documentation_generator",
|
|
59159
|
+
"typedoc.config.ts": "documentation_generator",
|
|
59160
|
+
"documentation.config.js": "documentation_generator",
|
|
59161
|
+
"docs.config.js": "documentation_generator",
|
|
59162
|
+
"api-extractor.json": "api_documentation_generator",
|
|
59163
|
+
"api-documenter.json": "api_documentation_generator",
|
|
59164
|
+
"jsdoc.json": "documentation_generator",
|
|
59165
|
+
"jsdoc.config.json": "documentation_generator",
|
|
59166
|
+
"compodoc.json": "angular_documentation_generator",
|
|
59167
|
+
"documentation.yml": "documentation_generator"
|
|
59168
|
+
};
|
|
59169
|
+
return roles[fileName] || "build_tool_configuration";
|
|
59170
|
+
}
|
|
59171
|
+
function generateAssumptions() {
|
|
59172
|
+
return [
|
|
59173
|
+
"Dynamic imports resolved statically where possible",
|
|
59174
|
+
"Runtime reflection not fully captured",
|
|
59175
|
+
"Only code reachable from entry points analyzed",
|
|
59176
|
+
"Third-party dependencies treated as black boxes",
|
|
59177
|
+
"Build-time code generation not reflected in static analysis",
|
|
59178
|
+
"ArcVision prioritizes execution-relevant structure over exhaustive file indexing. Non-runtime files are represented as envelope metadata unless they directly affect execution."
|
|
59179
|
+
];
|
|
59180
|
+
}
|
|
59181
|
+
module2.exports = { buildContext, getGitInfo, calculateIntegrityHash, generateAssumptions, generateStructuralLayers, generateProjectEnvelope, generateAdaptiveStructuralLayers };
|
|
58639
59182
|
}
|
|
58640
59183
|
});
|
|
58641
59184
|
|
|
@@ -65222,7 +65765,9 @@ var require_scanner = __commonJS({
|
|
|
65222
65765
|
const contextOptions = {
|
|
65223
65766
|
directory,
|
|
65224
65767
|
projectName: path2.basename(directory),
|
|
65225
|
-
contextSurface
|
|
65768
|
+
contextSurface,
|
|
65769
|
+
arcvisionVersion: process.env.npm_package_version || "0.1.0"
|
|
65770
|
+
// Pass version from package.json
|
|
65226
65771
|
};
|
|
65227
65772
|
let context = buildContext(nodes, edges, symbols, contextOptions);
|
|
65228
65773
|
console.log(" Validating structural context...");
|
|
@@ -65244,6 +65789,199 @@ var require_scanner = __commonJS({
|
|
|
65244
65789
|
}
|
|
65245
65790
|
});
|
|
65246
65791
|
|
|
65792
|
+
// src/core/diff-analyzer.js
|
|
65793
|
+
var require_diff_analyzer = __commonJS({
|
|
65794
|
+
"src/core/diff-analyzer.js"(exports2, module2) {
|
|
65795
|
+
function generateDiffSummary2(oldContext, newContext) {
|
|
65796
|
+
const diffSummary = {
|
|
65797
|
+
nodes_added: 0,
|
|
65798
|
+
nodes_removed: 0,
|
|
65799
|
+
edges_added: 0,
|
|
65800
|
+
edges_removed: 0,
|
|
65801
|
+
roles_changed: 0,
|
|
65802
|
+
blast_radius_changes: 0
|
|
65803
|
+
};
|
|
65804
|
+
const oldNodeMap = new Map(oldContext.nodes.map((node) => [node.path, node]));
|
|
65805
|
+
const newNodeMap = new Map(newContext.nodes.map((node) => [node.path, node]));
|
|
65806
|
+
for (const [path2, node] of newNodeMap) {
|
|
65807
|
+
if (!oldNodeMap.has(path2)) {
|
|
65808
|
+
diffSummary.nodes_added++;
|
|
65809
|
+
}
|
|
65810
|
+
}
|
|
65811
|
+
for (const [path2, node] of oldNodeMap) {
|
|
65812
|
+
if (!newNodeMap.has(path2)) {
|
|
65813
|
+
diffSummary.nodes_removed++;
|
|
65814
|
+
}
|
|
65815
|
+
}
|
|
65816
|
+
const oldEdgeMap = new Map(
|
|
65817
|
+
oldContext.edges.map((edge) => [`${edge.from}::${edge.to}::${edge.relation}`, edge])
|
|
65818
|
+
);
|
|
65819
|
+
const newEdgeMap = new Map(
|
|
65820
|
+
newContext.edges.map((edge) => [`${edge.from}::${edge.to}::${edge.relation}`, edge])
|
|
65821
|
+
);
|
|
65822
|
+
for (const [key, edge] of newEdgeMap) {
|
|
65823
|
+
if (!oldEdgeMap.has(key)) {
|
|
65824
|
+
diffSummary.edges_added++;
|
|
65825
|
+
}
|
|
65826
|
+
}
|
|
65827
|
+
for (const [key, edge] of oldEdgeMap) {
|
|
65828
|
+
if (!newEdgeMap.has(key)) {
|
|
65829
|
+
diffSummary.edges_removed++;
|
|
65830
|
+
}
|
|
65831
|
+
}
|
|
65832
|
+
for (const newNode of newContext.nodes) {
|
|
65833
|
+
const oldNode = oldNodeMap.get(newNode.path);
|
|
65834
|
+
if (oldNode && oldNode.role !== newNode.role) {
|
|
65835
|
+
diffSummary.roles_changed++;
|
|
65836
|
+
}
|
|
65837
|
+
}
|
|
65838
|
+
for (const newNode of newContext.nodes) {
|
|
65839
|
+
const oldNode = oldNodeMap.get(newNode.path);
|
|
65840
|
+
if (oldNode && oldNode.blast_radius !== newNode.blast_radius) {
|
|
65841
|
+
diffSummary.blast_radius_changes++;
|
|
65842
|
+
}
|
|
65843
|
+
}
|
|
65844
|
+
return {
|
|
65845
|
+
diff_summary: diffSummary
|
|
65846
|
+
};
|
|
65847
|
+
}
|
|
65848
|
+
module2.exports = { generateDiffSummary: generateDiffSummary2 };
|
|
65849
|
+
}
|
|
65850
|
+
});
|
|
65851
|
+
|
|
65852
|
+
// src/core/readme-generator.js
|
|
65853
|
+
var require_readme_generator = __commonJS({
|
|
65854
|
+
"src/core/readme-generator.js"(exports2, module2) {
|
|
65855
|
+
var fs2 = require("fs");
|
|
65856
|
+
var path2 = require("path");
|
|
65857
|
+
var { spawnSync } = require("child_process");
|
|
65858
|
+
function getCommitHash() {
|
|
65859
|
+
try {
|
|
65860
|
+
const result = spawnSync("git", ["rev-parse", "HEAD"], {
|
|
65861
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
65862
|
+
});
|
|
65863
|
+
if (result.status === 0) {
|
|
65864
|
+
return result.stdout.toString().trim();
|
|
65865
|
+
}
|
|
65866
|
+
return "unknown";
|
|
65867
|
+
} catch (error) {
|
|
65868
|
+
return "unknown";
|
|
65869
|
+
}
|
|
65870
|
+
}
|
|
65871
|
+
function generateReadmeContent(commitHash, timestamp, toolVersion, blastRadiusData = null) {
|
|
65872
|
+
let content = `# ArcVision System Context Artifact
|
|
65873
|
+
|
|
65874
|
+
|
|
65875
|
+
## What This Is [arcvision.context.json](./arcvision.context.json)
|
|
65876
|
+
|
|
65877
|
+
This file is the **canonical structural context** of this codebase.
|
|
65878
|
+
It represents how the system actually works \u2014 not how it is described.
|
|
65879
|
+
|
|
65880
|
+
It is generated directly from source code by ArcVision.
|
|
65881
|
+
|
|
65882
|
+
## What This Replaces
|
|
65883
|
+
|
|
65884
|
+
This artifact replaces:
|
|
65885
|
+
- Manual repository scanning
|
|
65886
|
+
- Tribal knowledge held by senior engineers
|
|
65887
|
+
- Re-explaining the system to new developers
|
|
65888
|
+
- Re-prompting LLMs with partial or incorrect context
|
|
65889
|
+
- Guessing blast radius of changes
|
|
65890
|
+
|
|
65891
|
+
## When You Must Use This
|
|
65892
|
+
|
|
65893
|
+
Use this artifact when:
|
|
65894
|
+
- Onboarding a new developer
|
|
65895
|
+
- Prompting an AI assistant about this codebase
|
|
65896
|
+
- Making architectural changes
|
|
65897
|
+
- Investigating unexpected behavior
|
|
65898
|
+
- Assessing risk before modifying core modules
|
|
65899
|
+
|
|
65900
|
+
## What This Artifact Contains
|
|
65901
|
+
|
|
65902
|
+
- Canonical module and dependency graph
|
|
65903
|
+
- Execution and data flow relationships
|
|
65904
|
+
- Structural roles (service, store, boundary, etc.)
|
|
65905
|
+
- Invariants inferred from the system
|
|
65906
|
+
- Impact metrics (blast radius, coupling)
|
|
65907
|
+
|
|
65908
|
+
## Determinism & Trust
|
|
65909
|
+
|
|
65910
|
+
- Generated from commit: ${commitHash}
|
|
65911
|
+
- Generation timestamp: ${timestamp}
|
|
65912
|
+
- Tool version: ${toolVersion}
|
|
65913
|
+
- Deterministic: same input \u2192 same output
|
|
65914
|
+
- Explicit assumptions listed inside the artifact
|
|
65915
|
+
|
|
65916
|
+
If this artifact conflicts with human memory, **trust the artifact**.`;
|
|
65917
|
+
if (blastRadiusData && blastRadiusData.topFiles && blastRadiusData.topFiles.length > 0) {
|
|
65918
|
+
content += `
|
|
65919
|
+
|
|
65920
|
+
## Structural Context Hubs
|
|
65921
|
+
|
|
65922
|
+
The following files have the highest blast radius and represent critical structural hubs in the system:
|
|
65923
|
+
|
|
65924
|
+
`;
|
|
65925
|
+
blastRadiusData.topFiles.forEach((item, index) => {
|
|
65926
|
+
let warningMessage = "";
|
|
65927
|
+
if (index === 0) {
|
|
65928
|
+
warningMessage = "Changes here may silently propagate across the system.";
|
|
65929
|
+
} else if (index === 1) {
|
|
65930
|
+
warningMessage = "Acts as a coordination layer between components.";
|
|
65931
|
+
} else {
|
|
65932
|
+
warningMessage = "Modifications can cause widespread inconsistencies.";
|
|
65933
|
+
}
|
|
65934
|
+
content += `- **${item.file}**
|
|
65935
|
+
- Blast Radius: ${item.blastRadius} files (${item.percentOfGraph}% of codebase)
|
|
65936
|
+
- Risk: ${warningMessage}
|
|
65937
|
+
|
|
65938
|
+
`;
|
|
65939
|
+
});
|
|
65940
|
+
} else {
|
|
65941
|
+
content += `
|
|
65942
|
+
|
|
65943
|
+
## Structural Context Hubs
|
|
65944
|
+
|
|
65945
|
+
No high-structure files detected based on import dependencies.`;
|
|
65946
|
+
}
|
|
65947
|
+
content += `
|
|
65948
|
+
|
|
65949
|
+
## How to Use With AI
|
|
65950
|
+
|
|
65951
|
+
When prompting AI tools, include this file as system context.
|
|
65952
|
+
Do not ask the AI to infer architecture without it.
|
|
65953
|
+
|
|
65954
|
+
## When to Regenerate
|
|
65955
|
+
|
|
65956
|
+
Regenerate this artifact when:
|
|
65957
|
+
- Core modules change
|
|
65958
|
+
- New services are added
|
|
65959
|
+
- Dependency structure shifts
|
|
65960
|
+
|
|
65961
|
+
Run:
|
|
65962
|
+
|
|
65963
|
+
\`\`\`
|
|
65964
|
+
arcvision scan --upload
|
|
65965
|
+
\`\`\`
|
|
65966
|
+
|
|
65967
|
+
## Source of Truth
|
|
65968
|
+
|
|
65969
|
+
This artifact is the **source of truth** for system structure.
|
|
65970
|
+
All explanations, decisions, and AI reasoning should reference it.`;
|
|
65971
|
+
return content;
|
|
65972
|
+
}
|
|
65973
|
+
function generateReadme(outputDir, toolVersion, blastRadiusData = null) {
|
|
65974
|
+
const commitHash = getCommitHash();
|
|
65975
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
65976
|
+
const readmeContent = generateReadmeContent(commitHash, timestamp, toolVersion, blastRadiusData);
|
|
65977
|
+
const readmePath = path2.join(outputDir, "README.md");
|
|
65978
|
+
fs2.writeFileSync(readmePath, readmeContent);
|
|
65979
|
+
console.log(`\u2705 System context README generated at ${readmePath}`);
|
|
65980
|
+
}
|
|
65981
|
+
module2.exports = { generateReadme, generateReadmeContent, getCommitHash };
|
|
65982
|
+
}
|
|
65983
|
+
});
|
|
65984
|
+
|
|
65247
65985
|
// src/index.js
|
|
65248
65986
|
var { Command } = require_commander();
|
|
65249
65987
|
var chalk = require_source();
|
|
@@ -65251,6 +65989,7 @@ var path = require("path");
|
|
|
65251
65989
|
var fs = require("fs");
|
|
65252
65990
|
var os = require("os");
|
|
65253
65991
|
var scanner = require_scanner();
|
|
65992
|
+
var { generateDiffSummary } = require_diff_analyzer();
|
|
65254
65993
|
var version = "1.0.0";
|
|
65255
65994
|
try {
|
|
65256
65995
|
const packageJsonPath = path.join(__dirname, "../package.json");
|
|
@@ -65267,7 +66006,9 @@ function analyzeBlastRadius(architectureMap) {
|
|
|
65267
66006
|
if (architectureMap.nodes && architectureMap.nodes.length > 0) {
|
|
65268
66007
|
architectureMap.nodes.forEach((node) => {
|
|
65269
66008
|
let blastRadius = 0;
|
|
65270
|
-
if (node.
|
|
66009
|
+
if (node.blast_radius !== void 0) {
|
|
66010
|
+
blastRadius = node.blast_radius;
|
|
66011
|
+
} else if (node.metadata && node.metadata.blast_radius !== void 0) {
|
|
65271
66012
|
blastRadius = node.metadata.blast_radius;
|
|
65272
66013
|
} else if (node.signals && node.signals.blast_radius !== void 0) {
|
|
65273
66014
|
blastRadius = node.signals.blast_radius;
|
|
@@ -65463,11 +66204,15 @@ program.command("scan").description("Scan the current directory and generate arc
|
|
|
65463
66204
|
}
|
|
65464
66205
|
if (options.upload) {
|
|
65465
66206
|
await uploadToDatabase(map);
|
|
66207
|
+
const { generateReadme } = require_readme_generator();
|
|
66208
|
+
generateReadme(".", version, blastRadiusAnalysis);
|
|
65466
66209
|
} else {
|
|
65467
66210
|
const fs2 = require("fs");
|
|
65468
66211
|
const outputFileName = "arcvision.context.json";
|
|
65469
66212
|
fs2.writeFileSync(outputFileName, JSON.stringify(map, null, 2));
|
|
65470
66213
|
console.log(chalk.green(`\u2705 Structural context saved to ${outputFileName}`));
|
|
66214
|
+
const { generateReadme } = require_readme_generator();
|
|
66215
|
+
generateReadme(".", version, blastRadiusAnalysis);
|
|
65471
66216
|
console.log(chalk.dim("\nUse --upload to send to dashboard."));
|
|
65472
66217
|
}
|
|
65473
66218
|
} catch (error) {
|
|
@@ -65492,4 +66237,29 @@ program.command("scan").description("Scan the current directory and generate arc
|
|
|
65492
66237
|
}
|
|
65493
66238
|
}
|
|
65494
66239
|
});
|
|
66240
|
+
program.command("diff").description("Compare two context artifacts and generate diff summary").argument("<old-file>", "Path to the old context artifact").argument("<new-file>", "Path to the new context artifact").action(async (oldFile, newFile) => {
|
|
66241
|
+
try {
|
|
66242
|
+
console.log(chalk.blue(`Comparing context artifacts:`));
|
|
66243
|
+
console.log(chalk.blue(` Old: ${oldFile}`));
|
|
66244
|
+
console.log(chalk.blue(` New: ${newFile}`));
|
|
66245
|
+
const oldContext = JSON.parse(fs.readFileSync(oldFile, "utf8"));
|
|
66246
|
+
const newContext = JSON.parse(fs.readFileSync(newFile, "utf8"));
|
|
66247
|
+
const diffResult = generateDiffSummary(oldContext, newContext);
|
|
66248
|
+
newContext.diff_summary = diffResult.diff_summary;
|
|
66249
|
+
const outputFileName = "arcvision.context.diff.json";
|
|
66250
|
+
fs.writeFileSync(outputFileName, JSON.stringify(newContext, null, 2));
|
|
66251
|
+
console.log(chalk.green("\u2705 Structural diff completed!"));
|
|
66252
|
+
console.log(chalk.green(`\u2705 Diff summary saved to ${outputFileName}`));
|
|
66253
|
+
console.log(chalk.yellow("\nDiff Summary:"));
|
|
66254
|
+
console.log(chalk.yellow(` Nodes Added: ${diffResult.diff_summary.nodes_added}`));
|
|
66255
|
+
console.log(chalk.yellow(` Nodes Removed: ${diffResult.diff_summary.nodes_removed}`));
|
|
66256
|
+
console.log(chalk.yellow(` Edges Added: ${diffResult.diff_summary.edges_added}`));
|
|
66257
|
+
console.log(chalk.yellow(` Edges Removed: ${diffResult.diff_summary.edges_removed}`));
|
|
66258
|
+
console.log(chalk.yellow(` Roles Changed: ${diffResult.diff_summary.roles_changed}`));
|
|
66259
|
+
console.log(chalk.yellow(` Blast Radius Changes: ${diffResult.diff_summary.blast_radius_changes}`));
|
|
66260
|
+
} catch (error) {
|
|
66261
|
+
console.error(chalk.red("\u274C Diff failed:"), error.message);
|
|
66262
|
+
process.exit(1);
|
|
66263
|
+
}
|
|
66264
|
+
});
|
|
65495
66265
|
program.parse();
|
package/package.json
CHANGED
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
"system",
|
|
9
9
|
"nodes",
|
|
10
10
|
"edges",
|
|
11
|
-
"metrics"
|
|
11
|
+
"metrics",
|
|
12
|
+
"assumptions",
|
|
13
|
+
"source",
|
|
14
|
+
"integrity",
|
|
15
|
+
"structural_layers",
|
|
16
|
+
"project_envelope"
|
|
12
17
|
],
|
|
13
18
|
"properties": {
|
|
14
19
|
"schema_version": {
|
|
@@ -79,6 +84,138 @@
|
|
|
79
84
|
"additionalProperties": {
|
|
80
85
|
"type": ["number", "string"]
|
|
81
86
|
}
|
|
87
|
+
},
|
|
88
|
+
"assumptions": {
|
|
89
|
+
"type": "array",
|
|
90
|
+
"description": "Explicit assumptions about analysis limitations",
|
|
91
|
+
"items": {
|
|
92
|
+
"type": "string"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"source": {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"description": "Source repository and commit information",
|
|
98
|
+
"required": ["repo", "commit", "generated_at", "arcvision_version"],
|
|
99
|
+
"properties": {
|
|
100
|
+
"repo": { "type": "string" },
|
|
101
|
+
"commit": { "type": "string" },
|
|
102
|
+
"generated_at": { "type": "string" },
|
|
103
|
+
"arcvision_version": { "type": "string" }
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"integrity": {
|
|
107
|
+
"type": "object",
|
|
108
|
+
"description": "Integrity hash of the artifact",
|
|
109
|
+
"required": ["sha256"],
|
|
110
|
+
"properties": {
|
|
111
|
+
"sha256": { "type": "string" }
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"structural_layers": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"description": "Defines which structural layers are included in the analysis",
|
|
117
|
+
"required": ["runtime_code", "execution_scripts", "infrastructure_scripts", "configuration", "documentation", "assets"],
|
|
118
|
+
"properties": {
|
|
119
|
+
"runtime_code": {
|
|
120
|
+
"type": "object",
|
|
121
|
+
"required": ["status", "description"],
|
|
122
|
+
"properties": {
|
|
123
|
+
"status": { "type": "string", "enum": ["included", "excluded"] },
|
|
124
|
+
"description": { "type": "string" }
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"execution_scripts": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"required": ["status", "description"],
|
|
130
|
+
"properties": {
|
|
131
|
+
"status": { "type": "string", "enum": ["included", "excluded"] },
|
|
132
|
+
"description": { "type": "string" }
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"infrastructure_scripts": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"required": ["status", "description"],
|
|
138
|
+
"properties": {
|
|
139
|
+
"status": { "type": "string", "enum": ["included", "excluded"] },
|
|
140
|
+
"description": { "type": "string" }
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"configuration": {
|
|
144
|
+
"type": "object",
|
|
145
|
+
"required": ["status", "description"],
|
|
146
|
+
"properties": {
|
|
147
|
+
"status": { "type": "string", "enum": ["included", "excluded", "optional"] },
|
|
148
|
+
"description": { "type": "string" }
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"documentation": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"required": ["status", "description"],
|
|
154
|
+
"properties": {
|
|
155
|
+
"status": { "type": "string", "enum": ["included", "excluded", "optional"] },
|
|
156
|
+
"description": { "type": "string" }
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"assets": {
|
|
160
|
+
"type": "object",
|
|
161
|
+
"required": ["status", "description"],
|
|
162
|
+
"properties": {
|
|
163
|
+
"status": { "type": "string", "enum": ["included", "excluded"] },
|
|
164
|
+
"description": { "type": "string" }
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"project_envelope": {
|
|
170
|
+
"type": "object",
|
|
171
|
+
"description": "Project-level files that provide context but are not execution graph nodes",
|
|
172
|
+
"properties": {
|
|
173
|
+
"configuration_files": {
|
|
174
|
+
"type": "array",
|
|
175
|
+
"items": {
|
|
176
|
+
"type": "object",
|
|
177
|
+
"properties": {
|
|
178
|
+
"path": { "type": "string" },
|
|
179
|
+
"role": { "type": "string" }
|
|
180
|
+
},
|
|
181
|
+
"required": ["path", "role"]
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"documentation": {
|
|
185
|
+
"type": "array",
|
|
186
|
+
"items": {
|
|
187
|
+
"type": "object",
|
|
188
|
+
"properties": {
|
|
189
|
+
"path": { "type": "string" },
|
|
190
|
+
"role": { "type": "string" }
|
|
191
|
+
},
|
|
192
|
+
"required": ["path", "role"]
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"build_tools": {
|
|
196
|
+
"type": "array",
|
|
197
|
+
"items": {
|
|
198
|
+
"type": "object",
|
|
199
|
+
"properties": {
|
|
200
|
+
"path": { "type": "string" },
|
|
201
|
+
"role": { "type": "string" }
|
|
202
|
+
},
|
|
203
|
+
"required": ["path", "role"]
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
"diff_summary": {
|
|
209
|
+
"type": "object",
|
|
210
|
+
"description": "Structural diff summary between commits",
|
|
211
|
+
"properties": {
|
|
212
|
+
"nodes_added": { "type": "number" },
|
|
213
|
+
"nodes_removed": { "type": "number" },
|
|
214
|
+
"edges_added": { "type": "number" },
|
|
215
|
+
"edges_removed": { "type": "number" },
|
|
216
|
+
"roles_changed": { "type": "number" },
|
|
217
|
+
"blast_radius_changes": { "type": "number" }
|
|
218
|
+
}
|
|
82
219
|
}
|
|
83
220
|
}
|
|
84
221
|
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"title": "Arcvision System-Level Structural Context",
|
|
4
|
-
"type": "object",
|
|
5
|
-
"required": [
|
|
6
|
-
"schema_version",
|
|
7
|
-
"generated_at",
|
|
8
|
-
"system",
|
|
9
|
-
"nodes",
|
|
10
|
-
"edges",
|
|
11
|
-
"metrics"
|
|
12
|
-
],
|
|
13
|
-
"properties": {
|
|
14
|
-
"schema_version": {
|
|
15
|
-
"type": "string",
|
|
16
|
-
"description": "Semantic version of the Arcvision context schema (e.g. 1.0.0)"
|
|
17
|
-
},
|
|
18
|
-
"generated_at": {
|
|
19
|
-
"type": "string",
|
|
20
|
-
"format": "date-time",
|
|
21
|
-
"description": "ISO-8601 timestamp when context was generated"
|
|
22
|
-
},
|
|
23
|
-
"system": {
|
|
24
|
-
"type": "object",
|
|
25
|
-
"required": ["name", "root_path", "language"],
|
|
26
|
-
"properties": {
|
|
27
|
-
"name": { "type": "string" },
|
|
28
|
-
"root_path": { "type": "string" },
|
|
29
|
-
"language": { "type": "string" }
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
"nodes": {
|
|
33
|
-
"type": "array",
|
|
34
|
-
"items": {
|
|
35
|
-
"type": "object",
|
|
36
|
-
"required": ["id", "type", "path", "role"],
|
|
37
|
-
"properties": {
|
|
38
|
-
"id": {
|
|
39
|
-
"type": "string",
|
|
40
|
-
"description": "Deterministic, stable ID (never random)"
|
|
41
|
-
},
|
|
42
|
-
"type": {
|
|
43
|
-
"type": "string",
|
|
44
|
-
"enum": ["file", "module", "class", "function", "service"]
|
|
45
|
-
},
|
|
46
|
-
"path": {
|
|
47
|
-
"type": "string",
|
|
48
|
-
"description": "Normalized relative path"
|
|
49
|
-
},
|
|
50
|
-
"role": {
|
|
51
|
-
"type": "string",
|
|
52
|
-
"description": "Why this node exists in the system"
|
|
53
|
-
},
|
|
54
|
-
"dependencies": {
|
|
55
|
-
"type": "array",
|
|
56
|
-
"items": { "type": "string" }
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
"edges": {
|
|
62
|
-
"type": "array",
|
|
63
|
-
"items": {
|
|
64
|
-
"type": "object",
|
|
65
|
-
"required": ["from", "to", "relation"],
|
|
66
|
-
"properties": {
|
|
67
|
-
"from": { "type": "string" },
|
|
68
|
-
"to": { "type": "string" },
|
|
69
|
-
"relation": {
|
|
70
|
-
"type": "string",
|
|
71
|
-
"enum": ["imports", "calls", "owns", "depends_on"]
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
"metrics": {
|
|
77
|
-
"type": "object",
|
|
78
|
-
"description": "System-wide aggregate metrics",
|
|
79
|
-
"additionalProperties": {
|
|
80
|
-
"type": ["number", "string"]
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|