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,263 @@
|
|
|
1
|
+
import type { Tier2Storage } from '../../storage/tier2.js';
|
|
2
|
+
import type { EmbeddingGenerator } from '../../indexing/embeddings.js';
|
|
3
|
+
import type {
|
|
4
|
+
ConfidenceSources,
|
|
5
|
+
CodebaseMatch,
|
|
6
|
+
DecisionMatch,
|
|
7
|
+
PatternMatch
|
|
8
|
+
} from '../../types/documentation.js';
|
|
9
|
+
|
|
10
|
+
// Common code patterns to detect
|
|
11
|
+
const CODE_PATTERNS = [
|
|
12
|
+
{ name: 'error-handling', regex: /try\s*\{[\s\S]*?\}\s*catch/i },
|
|
13
|
+
{ name: 'async-await', regex: /async\s+function|await\s+/i },
|
|
14
|
+
{ name: 'null-check', regex: /\?\.|!==?\s*null|===?\s*null/i },
|
|
15
|
+
{ name: 'array-methods', regex: /\.(map|filter|reduce|forEach|find)\s*\(/i },
|
|
16
|
+
{ name: 'destructuring', regex: /const\s+\{[\s\S]*?\}\s*=|const\s+\[[\s\S]*?\]\s*=/i },
|
|
17
|
+
{ name: 'arrow-function', regex: /=>\s*\{|=>\s*[^{]/i },
|
|
18
|
+
{ name: 'class-definition', regex: /class\s+\w+(\s+extends\s+\w+)?\s*\{/i },
|
|
19
|
+
{ name: 'interface-definition', regex: /interface\s+\w+\s*\{/i },
|
|
20
|
+
{ name: 'type-definition', regex: /type\s+\w+\s*=/i },
|
|
21
|
+
{ name: 'import-statement', regex: /import\s+.*\s+from\s+['"`]/i },
|
|
22
|
+
{ name: 'export-statement', regex: /export\s+(default\s+)?(class|function|const|interface|type)/i },
|
|
23
|
+
{ name: 'promise-handling', regex: /\.then\s*\(|\.catch\s*\(|Promise\./i },
|
|
24
|
+
{ name: 'validation', regex: /if\s*\(.*\)\s*(throw|return)/i },
|
|
25
|
+
{ name: 'logging', regex: /console\.(log|error|warn|info)/i },
|
|
26
|
+
{ name: 'event-handling', regex: /\.on\(|addEventListener|emit\(/i }
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export class SourceTracker {
|
|
30
|
+
private tier2: Tier2Storage;
|
|
31
|
+
private embeddingGenerator: EmbeddingGenerator;
|
|
32
|
+
|
|
33
|
+
constructor(tier2: Tier2Storage, embeddingGenerator: EmbeddingGenerator) {
|
|
34
|
+
this.tier2 = tier2;
|
|
35
|
+
this.embeddingGenerator = embeddingGenerator;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async trackSources(code: string, context?: string): Promise<ConfidenceSources> {
|
|
39
|
+
// Find similar code in codebase
|
|
40
|
+
const codebaseMatches = await this.findSimilarCode(code, context);
|
|
41
|
+
|
|
42
|
+
// Find related decisions
|
|
43
|
+
const decisionMatches = await this.findRelatedDecisions(code, context);
|
|
44
|
+
|
|
45
|
+
// Find matching patterns
|
|
46
|
+
const patternMatches = this.findMatchingPatterns(code);
|
|
47
|
+
|
|
48
|
+
// Determine if general knowledge was used
|
|
49
|
+
const usedGeneralKnowledge = codebaseMatches.length === 0 && decisionMatches.length === 0;
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
codebase: codebaseMatches,
|
|
53
|
+
decisions: decisionMatches,
|
|
54
|
+
patterns: patternMatches,
|
|
55
|
+
usedGeneralKnowledge
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private async findSimilarCode(code: string, context?: string): Promise<CodebaseMatch[]> {
|
|
60
|
+
const matches: CodebaseMatch[] = [];
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// Generate embedding for the code
|
|
64
|
+
const textToEmbed = context ? `${context}\n${code}` : code;
|
|
65
|
+
const embedding = await this.embeddingGenerator.embed(textToEmbed);
|
|
66
|
+
|
|
67
|
+
// Search for similar code
|
|
68
|
+
const results = this.tier2.search(embedding, 10);
|
|
69
|
+
|
|
70
|
+
for (const result of results) {
|
|
71
|
+
// Convert similarity to percentage (0-100)
|
|
72
|
+
const similarity = Math.round(result.similarity * 100);
|
|
73
|
+
|
|
74
|
+
if (similarity >= 30) { // Only include if at least 30% similar
|
|
75
|
+
const file = this.tier2.getFile(result.path);
|
|
76
|
+
const symbols = file ? this.tier2.getSymbolsByFile(file.id) : [];
|
|
77
|
+
const dependents = this.tier2.getFileDependents(result.path);
|
|
78
|
+
|
|
79
|
+
matches.push({
|
|
80
|
+
file: result.path,
|
|
81
|
+
similarity,
|
|
82
|
+
snippet: result.preview,
|
|
83
|
+
lastModified: file ? new Date(file.lastModified) : undefined,
|
|
84
|
+
usageCount: dependents.length + 1,
|
|
85
|
+
function: symbols.length > 0 ? symbols[0].name : undefined
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error('Error finding similar code:', error);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return matches.slice(0, 5); // Return top 5
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private async findRelatedDecisions(code: string, context?: string): Promise<DecisionMatch[]> {
|
|
97
|
+
const matches: DecisionMatch[] = [];
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
// Generate embedding for decision search
|
|
101
|
+
const textToEmbed = context ? `${context}\n${code}` : code;
|
|
102
|
+
const embedding = await this.embeddingGenerator.embed(textToEmbed);
|
|
103
|
+
|
|
104
|
+
// Search decisions
|
|
105
|
+
const decisions = this.tier2.searchDecisions(embedding, 5);
|
|
106
|
+
|
|
107
|
+
for (const decision of decisions) {
|
|
108
|
+
// Calculate relevance based on similarity
|
|
109
|
+
const relevance = Math.round(decision.similarity * 100);
|
|
110
|
+
|
|
111
|
+
if (relevance >= 40) { // Only include if at least 40% relevant
|
|
112
|
+
matches.push({
|
|
113
|
+
id: decision.id,
|
|
114
|
+
title: decision.title,
|
|
115
|
+
date: decision.createdAt,
|
|
116
|
+
relevance
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error('Error finding related decisions:', error);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return matches;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private findMatchingPatterns(code: string): PatternMatch[] {
|
|
128
|
+
const matches: PatternMatch[] = [];
|
|
129
|
+
|
|
130
|
+
for (const pattern of CODE_PATTERNS) {
|
|
131
|
+
if (pattern.regex.test(code)) {
|
|
132
|
+
// Calculate confidence based on how common the pattern is
|
|
133
|
+
const confidence = this.calculatePatternConfidence(pattern.name, code);
|
|
134
|
+
|
|
135
|
+
matches.push({
|
|
136
|
+
pattern: pattern.name,
|
|
137
|
+
confidence,
|
|
138
|
+
examples: this.findPatternExamples(pattern.name)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Sort by confidence
|
|
144
|
+
matches.sort((a, b) => b.confidence - a.confidence);
|
|
145
|
+
|
|
146
|
+
return matches.slice(0, 5); // Return top 5
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private calculatePatternConfidence(patternName: string, code: string): number {
|
|
150
|
+
// Base confidence for detecting a pattern
|
|
151
|
+
let confidence = 60;
|
|
152
|
+
|
|
153
|
+
// Boost for common patterns
|
|
154
|
+
const commonPatterns = ['error-handling', 'async-await', 'null-check', 'validation'];
|
|
155
|
+
if (commonPatterns.includes(patternName)) {
|
|
156
|
+
confidence += 15;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check if pattern is used correctly (basic heuristics)
|
|
160
|
+
switch (patternName) {
|
|
161
|
+
case 'error-handling':
|
|
162
|
+
if (/catch\s*\(\s*\w+\s*\)\s*\{[\s\S]*\}/.test(code)) confidence += 10;
|
|
163
|
+
break;
|
|
164
|
+
case 'async-await':
|
|
165
|
+
if (/await\s+[^;]+;/.test(code) && /async\s+/.test(code)) confidence += 10;
|
|
166
|
+
break;
|
|
167
|
+
case 'null-check':
|
|
168
|
+
if (/\?\.\w+/.test(code) || /!==?\s*null/.test(code)) confidence += 10;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return Math.min(95, confidence);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private findPatternExamples(patternName: string): string[] {
|
|
176
|
+
// Get files that use this pattern
|
|
177
|
+
const examples: string[] = [];
|
|
178
|
+
const files = this.tier2.getAllFiles();
|
|
179
|
+
|
|
180
|
+
for (const file of files.slice(0, 50)) { // Check first 50 files
|
|
181
|
+
const preview = file.preview || '';
|
|
182
|
+
const pattern = CODE_PATTERNS.find(p => p.name === patternName);
|
|
183
|
+
|
|
184
|
+
if (pattern && pattern.regex.test(preview)) {
|
|
185
|
+
examples.push(file.path);
|
|
186
|
+
if (examples.length >= 3) break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return examples;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Get detailed source tracking for display
|
|
194
|
+
async getDetailedTracking(code: string, context?: string): Promise<{
|
|
195
|
+
codebaseWeight: number;
|
|
196
|
+
decisionWeight: number;
|
|
197
|
+
patternWeight: number;
|
|
198
|
+
sources: ConfidenceSources;
|
|
199
|
+
formatted: string;
|
|
200
|
+
}> {
|
|
201
|
+
const sources = await this.trackSources(code, context);
|
|
202
|
+
|
|
203
|
+
// Calculate weights based on what was found
|
|
204
|
+
let codebaseWeight = 0.5;
|
|
205
|
+
let decisionWeight = 0.3;
|
|
206
|
+
let patternWeight = 0.2;
|
|
207
|
+
|
|
208
|
+
// Adjust weights if sources are missing
|
|
209
|
+
if (sources.codebase.length === 0) {
|
|
210
|
+
codebaseWeight = 0;
|
|
211
|
+
decisionWeight += 0.25;
|
|
212
|
+
patternWeight += 0.25;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (sources.decisions.length === 0) {
|
|
216
|
+
decisionWeight = 0;
|
|
217
|
+
codebaseWeight += 0.15;
|
|
218
|
+
patternWeight += 0.15;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Format for display
|
|
222
|
+
const lines: string[] = [];
|
|
223
|
+
lines.push('\u{1F4CA} Suggestion Sources\n');
|
|
224
|
+
|
|
225
|
+
if (sources.codebase.length > 0) {
|
|
226
|
+
lines.push(`Codebase (${Math.round(codebaseWeight * 100)}% weight):`);
|
|
227
|
+
for (const match of sources.codebase) {
|
|
228
|
+
lines.push(`\u251C\u2500\u2500 ${match.file}${match.line ? `:${match.line}` : ''} (${match.similarity}% similar)`);
|
|
229
|
+
}
|
|
230
|
+
lines.push('');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (sources.decisions.length > 0) {
|
|
234
|
+
lines.push(`Decisions (${Math.round(decisionWeight * 100)}% weight):`);
|
|
235
|
+
for (const decision of sources.decisions) {
|
|
236
|
+
lines.push(`\u2514\u2500\u2500 "${decision.title}" (${decision.relevance}% relevant)`);
|
|
237
|
+
}
|
|
238
|
+
lines.push('');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (sources.patterns.length > 0) {
|
|
242
|
+
lines.push(`Patterns (${Math.round(patternWeight * 100)}% weight):`);
|
|
243
|
+
for (const pattern of sources.patterns) {
|
|
244
|
+
lines.push(`\u2514\u2500\u2500 ${pattern.pattern} (${pattern.confidence}% confidence)`);
|
|
245
|
+
}
|
|
246
|
+
lines.push('');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (sources.usedGeneralKnowledge) {
|
|
250
|
+
lines.push('General Knowledge: Used (no codebase matches found)');
|
|
251
|
+
} else {
|
|
252
|
+
lines.push('General Knowledge: Not used');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
codebaseWeight,
|
|
257
|
+
decisionWeight,
|
|
258
|
+
patternWeight,
|
|
259
|
+
sources,
|
|
260
|
+
formatted: lines.join('\n')
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import type { Tier2Storage } from '../../storage/tier2.js';
|
|
2
|
+
import type {
|
|
3
|
+
ConfidenceSources,
|
|
4
|
+
ConfidenceWarning,
|
|
5
|
+
WarningType
|
|
6
|
+
} from '../../types/documentation.js';
|
|
7
|
+
|
|
8
|
+
// Security patterns to detect
|
|
9
|
+
const SECURITY_PATTERNS = [
|
|
10
|
+
{ pattern: /eval\s*\(/, issue: 'eval() usage', suggestion: 'Avoid eval() - use safer alternatives' },
|
|
11
|
+
{ pattern: /innerHTML\s*=/, issue: 'innerHTML assignment', suggestion: 'Use textContent or sanitize input to prevent XSS' },
|
|
12
|
+
{ pattern: /document\.write\s*\(/, issue: 'document.write() usage', suggestion: 'Use DOM manipulation methods instead' },
|
|
13
|
+
{ pattern: /\$\{.*\}.*(?:SELECT|INSERT|UPDATE|DELETE)/i, issue: 'SQL injection risk', suggestion: 'Use parameterized queries' },
|
|
14
|
+
{ pattern: /exec\s*\(.*\$\{/, issue: 'Command injection risk', suggestion: 'Sanitize user input before shell execution' },
|
|
15
|
+
{ pattern: /password\s*[:=]\s*['"`][^'"`]+['"`]/, issue: 'Hardcoded password', suggestion: 'Use environment variables or secure vaults' },
|
|
16
|
+
{ pattern: /api[_-]?key\s*[:=]\s*['"`][^'"`]+['"`]/i, issue: 'Hardcoded API key', suggestion: 'Use environment variables' },
|
|
17
|
+
{ pattern: /\bhttp:\/\//, issue: 'Insecure HTTP', suggestion: 'Use HTTPS for secure communication' },
|
|
18
|
+
{ pattern: /dangerouslySetInnerHTML/, issue: 'React XSS risk', suggestion: 'Sanitize content before using dangerouslySetInnerHTML' }
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// Deprecated patterns to detect
|
|
22
|
+
const DEPRECATED_PATTERNS = [
|
|
23
|
+
{ pattern: /var\s+\w+\s*=/, suggestion: 'Use const or let instead of var' },
|
|
24
|
+
{ pattern: /new\s+Buffer\s*\(/, suggestion: 'Use Buffer.from() or Buffer.alloc() instead' },
|
|
25
|
+
{ pattern: /\.substr\s*\(/, suggestion: 'Use .slice() or .substring() instead of .substr()' },
|
|
26
|
+
{ pattern: /__proto__/, suggestion: 'Use Object.getPrototypeOf() instead of __proto__' },
|
|
27
|
+
{ pattern: /arguments\s*\[/, suggestion: 'Use rest parameters (...args) instead of arguments' },
|
|
28
|
+
{ pattern: /\.bind\s*\(this\)/, suggestion: 'Consider using arrow functions instead of .bind(this)' }
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
// Complexity indicators
|
|
32
|
+
const COMPLEXITY_INDICATORS = [
|
|
33
|
+
{ pattern: /if\s*\([^)]*\)\s*{[^}]*if\s*\([^)]*\)\s*{[^}]*if/s, level: 'high' as const },
|
|
34
|
+
{ pattern: /\?\s*[^:]+\s*:\s*[^:]+\s*\?\s*[^:]+\s*:/s, level: 'high' as const },
|
|
35
|
+
{ pattern: /for\s*\([^)]*\)\s*{[^}]*for\s*\([^)]*\)\s*{/s, level: 'medium' as const },
|
|
36
|
+
{ pattern: /&&.*&&.*&&||\|\|.*\|\|.*\|\|/s, level: 'medium' as const }
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const WARNING_DEFINITIONS: Record<WarningType, { defaultMessage: string; defaultSeverity: 'info' | 'warning' | 'critical' }> = {
|
|
40
|
+
'no_similar_pattern': {
|
|
41
|
+
defaultMessage: 'No similar pattern found in your codebase',
|
|
42
|
+
defaultSeverity: 'warning'
|
|
43
|
+
},
|
|
44
|
+
'conflicts_with_decision': {
|
|
45
|
+
defaultMessage: 'This conflicts with a past decision',
|
|
46
|
+
defaultSeverity: 'critical'
|
|
47
|
+
},
|
|
48
|
+
'untested_approach': {
|
|
49
|
+
defaultMessage: 'This approach has no tests in your codebase',
|
|
50
|
+
defaultSeverity: 'info'
|
|
51
|
+
},
|
|
52
|
+
'high_complexity': {
|
|
53
|
+
defaultMessage: 'This is complex code',
|
|
54
|
+
defaultSeverity: 'warning'
|
|
55
|
+
},
|
|
56
|
+
'potential_security_issue': {
|
|
57
|
+
defaultMessage: 'Potential security concern detected',
|
|
58
|
+
defaultSeverity: 'critical'
|
|
59
|
+
},
|
|
60
|
+
'deprecated_approach': {
|
|
61
|
+
defaultMessage: 'This uses deprecated patterns',
|
|
62
|
+
defaultSeverity: 'warning'
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export class WarningDetector {
|
|
67
|
+
private tier2: Tier2Storage;
|
|
68
|
+
|
|
69
|
+
constructor(tier2: Tier2Storage) {
|
|
70
|
+
this.tier2 = tier2;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async detectWarnings(code: string, sources: ConfidenceSources): Promise<ConfidenceWarning[]> {
|
|
74
|
+
const warnings: ConfidenceWarning[] = [];
|
|
75
|
+
|
|
76
|
+
// 1. Check for no similar patterns
|
|
77
|
+
if (sources.codebase.length === 0 && sources.patterns.length === 0) {
|
|
78
|
+
warnings.push(this.createWarning(
|
|
79
|
+
'no_similar_pattern',
|
|
80
|
+
'No similar code or patterns found in your codebase',
|
|
81
|
+
'warning',
|
|
82
|
+
'Review carefully - this is new for your project'
|
|
83
|
+
));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 2. Check for security issues
|
|
87
|
+
const securityWarnings = this.detectSecurityIssues(code);
|
|
88
|
+
warnings.push(...securityWarnings);
|
|
89
|
+
|
|
90
|
+
// 3. Check for deprecated patterns
|
|
91
|
+
const deprecationWarnings = this.detectDeprecatedPatterns(code);
|
|
92
|
+
warnings.push(...deprecationWarnings);
|
|
93
|
+
|
|
94
|
+
// 4. Check complexity
|
|
95
|
+
const complexityWarning = this.detectComplexity(code);
|
|
96
|
+
if (complexityWarning) {
|
|
97
|
+
warnings.push(complexityWarning);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 5. Check for untested approach
|
|
101
|
+
const untestedWarning = await this.checkForTests(code, sources);
|
|
102
|
+
if (untestedWarning) {
|
|
103
|
+
warnings.push(untestedWarning);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Sort by severity (critical first)
|
|
107
|
+
warnings.sort((a, b) => {
|
|
108
|
+
const severityOrder = { critical: 0, warning: 1, info: 2 };
|
|
109
|
+
return severityOrder[a.severity] - severityOrder[b.severity];
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return warnings;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private detectSecurityIssues(code: string): ConfidenceWarning[] {
|
|
116
|
+
const warnings: ConfidenceWarning[] = [];
|
|
117
|
+
|
|
118
|
+
for (const { pattern, issue, suggestion } of SECURITY_PATTERNS) {
|
|
119
|
+
if (pattern.test(code)) {
|
|
120
|
+
warnings.push(this.createWarning(
|
|
121
|
+
'potential_security_issue',
|
|
122
|
+
`Security concern: ${issue}`,
|
|
123
|
+
'critical',
|
|
124
|
+
suggestion
|
|
125
|
+
));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return warnings;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private detectDeprecatedPatterns(code: string): ConfidenceWarning[] {
|
|
133
|
+
const warnings: ConfidenceWarning[] = [];
|
|
134
|
+
|
|
135
|
+
for (const { pattern, suggestion } of DEPRECATED_PATTERNS) {
|
|
136
|
+
if (pattern.test(code)) {
|
|
137
|
+
warnings.push(this.createWarning(
|
|
138
|
+
'deprecated_approach',
|
|
139
|
+
'Uses deprecated pattern',
|
|
140
|
+
'warning',
|
|
141
|
+
suggestion
|
|
142
|
+
));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return warnings;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private detectComplexity(code: string): ConfidenceWarning | null {
|
|
150
|
+
for (const { pattern, level } of COMPLEXITY_INDICATORS) {
|
|
151
|
+
if (pattern.test(code)) {
|
|
152
|
+
const severity = level === 'high' ? 'warning' : 'info';
|
|
153
|
+
return this.createWarning(
|
|
154
|
+
'high_complexity',
|
|
155
|
+
`${level.charAt(0).toUpperCase() + level.slice(1)} complexity detected`,
|
|
156
|
+
severity,
|
|
157
|
+
'Consider breaking this into smaller functions'
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Check line count and nesting
|
|
163
|
+
const lines = code.split('\n');
|
|
164
|
+
if (lines.length > 50) {
|
|
165
|
+
return this.createWarning(
|
|
166
|
+
'high_complexity',
|
|
167
|
+
'Long code block (>50 lines)',
|
|
168
|
+
'info',
|
|
169
|
+
'Consider splitting into multiple functions'
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private async checkForTests(code: string, sources: ConfidenceSources): Promise<ConfidenceWarning | null> {
|
|
177
|
+
// Check if any of the matched files have corresponding tests
|
|
178
|
+
const hasTests = sources.codebase.some(match => {
|
|
179
|
+
const testPath = match.file.replace(/\.ts$/, '.test.ts').replace(/\.js$/, '.test.js');
|
|
180
|
+
const specPath = match.file.replace(/\.ts$/, '.spec.ts').replace(/\.js$/, '.spec.js');
|
|
181
|
+
|
|
182
|
+
return this.tier2.getFile(testPath) !== null ||
|
|
183
|
+
this.tier2.getFile(specPath) !== null ||
|
|
184
|
+
match.file.includes('.test.') ||
|
|
185
|
+
match.file.includes('.spec.') ||
|
|
186
|
+
match.file.includes('__tests__');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
if (!hasTests && sources.codebase.length > 0) {
|
|
190
|
+
return this.createWarning(
|
|
191
|
+
'untested_approach',
|
|
192
|
+
'Similar code has no tests',
|
|
193
|
+
'info',
|
|
194
|
+
'Consider adding tests before using this approach'
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Check if the code itself looks like test code
|
|
199
|
+
const isTestCode = /describe\s*\(|it\s*\(|test\s*\(|expect\s*\(|assert\./i.test(code);
|
|
200
|
+
if (!isTestCode && code.includes('function') && sources.codebase.length === 0) {
|
|
201
|
+
return this.createWarning(
|
|
202
|
+
'untested_approach',
|
|
203
|
+
'New function without matching tests',
|
|
204
|
+
'info',
|
|
205
|
+
'Consider writing tests for this functionality'
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private createWarning(
|
|
213
|
+
type: WarningType,
|
|
214
|
+
message?: string,
|
|
215
|
+
severity?: 'info' | 'warning' | 'critical',
|
|
216
|
+
suggestion?: string
|
|
217
|
+
): ConfidenceWarning {
|
|
218
|
+
const defaults = WARNING_DEFINITIONS[type];
|
|
219
|
+
return {
|
|
220
|
+
type,
|
|
221
|
+
message: message || defaults.defaultMessage,
|
|
222
|
+
severity: severity || defaults.defaultSeverity,
|
|
223
|
+
suggestion
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Check for specific warning types
|
|
228
|
+
hasSecurityWarnings(code: string): boolean {
|
|
229
|
+
return SECURITY_PATTERNS.some(({ pattern }) => pattern.test(code));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
hasDeprecatedPatterns(code: string): boolean {
|
|
233
|
+
return DEPRECATED_PATTERNS.some(({ pattern }) => pattern.test(code));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
isHighComplexity(code: string): boolean {
|
|
237
|
+
return COMPLEXITY_INDICATORS.some(({ pattern, level }) =>
|
|
238
|
+
level === 'high' && pattern.test(code)
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|