neuronlayer 0.1.0 → 1.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/README.md +203 -123
  2. package/dist/index.js +635 -710
  3. package/dist/index.js.map +7 -0
  4. package/package.json +67 -63
  5. package/CONTRIBUTING.md +0 -127
  6. package/esbuild.config.js +0 -26
  7. package/src/cli/commands.ts +0 -382
  8. package/src/core/adr-exporter.ts +0 -253
  9. package/src/core/architecture/architecture-enforcement.ts +0 -228
  10. package/src/core/architecture/duplicate-detector.ts +0 -288
  11. package/src/core/architecture/index.ts +0 -6
  12. package/src/core/architecture/pattern-learner.ts +0 -306
  13. package/src/core/architecture/pattern-library.ts +0 -403
  14. package/src/core/architecture/pattern-validator.ts +0 -324
  15. package/src/core/change-intelligence/bug-correlator.ts +0 -444
  16. package/src/core/change-intelligence/change-intelligence.ts +0 -221
  17. package/src/core/change-intelligence/change-tracker.ts +0 -334
  18. package/src/core/change-intelligence/fix-suggester.ts +0 -340
  19. package/src/core/change-intelligence/index.ts +0 -5
  20. package/src/core/code-verifier.ts +0 -843
  21. package/src/core/confidence/confidence-scorer.ts +0 -251
  22. package/src/core/confidence/conflict-checker.ts +0 -289
  23. package/src/core/confidence/index.ts +0 -5
  24. package/src/core/confidence/source-tracker.ts +0 -263
  25. package/src/core/confidence/warning-detector.ts +0 -241
  26. package/src/core/context-rot/compaction.ts +0 -284
  27. package/src/core/context-rot/context-health.ts +0 -243
  28. package/src/core/context-rot/context-rot-prevention.ts +0 -213
  29. package/src/core/context-rot/critical-context.ts +0 -221
  30. package/src/core/context-rot/drift-detector.ts +0 -255
  31. package/src/core/context-rot/index.ts +0 -7
  32. package/src/core/context.ts +0 -263
  33. package/src/core/decision-extractor.ts +0 -339
  34. package/src/core/decisions.ts +0 -69
  35. package/src/core/deja-vu.ts +0 -421
  36. package/src/core/engine.ts +0 -1455
  37. package/src/core/feature-context.ts +0 -726
  38. package/src/core/ghost-mode.ts +0 -412
  39. package/src/core/learning.ts +0 -485
  40. package/src/core/living-docs/activity-tracker.ts +0 -296
  41. package/src/core/living-docs/architecture-generator.ts +0 -428
  42. package/src/core/living-docs/changelog-generator.ts +0 -348
  43. package/src/core/living-docs/component-generator.ts +0 -230
  44. package/src/core/living-docs/doc-engine.ts +0 -110
  45. package/src/core/living-docs/doc-validator.ts +0 -282
  46. package/src/core/living-docs/index.ts +0 -8
  47. package/src/core/project-manager.ts +0 -297
  48. package/src/core/summarizer.ts +0 -267
  49. package/src/core/test-awareness/change-validator.ts +0 -499
  50. package/src/core/test-awareness/index.ts +0 -5
  51. package/src/index.ts +0 -49
  52. package/src/indexing/ast.ts +0 -563
  53. package/src/indexing/embeddings.ts +0 -85
  54. package/src/indexing/indexer.ts +0 -245
  55. package/src/indexing/watcher.ts +0 -78
  56. package/src/server/gateways/aggregator.ts +0 -374
  57. package/src/server/gateways/index.ts +0 -473
  58. package/src/server/gateways/memory-ghost.ts +0 -343
  59. package/src/server/gateways/memory-query.ts +0 -452
  60. package/src/server/gateways/memory-record.ts +0 -346
  61. package/src/server/gateways/memory-review.ts +0 -410
  62. package/src/server/gateways/memory-status.ts +0 -517
  63. package/src/server/gateways/memory-verify.ts +0 -392
  64. package/src/server/gateways/router.ts +0 -434
  65. package/src/server/gateways/types.ts +0 -610
  66. package/src/server/mcp.ts +0 -154
  67. package/src/server/resources.ts +0 -85
  68. package/src/server/tools.ts +0 -2261
  69. package/src/storage/database.ts +0 -262
  70. package/src/storage/tier1.ts +0 -135
  71. package/src/storage/tier2.ts +0 -764
  72. package/src/storage/tier3.ts +0 -123
  73. package/src/types/documentation.ts +0 -619
  74. package/src/types/index.ts +0 -222
  75. package/src/utils/config.ts +0 -193
  76. package/src/utils/files.ts +0 -117
  77. package/src/utils/time.ts +0 -37
  78. package/src/utils/tokens.ts +0 -52
@@ -1,253 +0,0 @@
1
- import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
2
- import { join } from 'path';
3
- import type { Decision } from '../types/index.js';
4
-
5
- export interface ADRExportOptions {
6
- outputDir?: string;
7
- format?: 'madr' | 'nygard' | 'simple';
8
- includeIndex?: boolean;
9
- }
10
-
11
- export class ADRExporter {
12
- private projectPath: string;
13
-
14
- constructor(projectPath: string) {
15
- this.projectPath = projectPath;
16
- }
17
-
18
- // Export a single decision to ADR file
19
- exportDecision(decision: Decision, options: ADRExportOptions = {}): string {
20
- const outputDir = options.outputDir || join(this.projectPath, 'docs', 'decisions');
21
- const format = options.format || 'madr';
22
-
23
- // Ensure output directory exists
24
- if (!existsSync(outputDir)) {
25
- mkdirSync(outputDir, { recursive: true });
26
- }
27
-
28
- // Generate filename
29
- const existingFiles = this.getExistingADRFiles(outputDir);
30
- const nextNumber = this.getNextADRNumber(existingFiles);
31
- const slug = this.slugify(decision.title);
32
- const filename = `${String(nextNumber).padStart(4, '0')}-${slug}.md`;
33
- const filePath = join(outputDir, filename);
34
-
35
- // Generate content based on format
36
- let content: string;
37
- switch (format) {
38
- case 'madr':
39
- content = this.formatMADR(decision, nextNumber);
40
- break;
41
- case 'nygard':
42
- content = this.formatNygard(decision, nextNumber);
43
- break;
44
- case 'simple':
45
- default:
46
- content = this.formatSimple(decision, nextNumber);
47
- break;
48
- }
49
-
50
- // Write file
51
- writeFileSync(filePath, content);
52
-
53
- return filePath;
54
- }
55
-
56
- // Export all decisions
57
- exportAllDecisions(decisions: Decision[], options: ADRExportOptions = {}): string[] {
58
- const exportedFiles: string[] = [];
59
- const outputDir = options.outputDir || join(this.projectPath, 'docs', 'decisions');
60
-
61
- // Sort by creation date
62
- const sorted = [...decisions].sort((a, b) =>
63
- a.createdAt.getTime() - b.createdAt.getTime()
64
- );
65
-
66
- for (const decision of sorted) {
67
- const filePath = this.exportDecision(decision, { ...options, outputDir });
68
- exportedFiles.push(filePath);
69
- }
70
-
71
- // Generate index if requested
72
- if (options.includeIndex !== false) {
73
- const indexPath = this.generateIndex(decisions, outputDir);
74
- exportedFiles.push(indexPath);
75
- }
76
-
77
- return exportedFiles;
78
- }
79
-
80
- // Generate index file
81
- private generateIndex(decisions: Decision[], outputDir: string): string {
82
- const indexPath = join(outputDir, 'README.md');
83
-
84
- const lines: string[] = [
85
- '# Architecture Decision Records',
86
- '',
87
- 'This directory contains Architecture Decision Records (ADRs) for this project.',
88
- '',
89
- '## Decisions',
90
- '',
91
- '| # | Title | Status | Date |',
92
- '|---|-------|--------|------|'
93
- ];
94
-
95
- const sorted = [...decisions].sort((a, b) =>
96
- a.createdAt.getTime() - b.createdAt.getTime()
97
- );
98
-
99
- sorted.forEach((d, i) => {
100
- const num = String(i + 1).padStart(4, '0');
101
- const slug = this.slugify(d.title);
102
- const status = d.status || 'accepted';
103
- const date = d.createdAt.toISOString().split('T')[0];
104
- lines.push(`| ${num} | [${d.title}](./${num}-${slug}.md) | ${status} | ${date} |`);
105
- });
106
-
107
- lines.push('');
108
- lines.push('---');
109
- lines.push('');
110
- lines.push('*Generated by MemoryLayer*');
111
-
112
- writeFileSync(indexPath, lines.join('\n'));
113
- return indexPath;
114
- }
115
-
116
- // MADR format (Markdown Any Decision Records)
117
- private formatMADR(decision: Decision, number: number): string {
118
- const date = decision.createdAt.toISOString().split('T')[0];
119
- const status = decision.status || 'accepted';
120
-
121
- return `# ${decision.title}
122
-
123
- * Status: ${status}
124
- * Date: ${date}
125
- ${decision.author ? `* Author: ${decision.author}` : ''}
126
- ${decision.tags.length > 0 ? `* Tags: ${decision.tags.join(', ')}` : ''}
127
-
128
- ## Context and Problem Statement
129
-
130
- ${decision.description}
131
-
132
- ## Decision Drivers
133
-
134
- * [List the main factors that influenced this decision]
135
-
136
- ## Considered Options
137
-
138
- * [Option 1]
139
- * [Option 2]
140
- * [Option 3]
141
-
142
- ## Decision Outcome
143
-
144
- Chosen option: "${decision.title}"
145
-
146
- ### Consequences
147
-
148
- * Good, because [positive consequence]
149
- * Bad, because [negative consequence]
150
-
151
- ${decision.files.length > 0 ? `## Related Files
152
-
153
- ${decision.files.map(f => `* \`${f}\``).join('\n')}
154
- ` : ''}
155
- ${decision.supersededBy ? `## Superseded By
156
-
157
- This decision has been superseded by [ADR ${decision.supersededBy}](./${decision.supersededBy}.md).
158
- ` : ''}
159
- ---
160
- *Exported from MemoryLayer*
161
- `;
162
- }
163
-
164
- // Nygard format (original ADR format)
165
- private formatNygard(decision: Decision, number: number): string {
166
- const date = decision.createdAt.toISOString().split('T')[0];
167
- const status = decision.status || 'Accepted';
168
-
169
- return `# ${number}. ${decision.title}
170
-
171
- Date: ${date}
172
-
173
- ## Status
174
-
175
- ${status.charAt(0).toUpperCase() + status.slice(1)}
176
- ${decision.supersededBy ? `\nSuperseded by [ADR ${decision.supersededBy}](./${decision.supersededBy}.md)` : ''}
177
-
178
- ## Context
179
-
180
- ${decision.description}
181
-
182
- ## Decision
183
-
184
- We will ${decision.title.toLowerCase()}.
185
-
186
- ## Consequences
187
-
188
- [Describe the consequences of this decision]
189
-
190
- ${decision.files.length > 0 ? `## Related Files
191
-
192
- ${decision.files.map(f => `- ${f}`).join('\n')}
193
- ` : ''}
194
- ---
195
- *Exported from MemoryLayer*
196
- `;
197
- }
198
-
199
- // Simple format
200
- private formatSimple(decision: Decision, number: number): string {
201
- const date = decision.createdAt.toISOString().split('T')[0];
202
-
203
- return `# ${decision.title}
204
-
205
- **Date:** ${date}
206
- ${decision.author ? `**Author:** ${decision.author}` : ''}
207
- **Status:** ${decision.status || 'accepted'}
208
- ${decision.tags.length > 0 ? `**Tags:** ${decision.tags.join(', ')}` : ''}
209
-
210
- ## Description
211
-
212
- ${decision.description}
213
-
214
- ${decision.files.length > 0 ? `## Related Files
215
-
216
- ${decision.files.map(f => `- \`${f}\``).join('\n')}
217
- ` : ''}
218
- ---
219
- *Exported from MemoryLayer*
220
- `;
221
- }
222
-
223
- private getExistingADRFiles(dir: string): string[] {
224
- if (!existsSync(dir)) return [];
225
-
226
- try {
227
- const { readdirSync } = require('fs');
228
- return readdirSync(dir)
229
- .filter((f: string) => /^\d{4}-.*\.md$/.test(f))
230
- .sort();
231
- } catch {
232
- return [];
233
- }
234
- }
235
-
236
- private getNextADRNumber(existingFiles: string[]): number {
237
- if (existingFiles.length === 0) return 1;
238
-
239
- const numbers = existingFiles
240
- .map(f => parseInt(f.split('-')[0] || '0', 10))
241
- .filter(n => !isNaN(n));
242
-
243
- return Math.max(...numbers, 0) + 1;
244
- }
245
-
246
- private slugify(text: string): string {
247
- return text
248
- .toLowerCase()
249
- .replace(/[^a-z0-9]+/g, '-')
250
- .replace(/^-|-$/g, '')
251
- .slice(0, 50);
252
- }
253
- }
@@ -1,228 +0,0 @@
1
- import type Database from 'better-sqlite3';
2
- import type { Tier2Storage } from '../../storage/tier2.js';
3
- import type { EmbeddingGenerator } from '../../indexing/embeddings.js';
4
- import type {
5
- Pattern,
6
- PatternCategory,
7
- PatternValidationResult,
8
- ExistingFunction,
9
- CodeExample,
10
- PatternRule
11
- } from '../../types/documentation.js';
12
- import { PatternLibrary } from './pattern-library.js';
13
- import { PatternLearner } from './pattern-learner.js';
14
- import { PatternValidator } from './pattern-validator.js';
15
- import { DuplicateDetector } from './duplicate-detector.js';
16
-
17
- export class ArchitectureEnforcement {
18
- private patternLibrary: PatternLibrary;
19
- private patternLearner: PatternLearner;
20
- private patternValidator: PatternValidator;
21
- private duplicateDetector: DuplicateDetector;
22
- private initialized = false;
23
-
24
- constructor(
25
- db: Database.Database,
26
- tier2: Tier2Storage,
27
- embeddingGenerator: EmbeddingGenerator
28
- ) {
29
- this.patternLibrary = new PatternLibrary(db);
30
- this.duplicateDetector = new DuplicateDetector(tier2, embeddingGenerator);
31
- this.patternLearner = new PatternLearner(tier2, this.patternLibrary);
32
- this.patternValidator = new PatternValidator(this.patternLibrary, this.duplicateDetector, tier2);
33
- }
34
-
35
- // Initialize by learning patterns from codebase
36
- initialize(): { patternsLearned: number; examplesAdded: number } {
37
- if (this.initialized) return { patternsLearned: 0, examplesAdded: 0 };
38
-
39
- const result = this.patternLearner.learnFromCodebase();
40
- this.initialized = true;
41
-
42
- return {
43
- patternsLearned: result.patternsLearned,
44
- examplesAdded: result.examplesAdded
45
- };
46
- }
47
-
48
- // Validate code against patterns
49
- validatePattern(code: string, type?: PatternCategory | 'auto'): PatternValidationResult {
50
- return this.patternValidator.validate(code, type);
51
- }
52
-
53
- // Suggest existing functions for an intent
54
- suggestExisting(intent: string, limit?: number): ExistingFunction[] {
55
- return this.duplicateDetector.suggestExisting(intent, limit);
56
- }
57
-
58
- // Learn a new pattern
59
- learnPattern(
60
- code: string,
61
- name: string,
62
- description?: string,
63
- category?: PatternCategory
64
- ): { success: boolean; patternId?: string; message: string } {
65
- return this.patternLearner.learnPattern(code, name, description, category);
66
- }
67
-
68
- // List all patterns
69
- listPatterns(category?: PatternCategory): Pattern[] {
70
- if (category) {
71
- return this.patternLibrary.getPatternsByCategory(category);
72
- }
73
- return this.patternLibrary.getAllPatterns();
74
- }
75
-
76
- // Get a specific pattern
77
- getPattern(id: string): Pattern | null {
78
- return this.patternLibrary.getPattern(id);
79
- }
80
-
81
- // Add example to existing pattern
82
- addExample(patternId: string, code: string, explanation: string, isAntiPattern: boolean = false): boolean {
83
- const example: CodeExample = { code, explanation };
84
- return this.patternLibrary.addExample(patternId, example, isAntiPattern);
85
- }
86
-
87
- // Add rule to existing pattern
88
- addRule(patternId: string, rule: string, severity: 'info' | 'warning' | 'critical'): boolean {
89
- const patternRule: PatternRule = { rule, severity };
90
- return this.patternLibrary.addRule(patternId, patternRule);
91
- }
92
-
93
- // Search patterns
94
- searchPatterns(query: string): Pattern[] {
95
- return this.patternLibrary.searchPatterns(query);
96
- }
97
-
98
- // Delete a pattern
99
- deletePattern(id: string): boolean {
100
- return this.patternLibrary.deletePattern(id);
101
- }
102
-
103
- // Refresh duplicate detector index
104
- refreshIndex(): void {
105
- this.duplicateDetector.refresh();
106
- }
107
-
108
- // Get statistics
109
- getStats(): {
110
- patterns: {
111
- total: number;
112
- byCategory: Record<string, number>;
113
- topPatterns: Array<{ name: string; usageCount: number }>;
114
- };
115
- functions: {
116
- total: number;
117
- exported: number;
118
- byPurpose: Record<string, number>;
119
- };
120
- } {
121
- return {
122
- patterns: this.patternLearner.getStats(),
123
- functions: this.duplicateDetector.getStats()
124
- };
125
- }
126
-
127
- // Format validation result for display
128
- static formatValidationResult(result: PatternValidationResult): string {
129
- const lines: string[] = [];
130
-
131
- const scoreIcon = result.score >= 80 ? '\u{1F7E2}' :
132
- result.score >= 50 ? '\u{1F7E1}' : '\u{1F534}';
133
-
134
- lines.push(`\u{1F50D} Pattern Validation\n`);
135
- lines.push(`${scoreIcon} Score: ${result.score}/100`);
136
-
137
- if (result.matchedPattern) {
138
- lines.push(`Matched Pattern: ${result.matchedPattern}`);
139
- }
140
-
141
- if (result.violations.length > 0) {
142
- lines.push('\n\u274C Violations:');
143
- for (const v of result.violations) {
144
- const icon = v.severity === 'critical' ? '\u{1F534}' :
145
- v.severity === 'warning' ? '\u{1F7E1}' : '\u{2139}\u{FE0F}';
146
- lines.push(` ${icon} ${v.message}`);
147
- if (v.suggestion) {
148
- lines.push(` \u2192 ${v.suggestion}`);
149
- }
150
- }
151
- }
152
-
153
- if (result.existingAlternatives.length > 0) {
154
- lines.push('\n\u{1F4A1} Existing Alternatives:');
155
- for (const alt of result.existingAlternatives) {
156
- lines.push(` - ${alt.name}() in ${alt.file} (${alt.similarity}% similar)`);
157
- }
158
- }
159
-
160
- if (result.suggestions.length > 0) {
161
- lines.push('\n\u{1F4DD} Suggestions:');
162
- for (const s of result.suggestions) {
163
- const icon = s.priority === 'high' ? '\u{1F534}' :
164
- s.priority === 'medium' ? '\u{1F7E1}' : '\u{1F7E2}';
165
- lines.push(` ${icon} ${s.description}`);
166
- if (s.code) {
167
- lines.push(` ${s.code}`);
168
- }
169
- }
170
- }
171
-
172
- return lines.join('\n');
173
- }
174
-
175
- // Format pattern list for display
176
- static formatPatternList(patterns: Pattern[]): string {
177
- if (patterns.length === 0) {
178
- return 'No patterns found.';
179
- }
180
-
181
- const lines: string[] = [];
182
- lines.push(`\u{1F4DA} Patterns (${patterns.length})\n`);
183
-
184
- const byCategory: Record<string, Pattern[]> = {};
185
- for (const p of patterns) {
186
- if (!byCategory[p.category]) {
187
- byCategory[p.category] = [];
188
- }
189
- byCategory[p.category].push(p);
190
- }
191
-
192
- for (const [category, categoryPatterns] of Object.entries(byCategory)) {
193
- lines.push(`\n${category.toUpperCase()}:`);
194
- for (const p of categoryPatterns) {
195
- lines.push(` \u251C\u2500 ${p.name} (${p.usageCount} uses)`);
196
- if (p.description) {
197
- lines.push(` \u2502 ${p.description.slice(0, 50)}...`);
198
- }
199
- lines.push(` \u2502 Rules: ${p.rules.length}, Examples: ${p.examples.length}`);
200
- }
201
- }
202
-
203
- return lines.join('\n');
204
- }
205
-
206
- // Format existing function suggestions for display
207
- static formatSuggestions(suggestions: ExistingFunction[]): string {
208
- if (suggestions.length === 0) {
209
- return 'No existing functions found for this intent.';
210
- }
211
-
212
- const lines: string[] = [];
213
- lines.push(`\u{1F4A1} Existing Functions\n`);
214
-
215
- for (const s of suggestions) {
216
- lines.push(`\u251C\u2500 ${s.name}()`);
217
- lines.push(`\u2502 File: ${s.file}:${s.line}`);
218
- lines.push(`\u2502 Signature: ${s.signature}`);
219
- lines.push(`\u2502 Used: ${s.usageCount} times, Relevance: ${s.similarity}%`);
220
- if (s.description) {
221
- lines.push(`\u2502 ${s.description}`);
222
- }
223
- lines.push('');
224
- }
225
-
226
- return lines.join('\n');
227
- }
228
- }