neuronlayer 0.1.9 → 0.2.1

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 +7 -2
  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,284 +0,0 @@
1
- import type {
2
- ContextChunk,
3
- CompactionResult,
4
- CompactionOptions,
5
- CompactionSuggestion
6
- } from '../../types/documentation.js';
7
- import { ContextHealthMonitor } from './context-health.js';
8
- import { CriticalContextManager } from './critical-context.js';
9
-
10
- // Thresholds for different strategies
11
- const RELEVANCE_THRESHOLD_SUMMARIZE = 0.5;
12
- const RELEVANCE_THRESHOLD_SELECTIVE = 0.3;
13
- const RELEVANCE_THRESHOLD_AGGRESSIVE = 0.2;
14
-
15
- export class CompactionEngine {
16
- private healthMonitor: ContextHealthMonitor;
17
- private criticalManager: CriticalContextManager;
18
-
19
- constructor(healthMonitor: ContextHealthMonitor, criticalManager: CriticalContextManager) {
20
- this.healthMonitor = healthMonitor;
21
- this.criticalManager = criticalManager;
22
- }
23
-
24
- suggestCompaction(): CompactionSuggestion {
25
- const chunks = this.healthMonitor.getChunks();
26
- const tokenLimit = this.healthMonitor.getTokenLimit();
27
- const currentTokens = this.healthMonitor.getCurrentTokens();
28
-
29
- const critical: ContextChunk[] = [];
30
- const summarizable: ContextChunk[] = [];
31
- const removable: ContextChunk[] = [];
32
-
33
- for (const chunk of chunks) {
34
- if (chunk.isCritical || chunk.relevanceScore >= RELEVANCE_THRESHOLD_SUMMARIZE) {
35
- critical.push(chunk);
36
- } else if (chunk.relevanceScore >= RELEVANCE_THRESHOLD_SELECTIVE) {
37
- summarizable.push(chunk);
38
- } else {
39
- removable.push(chunk);
40
- }
41
- }
42
-
43
- const removableTokens = removable.reduce((sum, c) => sum + c.tokens, 0);
44
- const summarizableTokens = summarizable.reduce((sum, c) => sum + c.tokens, 0);
45
-
46
- // Estimate tokens after summarization (assume 70% compression)
47
- const summarizedTokens = Math.ceil(summarizableTokens * 0.3);
48
- const tokensSaved = removableTokens + (summarizableTokens - summarizedTokens);
49
-
50
- const newTokens = currentTokens - tokensSaved;
51
- const newUtilization = (newTokens / tokenLimit) * 100;
52
-
53
- return {
54
- critical,
55
- summarizable,
56
- removable,
57
- tokensSaved,
58
- newUtilization: Math.round(newUtilization * 10) / 10
59
- };
60
- }
61
-
62
- compact(options: CompactionOptions): CompactionResult {
63
- const { strategy, preserveRecent = 5, targetUtilization, preserveCritical = true } = options;
64
-
65
- const chunks = this.healthMonitor.getChunks();
66
- const tokensBefore = this.healthMonitor.getCurrentTokens();
67
-
68
- // Separate chunks by type
69
- const recentChunks = chunks.slice(-preserveRecent);
70
- const olderChunks = chunks.slice(0, -preserveRecent);
71
-
72
- let relevanceThreshold: number;
73
- switch (strategy) {
74
- case 'aggressive':
75
- relevanceThreshold = RELEVANCE_THRESHOLD_AGGRESSIVE;
76
- break;
77
- case 'selective':
78
- relevanceThreshold = RELEVANCE_THRESHOLD_SELECTIVE;
79
- break;
80
- case 'summarize':
81
- default:
82
- relevanceThreshold = RELEVANCE_THRESHOLD_SUMMARIZE;
83
- }
84
-
85
- const toKeep: ContextChunk[] = [];
86
- const toSummarize: ContextChunk[] = [];
87
- const toRemove: ContextChunk[] = [];
88
-
89
- for (const chunk of olderChunks) {
90
- // Always preserve critical if flag is set
91
- if (preserveCritical && chunk.isCritical) {
92
- toKeep.push(chunk);
93
- } else if (chunk.relevanceScore >= relevanceThreshold) {
94
- if (strategy === 'aggressive') {
95
- toSummarize.push(chunk);
96
- } else {
97
- toKeep.push(chunk);
98
- }
99
- } else if (chunk.relevanceScore >= relevanceThreshold * 0.5 && strategy !== 'aggressive') {
100
- toSummarize.push(chunk);
101
- } else {
102
- toRemove.push(chunk);
103
- }
104
- }
105
-
106
- // Generate summaries for chunks to summarize
107
- const summaries = this.generateSummaries(toSummarize);
108
-
109
- // Calculate new token count
110
- const keptTokens = toKeep.reduce((sum, c) => sum + c.tokens, 0);
111
- const recentTokens = recentChunks.reduce((sum, c) => sum + c.tokens, 0);
112
- const summaryTokens = summaries.reduce((sum, s) => sum + this.estimateTokens(s), 0);
113
-
114
- const tokensAfter = keptTokens + recentTokens + summaryTokens;
115
- const tokensSaved = tokensBefore - tokensAfter;
116
-
117
- // Update the health monitor with new chunks
118
- this.healthMonitor.clearChunks();
119
-
120
- // Re-add kept chunks
121
- for (const chunk of toKeep) {
122
- this.healthMonitor.addChunk(chunk);
123
- }
124
-
125
- // Add summary chunks
126
- for (const summary of summaries) {
127
- this.healthMonitor.addChunk({
128
- content: summary,
129
- tokens: this.estimateTokens(summary),
130
- timestamp: new Date(),
131
- type: 'message'
132
- });
133
- }
134
-
135
- // Re-add recent chunks
136
- for (const chunk of recentChunks) {
137
- this.healthMonitor.addChunk(chunk);
138
- }
139
-
140
- // Check if we hit target utilization
141
- if (targetUtilization) {
142
- const currentUtilization = (tokensAfter / this.healthMonitor.getTokenLimit()) * 100;
143
- if (currentUtilization > targetUtilization && strategy !== 'aggressive') {
144
- // Recursively compact with more aggressive strategy
145
- return this.compact({
146
- ...options,
147
- strategy: strategy === 'summarize' ? 'selective' : 'aggressive'
148
- });
149
- }
150
- }
151
-
152
- return {
153
- success: true,
154
- strategy,
155
- tokensBefore,
156
- tokensAfter,
157
- tokensSaved,
158
- preservedCritical: toKeep.filter(c => c.isCritical).length,
159
- summarizedChunks: toSummarize.length,
160
- removedChunks: toRemove.length,
161
- summaries
162
- };
163
- }
164
-
165
- private generateSummaries(chunks: ContextChunk[]): string[] {
166
- if (chunks.length === 0) return [];
167
-
168
- // Group chunks by type
169
- const grouped: Record<string, ContextChunk[]> = {};
170
- for (const chunk of chunks) {
171
- if (!grouped[chunk.type]) {
172
- grouped[chunk.type] = [];
173
- }
174
- grouped[chunk.type]!.push(chunk);
175
- }
176
-
177
- const summaries: string[] = [];
178
-
179
- for (const [type, typeChunks] of Object.entries(grouped)) {
180
- if (typeChunks.length === 0) continue;
181
-
182
- // Simple extractive summary: take key sentences
183
- const allContent = typeChunks.map(c => c.content).join(' ');
184
- const summary = this.extractiveSummarize(allContent, type);
185
- summaries.push(summary);
186
- }
187
-
188
- return summaries;
189
- }
190
-
191
- private extractiveSummarize(content: string, type: string): string {
192
- // Split into sentences
193
- const sentences = content.split(/[.!?]+/).map(s => s.trim()).filter(s => s.length > 10);
194
-
195
- if (sentences.length === 0) {
196
- return `[${type}]: ${content.slice(0, 100)}`;
197
- }
198
-
199
- // Score sentences by importance
200
- const scored = sentences.map(sentence => ({
201
- sentence,
202
- score: this.scoreSentence(sentence)
203
- }));
204
-
205
- // Sort by score and take top sentences
206
- scored.sort((a, b) => b.score - a.score);
207
- const topSentences = scored.slice(0, Math.min(3, sentences.length));
208
-
209
- // Sort back by original order for coherence
210
- const originalOrder = topSentences.sort((a, b) => {
211
- return sentences.indexOf(a.sentence) - sentences.indexOf(b.sentence);
212
- });
213
-
214
- const summary = originalOrder.map(s => s.sentence).join('. ') + '.';
215
-
216
- return `[Summary - ${type}]: ${summary}`;
217
- }
218
-
219
- private scoreSentence(sentence: string): number {
220
- let score = 0;
221
-
222
- // Longer sentences might have more info (but not too long)
223
- const wordCount = sentence.split(/\s+/).length;
224
- if (wordCount >= 5 && wordCount <= 30) {
225
- score += 1;
226
- }
227
-
228
- // Contains important keywords
229
- const importantWords = [
230
- 'decided', 'choose', 'use', 'implement', 'because', 'important',
231
- 'must', 'should', 'require', 'need', 'critical', 'key'
232
- ];
233
- for (const word of importantWords) {
234
- if (sentence.toLowerCase().includes(word)) {
235
- score += 0.5;
236
- }
237
- }
238
-
239
- // Contains technical terms (likely important)
240
- const technicalPatterns = [
241
- /\b[A-Z][a-z]+(?:[A-Z][a-z]+)+\b/, // CamelCase
242
- /\b\w+\(\)/, // Function calls
243
- /`[^`]+`/ // Code markers
244
- ];
245
- for (const pattern of technicalPatterns) {
246
- if (pattern.test(sentence)) {
247
- score += 0.3;
248
- }
249
- }
250
-
251
- return score;
252
- }
253
-
254
- private estimateTokens(text: string): number {
255
- // Rough estimation: ~4 characters per token
256
- return Math.ceil(text.length / 4);
257
- }
258
-
259
- autoCompact(): CompactionResult {
260
- const health = this.healthMonitor.getHealth();
261
-
262
- // Determine strategy based on health
263
- let strategy: CompactionOptions['strategy'];
264
- let targetUtilization: number;
265
-
266
- if (health.health === 'critical') {
267
- strategy = 'aggressive';
268
- targetUtilization = 40;
269
- } else if (health.health === 'warning') {
270
- strategy = 'selective';
271
- targetUtilization = 50;
272
- } else {
273
- strategy = 'summarize';
274
- targetUtilization = 60;
275
- }
276
-
277
- return this.compact({
278
- strategy,
279
- preserveRecent: 10,
280
- targetUtilization,
281
- preserveCritical: true
282
- });
283
- }
284
- }
@@ -1,243 +0,0 @@
1
- import type Database from 'better-sqlite3';
2
- import type { ContextHealth, ContextChunk } from '../../types/documentation.js';
3
- import { CriticalContextManager } from './critical-context.js';
4
-
5
- // Default token limits (can be overridden)
6
- const DEFAULT_TOKEN_LIMIT = 100000;
7
-
8
- // Health thresholds
9
- const UTILIZATION_WARNING = 0.7; // 70%
10
- const UTILIZATION_CRITICAL = 0.85; // 85%
11
- const DRIFT_WARNING = 0.3;
12
- const DRIFT_CRITICAL = 0.5;
13
-
14
- export class ContextHealthMonitor {
15
- private db: Database.Database;
16
- private criticalManager: CriticalContextManager;
17
- private tokenLimit: number;
18
-
19
- // In-memory tracking for current session
20
- private contextChunks: ContextChunk[] = [];
21
- private currentTokens: number = 0;
22
-
23
- constructor(db: Database.Database, criticalManager: CriticalContextManager, tokenLimit?: number) {
24
- this.db = db;
25
- this.criticalManager = criticalManager;
26
- this.tokenLimit = tokenLimit || DEFAULT_TOKEN_LIMIT;
27
- }
28
-
29
- setTokenLimit(limit: number): void {
30
- this.tokenLimit = limit;
31
- }
32
-
33
- getTokenLimit(): number {
34
- return this.tokenLimit;
35
- }
36
-
37
- addChunk(chunk: Omit<ContextChunk, 'id' | 'relevanceScore' | 'isCritical'>): ContextChunk {
38
- const id = `chunk_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
39
- const isCritical = this.criticalManager.isCritical(chunk.content);
40
-
41
- const fullChunk: ContextChunk = {
42
- ...chunk,
43
- id,
44
- relevanceScore: 1.0, // New chunks start with full relevance
45
- isCritical
46
- };
47
-
48
- this.contextChunks.push(fullChunk);
49
- this.currentTokens += chunk.tokens;
50
-
51
- // Decay relevance of older chunks
52
- this.decayRelevance();
53
-
54
- return fullChunk;
55
- }
56
-
57
- removeChunk(id: string): boolean {
58
- const index = this.contextChunks.findIndex(c => c.id === id);
59
- if (index === -1) return false;
60
-
61
- const chunk = this.contextChunks[index]!;
62
- this.currentTokens -= chunk.tokens;
63
- this.contextChunks.splice(index, 1);
64
-
65
- return true;
66
- }
67
-
68
- getChunks(): ContextChunk[] {
69
- return [...this.contextChunks];
70
- }
71
-
72
- clearChunks(): void {
73
- this.contextChunks = [];
74
- this.currentTokens = 0;
75
- }
76
-
77
- setCurrentTokens(tokens: number): void {
78
- this.currentTokens = tokens;
79
- }
80
-
81
- getCurrentTokens(): number {
82
- return this.currentTokens;
83
- }
84
-
85
- getHealth(driftScore: number = 0): ContextHealth {
86
- const tokensUsed = this.currentTokens;
87
- const utilizationPercent = (tokensUsed / this.tokenLimit) * 100;
88
-
89
- // Calculate relevance score (average of all chunks)
90
- const relevanceScore = this.contextChunks.length > 0
91
- ? this.contextChunks.reduce((sum, c) => sum + c.relevanceScore, 0) / this.contextChunks.length
92
- : 1.0;
93
-
94
- // Determine health status
95
- let health: ContextHealth['health'] = 'good';
96
- if (utilizationPercent >= UTILIZATION_CRITICAL * 100 || driftScore >= DRIFT_CRITICAL) {
97
- health = 'critical';
98
- } else if (utilizationPercent >= UTILIZATION_WARNING * 100 || driftScore >= DRIFT_WARNING) {
99
- health = 'warning';
100
- }
101
-
102
- // Check if compaction is needed
103
- const compactionNeeded = health !== 'good';
104
- const driftDetected = driftScore >= DRIFT_WARNING;
105
-
106
- // Generate suggestions
107
- const suggestions = this.generateSuggestions(health, utilizationPercent, driftScore);
108
-
109
- // Get critical context count
110
- const criticalContextCount = this.criticalManager.getCriticalCount();
111
-
112
- const healthResult: ContextHealth = {
113
- tokensUsed,
114
- tokensLimit: this.tokenLimit,
115
- utilizationPercent: Math.round(utilizationPercent * 10) / 10,
116
- health,
117
- relevanceScore: Math.round(relevanceScore * 100) / 100,
118
- driftScore: Math.round(driftScore * 100) / 100,
119
- criticalContextCount,
120
- driftDetected,
121
- compactionNeeded,
122
- suggestions
123
- };
124
-
125
- // Log to history
126
- this.logHealthCheck(healthResult);
127
-
128
- return healthResult;
129
- }
130
-
131
- private generateSuggestions(
132
- health: ContextHealth['health'],
133
- utilization: number,
134
- driftScore: number
135
- ): string[] {
136
- const suggestions: string[] = [];
137
-
138
- if (health === 'good') {
139
- suggestions.push('Context is healthy, no action needed');
140
- return suggestions;
141
- }
142
-
143
- if (utilization >= UTILIZATION_CRITICAL * 100) {
144
- suggestions.push('Context nearly full - compaction strongly recommended');
145
- suggestions.push('Consider using "aggressive" compaction strategy');
146
- } else if (utilization >= UTILIZATION_WARNING * 100) {
147
- suggestions.push('Context getting large - consider compaction');
148
- suggestions.push('Use "summarize" strategy to compress old context');
149
- }
150
-
151
- if (driftScore >= DRIFT_CRITICAL) {
152
- suggestions.push('Significant drift detected - AI may be ignoring earlier instructions');
153
- suggestions.push('Review critical context and add reminders if needed');
154
- } else if (driftScore >= DRIFT_WARNING) {
155
- suggestions.push('Some drift detected - consider marking critical items');
156
- }
157
-
158
- const criticalCount = this.criticalManager.getCriticalCount();
159
- if (criticalCount === 0) {
160
- suggestions.push('No critical context marked - consider marking important decisions/requirements');
161
- }
162
-
163
- return suggestions;
164
- }
165
-
166
- private decayRelevance(): void {
167
- // Decay relevance of chunks based on position (older = lower relevance)
168
- const totalChunks = this.contextChunks.length;
169
-
170
- for (let i = 0; i < totalChunks; i++) {
171
- const chunk = this.contextChunks[i]!;
172
-
173
- // Critical chunks decay slower
174
- const decayRate = chunk.isCritical ? 0.98 : 0.95;
175
-
176
- // Position-based decay (older chunks have lower position)
177
- const positionFactor = (i + 1) / totalChunks;
178
-
179
- // New relevance is combination of decay and position
180
- chunk.relevanceScore = Math.max(0.1, chunk.relevanceScore * decayRate * (0.5 + 0.5 * positionFactor));
181
- }
182
- }
183
-
184
- private logHealthCheck(health: ContextHealth): void {
185
- try {
186
- const stmt = this.db.prepare(`
187
- INSERT INTO context_health_history
188
- (tokens_used, tokens_limit, utilization_percent, drift_score, relevance_score, health, compaction_triggered)
189
- VALUES (?, ?, ?, ?, ?, ?, ?)
190
- `);
191
-
192
- stmt.run(
193
- health.tokensUsed,
194
- health.tokensLimit,
195
- health.utilizationPercent,
196
- health.driftScore,
197
- health.relevanceScore,
198
- health.health,
199
- 0
200
- );
201
- } catch {
202
- // Ignore logging errors
203
- }
204
- }
205
-
206
- getHealthHistory(limit: number = 20): Array<{
207
- timestamp: Date;
208
- health: ContextHealth['health'];
209
- utilizationPercent: number;
210
- driftScore: number;
211
- }> {
212
- try {
213
- const stmt = this.db.prepare(`
214
- SELECT timestamp, health, utilization_percent, drift_score
215
- FROM context_health_history
216
- ORDER BY timestamp DESC
217
- LIMIT ?
218
- `);
219
-
220
- const rows = stmt.all(limit) as Array<{
221
- timestamp: number;
222
- health: string;
223
- utilization_percent: number;
224
- drift_score: number;
225
- }>;
226
-
227
- return rows.map(row => ({
228
- timestamp: new Date(row.timestamp * 1000),
229
- health: row.health as ContextHealth['health'],
230
- utilizationPercent: row.utilization_percent,
231
- driftScore: row.drift_score
232
- }));
233
- } catch {
234
- return [];
235
- }
236
- }
237
-
238
- estimateTokens(text: string): number {
239
- // Rough estimation: ~4 characters per token for English
240
- // This is a simple heuristic; real implementation would use a proper tokenizer
241
- return Math.ceil(text.length / 4);
242
- }
243
- }