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,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 NeuronLayer*');
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 NeuronLayer*
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 NeuronLayer*
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 NeuronLayer*
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
- }