neuronlayer 0.1.0
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/CONTRIBUTING.md +127 -0
- package/LICENSE +21 -0
- package/README.md +305 -0
- package/dist/index.js +38016 -0
- package/esbuild.config.js +26 -0
- package/package.json +63 -0
- package/src/cli/commands.ts +382 -0
- package/src/core/adr-exporter.ts +253 -0
- package/src/core/architecture/architecture-enforcement.ts +228 -0
- package/src/core/architecture/duplicate-detector.ts +288 -0
- package/src/core/architecture/index.ts +6 -0
- package/src/core/architecture/pattern-learner.ts +306 -0
- package/src/core/architecture/pattern-library.ts +403 -0
- package/src/core/architecture/pattern-validator.ts +324 -0
- package/src/core/change-intelligence/bug-correlator.ts +444 -0
- package/src/core/change-intelligence/change-intelligence.ts +221 -0
- package/src/core/change-intelligence/change-tracker.ts +334 -0
- package/src/core/change-intelligence/fix-suggester.ts +340 -0
- package/src/core/change-intelligence/index.ts +5 -0
- package/src/core/code-verifier.ts +843 -0
- package/src/core/confidence/confidence-scorer.ts +251 -0
- package/src/core/confidence/conflict-checker.ts +289 -0
- package/src/core/confidence/index.ts +5 -0
- package/src/core/confidence/source-tracker.ts +263 -0
- package/src/core/confidence/warning-detector.ts +241 -0
- package/src/core/context-rot/compaction.ts +284 -0
- package/src/core/context-rot/context-health.ts +243 -0
- package/src/core/context-rot/context-rot-prevention.ts +213 -0
- package/src/core/context-rot/critical-context.ts +221 -0
- package/src/core/context-rot/drift-detector.ts +255 -0
- package/src/core/context-rot/index.ts +7 -0
- package/src/core/context.ts +263 -0
- package/src/core/decision-extractor.ts +339 -0
- package/src/core/decisions.ts +69 -0
- package/src/core/deja-vu.ts +421 -0
- package/src/core/engine.ts +1455 -0
- package/src/core/feature-context.ts +726 -0
- package/src/core/ghost-mode.ts +412 -0
- package/src/core/learning.ts +485 -0
- package/src/core/living-docs/activity-tracker.ts +296 -0
- package/src/core/living-docs/architecture-generator.ts +428 -0
- package/src/core/living-docs/changelog-generator.ts +348 -0
- package/src/core/living-docs/component-generator.ts +230 -0
- package/src/core/living-docs/doc-engine.ts +110 -0
- package/src/core/living-docs/doc-validator.ts +282 -0
- package/src/core/living-docs/index.ts +8 -0
- package/src/core/project-manager.ts +297 -0
- package/src/core/summarizer.ts +267 -0
- package/src/core/test-awareness/change-validator.ts +499 -0
- package/src/core/test-awareness/index.ts +5 -0
- package/src/index.ts +49 -0
- package/src/indexing/ast.ts +563 -0
- package/src/indexing/embeddings.ts +85 -0
- package/src/indexing/indexer.ts +245 -0
- package/src/indexing/watcher.ts +78 -0
- package/src/server/gateways/aggregator.ts +374 -0
- package/src/server/gateways/index.ts +473 -0
- package/src/server/gateways/memory-ghost.ts +343 -0
- package/src/server/gateways/memory-query.ts +452 -0
- package/src/server/gateways/memory-record.ts +346 -0
- package/src/server/gateways/memory-review.ts +410 -0
- package/src/server/gateways/memory-status.ts +517 -0
- package/src/server/gateways/memory-verify.ts +392 -0
- package/src/server/gateways/router.ts +434 -0
- package/src/server/gateways/types.ts +610 -0
- package/src/server/mcp.ts +154 -0
- package/src/server/resources.ts +85 -0
- package/src/server/tools.ts +2261 -0
- package/src/storage/database.ts +262 -0
- package/src/storage/tier1.ts +135 -0
- package/src/storage/tier2.ts +764 -0
- package/src/storage/tier3.ts +123 -0
- package/src/types/documentation.ts +619 -0
- package/src/types/index.ts +222 -0
- package/src/utils/config.ts +193 -0
- package/src/utils/files.ts +117 -0
- package/src/utils/time.ts +37 -0
- package/src/utils/tokens.ts +52 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import type { Tier2Storage } from '../../storage/tier2.js';
|
|
2
|
+
import type {
|
|
3
|
+
Pattern,
|
|
4
|
+
PatternCategory,
|
|
5
|
+
PatternValidationResult,
|
|
6
|
+
PatternViolation,
|
|
7
|
+
PatternSuggestion,
|
|
8
|
+
ExistingFunction
|
|
9
|
+
} from '../../types/documentation.js';
|
|
10
|
+
import type { PatternLibrary } from './pattern-library.js';
|
|
11
|
+
import type { DuplicateDetector } from './duplicate-detector.js';
|
|
12
|
+
|
|
13
|
+
// Validation rules
|
|
14
|
+
const VALIDATION_RULES: Array<{
|
|
15
|
+
name: string;
|
|
16
|
+
category: PatternCategory | 'all';
|
|
17
|
+
check: RegExp;
|
|
18
|
+
isViolation: boolean; // true = finding it is bad, false = NOT finding it is bad
|
|
19
|
+
severity: 'info' | 'warning' | 'critical';
|
|
20
|
+
message: string;
|
|
21
|
+
suggestion: string;
|
|
22
|
+
}> = [
|
|
23
|
+
// Error Handling
|
|
24
|
+
{
|
|
25
|
+
name: 'empty_catch',
|
|
26
|
+
category: 'error_handling',
|
|
27
|
+
check: /catch\s*\([^)]*\)\s*\{\s*\}/,
|
|
28
|
+
isViolation: true,
|
|
29
|
+
severity: 'critical',
|
|
30
|
+
message: 'Empty catch block swallows errors silently',
|
|
31
|
+
suggestion: 'Log the error or rethrow it'
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'console_log_in_catch',
|
|
35
|
+
category: 'error_handling',
|
|
36
|
+
check: /catch\s*\([^)]*\)\s*\{[\s\S]*console\.log[\s\S]*\}/,
|
|
37
|
+
isViolation: true,
|
|
38
|
+
severity: 'warning',
|
|
39
|
+
message: 'Using console.log for errors instead of console.error or logger',
|
|
40
|
+
suggestion: 'Use console.error() or a proper logger'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'no_error_handling',
|
|
44
|
+
category: 'api_call',
|
|
45
|
+
check: /(?:fetch|axios)\s*\([^)]*\)(?![\s\S]*\.catch|[\s\S]*try)/,
|
|
46
|
+
isViolation: true,
|
|
47
|
+
severity: 'critical',
|
|
48
|
+
message: 'API call without error handling',
|
|
49
|
+
suggestion: 'Wrap in try-catch or add .catch()'
|
|
50
|
+
},
|
|
51
|
+
// API Calls
|
|
52
|
+
{
|
|
53
|
+
name: 'no_response_check',
|
|
54
|
+
category: 'api_call',
|
|
55
|
+
check: /fetch\s*\([^)]*\)[\s\S]*\.json\(\)(?![\s\S]*\.ok|[\s\S]*response\.status)/,
|
|
56
|
+
isViolation: true,
|
|
57
|
+
severity: 'warning',
|
|
58
|
+
message: 'Parsing JSON without checking response status',
|
|
59
|
+
suggestion: 'Check response.ok before parsing'
|
|
60
|
+
},
|
|
61
|
+
// Components
|
|
62
|
+
{
|
|
63
|
+
name: 'no_props_type',
|
|
64
|
+
category: 'component',
|
|
65
|
+
check: /(?:function|const)\s+\w+\s*\(\s*props\s*\)/,
|
|
66
|
+
isViolation: true,
|
|
67
|
+
severity: 'warning',
|
|
68
|
+
message: 'Component props not typed',
|
|
69
|
+
suggestion: 'Define Props interface and destructure: ({ prop1, prop2 }: Props)'
|
|
70
|
+
},
|
|
71
|
+
// Validation
|
|
72
|
+
{
|
|
73
|
+
name: 'direct_property_access',
|
|
74
|
+
category: 'validation',
|
|
75
|
+
check: /\w+\.\w+\.\w+(?!\s*\?\.)(?!\s*&&)/,
|
|
76
|
+
isViolation: true,
|
|
77
|
+
severity: 'warning',
|
|
78
|
+
message: 'Deep property access without null checking',
|
|
79
|
+
suggestion: 'Use optional chaining: obj?.prop?.nested'
|
|
80
|
+
},
|
|
81
|
+
// General
|
|
82
|
+
{
|
|
83
|
+
name: 'var_usage',
|
|
84
|
+
category: 'all',
|
|
85
|
+
check: /\bvar\s+\w+/,
|
|
86
|
+
isViolation: true,
|
|
87
|
+
severity: 'info',
|
|
88
|
+
message: 'Using var instead of const/let',
|
|
89
|
+
suggestion: 'Use const for constants, let for variables'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'any_type',
|
|
93
|
+
category: 'all',
|
|
94
|
+
check: /:\s*any\b/,
|
|
95
|
+
isViolation: true,
|
|
96
|
+
severity: 'info',
|
|
97
|
+
message: 'Using any type reduces type safety',
|
|
98
|
+
suggestion: 'Define proper types or use unknown'
|
|
99
|
+
}
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
export class PatternValidator {
|
|
103
|
+
private patternLibrary: PatternLibrary;
|
|
104
|
+
private duplicateDetector: DuplicateDetector;
|
|
105
|
+
private tier2: Tier2Storage;
|
|
106
|
+
|
|
107
|
+
constructor(
|
|
108
|
+
patternLibrary: PatternLibrary,
|
|
109
|
+
duplicateDetector: DuplicateDetector,
|
|
110
|
+
tier2: Tier2Storage
|
|
111
|
+
) {
|
|
112
|
+
this.patternLibrary = patternLibrary;
|
|
113
|
+
this.duplicateDetector = duplicateDetector;
|
|
114
|
+
this.tier2 = tier2;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Validate code against patterns
|
|
118
|
+
validate(code: string, type?: PatternCategory | 'auto'): PatternValidationResult {
|
|
119
|
+
const violations: PatternViolation[] = [];
|
|
120
|
+
const suggestions: PatternSuggestion[] = [];
|
|
121
|
+
let score = 100;
|
|
122
|
+
|
|
123
|
+
// 1. Detect code type if auto
|
|
124
|
+
const category = type === 'auto' || !type ? this.detectCategory(code) : type;
|
|
125
|
+
|
|
126
|
+
// 2. Find matching pattern
|
|
127
|
+
const patterns = category ? this.patternLibrary.getPatternsByCategory(category) : this.patternLibrary.getAllPatterns();
|
|
128
|
+
const matchedPattern = this.findBestMatch(code, patterns);
|
|
129
|
+
|
|
130
|
+
// 3. Check validation rules
|
|
131
|
+
for (const rule of VALIDATION_RULES) {
|
|
132
|
+
if (rule.category !== 'all' && rule.category !== category) continue;
|
|
133
|
+
|
|
134
|
+
const matches = rule.check.test(code);
|
|
135
|
+
if (rule.isViolation && matches) {
|
|
136
|
+
violations.push({
|
|
137
|
+
rule: rule.name,
|
|
138
|
+
message: rule.message,
|
|
139
|
+
severity: rule.severity,
|
|
140
|
+
suggestion: rule.suggestion
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Deduct score based on severity
|
|
144
|
+
score -= rule.severity === 'critical' ? 20 : rule.severity === 'warning' ? 10 : 5;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 4. Check against pattern rules if matched
|
|
149
|
+
if (matchedPattern) {
|
|
150
|
+
this.patternLibrary.incrementUsage(matchedPattern.id);
|
|
151
|
+
|
|
152
|
+
for (const patternRule of matchedPattern.rules) {
|
|
153
|
+
// Check if code follows this rule (simple keyword check)
|
|
154
|
+
if (patternRule.check) {
|
|
155
|
+
const regex = new RegExp(patternRule.check, 'i');
|
|
156
|
+
if (!regex.test(code)) {
|
|
157
|
+
violations.push({
|
|
158
|
+
rule: patternRule.rule,
|
|
159
|
+
message: `Does not follow pattern rule: ${patternRule.rule}`,
|
|
160
|
+
severity: patternRule.severity
|
|
161
|
+
});
|
|
162
|
+
score -= patternRule.severity === 'critical' ? 15 : patternRule.severity === 'warning' ? 8 : 3;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check against anti-patterns
|
|
168
|
+
for (const antiPattern of matchedPattern.antiPatterns) {
|
|
169
|
+
if (this.matchesAntiPattern(code, antiPattern.code)) {
|
|
170
|
+
violations.push({
|
|
171
|
+
rule: 'anti_pattern',
|
|
172
|
+
message: `Code matches anti-pattern: ${antiPattern.explanation}`,
|
|
173
|
+
severity: 'warning',
|
|
174
|
+
suggestion: 'See pattern examples for correct approach'
|
|
175
|
+
});
|
|
176
|
+
score -= 15;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 5. Check for duplicates/existing functions
|
|
182
|
+
const duplicates = this.duplicateDetector.findDuplicates(code);
|
|
183
|
+
const existingAlternatives: ExistingFunction[] = duplicates.map(d => ({
|
|
184
|
+
name: d.name,
|
|
185
|
+
file: d.file,
|
|
186
|
+
line: d.line,
|
|
187
|
+
signature: d.signature,
|
|
188
|
+
usageCount: d.usageCount,
|
|
189
|
+
purpose: d.name,
|
|
190
|
+
similarity: d.similarity
|
|
191
|
+
}));
|
|
192
|
+
|
|
193
|
+
if (existingAlternatives.length > 0) {
|
|
194
|
+
const topMatch = existingAlternatives[0];
|
|
195
|
+
violations.push({
|
|
196
|
+
rule: 'duplicate_function',
|
|
197
|
+
message: `Similar function already exists: ${topMatch.name} in ${topMatch.file}`,
|
|
198
|
+
severity: 'critical',
|
|
199
|
+
suggestion: `Use existing ${topMatch.name}() instead of creating new function`
|
|
200
|
+
});
|
|
201
|
+
score -= 25;
|
|
202
|
+
|
|
203
|
+
suggestions.push({
|
|
204
|
+
description: `Use existing function ${topMatch.name}() from ${topMatch.file}`,
|
|
205
|
+
code: `import { ${topMatch.name} } from '${topMatch.file}';`,
|
|
206
|
+
priority: 'high'
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 6. Generate suggestions based on violations
|
|
211
|
+
for (const violation of violations) {
|
|
212
|
+
if (violation.suggestion && !suggestions.some(s => s.description === violation.suggestion)) {
|
|
213
|
+
suggestions.push({
|
|
214
|
+
description: violation.suggestion,
|
|
215
|
+
priority: violation.severity === 'critical' ? 'high' : violation.severity === 'warning' ? 'medium' : 'low'
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Ensure score is between 0 and 100
|
|
221
|
+
score = Math.max(0, Math.min(100, score));
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
valid: violations.filter(v => v.severity === 'critical').length === 0,
|
|
225
|
+
score,
|
|
226
|
+
matchedPattern: matchedPattern?.name,
|
|
227
|
+
violations,
|
|
228
|
+
suggestions,
|
|
229
|
+
existingAlternatives
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Detect what category of code this is
|
|
234
|
+
private detectCategory(code: string): PatternCategory | null {
|
|
235
|
+
if (/try\s*\{[\s\S]*catch/.test(code)) return 'error_handling';
|
|
236
|
+
if (/fetch\s*\(|axios\.|api\./.test(code)) return 'api_call';
|
|
237
|
+
if (/function\s+\w+.*\{[\s\S]*return\s*[(<]/.test(code)) return 'component';
|
|
238
|
+
if (/if\s*\(\s*!?\w+\s*(?:===?|!==?)/.test(code)) return 'validation';
|
|
239
|
+
if (/async\s+function|await\s+/.test(code)) return 'data_fetching';
|
|
240
|
+
if (/console\.|logger\./.test(code)) return 'logging';
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Find the best matching pattern
|
|
245
|
+
private findBestMatch(code: string, patterns: Pattern[]): Pattern | null {
|
|
246
|
+
let bestMatch: Pattern | null = null;
|
|
247
|
+
let bestScore = 0;
|
|
248
|
+
|
|
249
|
+
for (const pattern of patterns) {
|
|
250
|
+
let score = 0;
|
|
251
|
+
|
|
252
|
+
// Check examples
|
|
253
|
+
for (const example of pattern.examples) {
|
|
254
|
+
const similarity = this.calculateSimilarity(code, example.code);
|
|
255
|
+
score += similarity;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Check if follows rules
|
|
259
|
+
for (const rule of pattern.rules) {
|
|
260
|
+
if (rule.check) {
|
|
261
|
+
const regex = new RegExp(rule.check, 'i');
|
|
262
|
+
if (regex.test(code)) {
|
|
263
|
+
score += 10;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (score > bestScore) {
|
|
269
|
+
bestScore = score;
|
|
270
|
+
bestMatch = pattern;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return bestScore > 20 ? bestMatch : null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Check if code matches an anti-pattern
|
|
278
|
+
private matchesAntiPattern(code: string, antiPattern: string): boolean {
|
|
279
|
+
// Normalize both and check similarity
|
|
280
|
+
const similarity = this.calculateSimilarity(code, antiPattern);
|
|
281
|
+
return similarity > 60;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Calculate code similarity (simple token-based)
|
|
285
|
+
private calculateSimilarity(code1: string, code2: string): number {
|
|
286
|
+
const tokens1 = this.tokenize(code1);
|
|
287
|
+
const tokens2 = this.tokenize(code2);
|
|
288
|
+
|
|
289
|
+
if (tokens1.length === 0 || tokens2.length === 0) return 0;
|
|
290
|
+
|
|
291
|
+
const set1 = new Set(tokens1);
|
|
292
|
+
const set2 = new Set(tokens2);
|
|
293
|
+
|
|
294
|
+
let matches = 0;
|
|
295
|
+
for (const token of set1) {
|
|
296
|
+
if (set2.has(token)) matches++;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return (matches / Math.max(set1.size, set2.size)) * 100;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Tokenize code
|
|
303
|
+
private tokenize(code: string): string[] {
|
|
304
|
+
return code
|
|
305
|
+
.replace(/[^\w\s]/g, ' ')
|
|
306
|
+
.toLowerCase()
|
|
307
|
+
.split(/\s+/)
|
|
308
|
+
.filter(t => t.length > 2);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Get validation statistics
|
|
312
|
+
getValidationStats(): {
|
|
313
|
+
totalValidations: number;
|
|
314
|
+
avgScore: number;
|
|
315
|
+
commonViolations: Array<{ rule: string; count: number }>;
|
|
316
|
+
} {
|
|
317
|
+
// This would track stats over time
|
|
318
|
+
return {
|
|
319
|
+
totalValidations: 0,
|
|
320
|
+
avgScore: 0,
|
|
321
|
+
commonViolations: []
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
}
|