neuronlayer 0.1.9 → 0.2.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.

Potentially problematic release.


This version of neuronlayer might be problematic. Click here for more details.

Files changed (81) hide show
  1. package/README.md +3 -2
  2. package/dist/index.js +172 -90
  3. package/dist/index.js.map +7 -0
  4. package/package.json +6 -1
  5. package/esbuild.config.js +0 -26
  6. package/src/cli/commands.ts +0 -573
  7. package/src/core/adr-exporter.ts +0 -253
  8. package/src/core/architecture/architecture-enforcement.ts +0 -228
  9. package/src/core/architecture/duplicate-detector.ts +0 -288
  10. package/src/core/architecture/index.ts +0 -6
  11. package/src/core/architecture/pattern-learner.ts +0 -306
  12. package/src/core/architecture/pattern-library.ts +0 -403
  13. package/src/core/architecture/pattern-validator.ts +0 -324
  14. package/src/core/change-intelligence/bug-correlator.ts +0 -544
  15. package/src/core/change-intelligence/change-intelligence.ts +0 -264
  16. package/src/core/change-intelligence/change-tracker.ts +0 -334
  17. package/src/core/change-intelligence/fix-suggester.ts +0 -340
  18. package/src/core/change-intelligence/index.ts +0 -5
  19. package/src/core/code-verifier.ts +0 -843
  20. package/src/core/confidence/confidence-scorer.ts +0 -251
  21. package/src/core/confidence/conflict-checker.ts +0 -289
  22. package/src/core/confidence/index.ts +0 -5
  23. package/src/core/confidence/source-tracker.ts +0 -263
  24. package/src/core/confidence/warning-detector.ts +0 -241
  25. package/src/core/context-rot/compaction.ts +0 -284
  26. package/src/core/context-rot/context-health.ts +0 -243
  27. package/src/core/context-rot/context-rot-prevention.ts +0 -213
  28. package/src/core/context-rot/critical-context.ts +0 -221
  29. package/src/core/context-rot/drift-detector.ts +0 -255
  30. package/src/core/context-rot/index.ts +0 -7
  31. package/src/core/context.ts +0 -263
  32. package/src/core/decision-extractor.ts +0 -339
  33. package/src/core/decisions.ts +0 -69
  34. package/src/core/deja-vu.ts +0 -421
  35. package/src/core/engine.ts +0 -1646
  36. package/src/core/feature-context.ts +0 -726
  37. package/src/core/ghost-mode.ts +0 -465
  38. package/src/core/learning.ts +0 -519
  39. package/src/core/living-docs/activity-tracker.ts +0 -296
  40. package/src/core/living-docs/architecture-generator.ts +0 -428
  41. package/src/core/living-docs/changelog-generator.ts +0 -348
  42. package/src/core/living-docs/component-generator.ts +0 -230
  43. package/src/core/living-docs/doc-engine.ts +0 -134
  44. package/src/core/living-docs/doc-validator.ts +0 -282
  45. package/src/core/living-docs/index.ts +0 -8
  46. package/src/core/project-manager.ts +0 -301
  47. package/src/core/refresh/activity-gate.ts +0 -256
  48. package/src/core/refresh/git-staleness-checker.ts +0 -108
  49. package/src/core/refresh/index.ts +0 -27
  50. package/src/core/summarizer.ts +0 -290
  51. package/src/core/test-awareness/change-validator.ts +0 -499
  52. package/src/core/test-awareness/index.ts +0 -5
  53. package/src/index.ts +0 -90
  54. package/src/indexing/ast.ts +0 -868
  55. package/src/indexing/embeddings.ts +0 -85
  56. package/src/indexing/indexer.ts +0 -270
  57. package/src/indexing/watcher.ts +0 -78
  58. package/src/server/gateways/aggregator.ts +0 -374
  59. package/src/server/gateways/index.ts +0 -473
  60. package/src/server/gateways/memory-ghost.ts +0 -343
  61. package/src/server/gateways/memory-query.ts +0 -452
  62. package/src/server/gateways/memory-record.ts +0 -346
  63. package/src/server/gateways/memory-review.ts +0 -410
  64. package/src/server/gateways/memory-status.ts +0 -517
  65. package/src/server/gateways/memory-verify.ts +0 -392
  66. package/src/server/gateways/router.ts +0 -434
  67. package/src/server/gateways/types.ts +0 -610
  68. package/src/server/http.ts +0 -228
  69. package/src/server/mcp.ts +0 -154
  70. package/src/server/resources.ts +0 -85
  71. package/src/server/tools.ts +0 -2460
  72. package/src/storage/database.ts +0 -271
  73. package/src/storage/tier1.ts +0 -135
  74. package/src/storage/tier2.ts +0 -972
  75. package/src/storage/tier3.ts +0 -123
  76. package/src/types/documentation.ts +0 -619
  77. package/src/types/index.ts +0 -222
  78. package/src/utils/config.ts +0 -194
  79. package/src/utils/files.ts +0 -117
  80. package/src/utils/time.ts +0 -37
  81. package/src/utils/tokens.ts +0 -52
@@ -1,288 +0,0 @@
1
- import type { Tier2Storage } from '../../storage/tier2.js';
2
- import type { EmbeddingGenerator } from '../../indexing/embeddings.js';
3
- import type { ExistingFunction, FunctionIndex } from '../../types/documentation.js';
4
-
5
- // Common function purpose keywords
6
- const PURPOSE_KEYWORDS: Record<string, string[]> = {
7
- authentication: ['auth', 'login', 'logout', 'token', 'session', 'jwt', 'credential'],
8
- validation: ['validate', 'check', 'verify', 'assert', 'ensure', 'is', 'has'],
9
- formatting: ['format', 'parse', 'stringify', 'serialize', 'convert', 'transform'],
10
- fetching: ['fetch', 'get', 'load', 'retrieve', 'request', 'api', 'http'],
11
- storage: ['save', 'store', 'persist', 'cache', 'set', 'put'],
12
- utility: ['util', 'helper', 'tool', 'common', 'shared'],
13
- error: ['error', 'exception', 'throw', 'catch', 'handle'],
14
- logging: ['log', 'logger', 'debug', 'info', 'warn', 'error'],
15
- date: ['date', 'time', 'moment', 'day', 'month', 'year', 'timestamp']
16
- };
17
-
18
- export class DuplicateDetector {
19
- private tier2: Tier2Storage;
20
- private embeddingGenerator: EmbeddingGenerator;
21
- private functionIndex: Map<string, FunctionIndex> = new Map();
22
-
23
- constructor(tier2: Tier2Storage, embeddingGenerator: EmbeddingGenerator) {
24
- this.tier2 = tier2;
25
- this.embeddingGenerator = embeddingGenerator;
26
- this.buildFunctionIndex();
27
- }
28
-
29
- // Build index of all functions in codebase
30
- private buildFunctionIndex(): void {
31
- const files = this.tier2.getAllFiles();
32
-
33
- for (const file of files) {
34
- const symbols = this.tier2.getSymbolsByFile(file.id);
35
-
36
- for (const symbol of symbols) {
37
- if (symbol.kind === 'function' || symbol.kind === 'method') {
38
- const key = `${file.path}:${symbol.name}`;
39
- const dependents = this.tier2.getFileDependents(file.path);
40
-
41
- this.functionIndex.set(key, {
42
- name: symbol.name,
43
- file: file.path,
44
- line: symbol.lineStart,
45
- signature: symbol.signature || `${symbol.name}()`,
46
- exported: symbol.exported,
47
- usageCount: dependents.length + 1,
48
- parameters: this.extractParameters(symbol.signature || ''),
49
- returnType: this.extractReturnType(symbol.signature || ''),
50
- docstring: symbol.docstring
51
- });
52
- }
53
- }
54
- }
55
- }
56
-
57
- // Find duplicate or similar functions
58
- findDuplicates(code: string, threshold: number = 60): Array<FunctionIndex & { similarity: number }> {
59
- const duplicates: Array<FunctionIndex & { similarity: number }> = [];
60
-
61
- // Extract function name from code
62
- const funcNameMatch = code.match(/(?:function|const|let|var)\s+(\w+)/);
63
- const funcName = funcNameMatch ? funcNameMatch[1] : null;
64
-
65
- // Extract purpose from code
66
- const purpose = this.detectPurpose(code);
67
-
68
- for (const [_key, func] of this.functionIndex) {
69
- let similarity = 0;
70
-
71
- // Check name similarity
72
- if (funcName) {
73
- const nameSimilarity = this.calculateNameSimilarity(funcName, func.name);
74
- similarity += nameSimilarity * 0.3;
75
- }
76
-
77
- // Check purpose similarity
78
- const funcPurpose = this.detectPurpose(func.signature + ' ' + (func.docstring || ''));
79
- if (purpose && funcPurpose && purpose === funcPurpose) {
80
- similarity += 40;
81
- }
82
-
83
- // Check code structure similarity
84
- const structureSimilarity = this.calculateStructureSimilarity(code, func.signature);
85
- similarity += structureSimilarity * 0.3;
86
-
87
- if (similarity >= threshold) {
88
- duplicates.push({
89
- ...func,
90
- similarity: Math.round(similarity)
91
- });
92
- }
93
- }
94
-
95
- // Sort by similarity
96
- duplicates.sort((a, b) => b.similarity - a.similarity);
97
-
98
- return duplicates.slice(0, 5);
99
- }
100
-
101
- // Suggest existing functions based on intent
102
- suggestExisting(intent: string, limit: number = 5): ExistingFunction[] {
103
- const suggestions: Array<FunctionIndex & { relevance: number }> = [];
104
- const intentLower = intent.toLowerCase();
105
- const intentWords = intentLower.split(/\s+/);
106
-
107
- for (const [_key, func] of this.functionIndex) {
108
- if (!func.exported) continue;
109
-
110
- let relevance = 0;
111
- const funcLower = func.name.toLowerCase();
112
- const docLower = (func.docstring || '').toLowerCase();
113
- const combined = `${funcLower} ${docLower}`;
114
-
115
- // Check direct name match
116
- for (const word of intentWords) {
117
- if (word.length < 3) continue;
118
-
119
- if (funcLower.includes(word)) {
120
- relevance += 30;
121
- }
122
- if (docLower.includes(word)) {
123
- relevance += 20;
124
- }
125
- }
126
-
127
- // Check purpose match
128
- const purpose = this.detectPurpose(intent);
129
- const funcPurpose = this.detectPurpose(combined);
130
- if (purpose && funcPurpose && purpose === funcPurpose) {
131
- relevance += 25;
132
- }
133
-
134
- // Boost for commonly used functions
135
- relevance += Math.min(func.usageCount * 2, 15);
136
-
137
- if (relevance > 20) {
138
- suggestions.push({ ...func, relevance });
139
- }
140
- }
141
-
142
- // Sort by relevance
143
- suggestions.sort((a, b) => b.relevance - a.relevance);
144
-
145
- return suggestions.slice(0, limit).map(s => ({
146
- name: s.name,
147
- file: s.file,
148
- line: s.line,
149
- signature: s.signature,
150
- description: s.docstring,
151
- usageCount: s.usageCount,
152
- purpose: this.detectPurpose(s.name + ' ' + (s.docstring || '')) || 'utility',
153
- similarity: s.relevance
154
- }));
155
- }
156
-
157
- // Detect the purpose of code/function
158
- private detectPurpose(text: string): string | null {
159
- const lower = text.toLowerCase();
160
-
161
- for (const [purpose, keywords] of Object.entries(PURPOSE_KEYWORDS)) {
162
- if (keywords.some(k => lower.includes(k))) {
163
- return purpose;
164
- }
165
- }
166
-
167
- return null;
168
- }
169
-
170
- // Calculate name similarity
171
- private calculateNameSimilarity(name1: string, name2: string): number {
172
- const lower1 = name1.toLowerCase();
173
- const lower2 = name2.toLowerCase();
174
-
175
- // Exact match
176
- if (lower1 === lower2) return 100;
177
-
178
- // Contains
179
- if (lower1.includes(lower2) || lower2.includes(lower1)) return 70;
180
-
181
- // Token overlap
182
- const tokens1 = this.camelCaseToTokens(name1);
183
- const tokens2 = this.camelCaseToTokens(name2);
184
-
185
- let matches = 0;
186
- for (const t1 of tokens1) {
187
- for (const t2 of tokens2) {
188
- if (t1 === t2) matches++;
189
- }
190
- }
191
-
192
- const totalTokens = Math.max(tokens1.length, tokens2.length);
193
- return totalTokens > 0 ? (matches / totalTokens) * 100 : 0;
194
- }
195
-
196
- // Calculate structure similarity
197
- private calculateStructureSimilarity(code1: string, code2: string): number {
198
- // Extract structural elements
199
- const struct1 = this.extractStructure(code1);
200
- const struct2 = this.extractStructure(code2);
201
-
202
- let matches = 0;
203
- let total = 0;
204
-
205
- for (const key of Object.keys(struct1) as Array<keyof typeof struct1>) {
206
- total++;
207
- if (struct1[key] === struct2[key]) matches++;
208
- }
209
-
210
- return total > 0 ? (matches / total) * 100 : 0;
211
- }
212
-
213
- // Extract structural features
214
- private extractStructure(code: string): {
215
- hasAsync: boolean;
216
- hasReturn: boolean;
217
- hasTryCatch: boolean;
218
- hasLoop: boolean;
219
- hasConditional: boolean;
220
- paramCount: number;
221
- } {
222
- return {
223
- hasAsync: /async\s+/.test(code),
224
- hasReturn: /return\s+/.test(code),
225
- hasTryCatch: /try\s*\{/.test(code),
226
- hasLoop: /(?:for|while|do)\s*[\(\{]/.test(code),
227
- hasConditional: /if\s*\(/.test(code),
228
- paramCount: (code.match(/\([^)]*\)/)?.[0]?.split(',').length || 0)
229
- };
230
- }
231
-
232
- // Split camelCase to tokens
233
- private camelCaseToTokens(name: string): string[] {
234
- return name
235
- .replace(/([a-z])([A-Z])/g, '$1 $2')
236
- .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
237
- .toLowerCase()
238
- .split(/\s+/)
239
- .filter(t => t.length > 1);
240
- }
241
-
242
- // Extract parameters from signature
243
- private extractParameters(signature: string): string[] {
244
- const match = signature.match(/\(([^)]*)\)/);
245
- if (!match) return [];
246
-
247
- return match[1]
248
- .split(',')
249
- .map(p => p.trim())
250
- .filter(Boolean)
251
- .map(p => p.split(':')[0].trim());
252
- }
253
-
254
- // Extract return type from signature
255
- private extractReturnType(signature: string): string | undefined {
256
- const match = signature.match(/\):\s*(.+)$/);
257
- return match ? match[1].trim() : undefined;
258
- }
259
-
260
- // Refresh the function index
261
- refresh(): void {
262
- this.functionIndex.clear();
263
- this.buildFunctionIndex();
264
- }
265
-
266
- // Get index statistics
267
- getStats(): {
268
- totalFunctions: number;
269
- exportedFunctions: number;
270
- byPurpose: Record<string, number>;
271
- } {
272
- let exportedFunctions = 0;
273
- const byPurpose: Record<string, number> = {};
274
-
275
- for (const [_key, func] of this.functionIndex) {
276
- if (func.exported) exportedFunctions++;
277
-
278
- const purpose = this.detectPurpose(func.name) || 'other';
279
- byPurpose[purpose] = (byPurpose[purpose] || 0) + 1;
280
- }
281
-
282
- return {
283
- totalFunctions: this.functionIndex.size,
284
- exportedFunctions,
285
- byPurpose
286
- };
287
- }
288
- }
@@ -1,6 +0,0 @@
1
- // Architecture Enforcement Module - Phase 10
2
- export { ArchitectureEnforcement } from './architecture-enforcement.js';
3
- export { PatternLibrary } from './pattern-library.js';
4
- export { PatternLearner } from './pattern-learner.js';
5
- export { PatternValidator } from './pattern-validator.js';
6
- export { DuplicateDetector } from './duplicate-detector.js';
@@ -1,306 +0,0 @@
1
- import type { Tier2Storage } from '../../storage/tier2.js';
2
- import type { PatternCategory, CodeExample, PatternRule } from '../../types/documentation.js';
3
- import type { PatternLibrary } from './pattern-library.js';
4
-
5
- // Pattern detection rules
6
- const PATTERN_DETECTORS: Array<{
7
- category: PatternCategory;
8
- name: string;
9
- detect: RegExp;
10
- extractExample: (code: string) => string | null;
11
- rules: PatternRule[];
12
- }> = [
13
- {
14
- category: 'error_handling',
15
- name: 'Try-Catch Pattern',
16
- detect: /try\s*\{[\s\S]*?\}\s*catch\s*\(/,
17
- extractExample: (code: string) => {
18
- const match = code.match(/try\s*\{[\s\S]*?\}\s*catch\s*\([^)]*\)\s*\{[\s\S]*?\}/);
19
- return match ? match[0] : null;
20
- },
21
- rules: [
22
- { rule: 'Use try-catch for error-prone operations', severity: 'warning' },
23
- { rule: 'Log errors with context', severity: 'warning' }
24
- ]
25
- },
26
- {
27
- category: 'api_call',
28
- name: 'Fetch API Pattern',
29
- detect: /fetch\s*\(|axios\.|api\./,
30
- extractExample: (code: string) => {
31
- const match = code.match(/(?:await\s+)?(?:fetch|axios\.\w+|api\.\w+)\s*\([^)]*\)[\s\S]*?(?:\.json\(\)|;)/);
32
- return match ? match[0] : null;
33
- },
34
- rules: [
35
- { rule: 'Check response status', severity: 'critical' },
36
- { rule: 'Handle network errors', severity: 'critical' }
37
- ]
38
- },
39
- {
40
- category: 'component',
41
- name: 'React Component Pattern',
42
- detect: /(?:function|const)\s+\w+\s*(?::\s*React\.FC|\([^)]*\))\s*(?:=>|{)/,
43
- extractExample: (code: string) => {
44
- const match = code.match(/(?:interface|type)\s+\w*Props[\s\S]*?}[\s\S]*?(?:function|const)\s+\w+[\s\S]*?(?:return\s*\([\s\S]*?\);|\))/);
45
- return match ? match[0] : null;
46
- },
47
- rules: [
48
- { rule: 'Define Props interface', severity: 'warning' },
49
- { rule: 'Use functional components', severity: 'info' }
50
- ]
51
- },
52
- {
53
- category: 'validation',
54
- name: 'Input Validation Pattern',
55
- detect: /if\s*\(\s*!?\w+\s*(?:===?|!==?)\s*(?:null|undefined|''|""|0)\s*\)/,
56
- extractExample: (code: string) => {
57
- const match = code.match(/if\s*\([^)]*(?:null|undefined)[^)]*\)\s*\{[^}]*\}/);
58
- return match ? match[0] : null;
59
- },
60
- rules: [
61
- { rule: 'Validate inputs before use', severity: 'warning' },
62
- { rule: 'Use optional chaining for nested access', severity: 'info' }
63
- ]
64
- },
65
- {
66
- category: 'data_fetching',
67
- name: 'Async/Await Pattern',
68
- detect: /async\s+(?:function|\([^)]*\)\s*=>)/,
69
- extractExample: (code: string) => {
70
- const match = code.match(/async\s+(?:function\s+\w+)?\s*\([^)]*\)\s*(?::\s*Promise<[^>]+>)?\s*\{[\s\S]*?await[\s\S]*?\}/);
71
- return match ? match[0] : null;
72
- },
73
- rules: [
74
- { rule: 'Use async/await for asynchronous code', severity: 'info' },
75
- { rule: 'Always await promises', severity: 'warning' }
76
- ]
77
- },
78
- {
79
- category: 'logging',
80
- name: 'Logging Pattern',
81
- detect: /console\.(log|error|warn|info)|logger\./,
82
- extractExample: (code: string) => {
83
- const match = code.match(/(?:console|logger)\.\w+\s*\([^)]*\)/);
84
- return match ? match[0] : null;
85
- },
86
- rules: [
87
- { rule: 'Use structured logging', severity: 'info' },
88
- { rule: 'Include context in log messages', severity: 'info' }
89
- ]
90
- }
91
- ];
92
-
93
- export class PatternLearner {
94
- private tier2: Tier2Storage;
95
- private patternLibrary: PatternLibrary;
96
-
97
- constructor(tier2: Tier2Storage, patternLibrary: PatternLibrary) {
98
- this.tier2 = tier2;
99
- this.patternLibrary = patternLibrary;
100
- }
101
-
102
- // Learn patterns from the entire codebase
103
- learnFromCodebase(): {
104
- patternsLearned: number;
105
- examplesAdded: number;
106
- categories: Record<string, number>;
107
- } {
108
- const files = this.tier2.getAllFiles();
109
- const categories: Record<string, number> = {};
110
- let patternsLearned = 0;
111
- let examplesAdded = 0;
112
-
113
- for (const file of files) {
114
- if (!file.preview) continue;
115
-
116
- const filePatterns = this.detectPatterns(file.preview);
117
-
118
- for (const detected of filePatterns) {
119
- categories[detected.category] = (categories[detected.category] || 0) + 1;
120
-
121
- // Check if we already have this pattern
122
- const existingPatterns = this.patternLibrary.getPatternsByCategory(detected.category);
123
- const existing = existingPatterns.find(p => p.name === detected.name);
124
-
125
- if (existing) {
126
- // Add as example if different enough
127
- if (detected.example && !this.isDuplicate(existing.examples, detected.example)) {
128
- this.patternLibrary.addExample(existing.id, {
129
- code: detected.example,
130
- explanation: `Extracted from ${file.path}`,
131
- file: file.path
132
- });
133
- examplesAdded++;
134
- }
135
- } else {
136
- // Create new pattern
137
- this.patternLibrary.addPattern(
138
- detected.name,
139
- detected.category,
140
- `${detected.name} detected in codebase`,
141
- detected.example ? [{
142
- code: detected.example,
143
- explanation: `Extracted from ${file.path}`,
144
- file: file.path
145
- }] : [],
146
- [],
147
- detected.rules
148
- );
149
- patternsLearned++;
150
- }
151
- }
152
- }
153
-
154
- return { patternsLearned, examplesAdded, categories };
155
- }
156
-
157
- // Detect patterns in a code snippet
158
- detectPatterns(code: string): Array<{
159
- category: PatternCategory;
160
- name: string;
161
- example: string | null;
162
- rules: PatternRule[];
163
- }> {
164
- const detected: Array<{
165
- category: PatternCategory;
166
- name: string;
167
- example: string | null;
168
- rules: PatternRule[];
169
- }> = [];
170
-
171
- for (const detector of PATTERN_DETECTORS) {
172
- if (detector.detect.test(code)) {
173
- detected.push({
174
- category: detector.category,
175
- name: detector.name,
176
- example: detector.extractExample(code),
177
- rules: detector.rules
178
- });
179
- }
180
- }
181
-
182
- return detected;
183
- }
184
-
185
- // Learn a specific pattern from user input
186
- learnPattern(
187
- code: string,
188
- name: string,
189
- description?: string,
190
- category?: PatternCategory
191
- ): { success: boolean; patternId?: string; message: string } {
192
- // Auto-detect category if not provided
193
- const detectedCategory = category || this.inferCategory(code);
194
-
195
- // Check for existing similar pattern
196
- const existingPatterns = this.patternLibrary.searchPatterns(name);
197
- if (existingPatterns.some(p => p.name.toLowerCase() === name.toLowerCase())) {
198
- return {
199
- success: false,
200
- message: `Pattern "${name}" already exists. Use add_example to add to existing pattern.`
201
- };
202
- }
203
-
204
- // Extract rules from code
205
- const rules = this.extractRules(code);
206
-
207
- // Create the pattern
208
- const pattern = this.patternLibrary.addPattern(
209
- name,
210
- detectedCategory,
211
- description || `User-defined pattern: ${name}`,
212
- [{
213
- code,
214
- explanation: 'User-provided example'
215
- }],
216
- [],
217
- rules
218
- );
219
-
220
- return {
221
- success: true,
222
- patternId: pattern.id,
223
- message: `Pattern "${name}" created successfully`
224
- };
225
- }
226
-
227
- // Infer category from code
228
- private inferCategory(code: string): PatternCategory {
229
- for (const detector of PATTERN_DETECTORS) {
230
- if (detector.detect.test(code)) {
231
- return detector.category;
232
- }
233
- }
234
- return 'custom';
235
- }
236
-
237
- // Extract rules from code patterns
238
- private extractRules(code: string): PatternRule[] {
239
- const rules: PatternRule[] = [];
240
-
241
- // Detect common patterns and generate rules
242
- if (/try\s*\{/.test(code)) {
243
- rules.push({ rule: 'Use try-catch for error handling', severity: 'warning' });
244
- }
245
- if (/catch\s*\([^)]*\)\s*\{[\s\S]*console\.error/.test(code)) {
246
- rules.push({ rule: 'Log errors in catch blocks', severity: 'info' });
247
- }
248
- if (/async\s+/.test(code)) {
249
- rules.push({ rule: 'Use async functions for asynchronous operations', severity: 'info' });
250
- }
251
- if (/await\s+/.test(code)) {
252
- rules.push({ rule: 'Await all promises', severity: 'warning' });
253
- }
254
- if (/interface\s+\w+Props/.test(code)) {
255
- rules.push({ rule: 'Define Props interfaces for components', severity: 'warning' });
256
- }
257
- if (/\?\.\w+/.test(code)) {
258
- rules.push({ rule: 'Use optional chaining for safe property access', severity: 'info' });
259
- }
260
- if (/\?\?/.test(code)) {
261
- rules.push({ rule: 'Use nullish coalescing for default values', severity: 'info' });
262
- }
263
-
264
- return rules;
265
- }
266
-
267
- // Check if example is duplicate
268
- private isDuplicate(examples: CodeExample[], newExample: string): boolean {
269
- const normalized = this.normalizeCode(newExample);
270
- return examples.some(e => this.normalizeCode(e.code) === normalized);
271
- }
272
-
273
- // Normalize code for comparison
274
- private normalizeCode(code: string): string {
275
- return code
276
- .replace(/\s+/g, ' ')
277
- .replace(/['"`]/g, '"')
278
- .trim()
279
- .toLowerCase();
280
- }
281
-
282
- // Get learning statistics
283
- getStats(): {
284
- totalPatterns: number;
285
- byCategory: Record<string, number>;
286
- topPatterns: Array<{ name: string; usageCount: number }>;
287
- } {
288
- const patterns = this.patternLibrary.getAllPatterns();
289
- const byCategory: Record<string, number> = {};
290
-
291
- for (const pattern of patterns) {
292
- byCategory[pattern.category] = (byCategory[pattern.category] || 0) + 1;
293
- }
294
-
295
- const topPatterns = patterns
296
- .sort((a, b) => b.usageCount - a.usageCount)
297
- .slice(0, 5)
298
- .map(p => ({ name: p.name, usageCount: p.usageCount }));
299
-
300
- return {
301
- totalPatterns: patterns.length,
302
- byCategory,
303
- topPatterns
304
- };
305
- }
306
- }