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,267 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { CodeSymbol } from '../types/index.js';
3
+ import { estimateTokens } from '../utils/tokens.js';
4
+
5
+ interface FileSummary {
6
+ fileId: number;
7
+ summary: string;
8
+ tokens: number;
9
+ generatedAt: number;
10
+ }
11
+
12
+ export class FileSummarizer {
13
+ private db: Database.Database;
14
+
15
+ constructor(db: Database.Database) {
16
+ this.db = db;
17
+ }
18
+
19
+ // Generate a compressed summary of a file
20
+ generateSummary(
21
+ filePath: string,
22
+ content: string,
23
+ symbols: CodeSymbol[],
24
+ imports: Array<{ importedFrom: string; importedSymbols: string[] }>,
25
+ exports: Array<{ exportedName: string }>
26
+ ): string {
27
+ const lines: string[] = [];
28
+
29
+ // File name and type
30
+ const fileName = filePath.split(/[/\\]/).pop() || filePath;
31
+ const extension = fileName.split('.').pop() || '';
32
+ lines.push(`**${fileName}** (${this.getFileType(extension)})`);
33
+
34
+ // Purpose (inferred from file name and content)
35
+ const purpose = this.inferPurpose(fileName, content, symbols);
36
+ if (purpose) {
37
+ lines.push(`Purpose: ${purpose}`);
38
+ }
39
+
40
+ // Exports summary
41
+ if (exports.length > 0) {
42
+ const exportNames = exports.map(e => e.exportedName).slice(0, 10);
43
+ lines.push(`Exports: ${exportNames.join(', ')}${exports.length > 10 ? ` (+${exports.length - 10} more)` : ''}`);
44
+ }
45
+
46
+ // Key symbols
47
+ const functions = symbols.filter(s => s.kind === 'function' && s.exported);
48
+ const classes = symbols.filter(s => s.kind === 'class');
49
+ const interfaces = symbols.filter(s => s.kind === 'interface');
50
+
51
+ if (classes.length > 0) {
52
+ lines.push(`Classes: ${classes.map(c => c.name).join(', ')}`);
53
+ }
54
+
55
+ if (interfaces.length > 0) {
56
+ lines.push(`Interfaces: ${interfaces.map(i => i.name).slice(0, 5).join(', ')}`);
57
+ }
58
+
59
+ if (functions.length > 0) {
60
+ const funcNames = functions.map(f => f.signature || f.name).slice(0, 5);
61
+ lines.push(`Functions: ${funcNames.join(', ')}${functions.length > 5 ? ` (+${functions.length - 5} more)` : ''}`);
62
+ }
63
+
64
+ // Dependencies
65
+ if (imports.length > 0) {
66
+ const deps = imports
67
+ .filter(i => !i.importedFrom.startsWith('.'))
68
+ .map(i => i.importedFrom.split('/')[0])
69
+ .filter((v, i, a) => a.indexOf(v) === i)
70
+ .slice(0, 5);
71
+
72
+ if (deps.length > 0) {
73
+ lines.push(`Uses: ${deps.join(', ')}`);
74
+ }
75
+ }
76
+
77
+ // Local imports (internal dependencies)
78
+ const localImports = imports
79
+ .filter(i => i.importedFrom.startsWith('.'))
80
+ .map(i => i.importedFrom.replace(/^\.\//, '').replace(/\.[^.]+$/, ''))
81
+ .slice(0, 5);
82
+
83
+ if (localImports.length > 0) {
84
+ lines.push(`Imports from: ${localImports.join(', ')}`);
85
+ }
86
+
87
+ // Key patterns detected
88
+ const patterns = this.detectPatterns(content);
89
+ if (patterns.length > 0) {
90
+ lines.push(`Patterns: ${patterns.join(', ')}`);
91
+ }
92
+
93
+ return lines.join('\n');
94
+ }
95
+
96
+ private getFileType(extension: string): string {
97
+ const types: Record<string, string> = {
98
+ 'ts': 'TypeScript',
99
+ 'tsx': 'React Component',
100
+ 'js': 'JavaScript',
101
+ 'jsx': 'React Component',
102
+ 'py': 'Python',
103
+ 'go': 'Go',
104
+ 'rs': 'Rust',
105
+ 'java': 'Java',
106
+ 'rb': 'Ruby',
107
+ 'vue': 'Vue Component',
108
+ 'svelte': 'Svelte Component',
109
+ };
110
+ return types[extension] || extension.toUpperCase();
111
+ }
112
+
113
+ private inferPurpose(fileName: string, content: string, symbols: CodeSymbol[]): string {
114
+ const lowerName = fileName.toLowerCase();
115
+ const lowerContent = content.toLowerCase();
116
+
117
+ // Common file patterns
118
+ if (lowerName.includes('middleware')) return 'Request middleware/interceptor';
119
+ if (lowerName.includes('route') || lowerName.includes('router')) return 'API route definitions';
120
+ if (lowerName.includes('controller')) return 'Request handler/controller';
121
+ if (lowerName.includes('service')) return 'Business logic service';
122
+ if (lowerName.includes('model')) return 'Data model definitions';
123
+ if (lowerName.includes('schema')) return 'Schema/validation definitions';
124
+ if (lowerName.includes('util') || lowerName.includes('helper')) return 'Utility functions';
125
+ if (lowerName.includes('config')) return 'Configuration';
126
+ if (lowerName.includes('constant')) return 'Constants/enums';
127
+ if (lowerName.includes('type') || lowerName.includes('interface')) return 'Type definitions';
128
+ if (lowerName.includes('test') || lowerName.includes('spec')) return 'Tests';
129
+ if (lowerName.includes('hook')) return 'React hooks';
130
+ if (lowerName.includes('context')) return 'React context provider';
131
+ if (lowerName.includes('store')) return 'State management';
132
+ if (lowerName.includes('api')) return 'API client/definitions';
133
+ if (lowerName.includes('auth')) return 'Authentication';
134
+ if (lowerName.includes('db') || lowerName.includes('database')) return 'Database operations';
135
+
136
+ // Content-based inference
137
+ if (lowerContent.includes('express') && lowerContent.includes('router')) return 'Express router';
138
+ if (lowerContent.includes('mongoose') || lowerContent.includes('prisma')) return 'Database model';
139
+ if (lowerContent.includes('usestate') || lowerContent.includes('useeffect')) return 'React component';
140
+ if (lowerContent.includes('describe(') && lowerContent.includes('it(')) return 'Test suite';
141
+
142
+ // Symbol-based inference
143
+ const hasClasses = symbols.some(s => s.kind === 'class');
144
+ const hasInterfaces = symbols.some(s => s.kind === 'interface');
145
+ const hasFunctions = symbols.some(s => s.kind === 'function');
146
+
147
+ if (hasInterfaces && !hasClasses && !hasFunctions) return 'Type definitions';
148
+ if (hasClasses && symbols.filter(s => s.kind === 'class').length === 1) {
149
+ const className = symbols.find(s => s.kind === 'class')?.name;
150
+ return `${className} implementation`;
151
+ }
152
+
153
+ return '';
154
+ }
155
+
156
+ private detectPatterns(content: string): string[] {
157
+ const patterns: string[] = [];
158
+ const lower = content.toLowerCase();
159
+
160
+ // Architectural patterns
161
+ if (lower.includes('singleton') || /private\s+static\s+instance/i.test(content)) {
162
+ patterns.push('Singleton');
163
+ }
164
+ if (lower.includes('factory') || /create\w+\s*\(/i.test(content)) {
165
+ patterns.push('Factory');
166
+ }
167
+ if (lower.includes('observer') || lower.includes('subscriber') || lower.includes('eventemitter')) {
168
+ patterns.push('Observer');
169
+ }
170
+ if (/async\s+\*|yield\s+/i.test(content)) {
171
+ patterns.push('Generator');
172
+ }
173
+ if (lower.includes('decorator') || /@\w+\s*\(/i.test(content)) {
174
+ patterns.push('Decorator');
175
+ }
176
+
177
+ // Code patterns
178
+ if (lower.includes('try') && lower.includes('catch')) {
179
+ patterns.push('Error handling');
180
+ }
181
+ if (lower.includes('async') && lower.includes('await')) {
182
+ patterns.push('Async/await');
183
+ }
184
+ if (/\.then\s*\(/i.test(content)) {
185
+ patterns.push('Promise chain');
186
+ }
187
+ if (lower.includes('middleware')) {
188
+ patterns.push('Middleware');
189
+ }
190
+
191
+ return patterns.slice(0, 4);
192
+ }
193
+
194
+ // Store summary in database
195
+ storeSummary(fileId: number, summary: string): void {
196
+ const tokens = estimateTokens(summary);
197
+
198
+ const stmt = this.db.prepare(`
199
+ INSERT INTO file_summaries (file_id, summary, summary_tokens, generated_at)
200
+ VALUES (?, ?, ?, unixepoch())
201
+ ON CONFLICT(file_id) DO UPDATE SET
202
+ summary = excluded.summary,
203
+ summary_tokens = excluded.summary_tokens,
204
+ generated_at = unixepoch()
205
+ `);
206
+ stmt.run(fileId, summary, tokens);
207
+ }
208
+
209
+ // Get summary from database
210
+ getSummary(fileId: number): FileSummary | null {
211
+ const stmt = this.db.prepare(`
212
+ SELECT file_id as fileId, summary, summary_tokens as tokens, generated_at as generatedAt
213
+ FROM file_summaries
214
+ WHERE file_id = ?
215
+ `);
216
+ return stmt.get(fileId) as FileSummary | null;
217
+ }
218
+
219
+ // Get summaries for multiple files
220
+ getSummaries(fileIds: number[]): Map<number, string> {
221
+ const result = new Map<number, string>();
222
+
223
+ if (fileIds.length === 0) return result;
224
+
225
+ const placeholders = fileIds.map(() => '?').join(',');
226
+ const stmt = this.db.prepare(`
227
+ SELECT file_id, summary
228
+ FROM file_summaries
229
+ WHERE file_id IN (${placeholders})
230
+ `);
231
+ const rows = stmt.all(...fileIds) as Array<{ file_id: number; summary: string }>;
232
+
233
+ for (const row of rows) {
234
+ result.set(row.file_id, row.summary);
235
+ }
236
+
237
+ return result;
238
+ }
239
+
240
+ // Check if summary needs regeneration
241
+ needsRegeneration(fileId: number, fileLastModified: number): boolean {
242
+ const summary = this.getSummary(fileId);
243
+ if (!summary) return true;
244
+
245
+ // Regenerate if file was modified after summary was generated
246
+ return fileLastModified > summary.generatedAt;
247
+ }
248
+
249
+ // Get compression ratio stats
250
+ getCompressionStats(): { totalFiles: number; avgCompression: number; totalTokensSaved: number } {
251
+ const stmt = this.db.prepare(`
252
+ SELECT
253
+ COUNT(*) as total_files,
254
+ AVG(f.size_bytes / 4.0 / NULLIF(fs.summary_tokens, 0)) as avg_compression,
255
+ SUM(f.size_bytes / 4.0 - fs.summary_tokens) as tokens_saved
256
+ FROM file_summaries fs
257
+ JOIN files f ON fs.file_id = f.id
258
+ `);
259
+ const result = stmt.get() as { total_files: number; avg_compression: number; tokens_saved: number };
260
+
261
+ return {
262
+ totalFiles: result.total_files || 0,
263
+ avgCompression: result.avg_compression || 1,
264
+ totalTokensSaved: result.tokens_saved || 0
265
+ };
266
+ }
267
+ }