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.
Files changed (78) hide show
  1. package/CONTRIBUTING.md +127 -0
  2. package/LICENSE +21 -0
  3. package/README.md +305 -0
  4. package/dist/index.js +38016 -0
  5. package/esbuild.config.js +26 -0
  6. package/package.json +63 -0
  7. package/src/cli/commands.ts +382 -0
  8. package/src/core/adr-exporter.ts +253 -0
  9. package/src/core/architecture/architecture-enforcement.ts +228 -0
  10. package/src/core/architecture/duplicate-detector.ts +288 -0
  11. package/src/core/architecture/index.ts +6 -0
  12. package/src/core/architecture/pattern-learner.ts +306 -0
  13. package/src/core/architecture/pattern-library.ts +403 -0
  14. package/src/core/architecture/pattern-validator.ts +324 -0
  15. package/src/core/change-intelligence/bug-correlator.ts +444 -0
  16. package/src/core/change-intelligence/change-intelligence.ts +221 -0
  17. package/src/core/change-intelligence/change-tracker.ts +334 -0
  18. package/src/core/change-intelligence/fix-suggester.ts +340 -0
  19. package/src/core/change-intelligence/index.ts +5 -0
  20. package/src/core/code-verifier.ts +843 -0
  21. package/src/core/confidence/confidence-scorer.ts +251 -0
  22. package/src/core/confidence/conflict-checker.ts +289 -0
  23. package/src/core/confidence/index.ts +5 -0
  24. package/src/core/confidence/source-tracker.ts +263 -0
  25. package/src/core/confidence/warning-detector.ts +241 -0
  26. package/src/core/context-rot/compaction.ts +284 -0
  27. package/src/core/context-rot/context-health.ts +243 -0
  28. package/src/core/context-rot/context-rot-prevention.ts +213 -0
  29. package/src/core/context-rot/critical-context.ts +221 -0
  30. package/src/core/context-rot/drift-detector.ts +255 -0
  31. package/src/core/context-rot/index.ts +7 -0
  32. package/src/core/context.ts +263 -0
  33. package/src/core/decision-extractor.ts +339 -0
  34. package/src/core/decisions.ts +69 -0
  35. package/src/core/deja-vu.ts +421 -0
  36. package/src/core/engine.ts +1455 -0
  37. package/src/core/feature-context.ts +726 -0
  38. package/src/core/ghost-mode.ts +412 -0
  39. package/src/core/learning.ts +485 -0
  40. package/src/core/living-docs/activity-tracker.ts +296 -0
  41. package/src/core/living-docs/architecture-generator.ts +428 -0
  42. package/src/core/living-docs/changelog-generator.ts +348 -0
  43. package/src/core/living-docs/component-generator.ts +230 -0
  44. package/src/core/living-docs/doc-engine.ts +110 -0
  45. package/src/core/living-docs/doc-validator.ts +282 -0
  46. package/src/core/living-docs/index.ts +8 -0
  47. package/src/core/project-manager.ts +297 -0
  48. package/src/core/summarizer.ts +267 -0
  49. package/src/core/test-awareness/change-validator.ts +499 -0
  50. package/src/core/test-awareness/index.ts +5 -0
  51. package/src/index.ts +49 -0
  52. package/src/indexing/ast.ts +563 -0
  53. package/src/indexing/embeddings.ts +85 -0
  54. package/src/indexing/indexer.ts +245 -0
  55. package/src/indexing/watcher.ts +78 -0
  56. package/src/server/gateways/aggregator.ts +374 -0
  57. package/src/server/gateways/index.ts +473 -0
  58. package/src/server/gateways/memory-ghost.ts +343 -0
  59. package/src/server/gateways/memory-query.ts +452 -0
  60. package/src/server/gateways/memory-record.ts +346 -0
  61. package/src/server/gateways/memory-review.ts +410 -0
  62. package/src/server/gateways/memory-status.ts +517 -0
  63. package/src/server/gateways/memory-verify.ts +392 -0
  64. package/src/server/gateways/router.ts +434 -0
  65. package/src/server/gateways/types.ts +610 -0
  66. package/src/server/mcp.ts +154 -0
  67. package/src/server/resources.ts +85 -0
  68. package/src/server/tools.ts +2261 -0
  69. package/src/storage/database.ts +262 -0
  70. package/src/storage/tier1.ts +135 -0
  71. package/src/storage/tier2.ts +764 -0
  72. package/src/storage/tier3.ts +123 -0
  73. package/src/types/documentation.ts +619 -0
  74. package/src/types/index.ts +222 -0
  75. package/src/utils/config.ts +193 -0
  76. package/src/utils/files.ts +117 -0
  77. package/src/utils/time.ts +37 -0
  78. 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
+ }