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,262 @@
1
+ import Database from 'better-sqlite3';
2
+ import { mkdirSync, existsSync } from 'fs';
3
+ import { dirname } from 'path';
4
+
5
+ export function initializeDatabase(dbPath: string): Database.Database {
6
+ // Ensure directory exists
7
+ const dir = dirname(dbPath);
8
+ if (!existsSync(dir)) {
9
+ mkdirSync(dir, { recursive: true });
10
+ }
11
+
12
+ const db = new Database(dbPath);
13
+
14
+ // Enable WAL mode for better concurrent access
15
+ db.pragma('journal_mode = WAL');
16
+
17
+ // Create tables
18
+ db.exec(`
19
+ -- Files table: stores file metadata
20
+ CREATE TABLE IF NOT EXISTS files (
21
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
22
+ path TEXT UNIQUE NOT NULL,
23
+ content_hash TEXT NOT NULL,
24
+ preview TEXT,
25
+ language TEXT,
26
+ size_bytes INTEGER,
27
+ line_count INTEGER,
28
+ last_modified INTEGER,
29
+ indexed_at INTEGER DEFAULT (unixepoch())
30
+ );
31
+
32
+ -- Embeddings table: stores file embeddings as binary blobs
33
+ CREATE TABLE IF NOT EXISTS embeddings (
34
+ file_id INTEGER PRIMARY KEY REFERENCES files(id) ON DELETE CASCADE,
35
+ embedding BLOB NOT NULL,
36
+ dimension INTEGER NOT NULL
37
+ );
38
+
39
+ -- Dependencies table: tracks file relationships
40
+ CREATE TABLE IF NOT EXISTS dependencies (
41
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
42
+ source_file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
43
+ target_file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
44
+ relationship TEXT NOT NULL,
45
+ UNIQUE(source_file_id, target_file_id, relationship)
46
+ );
47
+
48
+ -- Decisions table: stores architectural decisions
49
+ CREATE TABLE IF NOT EXISTS decisions (
50
+ id TEXT PRIMARY KEY,
51
+ title TEXT NOT NULL,
52
+ description TEXT NOT NULL,
53
+ files TEXT,
54
+ tags TEXT,
55
+ created_at INTEGER DEFAULT (unixepoch()),
56
+ embedding BLOB,
57
+ -- Phase 4: Team features
58
+ author TEXT,
59
+ status TEXT DEFAULT 'accepted',
60
+ superseded_by TEXT
61
+ );
62
+
63
+ -- Sessions table: tracks session history
64
+ CREATE TABLE IF NOT EXISTS sessions (
65
+ id TEXT PRIMARY KEY,
66
+ start_time INTEGER NOT NULL,
67
+ end_time INTEGER,
68
+ files_viewed TEXT,
69
+ summary TEXT
70
+ );
71
+
72
+ -- Project summary table
73
+ CREATE TABLE IF NOT EXISTS project_summary (
74
+ id INTEGER PRIMARY KEY CHECK (id = 1),
75
+ name TEXT,
76
+ description TEXT,
77
+ languages TEXT,
78
+ key_directories TEXT,
79
+ architecture_notes TEXT,
80
+ updated_at INTEGER DEFAULT (unixepoch())
81
+ );
82
+
83
+ -- Phase 2: Symbols table - stores code symbols (functions, classes, etc.)
84
+ CREATE TABLE IF NOT EXISTS symbols (
85
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
86
+ file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
87
+ kind TEXT NOT NULL,
88
+ name TEXT NOT NULL,
89
+ signature TEXT,
90
+ docstring TEXT,
91
+ line_start INTEGER NOT NULL,
92
+ line_end INTEGER NOT NULL,
93
+ exported INTEGER NOT NULL DEFAULT 0
94
+ );
95
+
96
+ -- Phase 2: Imports table - tracks what each file imports
97
+ CREATE TABLE IF NOT EXISTS imports (
98
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
99
+ file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
100
+ imported_from TEXT NOT NULL,
101
+ imported_symbols TEXT NOT NULL,
102
+ is_default INTEGER NOT NULL DEFAULT 0,
103
+ is_namespace INTEGER NOT NULL DEFAULT 0,
104
+ line_number INTEGER NOT NULL
105
+ );
106
+
107
+ -- Phase 2: Exports table - tracks what each file exports
108
+ CREATE TABLE IF NOT EXISTS exports (
109
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
110
+ file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,
111
+ exported_name TEXT NOT NULL,
112
+ local_name TEXT,
113
+ is_default INTEGER NOT NULL DEFAULT 0,
114
+ line_number INTEGER NOT NULL
115
+ );
116
+
117
+ -- Create indexes for common queries
118
+ CREATE INDEX IF NOT EXISTS idx_files_path ON files(path);
119
+ CREATE INDEX IF NOT EXISTS idx_files_language ON files(language);
120
+ CREATE INDEX IF NOT EXISTS idx_files_last_modified ON files(last_modified);
121
+ CREATE INDEX IF NOT EXISTS idx_dependencies_source ON dependencies(source_file_id);
122
+ CREATE INDEX IF NOT EXISTS idx_dependencies_target ON dependencies(target_file_id);
123
+ CREATE INDEX IF NOT EXISTS idx_decisions_created_at ON decisions(created_at);
124
+
125
+ -- Phase 2: Symbol indexes
126
+ CREATE INDEX IF NOT EXISTS idx_symbols_file_id ON symbols(file_id);
127
+ CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);
128
+ CREATE INDEX IF NOT EXISTS idx_symbols_kind ON symbols(kind);
129
+ CREATE INDEX IF NOT EXISTS idx_imports_file_id ON imports(file_id);
130
+ CREATE INDEX IF NOT EXISTS idx_imports_from ON imports(imported_from);
131
+ CREATE INDEX IF NOT EXISTS idx_exports_file_id ON exports(file_id);
132
+ CREATE INDEX IF NOT EXISTS idx_exports_name ON exports(exported_name);
133
+
134
+ -- Phase 3: Usage tracking for learning
135
+ CREATE TABLE IF NOT EXISTS usage_events (
136
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
137
+ event_type TEXT NOT NULL,
138
+ file_path TEXT,
139
+ query TEXT,
140
+ context_used INTEGER DEFAULT 0,
141
+ timestamp INTEGER DEFAULT (unixepoch())
142
+ );
143
+
144
+ -- Phase 3: File access frequency for personalized ranking
145
+ CREATE TABLE IF NOT EXISTS file_access (
146
+ file_id INTEGER PRIMARY KEY REFERENCES files(id) ON DELETE CASCADE,
147
+ access_count INTEGER DEFAULT 0,
148
+ last_accessed INTEGER DEFAULT (unixepoch()),
149
+ relevance_score REAL DEFAULT 0.5
150
+ );
151
+
152
+ -- Phase 3: Query patterns for prediction
153
+ CREATE TABLE IF NOT EXISTS query_patterns (
154
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
155
+ query_hash TEXT UNIQUE NOT NULL,
156
+ query_text TEXT NOT NULL,
157
+ result_files TEXT,
158
+ hit_count INTEGER DEFAULT 1,
159
+ avg_usefulness REAL DEFAULT 0.5,
160
+ last_used INTEGER DEFAULT (unixepoch())
161
+ );
162
+
163
+ -- Phase 3: File summaries for compression
164
+ CREATE TABLE IF NOT EXISTS file_summaries (
165
+ file_id INTEGER PRIMARY KEY REFERENCES files(id) ON DELETE CASCADE,
166
+ summary TEXT NOT NULL,
167
+ summary_tokens INTEGER,
168
+ generated_at INTEGER DEFAULT (unixepoch())
169
+ );
170
+
171
+ -- Phase 3: Indexes for usage tracking
172
+ CREATE INDEX IF NOT EXISTS idx_usage_events_timestamp ON usage_events(timestamp);
173
+ CREATE INDEX IF NOT EXISTS idx_usage_events_file ON usage_events(file_path);
174
+ CREATE INDEX IF NOT EXISTS idx_file_access_count ON file_access(access_count DESC);
175
+ CREATE INDEX IF NOT EXISTS idx_query_patterns_hash ON query_patterns(query_hash);
176
+
177
+ -- Phase 6: Living Documentation tables
178
+ CREATE TABLE IF NOT EXISTS documentation (
179
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
180
+ file_id INTEGER REFERENCES files(id) ON DELETE CASCADE,
181
+ doc_type TEXT NOT NULL,
182
+ content TEXT NOT NULL,
183
+ generated_at INTEGER DEFAULT (unixepoch()),
184
+ UNIQUE(file_id, doc_type)
185
+ );
186
+
187
+ CREATE TABLE IF NOT EXISTS activity_log (
188
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
189
+ timestamp INTEGER DEFAULT (unixepoch()),
190
+ activity_type TEXT NOT NULL,
191
+ description TEXT,
192
+ file_path TEXT,
193
+ metadata TEXT,
194
+ commit_hash TEXT
195
+ );
196
+
197
+ CREATE INDEX IF NOT EXISTS idx_activity_timestamp ON activity_log(timestamp);
198
+ CREATE INDEX IF NOT EXISTS idx_activity_type ON activity_log(activity_type);
199
+ CREATE INDEX IF NOT EXISTS idx_documentation_file ON documentation(file_id);
200
+
201
+ -- Phase 7: Context Rot Prevention tables
202
+ CREATE TABLE IF NOT EXISTS critical_context (
203
+ id TEXT PRIMARY KEY,
204
+ type TEXT NOT NULL,
205
+ content TEXT NOT NULL,
206
+ reason TEXT,
207
+ source TEXT,
208
+ never_compress INTEGER DEFAULT 1,
209
+ created_at INTEGER DEFAULT (unixepoch())
210
+ );
211
+
212
+ CREATE TABLE IF NOT EXISTS context_health_history (
213
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
214
+ timestamp INTEGER DEFAULT (unixepoch()),
215
+ tokens_used INTEGER,
216
+ tokens_limit INTEGER,
217
+ utilization_percent REAL,
218
+ drift_score REAL,
219
+ relevance_score REAL,
220
+ health TEXT,
221
+ compaction_triggered INTEGER DEFAULT 0
222
+ );
223
+
224
+ CREATE INDEX IF NOT EXISTS idx_critical_context_type ON critical_context(type);
225
+ CREATE INDEX IF NOT EXISTS idx_critical_context_created ON critical_context(created_at);
226
+ CREATE INDEX IF NOT EXISTS idx_context_health_timestamp ON context_health_history(timestamp);
227
+
228
+ -- Phase 11: Test-Aware Suggestions tables
229
+ CREATE TABLE IF NOT EXISTS test_index (
230
+ id TEXT PRIMARY KEY,
231
+ file_path TEXT NOT NULL,
232
+ test_name TEXT NOT NULL,
233
+ describes TEXT,
234
+ covers_files TEXT, -- JSON array
235
+ covers_functions TEXT, -- JSON array
236
+ assertions TEXT, -- JSON array
237
+ line_start INTEGER,
238
+ line_end INTEGER,
239
+ last_status TEXT,
240
+ last_run INTEGER,
241
+ indexed_at INTEGER DEFAULT (unixepoch()),
242
+ UNIQUE(file_path, test_name)
243
+ );
244
+
245
+ CREATE TABLE IF NOT EXISTS test_config (
246
+ id INTEGER PRIMARY KEY CHECK (id = 1),
247
+ framework TEXT NOT NULL,
248
+ test_patterns TEXT, -- JSON array of glob patterns
249
+ last_indexed INTEGER
250
+ );
251
+
252
+ CREATE INDEX IF NOT EXISTS idx_test_index_file ON test_index(file_path);
253
+ CREATE INDEX IF NOT EXISTS idx_test_index_name ON test_index(test_name);
254
+ CREATE INDEX IF NOT EXISTS idx_test_covers_files ON test_index(covers_files);
255
+ `);
256
+
257
+ return db;
258
+ }
259
+
260
+ export function closeDatabase(db: Database.Database): void {
261
+ db.close();
262
+ }
@@ -0,0 +1,135 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
2
+ import { dirname, join } from 'path';
3
+ import type { Tier1Context, Decision, ActiveFile, ContextSnippet, Session } from '../types/index.js';
4
+
5
+ const MAX_RECENT_DECISIONS = 20;
6
+ const MAX_IMMEDIATE_CONTEXT = 10;
7
+ const MAX_FILES_VIEWED = 50;
8
+
9
+ export class Tier1Storage {
10
+ private filePath: string;
11
+ private context: Tier1Context;
12
+
13
+ constructor(dataDir: string) {
14
+ this.filePath = join(dataDir, 'tier1.json');
15
+ this.context = this.load();
16
+ }
17
+
18
+ private getDefaultContext(): Tier1Context {
19
+ return {
20
+ activeFile: null,
21
+ recentDecisions: [],
22
+ session: {
23
+ startTime: new Date(),
24
+ filesViewed: [],
25
+ currentGoal: undefined
26
+ },
27
+ immediateContext: []
28
+ };
29
+ }
30
+
31
+ load(): Tier1Context {
32
+ try {
33
+ if (existsSync(this.filePath)) {
34
+ const data = JSON.parse(readFileSync(this.filePath, 'utf-8'));
35
+ // Parse dates
36
+ if (data.session?.startTime) {
37
+ data.session.startTime = new Date(data.session.startTime);
38
+ }
39
+ if (data.recentDecisions) {
40
+ data.recentDecisions = data.recentDecisions.map((d: Decision) => ({
41
+ ...d,
42
+ createdAt: new Date(d.createdAt)
43
+ }));
44
+ }
45
+ if (data.immediateContext) {
46
+ data.immediateContext = data.immediateContext.map((c: ContextSnippet) => ({
47
+ ...c,
48
+ timestamp: new Date(c.timestamp)
49
+ }));
50
+ }
51
+ return data;
52
+ }
53
+ } catch (error) {
54
+ console.error('Error loading tier1 context:', error);
55
+ }
56
+ return this.getDefaultContext();
57
+ }
58
+
59
+ save(): void {
60
+ try {
61
+ const dir = dirname(this.filePath);
62
+ if (!existsSync(dir)) {
63
+ mkdirSync(dir, { recursive: true });
64
+ }
65
+ writeFileSync(this.filePath, JSON.stringify(this.context, null, 2));
66
+ } catch (error) {
67
+ console.error('Error saving tier1 context:', error);
68
+ }
69
+ }
70
+
71
+ getContext(): Tier1Context {
72
+ return this.context;
73
+ }
74
+
75
+ setActiveFile(file: ActiveFile | null): void {
76
+ this.context.activeFile = file;
77
+
78
+ if (file && !this.context.session.filesViewed.includes(file.path)) {
79
+ this.context.session.filesViewed.unshift(file.path);
80
+ // Limit files viewed list
81
+ if (this.context.session.filesViewed.length > MAX_FILES_VIEWED) {
82
+ this.context.session.filesViewed = this.context.session.filesViewed.slice(0, MAX_FILES_VIEWED);
83
+ }
84
+ }
85
+
86
+ this.save();
87
+ }
88
+
89
+ addDecision(decision: Decision): void {
90
+ // Remove existing decision with same ID if present
91
+ this.context.recentDecisions = this.context.recentDecisions.filter(d => d.id !== decision.id);
92
+
93
+ // Add new decision at the beginning
94
+ this.context.recentDecisions.unshift(decision);
95
+
96
+ // Limit recent decisions
97
+ if (this.context.recentDecisions.length > MAX_RECENT_DECISIONS) {
98
+ this.context.recentDecisions = this.context.recentDecisions.slice(0, MAX_RECENT_DECISIONS);
99
+ }
100
+
101
+ this.save();
102
+ }
103
+
104
+ getRecentDecisions(limit: number = 10): Decision[] {
105
+ return this.context.recentDecisions.slice(0, limit);
106
+ }
107
+
108
+ addImmediateContext(snippet: ContextSnippet): void {
109
+ this.context.immediateContext.unshift(snippet);
110
+
111
+ if (this.context.immediateContext.length > MAX_IMMEDIATE_CONTEXT) {
112
+ this.context.immediateContext = this.context.immediateContext.slice(0, MAX_IMMEDIATE_CONTEXT);
113
+ }
114
+
115
+ this.save();
116
+ }
117
+
118
+ setCurrentGoal(goal: string | undefined): void {
119
+ this.context.session.currentGoal = goal;
120
+ this.save();
121
+ }
122
+
123
+ startNewSession(): void {
124
+ this.context = this.getDefaultContext();
125
+ this.save();
126
+ }
127
+
128
+ getSession(): Session {
129
+ return this.context.session;
130
+ }
131
+
132
+ getFilesViewed(): string[] {
133
+ return this.context.session.filesViewed;
134
+ }
135
+ }