arcvision 0.2.17 → 0.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.arcvision/logs/errors.log +7 -0
- package/arcvision_context/architecture.authority.ledger.json +6 -63
- package/bin/arcvision.js +12 -0
- package/package.json +3 -2
- package/src/arcvision-guard.js +17 -17
- package/src/core/artifact-manager.js +131 -0
- package/src/core/command-base.js +107 -0
- package/src/core/config-validator.js +192 -0
- package/src/core/context_builder.js +3 -2
- package/src/core/error-handler.js +106 -0
- package/src/core/feature-manager.js +232 -0
- package/src/core/feedback-generator.js +260 -0
- package/src/core/invariant-analyzer.js +22 -2
- package/src/core/invariant-detector.js +254 -3
- package/src/core/parser.js +85 -1
- package/src/core/scanner.js +20 -7
- package/src/engine/context_builder.js +21 -3
- package/src/engine/context_validator.js +7 -1
- package/src/engine/pass1_facts.js +2 -2
- package/src/index.js +79 -21
- package/test-block-functionality.js +40 -0
- package/test-dev-project/.arcvision/invariants.json +19 -0
- package/{arcvision_context → test-dev-project/arcvision_context}/README.md +9 -9
- package/test-dev-project/arcvision_context/architecture.authority.ledger.json +45 -0
- package/{arcvision.context.json → test-dev-project/arcvision_context/arcvision.context.json} +498 -496
- package/test-dev-project/src/core/data-service.js +0 -0
- package/test-dev-project/src/ui/user-profile.js +0 -0
- package/test-dev-project/src/utils/helpers.js +0 -0
- package/ARCVISION_DIRECTORY_STRUCTURE.md +0 -104
- package/CLI_STRUCTURE.md +0 -110
- package/CONFIGURATION.md +0 -119
- package/IMPLEMENTATION_SUMMARY.md +0 -99
- package/README.md +0 -149
- package/architecture.authority.ledger.json +0 -46
- 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 +0 -2181
- package/arcvision.context.v1.json +0 -2163
- package/arcvision.context.v2.json +0 -2173
- package/arcvision_context/arcvision.context.json +0 -6884
- package/debug-cycle-detection.js +0 -56
- package/docs/ENHANCED_ACCURACY_SAFETY_PROTOCOL.md +0 -172
- package/docs/accuracy-enhancement-artifacts/enhanced-validation-config.json +0 -98
- package/docs/acig-robustness-guide.md +0 -164
- package/docs/authoritative-gate-implementation.md +0 -168
- package/docs/blast-radius-implementation.md +0 -76
- package/docs/blast-radius.md +0 -44
- package/docs/cli-strengthening-summary.md +0 -232
- package/docs/invariant-system-summary.md +0 -100
- package/docs/invariant-system.md +0 -112
- package/generate_large_test.js +0 -42
- package/large_test_repo.json +0 -1
- package/output1.json +0 -2163
- package/output2.json +0 -2163
- 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/temp_original.js +0 -0
- package/test/determinism-test.js +0 -83
- package/test-authoritative-context.js +0 -53
- package/test-real-authoritative-context.js +0 -118
- package/test-upload-enhancements.js +0 -111
- package/verify_engine.js +0 -116
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{"timestamp":"2026-01-25T01:45:35.206Z","error":{"category":"UNKNOWN","message":"Missing required artifacts: arcvision_context/arcvision.context.json","code":null,"type":"Error"},"context":{"operation":"scan","directory":"C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\test-dev-project"},"stack":"Error: Missing required artifacts: arcvision_context/arcvision.context.json\n at ArtifactManager.validateArtifacts (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\artifact-manager.js:87:13)\n at ArtifactManager.ensureArtifacts (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\artifact-manager.js:26:10)\n at Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:413:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}
|
|
2
|
+
{"timestamp":"2026-01-25T01:53:22.074Z","error":{"category":"UNKNOWN","message":"Missing required artifacts: arcvision_context/arcvision.context.json","code":null,"type":"Error"},"context":{"operation":"scan","directory":"C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\test-dev-project"},"stack":"Error: Missing required artifacts: arcvision_context/arcvision.context.json\n at ArtifactManager.validateArtifacts (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\artifact-manager.js:87:13)\n at ArtifactManager.ensureArtifacts (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\artifact-manager.js:26:10)\n at Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:413:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}
|
|
3
|
+
{"timestamp":"2026-01-25T02:04:57.719Z","error":{"category":"UNKNOWN","message":"Invalid ledger structure","code":null,"type":"Error"},"context":{"operation":"evaluate","directory":"C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\test-dev-project"},"stack":"Error: Invalid ledger structure\n at AuthorityLedger.readLedger (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:203:15)\n at AuthorityLedger.appendEvent (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:176:27)\n at AuthorityLedger.recordBlocked (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:81:10)\n at Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:662:35)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}
|
|
4
|
+
{"timestamp":"2026-01-25T02:05:38.566Z","error":{"category":"UNKNOWN","message":"Invalid ledger structure","code":null,"type":"Error"},"context":{"operation":"evaluate","directory":"C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\test-dev-project"},"stack":"Error: Invalid ledger structure\n at AuthorityLedger.readLedger (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:203:15)\n at AuthorityLedger.appendEvent (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:176:27)\n at AuthorityLedger.recordBlocked (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\authority-ledger.js:81:10)\n at Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:662:35)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}
|
|
5
|
+
{"timestamp":"2026-01-25T03:16:17.596Z","error":{"category":"CONFIGURATION","message":"Invalid or revoked token","code":null,"type":"Error"},"context":{"operation":"standard_upload"},"stack":"Error: Invalid or revoked token\n at C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:330:19\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async RetryHandler.executeWithRetry (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\retry-handler.js:23:24)\n at async uploadToDatabase (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:294:24)\n at async Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:462:9)"}
|
|
6
|
+
{"timestamp":"2026-01-25T10:28:14.750Z","error":{"category":"UNKNOWN","message":"Failed to initiate upload session","code":null,"type":"Error"},"context":{"operation":"chunked_upload"},"stack":"Error: Failed to initiate upload session\n at ChunkedUploader.uploadInChunks (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\chunked-uploader.js:58:13)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:177:18\n at async RetryHandler.executeWithRetry (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\retry-handler.js:23:24)\n at async uploadToDatabase (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:176:24)\n at async Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:473:9)"}
|
|
7
|
+
{"timestamp":"2026-01-25T14:09:23.628Z","error":{"category":"CONFIGURATION","message":"Invalid or revoked token","code":null,"type":"Error"},"context":{"operation":"standard_upload"},"stack":"Error: Invalid or revoked token\n at C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:341:19\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async RetryHandler.executeWithRetry (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\core\\retry-handler.js:23:24)\n at async uploadToDatabase (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:294:24)\n at async Command.<anonymous> (C:\\Users\\AHMAD RAZA\\Downloads\\ArcVision\\cli\\src\\index.js:473:9)"}
|
|
@@ -1,77 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "1.0",
|
|
3
3
|
"system_id": "cli",
|
|
4
|
-
"created_at": "2026-01-
|
|
4
|
+
"created_at": "2026-01-25T01:42:21.875Z",
|
|
5
5
|
"ledger": [
|
|
6
6
|
{
|
|
7
|
-
"event_id": "
|
|
8
|
-
"timestamp": "2026-01-
|
|
7
|
+
"event_id": "evt_1769306597736_165d6ogio",
|
|
8
|
+
"timestamp": "2026-01-25T02:03:17.736Z",
|
|
9
9
|
"decision": "BLOCKED",
|
|
10
10
|
"commit": "HEAD",
|
|
11
11
|
"branch": "unknown",
|
|
12
12
|
"author": "unknown",
|
|
13
13
|
"violations": [
|
|
14
14
|
{
|
|
15
|
-
"id": "no-
|
|
16
|
-
"description": "
|
|
17
|
-
"system": "
|
|
18
|
-
"severity": "block"
|
|
19
|
-
}
|
|
20
|
-
],
|
|
21
|
-
"blast_radius": 0,
|
|
22
|
-
"affected_nodes": 0,
|
|
23
|
-
"override": false
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"event_id": "evt_1769074540287_n0z3a3fy3",
|
|
27
|
-
"timestamp": "2026-01-22T09:35:40.287Z",
|
|
28
|
-
"decision": "BLOCKED",
|
|
29
|
-
"commit": "HEAD",
|
|
30
|
-
"branch": "unknown",
|
|
31
|
-
"author": "unknown",
|
|
32
|
-
"violations": [
|
|
33
|
-
{
|
|
34
|
-
"id": "no-circular-dependencies",
|
|
35
|
-
"description": "Circular dependencies between modules are forbidden",
|
|
36
|
-
"system": "blocked-legacy-monolith",
|
|
37
|
-
"severity": "block"
|
|
38
|
-
}
|
|
39
|
-
],
|
|
40
|
-
"blast_radius": 0,
|
|
41
|
-
"affected_nodes": 0,
|
|
42
|
-
"override": false
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"event_id": "evt_1769074680315_phm7zyzp4",
|
|
46
|
-
"timestamp": "2026-01-22T09:38:00.315Z",
|
|
47
|
-
"decision": "BLOCKED",
|
|
48
|
-
"commit": "HEAD",
|
|
49
|
-
"branch": "unknown",
|
|
50
|
-
"author": "unknown",
|
|
51
|
-
"violations": [
|
|
52
|
-
{
|
|
53
|
-
"id": "no-circular-dependencies",
|
|
54
|
-
"description": "Circular dependencies between modules are forbidden",
|
|
55
|
-
"system": "blocked-legacy-monolith",
|
|
56
|
-
"severity": "block"
|
|
57
|
-
}
|
|
58
|
-
],
|
|
59
|
-
"blast_radius": 0,
|
|
60
|
-
"affected_nodes": 0,
|
|
61
|
-
"override": false
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
"event_id": "evt_1769089584032_49cj329l0",
|
|
65
|
-
"timestamp": "2026-01-22T13:46:24.032Z",
|
|
66
|
-
"decision": "BLOCKED",
|
|
67
|
-
"commit": "HEAD",
|
|
68
|
-
"branch": "unknown",
|
|
69
|
-
"author": "unknown",
|
|
70
|
-
"violations": [
|
|
71
|
-
{
|
|
72
|
-
"id": "no-circular-dependencies",
|
|
73
|
-
"description": "Circular dependencies between modules are forbidden",
|
|
74
|
-
"system": "blocked-legacy-monolith",
|
|
15
|
+
"id": "no-ui-imports-core",
|
|
16
|
+
"description": "UI components should not import from core modules",
|
|
17
|
+
"system": "layering",
|
|
75
18
|
"severity": "block"
|
|
76
19
|
}
|
|
77
20
|
],
|
package/bin/arcvision.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// ArcVision CLI Entry Point
|
|
4
|
+
// This file serves as the executable binary for the ArcVision CLI
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
// Require the main CLI module
|
|
8
|
+
require('../src/index.js');
|
|
9
|
+
} catch (error) {
|
|
10
|
+
console.error('Failed to start ArcVision CLI:', error.message);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arcvision",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.21",
|
|
4
4
|
"description": "ArcVision CLI - Architectural Governance and Invariant Detection Tool",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"arcvision": "
|
|
7
|
+
"arcvision": "./bin/arcvision.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node src/index.js",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"@babel/parser": "^7.24.0",
|
|
29
29
|
"@babel/traverse": "^7.24.0",
|
|
30
30
|
"ajv": "^8.12.0",
|
|
31
|
+
"ajv-formats": "^3.0.1",
|
|
31
32
|
"chalk": "^4.1.2",
|
|
32
33
|
"commander": "^9.4.1",
|
|
33
34
|
"fast-glob": "^3.2.12",
|
package/src/arcvision-guard.js
CHANGED
|
@@ -206,11 +206,17 @@ program
|
|
|
206
206
|
fs.mkdirSync(tokensDir, { recursive: true });
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
//
|
|
210
|
-
const
|
|
211
|
-
if (fs.existsSync(
|
|
212
|
-
|
|
213
|
-
|
|
209
|
+
// Create default configuration (no longer using separate invariants file as they're stored in context)
|
|
210
|
+
const configPath = path.join(arcDir, 'config.json');
|
|
211
|
+
if (!fs.existsSync(configPath)) {
|
|
212
|
+
const defaultConfig = {
|
|
213
|
+
guard_rules: {
|
|
214
|
+
blast_radius: {
|
|
215
|
+
critical_threshold: 50
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
|
|
214
220
|
console.log(chalk.green('✅ Configuration files created'));
|
|
215
221
|
}
|
|
216
222
|
|
|
@@ -223,7 +229,7 @@ program
|
|
|
223
229
|
console.log(chalk.green('\n🎉 ArcVision Impact Guard initialized successfully!'));
|
|
224
230
|
console.log(chalk.yellow('\nNext steps:'));
|
|
225
231
|
console.log(chalk.yellow('1. Review .arcvision/config.json for project settings'));
|
|
226
|
-
console.log(chalk.yellow('2.
|
|
232
|
+
console.log(chalk.yellow('2. Auto-detect architectural invariants by running: arcvision scan'));
|
|
227
233
|
console.log(chalk.yellow('3. Run: arcvision-guard check'));
|
|
228
234
|
console.log(chalk.yellow('4. For critical changes: arcvision-guard bypass-request --reason "your reason"'));
|
|
229
235
|
});
|
|
@@ -246,17 +252,11 @@ program
|
|
|
246
252
|
remediation: "Define appropriate remediation steps"
|
|
247
253
|
};
|
|
248
254
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const invariants = JSON.parse(fs.readFileSync(invariantsPath, 'utf8'));
|
|
256
|
-
invariants.project_specific_invariants.push(invariant);
|
|
257
|
-
|
|
258
|
-
fs.writeFileSync(invariantsPath, JSON.stringify(invariants, null, 2));
|
|
259
|
-
console.log(chalk.green(`✅ Added invariant: ${name}`));
|
|
255
|
+
// Note: Invariants are now automatically detected by scanning and stored in arcvision.context.json
|
|
256
|
+
console.log(chalk.red('❌ Custom invariants are now managed differently.'));
|
|
257
|
+
console.log(chalk.yellow('💡 Run "arcvision scan" to auto-detect invariants from your codebase.'));
|
|
258
|
+
console.log(chalk.yellow('💡 Or manually edit the invariants section in arcvision_context/arcvision.context.json if needed.'));
|
|
259
|
+
process.exit(1);
|
|
260
260
|
});
|
|
261
261
|
|
|
262
262
|
// Helper functions
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
class ArtifactManager {
|
|
5
|
+
constructor(projectRoot) {
|
|
6
|
+
this.projectRoot = projectRoot;
|
|
7
|
+
// Remove .arcvision directory as invariants should be in main context file only
|
|
8
|
+
this.requiredDirs = ['arcvision_context'];
|
|
9
|
+
this.requiredFiles = {
|
|
10
|
+
context: 'arcvision_context/arcvision.context.json',
|
|
11
|
+
ledger: 'arcvision_context/architecture.authority.ledger.json'
|
|
12
|
+
// Remove invariants from separate file as they should be in main context per schema
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Ensures all required artifacts exist with proper structure
|
|
18
|
+
*/
|
|
19
|
+
ensureArtifacts() {
|
|
20
|
+
// Create required directories
|
|
21
|
+
this.createDirectories();
|
|
22
|
+
|
|
23
|
+
// Create required files with defaults if missing
|
|
24
|
+
this.createMissingFiles();
|
|
25
|
+
|
|
26
|
+
// Validate artifact integrity (excluding context file which is created by scanner)
|
|
27
|
+
this.validateArtifactsExceptContext();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates required directories if they don't exist
|
|
32
|
+
*/
|
|
33
|
+
createDirectories() {
|
|
34
|
+
this.requiredDirs.forEach(dir => {
|
|
35
|
+
const fullPath = path.join(this.projectRoot, dir);
|
|
36
|
+
if (!fs.existsSync(fullPath)) {
|
|
37
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
38
|
+
this.logCreation(dir);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Creates missing files with default content
|
|
45
|
+
*/
|
|
46
|
+
createMissingFiles() {
|
|
47
|
+
// Create default ledger if missing
|
|
48
|
+
const ledgerPath = path.join(this.projectRoot, this.requiredFiles.ledger);
|
|
49
|
+
if (!fs.existsSync(ledgerPath)) {
|
|
50
|
+
const defaultLedger = {
|
|
51
|
+
schema_version: '1.0',
|
|
52
|
+
system_id: path.basename(this.projectRoot),
|
|
53
|
+
created_at: new Date().toISOString(),
|
|
54
|
+
ledger: []
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
fs.writeFileSync(ledgerPath, JSON.stringify(defaultLedger, null, 2));
|
|
58
|
+
this.logCreation(this.requiredFiles.ledger);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Validates that all required artifacts exist and are accessible
|
|
64
|
+
*/
|
|
65
|
+
validateArtifacts() {
|
|
66
|
+
const missingArtifacts = [];
|
|
67
|
+
|
|
68
|
+
Object.entries(this.requiredFiles).forEach(([name, relativePath]) => {
|
|
69
|
+
const fullPath = path.join(this.projectRoot, relativePath);
|
|
70
|
+
if (!fs.existsSync(fullPath)) {
|
|
71
|
+
missingArtifacts.push(relativePath);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (missingArtifacts.length > 0) {
|
|
76
|
+
throw new Error(`Missing required artifacts: ${missingArtifacts.join(', ')}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Validates artifacts except context file (which is created by scanner)
|
|
82
|
+
*/
|
|
83
|
+
validateArtifactsExceptContext() {
|
|
84
|
+
const missingArtifacts = [];
|
|
85
|
+
|
|
86
|
+
Object.entries(this.requiredFiles).forEach(([name, relativePath]) => {
|
|
87
|
+
// Skip context file validation as it's created by scanner
|
|
88
|
+
if (name === 'context') return;
|
|
89
|
+
|
|
90
|
+
const fullPath = path.join(this.projectRoot, relativePath);
|
|
91
|
+
if (!fs.existsSync(fullPath)) {
|
|
92
|
+
missingArtifacts.push(relativePath);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (missingArtifacts.length > 0) {
|
|
97
|
+
throw new Error(`Missing required artifacts: ${missingArtifacts.join(', ')}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Checks if artifacts exist
|
|
103
|
+
*/
|
|
104
|
+
artifactsExist() {
|
|
105
|
+
try {
|
|
106
|
+
this.validateArtifacts();
|
|
107
|
+
return true;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Gets the path for a specific artifact
|
|
115
|
+
*/
|
|
116
|
+
getArtifactPath(artifactName) {
|
|
117
|
+
if (this.requiredFiles[artifactName]) {
|
|
118
|
+
return path.join(this.projectRoot, this.requiredFiles[artifactName]);
|
|
119
|
+
}
|
|
120
|
+
throw new Error(`Unknown artifact: ${artifactName}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Logs artifact creation
|
|
125
|
+
*/
|
|
126
|
+
logCreation(artifact) {
|
|
127
|
+
console.log(`📁 Created required artifact: ${artifact}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = { ArtifactManager };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
class ArcVisionCommand {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options || {};
|
|
6
|
+
this.projectRoot = options.projectRoot || '.';
|
|
7
|
+
this.operation = options.operation || 'unknown';
|
|
8
|
+
|
|
9
|
+
// Initialize core components
|
|
10
|
+
const { ArtifactManager } = require('./artifact-manager');
|
|
11
|
+
const { ErrorHandler } = require('./error-handler');
|
|
12
|
+
const { ConfigValidator } = require('./config-validator');
|
|
13
|
+
const { FeatureManager } = require('./feature-manager');
|
|
14
|
+
const { FeedbackGenerator } = require('./feedback-generator');
|
|
15
|
+
|
|
16
|
+
this.artifactManager = new ArtifactManager(this.projectRoot);
|
|
17
|
+
this.errorHandler = ErrorHandler;
|
|
18
|
+
this.validator = ConfigValidator;
|
|
19
|
+
this.featureManager = FeatureManager;
|
|
20
|
+
this.feedbackGenerator = FeedbackGenerator;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Execute the command with standardized flow
|
|
25
|
+
*/
|
|
26
|
+
async execute() {
|
|
27
|
+
try {
|
|
28
|
+
// Pre-execution validation
|
|
29
|
+
await this.validate();
|
|
30
|
+
|
|
31
|
+
// Ensure required artifacts exist
|
|
32
|
+
this.artifactManager.ensureArtifacts();
|
|
33
|
+
|
|
34
|
+
// Execute command-specific logic
|
|
35
|
+
const result = await this.run();
|
|
36
|
+
|
|
37
|
+
// Generate feedback based on result
|
|
38
|
+
const feedback = this.generateFeedback(result);
|
|
39
|
+
|
|
40
|
+
// Return comprehensive result
|
|
41
|
+
return {
|
|
42
|
+
success: true,
|
|
43
|
+
result,
|
|
44
|
+
feedback,
|
|
45
|
+
operation: this.operation
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
} catch (error) {
|
|
49
|
+
// Handle error with standardized approach
|
|
50
|
+
return this.errorHandler.handle(error, this.operation);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Validate command-specific requirements
|
|
56
|
+
*/
|
|
57
|
+
async validate() {
|
|
58
|
+
// Command-specific validation - to be implemented by subclasses
|
|
59
|
+
throw new Error('Must implement validate() method');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Execute command-specific logic
|
|
64
|
+
*/
|
|
65
|
+
async run() {
|
|
66
|
+
// Command-specific execution - to be implemented by subclasses
|
|
67
|
+
throw new Error('Must implement run() method');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Generate command-specific feedback
|
|
72
|
+
*/
|
|
73
|
+
generateFeedback(result) {
|
|
74
|
+
// Command-specific feedback generation - to be implemented by subclasses
|
|
75
|
+
throw new Error('Must implement generateFeedback() method');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get current feature availability
|
|
80
|
+
*/
|
|
81
|
+
getAvailableFeatures() {
|
|
82
|
+
return this.featureManager.getAvailableFeatures(this.projectRoot);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get recommendations for this project
|
|
87
|
+
*/
|
|
88
|
+
getRecommendations() {
|
|
89
|
+
return this.featureManager.getRecommendations(this.projectRoot);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get next steps for this project
|
|
94
|
+
*/
|
|
95
|
+
getNextSteps() {
|
|
96
|
+
return this.featureManager.getNextSteps(this.projectRoot);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Generate user report
|
|
101
|
+
*/
|
|
102
|
+
generateUserReport() {
|
|
103
|
+
return this.featureManager.generateUserReport(this.projectRoot);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = { ArcVisionCommand };
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
class ConfigValidator {
|
|
5
|
+
/**
|
|
6
|
+
* Validates that the project has the required ArcVision artifacts
|
|
7
|
+
*/
|
|
8
|
+
static validateProjectStructure(projectPath) {
|
|
9
|
+
const requiredPaths = [
|
|
10
|
+
path.join(projectPath, 'arcvision_context')
|
|
11
|
+
// Removed .arcvision as invariants are now stored in main context file
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const optionalPaths = [
|
|
15
|
+
path.join(projectPath, 'arcvision_context', 'arcvision.context.json'),
|
|
16
|
+
// Removed .arcvision/invariants.json as invariants are now stored in main context file
|
|
17
|
+
path.join(projectPath, 'arcvision_context', 'architecture.authority.ledger.json')
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const validation = {
|
|
21
|
+
isValid: true,
|
|
22
|
+
errors: [],
|
|
23
|
+
warnings: [],
|
|
24
|
+
requiredPaths: {},
|
|
25
|
+
optionalPaths: {}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Validate required paths exist
|
|
29
|
+
requiredPaths.forEach(requiredPath => {
|
|
30
|
+
const exists = fs.existsSync(requiredPath);
|
|
31
|
+
validation.requiredPaths[requiredPath] = exists;
|
|
32
|
+
if (!exists) {
|
|
33
|
+
validation.isValid = false;
|
|
34
|
+
validation.errors.push(`Required path does not exist: ${requiredPath}`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Check optional paths
|
|
39
|
+
optionalPaths.forEach(optionalPath => {
|
|
40
|
+
const exists = fs.existsSync(optionalPath);
|
|
41
|
+
validation.optionalPaths[optionalPath] = exists;
|
|
42
|
+
if (!exists) {
|
|
43
|
+
validation.warnings.push(`Optional path does not exist: ${optionalPath}`);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return validation;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Validates invariant file structure
|
|
52
|
+
*/
|
|
53
|
+
static validateInvariantsFile(filePath) {
|
|
54
|
+
if (!fs.existsSync(filePath)) {
|
|
55
|
+
return {
|
|
56
|
+
isValid: false,
|
|
57
|
+
error: 'File does not exist'
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
63
|
+
const data = JSON.parse(content);
|
|
64
|
+
|
|
65
|
+
const validation = {
|
|
66
|
+
isValid: true,
|
|
67
|
+
errors: []
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Check for required structure
|
|
71
|
+
if (!data.project_specific_invariants) {
|
|
72
|
+
validation.isValid = false;
|
|
73
|
+
validation.errors.push('Missing project_specific_invariants array');
|
|
74
|
+
} else if (!Array.isArray(data.project_specific_invariants)) {
|
|
75
|
+
validation.isValid = false;
|
|
76
|
+
validation.errors.push('project_specific_invariants must be an array');
|
|
77
|
+
} else {
|
|
78
|
+
// Validate each invariant
|
|
79
|
+
data.project_specific_invariants.forEach((invariant, index) => {
|
|
80
|
+
if (!invariant.id) {
|
|
81
|
+
validation.errors.push(`Invariant at index ${index} missing id`);
|
|
82
|
+
}
|
|
83
|
+
if (!invariant.system) {
|
|
84
|
+
validation.errors.push(`Invariant at index ${index} missing system`);
|
|
85
|
+
}
|
|
86
|
+
if (!invariant.description) {
|
|
87
|
+
validation.errors.push(`Invariant at index ${index} missing description`);
|
|
88
|
+
}
|
|
89
|
+
if (!invariant.severity || !['block', 'risk'].includes(invariant.severity)) {
|
|
90
|
+
validation.errors.push(`Invariant at index ${index} has invalid severity (must be 'block' or 'risk')`);
|
|
91
|
+
}
|
|
92
|
+
if (!invariant.scope) {
|
|
93
|
+
validation.errors.push(`Invariant at index ${index} missing scope`);
|
|
94
|
+
}
|
|
95
|
+
if (!invariant.rule) {
|
|
96
|
+
validation.errors.push(`Invariant at index ${index} missing rule`);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (validation.errors.length > 0) {
|
|
102
|
+
validation.isValid = false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return validation;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
return {
|
|
108
|
+
isValid: false,
|
|
109
|
+
error: `Invalid JSON: ${error.message}`
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Validates context file structure
|
|
116
|
+
*/
|
|
117
|
+
static validateContextFile(filePath) {
|
|
118
|
+
if (!fs.existsSync(filePath)) {
|
|
119
|
+
return {
|
|
120
|
+
isValid: false,
|
|
121
|
+
error: 'File does not exist'
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
127
|
+
const data = JSON.parse(content);
|
|
128
|
+
|
|
129
|
+
const validation = {
|
|
130
|
+
isValid: true,
|
|
131
|
+
errors: []
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Basic structure validation
|
|
135
|
+
if (!data.schema_version) {
|
|
136
|
+
validation.errors.push('Missing schema_version');
|
|
137
|
+
}
|
|
138
|
+
if (!data.nodes) {
|
|
139
|
+
validation.errors.push('Missing nodes array');
|
|
140
|
+
}
|
|
141
|
+
if (!Array.isArray(data.nodes)) {
|
|
142
|
+
validation.errors.push('nodes must be an array');
|
|
143
|
+
}
|
|
144
|
+
if (!data.edges) {
|
|
145
|
+
validation.errors.push('Missing edges array');
|
|
146
|
+
}
|
|
147
|
+
if (!Array.isArray(data.edges)) {
|
|
148
|
+
validation.errors.push('edges must be an array');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (validation.errors.length > 0) {
|
|
152
|
+
validation.isValid = false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return validation;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
isValid: false,
|
|
159
|
+
error: `Invalid JSON: ${error.message}`
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Validates the entire ArcVision configuration
|
|
166
|
+
*/
|
|
167
|
+
static validateConfiguration(projectPath) {
|
|
168
|
+
const projectValidation = this.validateProjectStructure(projectPath);
|
|
169
|
+
|
|
170
|
+
const configValidation = {
|
|
171
|
+
projectStructure: projectValidation,
|
|
172
|
+
invariantsFile: null,
|
|
173
|
+
contextFile: null,
|
|
174
|
+
isValid: projectValidation.isValid
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// No longer validating separate invariants file as they are stored in main context file
|
|
178
|
+
|
|
179
|
+
// Validate context file if it exists
|
|
180
|
+
const contextPath = path.join(projectPath, 'arcvision_context', 'arcvision.context.json');
|
|
181
|
+
if (fs.existsSync(contextPath)) {
|
|
182
|
+
configValidation.contextFile = this.validateContextFile(contextPath);
|
|
183
|
+
if (!configValidation.contextFile.isValid) {
|
|
184
|
+
configValidation.isValid = false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return configValidation;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = { ConfigValidator };
|
|
@@ -190,8 +190,9 @@ function buildContext(fileNodes, edges, symbols, options = {}) {
|
|
|
190
190
|
structural_hubs: options.structuralHubs || [],
|
|
191
191
|
architectural_boundaries: options.architecturalBoundaries || {},
|
|
192
192
|
structural_invariants: options.structuralInvariants || [],
|
|
193
|
-
// Include detected invariants from the current scan
|
|
194
|
-
invariants: options.
|
|
193
|
+
// Include detected invariants from the current scan - these should conform to the schema specification
|
|
194
|
+
invariants: Array.isArray(options.autoDetectedInvariants) ? options.autoDetectedInvariants :
|
|
195
|
+
Array.isArray(options.detectedInvariants) ? options.detectedInvariants : [],
|
|
195
196
|
// Include invariant analysis results
|
|
196
197
|
invariant_analysis: options.invariantAnalysis || null,
|
|
197
198
|
// Include architectural health assessment
|