arcvision 0.2.17 → 0.2.20
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 +5 -0
- package/arcvision_context/architecture.authority.ledger.json +6 -63
- package/bin/arcvision.js +12 -0
- package/package.json +3 -2
- package/src/core/artifact-manager.js +143 -0
- package/src/core/command-base.js +107 -0
- package/src/core/config-validator.js +199 -0
- package/src/core/error-handler.js +106 -0
- package/src/core/feature-manager.js +218 -0
- package/src/core/feedback-generator.js +260 -0
- package/src/core/invariant-analyzer.js +22 -2
- package/src/core/invariant-detector.js +236 -3
- package/src/core/parser.js +85 -1
- package/src/core/scanner.js +18 -6
- 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 +41 -13
- 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,218 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
class FeatureManager {
|
|
5
|
+
/**
|
|
6
|
+
* Determines which ArcVision features are available based on existing artifacts
|
|
7
|
+
*/
|
|
8
|
+
static getAvailableFeatures(projectPath) {
|
|
9
|
+
const artifacts = this.checkArtifacts(projectPath);
|
|
10
|
+
|
|
11
|
+
const features = {
|
|
12
|
+
basic_analysis: artifacts.context_exists,
|
|
13
|
+
invariant_checking: artifacts.invariants_exists,
|
|
14
|
+
authority_governance: artifacts.ledger_exists,
|
|
15
|
+
advanced_reporting: artifacts.readme_exists,
|
|
16
|
+
context_visualization: artifacts.context_exists,
|
|
17
|
+
architectural_health: artifacts.context_exists && artifacts.invariants_exists
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
available: Object.entries(features)
|
|
22
|
+
.filter(([_, available]) => available)
|
|
23
|
+
.map(([feature, _]) => feature),
|
|
24
|
+
all: features,
|
|
25
|
+
artifacts: artifacts
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Checks for the presence of key artifacts
|
|
31
|
+
*/
|
|
32
|
+
static checkArtifacts(projectPath) {
|
|
33
|
+
return {
|
|
34
|
+
context_exists: fs.existsSync(path.join(projectPath, 'arcvision_context', 'arcvision.context.json')),
|
|
35
|
+
invariants_exists: fs.existsSync(path.join(projectPath, '.arcvision', 'invariants.json')),
|
|
36
|
+
ledger_exists: fs.existsSync(path.join(projectPath, 'arcvision_context', 'architecture.authority.ledger.json')),
|
|
37
|
+
readme_exists: fs.existsSync(path.join(projectPath, 'arcvision_context', 'README.md')),
|
|
38
|
+
arcvision_dir_exists: fs.existsSync(path.join(projectPath, '.arcvision')),
|
|
39
|
+
context_dir_exists: fs.existsSync(path.join(projectPath, 'arcvision_context'))
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Generates recommendations based on missing features
|
|
45
|
+
*/
|
|
46
|
+
static getRecommendations(projectPath) {
|
|
47
|
+
const artifacts = this.checkArtifacts(projectPath);
|
|
48
|
+
const recommendations = [];
|
|
49
|
+
|
|
50
|
+
if (!artifacts.invariants_exists) {
|
|
51
|
+
recommendations.push({
|
|
52
|
+
type: 'SETUP',
|
|
53
|
+
priority: 'HIGH',
|
|
54
|
+
message: 'Define architectural invariants for governance',
|
|
55
|
+
action: 'arcvision init-invariants',
|
|
56
|
+
description: 'Create custom rules to govern your architectural decisions'
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!artifacts.context_exists) {
|
|
61
|
+
recommendations.push({
|
|
62
|
+
type: 'ANALYSIS',
|
|
63
|
+
priority: 'HIGH',
|
|
64
|
+
message: 'Generate structural context',
|
|
65
|
+
action: 'arcvision scan',
|
|
66
|
+
description: 'Analyze your codebase to understand its structure'
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!artifacts.ledger_exists) {
|
|
71
|
+
recommendations.push({
|
|
72
|
+
type: 'GOVERNANCE',
|
|
73
|
+
priority: 'MEDIUM',
|
|
74
|
+
message: 'Enable authority ledger',
|
|
75
|
+
action: 'arcvision acig',
|
|
76
|
+
description: 'Track architectural decisions and violations'
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!artifacts.readme_exists) {
|
|
81
|
+
recommendations.push({
|
|
82
|
+
type: 'DOCUMENTATION',
|
|
83
|
+
priority: 'LOW',
|
|
84
|
+
message: 'Generate documentation',
|
|
85
|
+
action: 'arcvision scan',
|
|
86
|
+
description: 'Create contextual documentation for your architecture'
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return recommendations;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Generates next steps for users
|
|
95
|
+
*/
|
|
96
|
+
static getNextSteps(projectPath) {
|
|
97
|
+
const features = this.getAvailableFeatures(projectPath);
|
|
98
|
+
const recommendations = this.getRecommendations(projectPath);
|
|
99
|
+
|
|
100
|
+
const steps = [];
|
|
101
|
+
|
|
102
|
+
if (features.available.length === 0) {
|
|
103
|
+
steps.push({
|
|
104
|
+
order: 1,
|
|
105
|
+
action: 'arcvision scan',
|
|
106
|
+
description: 'Start by scanning your project to generate structural context'
|
|
107
|
+
});
|
|
108
|
+
} else if (!features.all.invariant_checking) {
|
|
109
|
+
steps.push({
|
|
110
|
+
order: 1,
|
|
111
|
+
action: 'arcvision init-invariants',
|
|
112
|
+
description: 'Create invariants to govern your architecture'
|
|
113
|
+
});
|
|
114
|
+
steps.push({
|
|
115
|
+
order: 2,
|
|
116
|
+
action: 'arcvision acig',
|
|
117
|
+
description: 'Evaluate your code against the defined invariants'
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
steps.push({
|
|
121
|
+
order: 1,
|
|
122
|
+
action: 'arcvision acig',
|
|
123
|
+
description: 'Check your code against defined architectural invariants'
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return steps;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Gets feature status summary
|
|
132
|
+
*/
|
|
133
|
+
static getStatusSummary(projectPath) {
|
|
134
|
+
const features = this.getAvailableFeatures(projectPath);
|
|
135
|
+
const recommendations = this.getRecommendations(projectPath);
|
|
136
|
+
const artifacts = this.checkArtifacts(projectPath);
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
projectPath,
|
|
140
|
+
featureCount: features.available.length,
|
|
141
|
+
availableFeatures: features.available,
|
|
142
|
+
missingFeatures: Object.entries(features.all)
|
|
143
|
+
.filter(([_, available]) => !available)
|
|
144
|
+
.map(([feature, _]) => feature),
|
|
145
|
+
recommendations: recommendations,
|
|
146
|
+
artifacts: artifacts,
|
|
147
|
+
readinessLevel: this.calculateReadinessLevel(features.available.length),
|
|
148
|
+
nextSteps: this.getNextSteps(projectPath)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Calculates readiness level based on available features
|
|
154
|
+
*/
|
|
155
|
+
static calculateReadinessLevel(featureCount) {
|
|
156
|
+
if (featureCount === 0) return 'STARTER';
|
|
157
|
+
if (featureCount <= 2) return 'BEGINNER';
|
|
158
|
+
if (featureCount <= 4) return 'INTERMEDIATE';
|
|
159
|
+
return 'ADVANCED';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Generates user-friendly report
|
|
164
|
+
*/
|
|
165
|
+
static generateUserReport(projectPath) {
|
|
166
|
+
const status = this.getStatusSummary(projectPath);
|
|
167
|
+
|
|
168
|
+
let report = `🎯 ArcVision Project Status Report\n`;
|
|
169
|
+
report += `====================================\n\n`;
|
|
170
|
+
report += `Project: ${path.basename(projectPath)}\n`;
|
|
171
|
+
report += `Readiness Level: ${status.readinessLevel}\n`;
|
|
172
|
+
report += `Available Features: ${status.featureCount}/6\n\n`;
|
|
173
|
+
|
|
174
|
+
report += `📋 Available Features:\n`;
|
|
175
|
+
status.availableFeatures.forEach(feature => {
|
|
176
|
+
report += ` • ${this.formatFeatureName(feature)}\n`;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
if (status.missingFeatures.length > 0) {
|
|
180
|
+
report += `\n⚠️ Missing Features:\n`;
|
|
181
|
+
status.missingFeatures.forEach(feature => {
|
|
182
|
+
report += ` • ${this.formatFeatureName(feature)}\n`;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (status.recommendations.length > 0) {
|
|
187
|
+
report += `\n💡 Recommendations:\n`;
|
|
188
|
+
status.recommendations.forEach(rec => {
|
|
189
|
+
report += ` • [${rec.priority}] ${rec.message}\n`;
|
|
190
|
+
report += ` Run: ${rec.action}\n`;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
report += `\n🚀 Next Steps:\n`;
|
|
195
|
+
status.nextSteps.forEach(step => {
|
|
196
|
+
report += ` ${step.order}. ${step.action}\n ${step.description}\n`;
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
return report;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Formats feature names for display
|
|
204
|
+
*/
|
|
205
|
+
static formatFeatureName(feature) {
|
|
206
|
+
const names = {
|
|
207
|
+
'basic_analysis': 'Basic Code Analysis',
|
|
208
|
+
'invariant_checking': 'Invariant Checking',
|
|
209
|
+
'authority_governance': 'Authority Governance',
|
|
210
|
+
'advanced_reporting': 'Advanced Reporting',
|
|
211
|
+
'context_visualization': 'Context Visualization',
|
|
212
|
+
'architectural_health': 'Architectural Health Assessment'
|
|
213
|
+
};
|
|
214
|
+
return names[feature] || feature.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = { FeatureManager };
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
class FeedbackGenerator {
|
|
5
|
+
/**
|
|
6
|
+
* Generates comprehensive scan report with structured feedback
|
|
7
|
+
*/
|
|
8
|
+
static generateScanReport(analysisResults, artifactsCreated, projectPath) {
|
|
9
|
+
const { FeatureManager } = require('./feature-manager');
|
|
10
|
+
const features = FeatureManager.getAvailableFeatures(projectPath);
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
status: 'SUCCESS',
|
|
14
|
+
timestamp: new Date().toISOString(),
|
|
15
|
+
artifacts: {
|
|
16
|
+
created: artifactsCreated,
|
|
17
|
+
existing: analysisResults.existingArtifacts,
|
|
18
|
+
total: artifactsCreated.length + (analysisResults.existingArtifacts?.length || 0)
|
|
19
|
+
},
|
|
20
|
+
analysis: {
|
|
21
|
+
nodes: analysisResults.nodes?.length || 0,
|
|
22
|
+
edges: analysisResults.edges?.length || 0,
|
|
23
|
+
symbols: analysisResults.symbols?.length || 0,
|
|
24
|
+
scanTimeMs: analysisResults.scanTimeMs || 0
|
|
25
|
+
},
|
|
26
|
+
features: features,
|
|
27
|
+
recommendations: this.getRecommendations(analysisResults, projectPath),
|
|
28
|
+
nextSteps: this.getNextSteps(analysisResults, projectPath),
|
|
29
|
+
summary: this.generateSummary(analysisResults, artifactsCreated)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Generates recommendations based on analysis results
|
|
35
|
+
*/
|
|
36
|
+
static getRecommendations(analysisResults, projectPath) {
|
|
37
|
+
const { FeatureManager } = require('./feature-manager');
|
|
38
|
+
const recommendations = FeatureManager.getRecommendations(projectPath);
|
|
39
|
+
|
|
40
|
+
// Add specific analysis-based recommendations
|
|
41
|
+
if (analysisResults.nodes && analysisResults.nodes.length > 100) {
|
|
42
|
+
recommendations.unshift({
|
|
43
|
+
type: 'ARCHITECTURE',
|
|
44
|
+
priority: 'HIGH',
|
|
45
|
+
message: 'Large codebase detected - consider defining architectural invariants',
|
|
46
|
+
action: 'arcvision init-invariants',
|
|
47
|
+
description: 'Protect your architecture as it grows in complexity'
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (analysisResults.edges && analysisResults.edges.length > 0) {
|
|
52
|
+
const avgDependencies = analysisResults.edges.length / (analysisResults.nodes?.length || 1);
|
|
53
|
+
if (avgDependencies > 5) {
|
|
54
|
+
recommendations.push({
|
|
55
|
+
type: 'DEPENDENCY',
|
|
56
|
+
priority: 'MEDIUM',
|
|
57
|
+
message: 'High average dependencies per file detected',
|
|
58
|
+
action: 'arcvision acig',
|
|
59
|
+
description: 'Check for potential architectural violations'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return recommendations;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Generates next steps based on analysis
|
|
69
|
+
*/
|
|
70
|
+
static getNextSteps(analysisResults, projectPath) {
|
|
71
|
+
const { FeatureManager } = require('./feature-manager');
|
|
72
|
+
const baseSteps = FeatureManager.getNextSteps(projectPath);
|
|
73
|
+
|
|
74
|
+
// Add analysis-specific steps
|
|
75
|
+
if (analysisResults.nodes && analysisResults.nodes.length > 0) {
|
|
76
|
+
baseSteps.push({
|
|
77
|
+
order: baseSteps.length + 1,
|
|
78
|
+
action: 'arcvision acig',
|
|
79
|
+
description: 'Evaluate your codebase against architectural invariants'
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return baseSteps;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Generates a summary of the scan results
|
|
88
|
+
*/
|
|
89
|
+
static generateSummary(analysisResults, artifactsCreated) {
|
|
90
|
+
const nodeCount = analysisResults.nodes?.length || 0;
|
|
91
|
+
const edgeCount = analysisResults.edges?.length || 0;
|
|
92
|
+
const symbolCount = analysisResults.symbols?.length || 0;
|
|
93
|
+
|
|
94
|
+
let summary = `Scan completed successfully!\n`;
|
|
95
|
+
summary += `- Analyzed ${nodeCount} files\n`;
|
|
96
|
+
summary += `- Found ${edgeCount} dependencies\n`;
|
|
97
|
+
summary += `- Processed ${symbolCount} symbols\n`;
|
|
98
|
+
summary += `- Created ${artifactsCreated.length} new artifacts\n`;
|
|
99
|
+
|
|
100
|
+
if (nodeCount > 100) {
|
|
101
|
+
summary += `- Large project detected (${nodeCount} files)\n`;
|
|
102
|
+
} else if (nodeCount > 20) {
|
|
103
|
+
summary += `- Medium-sized project detected\n`;
|
|
104
|
+
} else {
|
|
105
|
+
summary += `- Small project detected\n`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return summary;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Generates feedback for ACIG evaluation
|
|
113
|
+
*/
|
|
114
|
+
static generateAcigReport(evaluation, artifactsUsed) {
|
|
115
|
+
const decision = evaluation.decision;
|
|
116
|
+
|
|
117
|
+
let report = {
|
|
118
|
+
decision: decision,
|
|
119
|
+
timestamp: new Date().toISOString(),
|
|
120
|
+
artifacts: artifactsUsed,
|
|
121
|
+
violations: evaluation.violations?.length || 0,
|
|
122
|
+
affectedFiles: evaluation.changedFiles?.length || 0,
|
|
123
|
+
invariantCount: evaluation.invariants?.length || 0,
|
|
124
|
+
message: this.generateAcigMessage(decision, evaluation),
|
|
125
|
+
details: evaluation.details || {}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
return report;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Generates user-friendly message for ACIG decision
|
|
133
|
+
*/
|
|
134
|
+
static generateAcigMessage(decision, evaluation) {
|
|
135
|
+
switch(decision) {
|
|
136
|
+
case 'ALLOWED':
|
|
137
|
+
return '✅ Change allowed - No critical violations detected';
|
|
138
|
+
case 'RISKY':
|
|
139
|
+
return `⚠️ Change is risky - ${evaluation.violations?.length || 0} warnings issued`;
|
|
140
|
+
case 'BLOCKED':
|
|
141
|
+
return `❌ Change blocked - ${evaluation.violations?.length || 0} critical violations detected`;
|
|
142
|
+
default:
|
|
143
|
+
return 'ℹ️ Evaluation completed with neutral result';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Generates structured feedback for CLI commands
|
|
149
|
+
*/
|
|
150
|
+
static generateCliFeedback(command, result, context = {}) {
|
|
151
|
+
const timestamp = new Date().toISOString();
|
|
152
|
+
|
|
153
|
+
switch(command) {
|
|
154
|
+
case 'scan':
|
|
155
|
+
return {
|
|
156
|
+
command: 'scan',
|
|
157
|
+
status: result.success ? 'SUCCESS' : 'FAILURE',
|
|
158
|
+
timestamp,
|
|
159
|
+
details: {
|
|
160
|
+
directory: context.directory,
|
|
161
|
+
filesProcessed: result.analysis?.nodes?.length,
|
|
162
|
+
artifactsCreated: result.artifacts?.created?.length,
|
|
163
|
+
durationMs: result.durationMs
|
|
164
|
+
},
|
|
165
|
+
message: result.success
|
|
166
|
+
? `✅ Scan completed successfully in ${result.durationMs}ms`
|
|
167
|
+
: `❌ Scan failed: ${result.error}`
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
case 'acig':
|
|
171
|
+
return {
|
|
172
|
+
command: 'acig',
|
|
173
|
+
status: result.success ? 'SUCCESS' : 'FAILURE',
|
|
174
|
+
timestamp,
|
|
175
|
+
details: {
|
|
176
|
+
decision: result.decision,
|
|
177
|
+
violations: result.violations?.length,
|
|
178
|
+
filesEvaluated: result.changedFiles?.length
|
|
179
|
+
},
|
|
180
|
+
message: result.success
|
|
181
|
+
? `🔒 ACIG evaluation: ${result.decision}`
|
|
182
|
+
: `❌ ACIG evaluation failed: ${result.error}`
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
default:
|
|
186
|
+
return {
|
|
187
|
+
command,
|
|
188
|
+
status: 'UNKNOWN',
|
|
189
|
+
timestamp,
|
|
190
|
+
message: `Command ${command} executed`
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Generates progress indicators for long-running operations
|
|
197
|
+
*/
|
|
198
|
+
static generateProgressIndicator(current, total, operation = 'Processing') {
|
|
199
|
+
const percentage = Math.round((current / total) * 100);
|
|
200
|
+
const barLength = 30;
|
|
201
|
+
const filledLength = Math.round((current / total) * barLength);
|
|
202
|
+
const bar = '█'.repeat(filledLength) + '░'.repeat(barLength - filledLength);
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
percentage,
|
|
206
|
+
bar,
|
|
207
|
+
message: `${operation}: ${current}/${total} (${percentage}%)`,
|
|
208
|
+
isComplete: current >= total
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Generates error feedback with actionable information
|
|
214
|
+
*/
|
|
215
|
+
static generateErrorFeedback(error, operation, context = {}) {
|
|
216
|
+
return {
|
|
217
|
+
type: 'ERROR',
|
|
218
|
+
operation,
|
|
219
|
+
timestamp: new Date().toISOString(),
|
|
220
|
+
error: {
|
|
221
|
+
message: error.message,
|
|
222
|
+
stack: error.stack,
|
|
223
|
+
name: error.name
|
|
224
|
+
},
|
|
225
|
+
context,
|
|
226
|
+
suggestion: this.getErrorSuggestion(error, operation)
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Provides actionable suggestions for common errors
|
|
232
|
+
*/
|
|
233
|
+
static getErrorSuggestion(error, operation) {
|
|
234
|
+
const message = error.message?.toLowerCase() || '';
|
|
235
|
+
|
|
236
|
+
if (message.includes('no such file') || message.includes('enoent')) {
|
|
237
|
+
return 'Ensure the specified directory exists and contains code files.';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (message.includes('permission') || message.includes('eacces')) {
|
|
241
|
+
return 'Check directory permissions and ensure you have read/write access.';
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (message.includes('memory') || message.includes('heap out of memory')) {
|
|
245
|
+
return 'Try scanning a smaller subset of your project or increase Node.js memory limit.';
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (operation === 'scan' && message.includes('property') && message.includes('undefined')) {
|
|
249
|
+
return 'This may be a parsing issue with certain file types. Try excluding problematic files.';
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (operation === 'acig' && message.includes('invariant')) {
|
|
253
|
+
return 'Check your invariants file (.arcvision/invariants.json) for correct format.';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return 'Review the error message above and check the ArcVision documentation for troubleshooting tips.';
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
module.exports = { FeedbackGenerator };
|
|
@@ -77,7 +77,17 @@ class InvariantAnalyzer {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
if (invariant.scope) {
|
|
80
|
-
|
|
80
|
+
// Handle both old string format and new object format for scope
|
|
81
|
+
let scopeKey;
|
|
82
|
+
if (typeof invariant.scope === 'string') {
|
|
83
|
+
scopeKey = invariant.scope.toLowerCase();
|
|
84
|
+
} else if (typeof invariant.scope === 'object' && invariant.scope.files) {
|
|
85
|
+
// For object format with files array, categorize based on presence of files
|
|
86
|
+
scopeKey = 'module'; // Default to module for file-based scopes
|
|
87
|
+
} else {
|
|
88
|
+
scopeKey = 'module'; // Default fallback
|
|
89
|
+
}
|
|
90
|
+
|
|
81
91
|
if (categorized.by_scope[scopeKey]) {
|
|
82
92
|
categorized.by_scope[scopeKey].push(invariant);
|
|
83
93
|
}
|
|
@@ -253,7 +263,17 @@ class InvariantAnalyzer {
|
|
|
253
263
|
score += Math.min(criticalCount * 10, 30); // Up to 30 points for critical invariants
|
|
254
264
|
|
|
255
265
|
// Boost for system scope invariants
|
|
256
|
-
const systemCount = invariants.filter(inv =>
|
|
266
|
+
const systemCount = invariants.filter(inv => {
|
|
267
|
+
if (typeof inv.scope === 'string') {
|
|
268
|
+
return inv.scope === 'system';
|
|
269
|
+
} else if (typeof inv.scope === 'object') {
|
|
270
|
+
// Consider as system scope if it has system-level characteristics
|
|
271
|
+
return inv.scope.files && Array.isArray(inv.scope.files) && inv.scope.files.some(file =>
|
|
272
|
+
file && typeof file === 'string' && (file.includes('/core/') || file.includes('/lib/') || file.includes('/shared/'))
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
276
|
+
}).length;
|
|
257
277
|
score += Math.min(systemCount * 5, 20); // Up to 20 points for system invariants
|
|
258
278
|
|
|
259
279
|
// Cap the score
|