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,452 @@
1
+ /**
2
+ * Memory Query Gateway
3
+ *
4
+ * Routes to: get_context, search_codebase, get_file_context, get_file_summary,
5
+ * get_symbol, get_dependencies, get_predicted_files, get_confidence,
6
+ * list_sources, suggest_existing
7
+ */
8
+
9
+ import type { MemoryLayerEngine } from '../../core/engine.js';
10
+ import type { MemoryQueryInput, MemoryQueryResponse, MemoryQueryAction } from './types.js';
11
+ import { detectQueryAction, parseQuery, isFilePath } from './router.js';
12
+ import { aggregateQueryResults, mergeSearchResults } from './aggregator.js';
13
+ import { formatTimeAgo } from '../../utils/time.js';
14
+
15
+ /**
16
+ * Handle a memory_query gateway call
17
+ */
18
+ export async function handleMemoryQuery(
19
+ engine: MemoryLayerEngine,
20
+ input: MemoryQueryInput
21
+ ): Promise<MemoryQueryResponse> {
22
+ const action = detectQueryAction(input);
23
+ const sourcesUsed: string[] = [];
24
+
25
+ // Route based on detected/explicit action
26
+ switch (action) {
27
+ case 'file':
28
+ return handleFileQuery(engine, input, sourcesUsed);
29
+
30
+ case 'summary':
31
+ return handleSummaryQuery(engine, input, sourcesUsed);
32
+
33
+ case 'symbol':
34
+ return handleSymbolQuery(engine, input, sourcesUsed);
35
+
36
+ case 'dependencies':
37
+ return handleDependenciesQuery(engine, input, sourcesUsed);
38
+
39
+ case 'predict':
40
+ return handlePredictQuery(engine, input, sourcesUsed);
41
+
42
+ case 'confidence':
43
+ return handleConfidenceQuery(engine, input, sourcesUsed);
44
+
45
+ case 'sources':
46
+ return handleSourcesQuery(engine, input, sourcesUsed);
47
+
48
+ case 'existing':
49
+ return handleExistingQuery(engine, input, sourcesUsed);
50
+
51
+ case 'search':
52
+ return handleSearchOnlyQuery(engine, input, sourcesUsed);
53
+
54
+ case 'context':
55
+ default:
56
+ return handleContextQuery(engine, input, sourcesUsed);
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Combined context + search query (default behavior)
62
+ * Enhanced with déjà vu detection and proactive predictions
63
+ */
64
+ async function handleContextQuery(
65
+ engine: MemoryLayerEngine,
66
+ input: MemoryQueryInput,
67
+ sourcesUsed: string[]
68
+ ): Promise<MemoryQueryResponse> {
69
+ sourcesUsed.push('get_context', 'search_codebase');
70
+
71
+ // Notify ghost mode of file access for silent tracking
72
+ if (input.file) {
73
+ engine.notifyFileAccess(input.file).catch(err => {
74
+ console.error('Ghost mode file access error:', err);
75
+ });
76
+ }
77
+
78
+ // Run context, search, and déjà vu in parallel
79
+ const [contextResult, searchResults, dejaVuMatches] = await Promise.all([
80
+ engine.getContext(input.query, input.file, input.max_tokens),
81
+ engine.searchCodebase(input.query, input.max_results || 10),
82
+ engine.findDejaVu(input.query, 3), // Check for similar past problems
83
+ ]);
84
+
85
+ const response = aggregateQueryResults(
86
+ contextResult,
87
+ searchResults,
88
+ sourcesUsed
89
+ ) as MemoryQueryResponse;
90
+
91
+ // Add déjà vu matches if found (proactive intelligence)
92
+ // Surfaced prominently to address "I feel like I solved this before" problem
93
+ if (dejaVuMatches.length > 0) {
94
+ sourcesUsed.push('deja_vu');
95
+
96
+ // Format user-friendly messages
97
+ const formattedMatches = dejaVuMatches.map(m => ({
98
+ type: m.type,
99
+ message: m.message,
100
+ file: m.file,
101
+ similarity: m.similarity,
102
+ when: m.when.toISOString(),
103
+ context: m.context,
104
+ // Human-readable time ago
105
+ time_ago: formatTimeAgo(m.when),
106
+ }));
107
+
108
+ (response as MemoryQueryResponse & { deja_vu?: unknown }).deja_vu = {
109
+ has_matches: true,
110
+ hint: formattedMatches.length === 1
111
+ ? `You worked on something similar ${formattedMatches[0]?.time_ago || 'recently'}`
112
+ : `Found ${formattedMatches.length} similar past problems`,
113
+ matches: formattedMatches,
114
+ };
115
+ }
116
+
117
+ // Add predicted files (proactive context)
118
+ if (input.file) {
119
+ sourcesUsed.push('predict_files');
120
+ const predictedFiles = engine.getPredictedFiles(input.file, input.query);
121
+ if (predictedFiles.length > 0) {
122
+ (response as MemoryQueryResponse & { predictions?: unknown }).predictions = {
123
+ likely_next_files: predictedFiles.slice(0, 5),
124
+ };
125
+ }
126
+ }
127
+
128
+ // If confidence requested, add it
129
+ if (input.include_confidence && input.code) {
130
+ sourcesUsed.push('get_confidence');
131
+ const confidence = await engine.getConfidence(input.code, input.query);
132
+ response.confidence = {
133
+ level: confidence.confidence,
134
+ score: confidence.score,
135
+ reasoning: confidence.reasoning,
136
+ indicator: engine.getConfidenceIndicator(confidence.confidence),
137
+ };
138
+ }
139
+
140
+ // Record query for future déjà vu detection
141
+ engine.recordQueryForDejaVu(input.query, contextResult.sources);
142
+
143
+ return response;
144
+ }
145
+
146
+ /**
147
+ * Search only (no context assembly)
148
+ */
149
+ async function handleSearchOnlyQuery(
150
+ engine: MemoryLayerEngine,
151
+ input: MemoryQueryInput,
152
+ sourcesUsed: string[]
153
+ ): Promise<MemoryQueryResponse> {
154
+ sourcesUsed.push('search_codebase');
155
+
156
+ const searchResults = await engine.searchCodebase(
157
+ input.query,
158
+ input.max_results || 10
159
+ );
160
+
161
+ return {
162
+ sources_used: sourcesUsed,
163
+ search_results: searchResults.map(r => ({
164
+ file: r.file,
165
+ preview: r.preview,
166
+ relevance: r.similarity,
167
+ line_start: r.lineStart,
168
+ line_end: r.lineEnd,
169
+ })),
170
+ };
171
+ }
172
+
173
+ /**
174
+ * File context retrieval
175
+ */
176
+ async function handleFileQuery(
177
+ engine: MemoryLayerEngine,
178
+ input: MemoryQueryInput,
179
+ sourcesUsed: string[]
180
+ ): Promise<MemoryQueryResponse> {
181
+ sourcesUsed.push('get_file_context');
182
+
183
+ // Determine file path from input.file or input.query
184
+ const filePath = input.file || (isFilePath(input.query) ? input.query : null);
185
+
186
+ if (!filePath) {
187
+ return {
188
+ sources_used: sourcesUsed,
189
+ file_content: undefined,
190
+ };
191
+ }
192
+
193
+ const result = await engine.getFileContext(filePath);
194
+
195
+ if (!result) {
196
+ return {
197
+ sources_used: sourcesUsed,
198
+ file_content: undefined,
199
+ };
200
+ }
201
+
202
+ return {
203
+ sources_used: sourcesUsed,
204
+ file_content: {
205
+ path: filePath,
206
+ content: result.content,
207
+ language: result.language,
208
+ lines: result.lines,
209
+ },
210
+ };
211
+ }
212
+
213
+ /**
214
+ * File summary retrieval
215
+ */
216
+ async function handleSummaryQuery(
217
+ engine: MemoryLayerEngine,
218
+ input: MemoryQueryInput,
219
+ sourcesUsed: string[]
220
+ ): Promise<MemoryQueryResponse> {
221
+ sourcesUsed.push('get_file_summary');
222
+
223
+ const filePath = input.file || (isFilePath(input.query) ? input.query : null);
224
+
225
+ if (!filePath) {
226
+ return {
227
+ sources_used: sourcesUsed,
228
+ file_summary: undefined,
229
+ };
230
+ }
231
+
232
+ const summary = engine.getFileSummary(filePath);
233
+
234
+ return {
235
+ sources_used: sourcesUsed,
236
+ file_summary: summary ? {
237
+ path: filePath,
238
+ summary,
239
+ } : undefined,
240
+ };
241
+ }
242
+
243
+ /**
244
+ * Symbol lookup
245
+ */
246
+ async function handleSymbolQuery(
247
+ engine: MemoryLayerEngine,
248
+ input: MemoryQueryInput,
249
+ sourcesUsed: string[]
250
+ ): Promise<MemoryQueryResponse> {
251
+ sourcesUsed.push('get_symbol');
252
+
253
+ const symbolName = input.symbol || input.query;
254
+ const results = await engine.searchSymbols(
255
+ symbolName,
256
+ input.symbol_kind,
257
+ input.max_results || 10
258
+ );
259
+
260
+ // If we have results and a specific file, also get dependencies
261
+ const firstResult = results[0];
262
+ if (results.length > 0 && firstResult && firstResult.filePath) {
263
+ sourcesUsed.push('get_dependencies');
264
+ const deps = engine.getFileDependencies(firstResult.filePath);
265
+
266
+ return {
267
+ sources_used: sourcesUsed,
268
+ symbols: results.map(s => ({
269
+ name: s.name,
270
+ kind: s.kind,
271
+ file: s.filePath,
272
+ line_start: s.lineStart,
273
+ line_end: s.lineEnd,
274
+ signature: s.signature || undefined,
275
+ exported: s.exported,
276
+ })),
277
+ dependencies: {
278
+ file: firstResult.filePath,
279
+ imports: deps.imports,
280
+ imported_by: deps.importedBy,
281
+ symbols: deps.symbols,
282
+ },
283
+ };
284
+ }
285
+
286
+ return {
287
+ sources_used: sourcesUsed,
288
+ symbols: results.map(s => ({
289
+ name: s.name,
290
+ kind: s.kind,
291
+ file: s.filePath,
292
+ line_start: s.lineStart,
293
+ line_end: s.lineEnd,
294
+ signature: s.signature || undefined,
295
+ exported: s.exported,
296
+ })),
297
+ };
298
+ }
299
+
300
+ /**
301
+ * Dependency lookup
302
+ */
303
+ async function handleDependenciesQuery(
304
+ engine: MemoryLayerEngine,
305
+ input: MemoryQueryInput,
306
+ sourcesUsed: string[]
307
+ ): Promise<MemoryQueryResponse> {
308
+ sourcesUsed.push('get_dependencies');
309
+
310
+ const filePath = input.file || (isFilePath(input.query) ? input.query : null);
311
+
312
+ if (!filePath) {
313
+ return {
314
+ sources_used: sourcesUsed,
315
+ dependencies: undefined,
316
+ };
317
+ }
318
+
319
+ const deps = engine.getFileDependencies(filePath);
320
+
321
+ return {
322
+ sources_used: sourcesUsed,
323
+ dependencies: {
324
+ file: filePath,
325
+ imports: deps.imports,
326
+ imported_by: deps.importedBy,
327
+ symbols: deps.symbols,
328
+ },
329
+ };
330
+ }
331
+
332
+ /**
333
+ * Predicted files query
334
+ */
335
+ async function handlePredictQuery(
336
+ engine: MemoryLayerEngine,
337
+ input: MemoryQueryInput,
338
+ sourcesUsed: string[]
339
+ ): Promise<MemoryQueryResponse> {
340
+ sourcesUsed.push('get_predicted_files');
341
+
342
+ if (!input.file) {
343
+ return {
344
+ sources_used: sourcesUsed,
345
+ predicted_files: undefined,
346
+ };
347
+ }
348
+
349
+ const predicted = engine.getPredictedFiles(input.file, input.query);
350
+ const preFetched = await engine.preFetchFiles(input.file, input.query);
351
+
352
+ return {
353
+ sources_used: sourcesUsed,
354
+ predicted_files: {
355
+ files: predicted,
356
+ pre_fetched: preFetched,
357
+ },
358
+ };
359
+ }
360
+
361
+ /**
362
+ * Confidence assessment query
363
+ */
364
+ async function handleConfidenceQuery(
365
+ engine: MemoryLayerEngine,
366
+ input: MemoryQueryInput,
367
+ sourcesUsed: string[]
368
+ ): Promise<MemoryQueryResponse> {
369
+ sourcesUsed.push('get_confidence');
370
+
371
+ if (!input.code) {
372
+ return {
373
+ sources_used: sourcesUsed,
374
+ confidence: undefined,
375
+ };
376
+ }
377
+
378
+ const result = await engine.getConfidence(input.code, input.query);
379
+
380
+ return {
381
+ sources_used: sourcesUsed,
382
+ confidence: {
383
+ level: result.confidence,
384
+ score: result.score,
385
+ reasoning: result.reasoning,
386
+ indicator: engine.getConfidenceIndicator(result.confidence),
387
+ },
388
+ source_attribution: {
389
+ codebase_matches: result.sources.codebase.length,
390
+ decision_matches: result.sources.decisions.length,
391
+ pattern_matches: result.sources.patterns.length,
392
+ used_general_knowledge: result.sources.usedGeneralKnowledge,
393
+ },
394
+ };
395
+ }
396
+
397
+ /**
398
+ * Source attribution query
399
+ */
400
+ async function handleSourcesQuery(
401
+ engine: MemoryLayerEngine,
402
+ input: MemoryQueryInput,
403
+ sourcesUsed: string[]
404
+ ): Promise<MemoryQueryResponse> {
405
+ sourcesUsed.push('list_sources');
406
+
407
+ if (!input.code) {
408
+ return {
409
+ sources_used: sourcesUsed,
410
+ source_attribution: undefined,
411
+ };
412
+ }
413
+
414
+ const sources = await engine.listConfidenceSources(input.code, input.query, true);
415
+
416
+ return {
417
+ sources_used: sourcesUsed,
418
+ source_attribution: {
419
+ codebase_matches: sources.codebase.length,
420
+ decision_matches: sources.decisions.length,
421
+ pattern_matches: sources.patterns.length,
422
+ used_general_knowledge: sources.usedGeneralKnowledge,
423
+ },
424
+ };
425
+ }
426
+
427
+ /**
428
+ * Existing function suggestions query
429
+ */
430
+ async function handleExistingQuery(
431
+ engine: MemoryLayerEngine,
432
+ input: MemoryQueryInput,
433
+ sourcesUsed: string[]
434
+ ): Promise<MemoryQueryResponse> {
435
+ sourcesUsed.push('suggest_existing');
436
+
437
+ const suggestions = engine.suggestExisting(
438
+ input.query,
439
+ input.max_results || 5
440
+ );
441
+
442
+ return {
443
+ sources_used: sourcesUsed,
444
+ existing_functions: suggestions.map(s => ({
445
+ name: s.name,
446
+ file: s.file,
447
+ line: s.line,
448
+ signature: s.signature,
449
+ similarity: s.similarity,
450
+ })),
451
+ };
452
+ }