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,85 +0,0 @@
1
- import { pipeline, type FeatureExtractionPipeline } from '@xenova/transformers';
2
-
3
- export class EmbeddingGenerator {
4
- private model: FeatureExtractionPipeline | null = null;
5
- private initialized = false;
6
- private initializing = false;
7
- private modelName: string;
8
- private dimension: number = 384; // Default for MiniLM
9
-
10
- constructor(modelName: string = 'Xenova/all-MiniLM-L6-v2') {
11
- this.modelName = modelName;
12
- }
13
-
14
- async initialize(): Promise<void> {
15
- if (this.initialized) return;
16
- if (this.initializing) {
17
- // Wait for initialization to complete
18
- while (this.initializing) {
19
- await new Promise(resolve => setTimeout(resolve, 100));
20
- }
21
- return;
22
- }
23
-
24
- this.initializing = true;
25
-
26
- try {
27
- console.error(`Loading embedding model: ${this.modelName}...`);
28
-
29
- this.model = await pipeline('feature-extraction', this.modelName, {
30
- quantized: true
31
- });
32
-
33
- this.initialized = true;
34
- console.error('Embedding model loaded successfully');
35
- } catch (error) {
36
- console.error('Failed to load embedding model:', error);
37
- throw error;
38
- } finally {
39
- this.initializing = false;
40
- }
41
- }
42
-
43
- async embed(text: string): Promise<Float32Array> {
44
- await this.initialize();
45
-
46
- if (!this.model) {
47
- throw new Error('Embedding model not initialized');
48
- }
49
-
50
- // Truncate very long texts
51
- const maxChars = 8000; // ~2000 tokens
52
- const truncatedText = text.length > maxChars ? text.slice(0, maxChars) : text;
53
-
54
- const output = await this.model(truncatedText, {
55
- pooling: 'mean',
56
- normalize: true
57
- });
58
-
59
- // Extract the embedding data
60
- const data = output.data as Float32Array;
61
- this.dimension = data.length;
62
-
63
- return new Float32Array(data);
64
- }
65
-
66
- async embedBatch(texts: string[], batchSize: number = 8): Promise<Float32Array[]> {
67
- const results: Float32Array[] = [];
68
-
69
- for (let i = 0; i < texts.length; i += batchSize) {
70
- const batch = texts.slice(i, i + batchSize);
71
- const embeddings = await Promise.all(batch.map(t => this.embed(t)));
72
- results.push(...embeddings);
73
- }
74
-
75
- return results;
76
- }
77
-
78
- getDimension(): number {
79
- return this.dimension;
80
- }
81
-
82
- isInitialized(): boolean {
83
- return this.initialized;
84
- }
85
- }
@@ -1,270 +0,0 @@
1
- import { readFileSync, statSync } from 'fs';
2
- import { glob } from 'glob';
3
- import { join, relative } from 'path';
4
- import { EventEmitter } from 'events';
5
- import { EmbeddingGenerator } from './embeddings.js';
6
- import { ASTParser } from './ast.js';
7
- import { FileWatcher, type FileEvent } from './watcher.js';
8
- import { Tier2Storage } from '../storage/tier2.js';
9
- import { isCodeFile, detectLanguage, hashContent, getPreview, countLines } from '../utils/files.js';
10
- import type { NeuronLayerConfig, IndexingProgress } from '../types/index.js';
11
-
12
- export class Indexer extends EventEmitter {
13
- private config: NeuronLayerConfig;
14
- private embeddingGenerator: EmbeddingGenerator;
15
- private astParser: ASTParser;
16
- private watcher: FileWatcher;
17
- private tier2: Tier2Storage;
18
- private isIndexing = false;
19
- private pendingFiles: Set<string> = new Set();
20
- private processTimeout: NodeJS.Timeout | null = null;
21
-
22
- constructor(config: NeuronLayerConfig, tier2: Tier2Storage) {
23
- super();
24
- this.config = config;
25
- this.tier2 = tier2;
26
- this.embeddingGenerator = new EmbeddingGenerator(config.embeddingModel);
27
- this.astParser = new ASTParser(config.dataDir);
28
- this.watcher = new FileWatcher(config.projectPath, config.watchIgnore);
29
-
30
- this.setupWatcher();
31
- }
32
-
33
- private setupWatcher(): void {
34
- this.watcher.on('file', (event: FileEvent) => {
35
- this.handleFileEvent(event);
36
- });
37
-
38
- this.watcher.on('ready', () => {
39
- this.emit('watcherReady');
40
- });
41
-
42
- this.watcher.on('error', (error) => {
43
- this.emit('error', error);
44
- });
45
- }
46
-
47
- private handleFileEvent(event: FileEvent): void {
48
- // Only process code files
49
- if (!isCodeFile(event.path)) {
50
- return;
51
- }
52
-
53
- if (event.type === 'unlink') {
54
- // File deleted
55
- this.tier2.deleteFile(event.relativePath);
56
- this.emit('fileRemoved', event.relativePath);
57
- return;
58
- }
59
-
60
- // Add or change - queue for processing
61
- this.pendingFiles.add(event.path);
62
- this.schedulePendingProcessing();
63
- }
64
-
65
- private schedulePendingProcessing(): void {
66
- // Debounce processing
67
- if (this.processTimeout) {
68
- clearTimeout(this.processTimeout);
69
- }
70
-
71
- this.processTimeout = setTimeout(() => {
72
- this.processPendingFiles();
73
- }, 500);
74
- }
75
-
76
- private async processPendingFiles(): Promise<void> {
77
- if (this.isIndexing || this.pendingFiles.size === 0) {
78
- return;
79
- }
80
-
81
- const files = Array.from(this.pendingFiles);
82
- this.pendingFiles.clear();
83
-
84
- for (const file of files) {
85
- try {
86
- await this.indexFile(file);
87
- } catch (error) {
88
- console.error(`Error indexing ${file}:`, error);
89
- }
90
- }
91
- }
92
-
93
- async indexFile(absolutePath: string): Promise<boolean> {
94
- try {
95
- const content = readFileSync(absolutePath, 'utf-8');
96
- const stats = statSync(absolutePath);
97
- const relativePath = relative(this.config.projectPath, absolutePath);
98
-
99
- const contentHash = hashContent(content);
100
- const existingFile = this.tier2.getFile(relativePath);
101
-
102
- // Skip if content hasn't changed
103
- if (existingFile && existingFile.contentHash === contentHash) {
104
- return false; // Not indexed, skipped
105
- }
106
-
107
- const language = detectLanguage(absolutePath);
108
- const preview = getPreview(content);
109
- const lineCount = countLines(content);
110
-
111
- // Store file metadata
112
- const fileId = this.tier2.upsertFile(
113
- relativePath,
114
- contentHash,
115
- preview,
116
- language,
117
- stats.size,
118
- lineCount,
119
- Math.floor(stats.mtimeMs)
120
- );
121
-
122
- // Generate and store embedding
123
- const embedding = await this.embeddingGenerator.embed(content);
124
- this.tier2.upsertEmbedding(fileId, embedding);
125
-
126
- // Phase 2: Parse AST and extract symbols
127
- try {
128
- const parsed = await this.astParser.parseFile(relativePath, content);
129
- if (parsed) {
130
- // Clear old symbols/imports/exports for this file
131
- this.tier2.clearSymbols(fileId);
132
- this.tier2.clearImports(fileId);
133
- this.tier2.clearExports(fileId);
134
-
135
- // Insert new symbols with fileId
136
- if (parsed.symbols.length > 0) {
137
- const symbolsWithFileId = parsed.symbols.map(s => ({ ...s, fileId }));
138
- this.tier2.insertSymbols(symbolsWithFileId);
139
- }
140
-
141
- // Insert imports with fileId
142
- if (parsed.imports.length > 0) {
143
- const importsWithFileId = parsed.imports.map(i => ({ ...i, fileId }));
144
- this.tier2.insertImports(importsWithFileId);
145
- }
146
-
147
- // Insert exports with fileId
148
- if (parsed.exports.length > 0) {
149
- const exportsWithFileId = parsed.exports.map(e => ({ ...e, fileId }));
150
- this.tier2.insertExports(exportsWithFileId);
151
- }
152
-
153
- // Build dependency edges from imports
154
- if (parsed.imports.length > 0) {
155
- this.tier2.clearDependencies(fileId);
156
- for (const imp of parsed.imports) {
157
- const targetFile = this.tier2.resolveImportToFile(relativePath, imp.importedFrom);
158
- if (targetFile) {
159
- this.tier2.addDependency(fileId, targetFile.id, 'imports');
160
- }
161
- }
162
- }
163
- }
164
- } catch (astError) {
165
- // AST parsing is optional, don't fail the whole index
166
- console.error(`AST parsing failed for ${relativePath}:`, astError);
167
- }
168
-
169
- this.emit('fileIndexed', relativePath);
170
-
171
- // Emit impact warning for changed files (not during initial indexing)
172
- if (!this.isIndexing) {
173
- const dependents = this.tier2.getFileDependents(relativePath);
174
- if (dependents.length > 0) {
175
- this.emit('fileImpact', {
176
- file: relativePath,
177
- affectedFiles: dependents.map(d => d.file),
178
- affectedCount: dependents.length,
179
- imports: dependents.map(d => ({ file: d.file, symbols: d.imports }))
180
- });
181
- }
182
- }
183
-
184
- return true; // Actually indexed
185
- } catch (error) {
186
- console.error(`Error indexing ${absolutePath}:`, error);
187
- this.emit('indexError', { path: absolutePath, error });
188
- return false;
189
- }
190
- }
191
-
192
- async performInitialIndex(): Promise<void> {
193
- if (this.isIndexing) {
194
- return;
195
- }
196
-
197
- this.isIndexing = true;
198
- this.emit('indexingStarted');
199
-
200
- try {
201
- // Find all code files
202
- const patterns = [
203
- '**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.mjs', '**/*.cjs',
204
- '**/*.py', '**/*.rb', '**/*.go', '**/*.rs', '**/*.java', '**/*.kt',
205
- '**/*.cs', '**/*.cpp', '**/*.c', '**/*.h', '**/*.hpp',
206
- '**/*.php', '**/*.swift', '**/*.vue', '**/*.svelte',
207
- '**/*.md', '**/*.json', '**/*.yaml', '**/*.yml',
208
- '**/*.sql', '**/*.sh', '**/*.dockerfile',
209
- '**/*.prisma', '**/*.graphql'
210
- ];
211
-
212
- const files: string[] = [];
213
-
214
- for (const pattern of patterns) {
215
- const matches = await glob(pattern, {
216
- cwd: this.config.projectPath,
217
- ignore: this.config.watchIgnore,
218
- absolute: true,
219
- nodir: true
220
- });
221
- files.push(...matches);
222
- }
223
-
224
- // Deduplicate
225
- const uniqueFiles = [...new Set(files)];
226
-
227
- let checked = 0;
228
- let indexed = 0;
229
- const total = uniqueFiles.length;
230
-
231
- // Index files (only shows progress for actually indexed files)
232
- for (const file of uniqueFiles) {
233
- try {
234
- const wasIndexed = await this.indexFile(file);
235
- checked++;
236
- if (wasIndexed) {
237
- indexed++;
238
- this.emit('progress', { total, indexed, current: relative(this.config.projectPath, file) });
239
- }
240
- } catch (error) {
241
- console.error(`Error indexing ${file}:`, error);
242
- }
243
- }
244
-
245
- this.emit('indexingComplete', {
246
- total: checked,
247
- indexed,
248
- skipped: checked - indexed
249
- });
250
- } finally {
251
- this.isIndexing = false;
252
- }
253
- }
254
-
255
- startWatching(): void {
256
- this.watcher.start();
257
- }
258
-
259
- stopWatching(): void {
260
- this.watcher.stop();
261
- }
262
-
263
- getEmbeddingGenerator(): EmbeddingGenerator {
264
- return this.embeddingGenerator;
265
- }
266
-
267
- isCurrentlyIndexing(): boolean {
268
- return this.isIndexing;
269
- }
270
- }
@@ -1,78 +0,0 @@
1
- import chokidar, { type FSWatcher } from 'chokidar';
2
- import { EventEmitter } from 'events';
3
- import { relative } from 'path';
4
-
5
- export interface FileEvent {
6
- type: 'add' | 'change' | 'unlink';
7
- path: string;
8
- relativePath: string;
9
- }
10
-
11
- export class FileWatcher extends EventEmitter {
12
- private watcher: FSWatcher | null = null;
13
- private projectPath: string;
14
- private ignorePatterns: string[];
15
-
16
- constructor(projectPath: string, ignorePatterns: string[] = []) {
17
- super();
18
- this.projectPath = projectPath;
19
- this.ignorePatterns = ignorePatterns;
20
- }
21
-
22
- start(): void {
23
- if (this.watcher) {
24
- return;
25
- }
26
-
27
- this.watcher = chokidar.watch(this.projectPath, {
28
- ignored: [
29
- /(^|[\/\\])\../, // dotfiles
30
- ...this.ignorePatterns
31
- ],
32
- persistent: true,
33
- ignoreInitial: false, // We want initial add events for indexing
34
- awaitWriteFinish: {
35
- stabilityThreshold: 300,
36
- pollInterval: 100
37
- },
38
- usePolling: false, // Use native events when possible
39
- depth: 20 // Limit recursion depth
40
- });
41
-
42
- this.watcher
43
- .on('add', (path) => this.handleEvent('add', path))
44
- .on('change', (path) => this.handleEvent('change', path))
45
- .on('unlink', (path) => this.handleEvent('unlink', path))
46
- .on('error', (error) => {
47
- console.error('File watcher error:', error);
48
- this.emit('error', error);
49
- })
50
- .on('ready', () => {
51
- console.error('File watcher ready');
52
- this.emit('ready');
53
- });
54
- }
55
-
56
- private handleEvent(type: 'add' | 'change' | 'unlink', path: string): void {
57
- const relativePath = relative(this.projectPath, path);
58
-
59
- const event: FileEvent = {
60
- type,
61
- path,
62
- relativePath
63
- };
64
-
65
- this.emit('file', event);
66
- }
67
-
68
- stop(): void {
69
- if (this.watcher) {
70
- this.watcher.close();
71
- this.watcher = null;
72
- }
73
- }
74
-
75
- isRunning(): boolean {
76
- return this.watcher !== null;
77
- }
78
- }