@ulrichc1/sparn 1.2.1 → 1.4.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 (42) hide show
  1. package/PRIVACY.md +1 -1
  2. package/README.md +136 -642
  3. package/SECURITY.md +1 -1
  4. package/dist/cli/dashboard.cjs +3977 -0
  5. package/dist/cli/dashboard.cjs.map +1 -0
  6. package/dist/cli/dashboard.d.cts +17 -0
  7. package/dist/cli/dashboard.d.ts +17 -0
  8. package/dist/cli/dashboard.js +3932 -0
  9. package/dist/cli/dashboard.js.map +1 -0
  10. package/dist/cli/index.cjs +3855 -486
  11. package/dist/cli/index.cjs.map +1 -1
  12. package/dist/cli/index.js +3812 -459
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/daemon/index.cjs +411 -99
  15. package/dist/daemon/index.cjs.map +1 -1
  16. package/dist/daemon/index.js +423 -103
  17. package/dist/daemon/index.js.map +1 -1
  18. package/dist/hooks/post-tool-result.cjs +129 -225
  19. package/dist/hooks/post-tool-result.cjs.map +1 -1
  20. package/dist/hooks/post-tool-result.js +129 -225
  21. package/dist/hooks/post-tool-result.js.map +1 -1
  22. package/dist/hooks/pre-prompt.cjs +206 -242
  23. package/dist/hooks/pre-prompt.cjs.map +1 -1
  24. package/dist/hooks/pre-prompt.js +192 -243
  25. package/dist/hooks/pre-prompt.js.map +1 -1
  26. package/dist/hooks/stop-docs-refresh.cjs +123 -0
  27. package/dist/hooks/stop-docs-refresh.cjs.map +1 -0
  28. package/dist/hooks/stop-docs-refresh.d.cts +1 -0
  29. package/dist/hooks/stop-docs-refresh.d.ts +1 -0
  30. package/dist/hooks/stop-docs-refresh.js +126 -0
  31. package/dist/hooks/stop-docs-refresh.js.map +1 -0
  32. package/dist/index.cjs +1756 -339
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +540 -41
  35. package/dist/index.d.ts +540 -41
  36. package/dist/index.js +1739 -331
  37. package/dist/index.js.map +1 -1
  38. package/dist/mcp/index.cjs +306 -73
  39. package/dist/mcp/index.cjs.map +1 -1
  40. package/dist/mcp/index.js +310 -73
  41. package/dist/mcp/index.js.map +1 -1
  42. package/package.json +10 -3
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/btsp-embedder.ts","../src/utils/hash.ts","../src/core/confidence-states.ts","../src/core/engram-scorer.ts","../src/utils/tokenizer.ts","../src/core/sparse-pruner.ts","../src/utils/context-parser.ts","../src/adapters/claude-code.ts","../src/adapters/generic.ts","../src/core/budget-pruner.ts","../src/core/metrics.ts","../src/core/incremental-optimizer.ts","../src/core/context-pipeline.ts","../src/core/kv-memory.ts","../src/core/sleep-compressor.ts","../src/daemon/daemon-process.ts","../src/daemon/file-tracker.ts","../src/daemon/session-watcher.ts","../src/mcp/server.ts","../src/types/config.ts","../src/utils/logger.ts"],"sourcesContent":["/**\n * BTSP Embedder - Implements behavioral timescale synaptic plasticity\n *\n * Neuroscience: One-shot learning from critical events (errors, conflicts).\n * Application: Detect high-importance patterns and mark for permanent retention.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { MemoryEntry } from '../types/memory.js';\nimport { hashContent } from '../utils/hash.js';\n\nexport interface BTSPEmbedder {\n /**\n * Detect if content contains BTSP patterns (errors, stack traces, conflicts, git diffs)\n * @param content - Content to analyze\n * @returns True if BTSP pattern detected\n */\n detectBTSP(content: string): boolean;\n\n /**\n * Create a new memory entry marked as BTSP (one-shot learned)\n * @param content - Entry content\n * @param tags - Optional tags\n * @param metadata - Optional metadata\n * @returns BTSP-marked memory entry\n */\n createBTSPEntry(\n content: string,\n tags?: string[],\n metadata?: Record<string, unknown>,\n ): MemoryEntry;\n}\n\n/**\n * Create a BTSP embedder instance\n * @returns BTSPEmbedder instance\n */\nexport function createBTSPEmbedder(): BTSPEmbedder {\n // Patterns that indicate critical events\n const BTSP_PATTERNS = [\n // Error patterns\n /\\b(error|exception|failure|fatal|critical|panic)\\b/i,\n /\\b(TypeError|ReferenceError|SyntaxError|RangeError|URIError)\\b/,\n /\\bENOENT|EACCES|ECONNREFUSED|ETIMEDOUT\\b/,\n\n // Stack trace patterns\n /^\\s+at\\s+.*\\(.*:\\d+:\\d+\\)/m, // JavaScript stack trace\n /^\\s+at\\s+.*\\.[a-zA-Z]+:\\d+/m, // Python/Ruby stack trace\n\n // Git diff new files\n /^new file mode \\d+$/m,\n /^--- \\/dev\\/null$/m,\n\n // Merge conflict markers\n /^<<<<<<< /m,\n /^=======/m,\n /^>>>>>>> /m,\n ];\n\n function detectBTSP(content: string): boolean {\n return BTSP_PATTERNS.some((pattern) => pattern.test(content));\n }\n\n function createBTSPEntry(\n content: string,\n tags: string[] = [],\n metadata: Record<string, unknown> = {},\n ): MemoryEntry {\n return {\n id: randomUUID(),\n content,\n hash: hashContent(content),\n timestamp: Date.now(),\n score: 1.0, // Maximum initial score\n ttl: 365 * 24 * 3600, // 1 year in seconds (long retention)\n state: 'active', // Always active\n accessCount: 0,\n tags: [...tags, 'btsp'],\n metadata,\n isBTSP: true,\n };\n }\n\n return {\n detectBTSP,\n createBTSPEntry,\n };\n}\n","/**\n * Content hashing utilities.\n * Uses SHA-256 for deduplication.\n */\n\nimport { createHash } from 'node:crypto';\n\n/**\n * Generate SHA-256 hash of content for deduplication.\n *\n * @param content - Content to hash\n * @returns 64-character hex string (SHA-256)\n *\n * @example\n * ```typescript\n * const hash = hashContent('Hello world');\n * console.log(hash.length); // 64\n * ```\n */\nexport function hashContent(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n","/**\n * Confidence States - Implements multi-state synapses\n *\n * Neuroscience: Synapses exist in three states: silent, ready (potentiated), active.\n * Application: Classify memory entries by score into silent/ready/active states.\n */\n\nimport type { ConfidenceState, MemoryEntry, StateDistribution } from '../types/memory.js';\n\nexport interface ConfidenceStatesConfig {\n /** Score threshold for active state (e.g., 0.7) */\n activeThreshold: number;\n /** Score threshold for ready state (e.g., 0.3) */\n readyThreshold: number;\n}\n\nexport interface ConfidenceStates {\n /**\n * Calculate state based on entry score and BTSP flag\n * @param entry - Memory entry\n * @returns Confidence state\n */\n calculateState(entry: MemoryEntry): ConfidenceState;\n\n /**\n * Transition entry to correct state based on its score\n * @param entry - Entry to transition\n * @returns Entry with updated state\n */\n transition(entry: MemoryEntry): MemoryEntry;\n\n /**\n * Get distribution of states across all entries\n * @param entries - All memory entries\n * @returns State distribution with counts\n */\n getDistribution(entries: MemoryEntry[]): StateDistribution;\n}\n\n/**\n * Create a confidence states manager\n * @param config - States configuration\n * @returns ConfidenceStates instance\n */\nexport function createConfidenceStates(config: ConfidenceStatesConfig): ConfidenceStates {\n const { activeThreshold, readyThreshold } = config;\n\n function calculateState(entry: MemoryEntry): ConfidenceState {\n // BTSP entries are always active\n if (entry.isBTSP) {\n return 'active';\n }\n\n // State based on score thresholds\n // Active: score > 0.7\n if (entry.score > activeThreshold) {\n return 'active';\n }\n\n // Ready: 0.3 <= score <= 0.7\n if (entry.score >= readyThreshold) {\n return 'ready';\n }\n\n // Silent: score < 0.3\n return 'silent';\n }\n\n function transition(entry: MemoryEntry): MemoryEntry {\n const newState = calculateState(entry);\n\n return {\n ...entry,\n state: newState,\n };\n }\n\n function getDistribution(entries: MemoryEntry[]): StateDistribution {\n const distribution: StateDistribution = {\n silent: 0,\n ready: 0,\n active: 0,\n total: entries.length,\n };\n\n for (const entry of entries) {\n const state = calculateState(entry);\n distribution[state]++;\n }\n\n return distribution;\n }\n\n return {\n calculateState,\n transition,\n getDistribution,\n };\n}\n","/**\n * Engram Scorer - Implements engram theory (memory decay)\n *\n * Neuroscience: Memories fade over time without reinforcement.\n * Application: Apply exponential decay formula to memory scores based on age and access count.\n *\n * Formula: decay = 1 - e^(-age/TTL)\n * Score adjustment: score_new = score_old * (1 - decay) + (accessCount bonus)\n */\n\nimport type { MemoryEntry } from '../types/memory.js';\n\nexport interface EngramScorerConfig {\n /** Default TTL in hours for new entries */\n defaultTTL: number;\n /** Decay threshold (0.0-1.0) above which entries are marked for pruning */\n decayThreshold: number;\n}\n\nexport interface EngramScorer {\n /**\n * Calculate current score for an entry based on decay and access count\n * @param entry - Memory entry to score\n * @param currentTime - Current timestamp in milliseconds (for testing)\n * @returns Updated score (0.0-1.0)\n */\n calculateScore(entry: MemoryEntry, currentTime?: number): number;\n\n /**\n * Refresh TTL to default value\n * @param entry - Entry to refresh\n * @returns Entry with refreshed TTL and timestamp\n */\n refreshTTL(entry: MemoryEntry): MemoryEntry;\n\n /**\n * Calculate decay factor (0.0-1.0) based on age and TTL\n * @param ageInSeconds - Age of entry in seconds\n * @param ttlInSeconds - TTL in seconds\n * @returns Decay factor (0.0 = fresh, 1.0 = fully decayed)\n */\n calculateDecay(ageInSeconds: number, ttlInSeconds: number): number;\n}\n\n/**\n * Create an engram scorer instance\n * @param config - Scorer configuration\n * @returns EngramScorer instance\n */\nexport function createEngramScorer(config: EngramScorerConfig): EngramScorer {\n const { defaultTTL } = config;\n\n function calculateDecay(ageInSeconds: number, ttlInSeconds: number): number {\n if (ttlInSeconds === 0) return 1.0; // Instant decay\n if (ageInSeconds <= 0) return 0.0; // Fresh entry\n\n // Exponential decay: 1 - e^(-age/TTL)\n const ratio = ageInSeconds / ttlInSeconds;\n const decay = 1 - Math.exp(-ratio);\n\n // Clamp to [0.0, 1.0]\n return Math.max(0, Math.min(1, decay));\n }\n\n function calculateScore(entry: MemoryEntry, currentTime: number = Date.now()): number {\n // Calculate age in seconds\n const ageInMilliseconds = currentTime - entry.timestamp;\n const ageInSeconds = Math.max(0, ageInMilliseconds / 1000);\n\n // Calculate decay factor\n const decay = calculateDecay(ageInSeconds, entry.ttl);\n\n // Base score reduced by decay\n let score = entry.score * (1 - decay);\n\n // Access count bonus (diminishing returns via log)\n if (entry.accessCount > 0) {\n const accessBonus = Math.log(entry.accessCount + 1) * 0.1;\n score = Math.min(1.0, score + accessBonus);\n }\n\n // BTSP entries maintain high score\n if (entry.isBTSP) {\n score = Math.max(score, 0.9);\n }\n\n return Math.max(0, Math.min(1, score));\n }\n\n function refreshTTL(entry: MemoryEntry): MemoryEntry {\n return {\n ...entry,\n ttl: defaultTTL * 3600, // Convert hours to seconds\n timestamp: Date.now(),\n };\n }\n\n return {\n calculateScore,\n refreshTTL,\n calculateDecay,\n };\n}\n","/**\n * Token estimation utilities.\n * Uses whitespace heuristic (~90% accuracy vs GPT tokenizer).\n */\n\n/**\n * Estimate token count for text using heuristic.\n *\n * Approximation: 1 token ≈ 4 chars or 0.75 words\n * Provides ~90% accuracy compared to GPT tokenizer, sufficient for optimization heuristics.\n *\n * @param text - Text to count\n * @returns Estimated token count\n *\n * @example\n * ```typescript\n * const tokens = estimateTokens('Hello world');\n * console.log(tokens); // ~2\n * ```\n */\nexport function estimateTokens(text: string): number {\n if (!text || text.length === 0) {\n return 0;\n }\n\n // Split on whitespace to get words\n const words = text.split(/\\s+/).filter((w) => w.length > 0);\n const wordCount = words.length;\n\n // Character-based estimate\n const charCount = text.length;\n const charEstimate = Math.ceil(charCount / 4);\n\n // Word-based estimate\n const wordEstimate = Math.ceil(wordCount * 0.75);\n\n // Return the maximum of both estimates (more conservative)\n return Math.max(wordEstimate, charEstimate);\n}\n","/**\n * Sparse Pruner - Implements sparse coding principle\n *\n * Neuroscience: Only 2-5% of neurons fire at any given time.\n * Application: Keep only top 5% most relevant context entries by TF-IDF score.\n */\n\nimport type { MemoryEntry } from '../types/memory.js';\nimport type { PruneResult } from '../types/pruner.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\n\nexport interface SparsePrunerConfig {\n /** Percentage threshold for pruning (e.g., 5 = keep top 5%) */\n threshold: number;\n}\n\nexport interface SparsePruner {\n /**\n * Prune entries to keep only top N% by relevance score\n * @param entries - Memory entries to prune\n * @returns Result with kept/removed entries and token counts\n */\n prune(entries: MemoryEntry[]): PruneResult;\n\n /**\n * Calculate TF-IDF relevance score for a single entry\n * @param entry - Entry to score\n * @param allEntries - All entries for IDF calculation\n * @returns Relevance score (0.0-1.0)\n */\n scoreEntry(entry: MemoryEntry, allEntries: MemoryEntry[]): number;\n}\n\n/**\n * Create a sparse pruner instance\n * @param config - Pruner configuration\n * @returns SparsePruner instance\n */\nexport function createSparsePruner(config: SparsePrunerConfig): SparsePruner {\n const { threshold } = config;\n\n function tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length > 0);\n }\n\n function calculateTF(term: string, tokens: string[]): number {\n const count = tokens.filter((t) => t === term).length;\n // Sqrt capping to prevent common words from dominating\n return Math.sqrt(count);\n }\n\n function calculateIDF(term: string, allEntries: MemoryEntry[]): number {\n const totalDocs = allEntries.length;\n const docsWithTerm = allEntries.filter((entry) => {\n const tokens = tokenize(entry.content);\n return tokens.includes(term);\n }).length;\n\n if (docsWithTerm === 0) return 0;\n\n return Math.log(totalDocs / docsWithTerm);\n }\n\n function scoreEntry(entry: MemoryEntry, allEntries: MemoryEntry[]): number {\n const tokens = tokenize(entry.content);\n if (tokens.length === 0) return 0;\n\n const uniqueTerms = [...new Set(tokens)];\n let totalScore = 0;\n\n for (const term of uniqueTerms) {\n const tf = calculateTF(term, tokens);\n const idf = calculateIDF(term, allEntries);\n totalScore += tf * idf;\n }\n\n // Normalize by entry length\n return totalScore / tokens.length;\n }\n\n function prune(entries: MemoryEntry[]): PruneResult {\n if (entries.length === 0) {\n return {\n kept: [],\n removed: [],\n originalTokens: 0,\n prunedTokens: 0,\n };\n }\n\n // Calculate original token count\n const originalTokens = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Score all entries\n const scored = entries.map((entry) => ({\n entry,\n score: scoreEntry(entry, entries),\n }));\n\n // Sort by score descending\n scored.sort((a, b) => b.score - a.score);\n\n // Keep top N% (minimum 1 entry)\n const keepCount = Math.max(1, Math.ceil(entries.length * (threshold / 100)));\n const kept = scored.slice(0, keepCount).map((s) => s.entry);\n const removed = scored.slice(keepCount).map((s) => s.entry);\n\n // Calculate pruned token count\n const prunedTokens = kept.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n return {\n kept,\n removed,\n originalTokens,\n prunedTokens,\n };\n }\n\n return {\n prune,\n scoreEntry,\n };\n}\n","/**\n * Context Parser - Shared utilities for parsing agent contexts into memory entries\n *\n * Extracted from claude-code adapter to enable reuse across:\n * - Adapters (claude-code, generic)\n * - Real-time pipeline (streaming context)\n * - Hooks (pre-prompt, post-tool-result)\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { MemoryEntry } from '../types/memory.js';\nimport { hashContent } from './hash.js';\n\n/**\n * Block type classification for Claude Code context\n */\nexport type BlockType = 'conversation' | 'tool' | 'result' | 'other';\n\n/**\n * Parse Claude Code context into memory entries\n * Handles conversation turns, tool uses, and results\n * @param context - Raw context string\n * @returns Array of memory entries\n */\nexport function parseClaudeCodeContext(context: string): MemoryEntry[] {\n const entries: MemoryEntry[] = [];\n const now = Date.now();\n\n // Split by conversation turns and tool boundaries\n const lines = context.split('\\n');\n let currentBlock: string[] = [];\n let blockType: BlockType = 'other';\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Detect conversation turns\n if (trimmed.startsWith('User:') || trimmed.startsWith('Assistant:')) {\n if (currentBlock.length > 0) {\n entries.push(createEntry(currentBlock.join('\\n'), blockType, now));\n currentBlock = [];\n }\n blockType = 'conversation';\n currentBlock.push(line);\n }\n // Detect tool calls\n else if (\n trimmed.includes('<function_calls>') ||\n trimmed.includes('<invoke>') ||\n trimmed.includes('<tool_use>')\n ) {\n if (currentBlock.length > 0) {\n entries.push(createEntry(currentBlock.join('\\n'), blockType, now));\n currentBlock = [];\n }\n blockType = 'tool';\n currentBlock.push(line);\n }\n // Detect tool results\n else if (trimmed.includes('<function_results>') || trimmed.includes('</function_results>')) {\n if (currentBlock.length > 0 && blockType !== 'result') {\n entries.push(createEntry(currentBlock.join('\\n'), blockType, now));\n currentBlock = [];\n }\n blockType = 'result';\n currentBlock.push(line);\n }\n // Continue current block\n else if (currentBlock.length > 0) {\n currentBlock.push(line);\n }\n // Start new block if line has content\n else if (trimmed.length > 0) {\n currentBlock.push(line);\n blockType = 'other';\n }\n }\n\n // Add final block\n if (currentBlock.length > 0) {\n entries.push(createEntry(currentBlock.join('\\n'), blockType, now));\n }\n\n return entries.filter((e) => e.content.trim().length > 0);\n}\n\n/**\n * Create a memory entry from a content block\n * @param content - Block content\n * @param type - Block type\n * @param baseTime - Base timestamp\n * @returns Memory entry\n */\nexport function createEntry(content: string, type: BlockType, baseTime: number): MemoryEntry {\n const tags: string[] = [type];\n\n // Assign initial score based on type\n let initialScore = 0.5;\n if (type === 'conversation') initialScore = 0.8; // Prioritize conversation\n if (type === 'tool') initialScore = 0.7; // Tool calls are important\n if (type === 'result') initialScore = 0.4; // Results can be verbose\n\n return {\n id: randomUUID(),\n content,\n hash: hashContent(content),\n timestamp: baseTime,\n score: initialScore,\n state: initialScore > 0.7 ? 'active' : initialScore > 0.3 ? 'ready' : 'silent',\n ttl: 24 * 3600, // 24 hours default\n accessCount: 0,\n tags,\n metadata: { type },\n isBTSP: false,\n };\n}\n\n/**\n * Parse generic context (fallback for non-Claude-Code agents)\n * Splits on double newlines, treats as paragraphs\n * @param context - Raw context string\n * @returns Array of memory entries\n */\nexport function parseGenericContext(context: string): MemoryEntry[] {\n const entries: MemoryEntry[] = [];\n const now = Date.now();\n\n // Split on double newlines (paragraph boundaries)\n const blocks = context.split(/\\n\\n+/);\n\n for (const block of blocks) {\n const trimmed = block.trim();\n if (trimmed.length === 0) continue;\n\n entries.push(createEntry(trimmed, 'other', now));\n }\n\n return entries;\n}\n","/**\n * Claude Code Adapter - Claude Code-specific optimization pipeline\n *\n * Optimized for Claude Code's conversation patterns, tool use, and context management.\n * Implements the same AgentAdapter interface as GenericAdapter but with Claude-specific tuning.\n */\n\nimport { createBTSPEmbedder } from '../core/btsp-embedder.js';\nimport { createConfidenceStates } from '../core/confidence-states.js';\nimport { createEngramScorer } from '../core/engram-scorer.js';\nimport type { KVMemory } from '../core/kv-memory.js';\nimport { createSparsePruner } from '../core/sparse-pruner.js';\nimport type { AgentAdapter, OptimizationResult, OptimizeOptions } from '../types/adapter.js';\nimport type { SparnConfig } from '../types/config.js';\nimport { parseClaudeCodeContext } from '../utils/context-parser.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\n\n/**\n * Claude Code-specific optimization profile\n * Tuned for Claude's conversation patterns and tool use\n */\nconst CLAUDE_CODE_PROFILE = {\n // More aggressive pruning for tool results (they can be verbose)\n toolResultThreshold: 3, // Keep top 3% of tool results\n\n // Preserve conversation turns more aggressively\n conversationBoost: 1.5, // 50% boost for User/Assistant exchanges\n\n // Prioritize recent context (Claude Code sessions are typically focused)\n recentContextWindow: 10 * 60, // Last 10 minutes gets priority\n\n // BTSP patterns specific to Claude Code\n btspPatterns: [\n // Error patterns\n /\\b(error|exception|failure|fatal|critical|panic)\\b/i,\n /^\\s+at\\s+.*\\(.*:\\d+:\\d+\\)/m, // Stack traces\n /^Error:/m,\n\n // Git conflict markers\n /^<<<<<<< /m,\n /^=======/m,\n /^>>>>>>> /m,\n\n // Tool use patterns (important for context)\n /<function_calls>/,\n /<invoke>/,\n /<tool_use>/,\n\n // File operation results (often critical)\n /ENOENT|EACCES|EISDIR|EEXIST/,\n ],\n};\n\n/**\n * Create a Claude Code adapter instance\n * @param memory - KV memory store\n * @param config - Sparn configuration\n * @returns AgentAdapter instance optimized for Claude Code\n */\nexport function createClaudeCodeAdapter(memory: KVMemory, config: SparnConfig): AgentAdapter {\n // Create core modules with Claude Code-optimized settings\n const pruner = createSparsePruner({\n threshold: config.pruning.threshold,\n });\n\n const scorer = createEngramScorer(config.decay);\n const states = createConfidenceStates(config.states);\n const btsp = createBTSPEmbedder();\n\n async function optimize(\n context: string,\n options: OptimizeOptions = {},\n ): Promise<OptimizationResult> {\n const startTime = Date.now();\n\n // Parse context into entries\n // For Claude Code, we parse by conversation turns and tool uses\n const entries = parseClaudeCodeContext(context);\n\n // Apply BTSP detection with Claude Code-specific patterns\n const entriesWithBTSP = entries.map((entry) => {\n const isBTSP = CLAUDE_CODE_PROFILE.btspPatterns.some((pattern) =>\n pattern.test(entry.content),\n );\n\n if (isBTSP) {\n const btspEntry = btsp.createBTSPEntry(entry.content, [...entry.tags, 'claude-code'], {\n originalTimestamp: entry.timestamp,\n });\n // Preserve original timestamp\n return {\n ...btspEntry,\n timestamp: entry.timestamp,\n };\n }\n\n return entry;\n });\n\n // Apply conversation boost to User/Assistant exchanges\n const boostedEntries = entriesWithBTSP.map((entry) => {\n const isConversationTurn =\n entry.content.trim().startsWith('User:') || entry.content.trim().startsWith('Assistant:');\n\n if (isConversationTurn) {\n return {\n ...entry,\n score: entry.score * CLAUDE_CODE_PROFILE.conversationBoost,\n };\n }\n\n return entry;\n });\n\n // Score entries with decay\n const scoredEntries = boostedEntries.map((entry) => {\n const decayScore = scorer.calculateScore(entry);\n return {\n ...entry,\n score: decayScore,\n };\n });\n\n // Calculate states\n const entriesWithStates = scoredEntries.map((entry) => {\n const state = states.calculateState(entry);\n return {\n ...entry,\n state,\n };\n });\n\n // Prune entries (keep top N%)\n const pruneResult = pruner.prune(entriesWithStates);\n\n // Store kept entries in memory (if not dry-run)\n if (!options.dryRun) {\n for (const entry of pruneResult.kept) {\n await memory.put(entry);\n }\n\n // Record optimization stats\n await memory.recordOptimization({\n timestamp: Date.now(),\n tokens_before: pruneResult.originalTokens,\n tokens_after: pruneResult.prunedTokens,\n entries_pruned: pruneResult.removed.length,\n duration_ms: Date.now() - startTime,\n });\n }\n\n // Build optimized context from kept entries\n const optimizedContext = pruneResult.kept.map((entry) => entry.content).join('\\n');\n\n // Calculate state distribution\n const stateDistribution = states.getDistribution(pruneResult.kept);\n\n // Build result\n const result: OptimizationResult = {\n optimizedContext,\n tokensBefore: pruneResult.originalTokens,\n tokensAfter: pruneResult.prunedTokens,\n reduction:\n pruneResult.originalTokens > 0\n ? (pruneResult.originalTokens - pruneResult.prunedTokens) / pruneResult.originalTokens\n : 0,\n entriesProcessed: entries.length,\n entriesKept: pruneResult.kept.length,\n durationMs: Date.now() - startTime,\n stateDistribution,\n };\n\n // Add verbose details if requested\n if (options.verbose) {\n result.details = pruneResult.kept.map((entry) => ({\n id: entry.id,\n score: entry.score,\n state: entry.state || 'unknown',\n isBTSP: entry.tags.includes('btsp'),\n tokens: estimateTokens(entry.content),\n }));\n }\n\n return result;\n }\n\n return {\n optimize,\n };\n}\n","/**\n * Generic Adapter - Agent-agnostic optimization pipeline\n *\n * Orchestrates all 6 neuroscience modules to optimize context memory.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { createBTSPEmbedder } from '../core/btsp-embedder.js';\nimport { createConfidenceStates } from '../core/confidence-states.js';\nimport { createEngramScorer } from '../core/engram-scorer.js';\nimport type { KVMemory } from '../core/kv-memory.js';\nimport { createSparsePruner } from '../core/sparse-pruner.js';\nimport type { AgentAdapter, OptimizationResult, OptimizeOptions } from '../types/adapter.js';\nimport type { SparnConfig } from '../types/config.js';\nimport type { MemoryEntry } from '../types/memory.js';\nimport { hashContent } from '../utils/hash.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\n\n/**\n * Create a generic adapter instance\n * @param memory - KV memory store\n * @param config - Sparn configuration\n * @returns AgentAdapter instance\n */\nexport function createGenericAdapter(memory: KVMemory, config: SparnConfig): AgentAdapter {\n const pruner = createSparsePruner(config.pruning);\n const scorer = createEngramScorer(config.decay);\n const states = createConfidenceStates(config.states);\n const btsp = createBTSPEmbedder();\n\n async function optimize(\n context: string,\n options: OptimizeOptions = {},\n ): Promise<OptimizationResult> {\n const startTime = Date.now();\n\n // Parse context into entries (line-based for simplicity)\n const lines = context.split('\\n').filter((line) => line.trim().length > 0);\n const entries: MemoryEntry[] = lines.map((content) => ({\n id: randomUUID(),\n content,\n hash: hashContent(content),\n timestamp: Date.now(),\n score: btsp.detectBTSP(content) ? 1.0 : 0.5, // BTSP gets high initial score\n ttl: config.decay.defaultTTL * 3600, // Convert hours to seconds\n state: 'ready' as const,\n accessCount: 0,\n tags: [],\n metadata: {},\n isBTSP: btsp.detectBTSP(content),\n }));\n\n // Calculate original token count\n const tokensBefore = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Step 1: Update scores with decay\n const scoredEntries = entries.map((entry) => ({\n ...entry,\n score: scorer.calculateScore(entry),\n }));\n\n // Step 2: Transition states based on scores\n const statedEntries = scoredEntries.map((entry) => states.transition(entry));\n\n // Step 3: Apply sparse pruning\n const pruneResult = pruner.prune(statedEntries);\n\n // Step 4: Keep active and ready entries, discard silent\n const optimizedEntries = pruneResult.kept.filter(\n (e) => e.state === 'active' || e.state === 'ready',\n );\n\n // Calculate final token count\n const tokensAfter = optimizedEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Reconstruct optimized context\n const optimizedContext = optimizedEntries.map((e) => e.content).join('\\n');\n\n // Store entries in memory (if not dry run)\n if (!options.dryRun) {\n for (const entry of optimizedEntries) {\n await memory.put(entry);\n }\n\n // Record optimization statistics\n await memory.recordOptimization({\n timestamp: Date.now(),\n tokens_before: tokensBefore,\n tokens_after: tokensAfter,\n entries_pruned: entries.length - optimizedEntries.length,\n duration_ms: Date.now() - startTime,\n });\n }\n\n // Get state distribution\n const distribution = states.getDistribution(optimizedEntries);\n\n const result: OptimizationResult = {\n optimizedContext,\n tokensBefore,\n tokensAfter,\n reduction: tokensBefore > 0 ? (tokensBefore - tokensAfter) / tokensBefore : 0,\n entriesProcessed: entries.length,\n entriesKept: optimizedEntries.length,\n stateDistribution: distribution,\n durationMs: Date.now() - startTime,\n };\n\n // Add verbose details if requested\n if (options.verbose) {\n result.details = optimizedEntries.map((e) => ({\n id: e.id,\n score: e.score,\n state: e.state,\n isBTSP: e.isBTSP,\n tokens: estimateTokens(e.content),\n }));\n }\n\n return result;\n }\n\n return {\n optimize,\n };\n}\n","/**\n * Budget-Aware Pruner - Token budget optimization\n *\n * Unlike SparsePruner which keeps top N% entries, BudgetPruner fits entries\n * within a target token budget using priority scoring that combines:\n * - TF-IDF relevance\n * - Engram decay\n * - Confidence state multipliers\n * - BTSP bypass (always included)\n *\n * Target use case: Real-time optimization for Opus model (~50K token budget)\n */\n\nimport type { RealtimeConfig } from '../types/config.js';\nimport type { MemoryEntry } from '../types/memory.js';\nimport type { PruneResult } from '../types/pruner.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\nimport { createEngramScorer } from './engram-scorer.js';\n\nexport interface BudgetPrunerConfig {\n /** Target token budget */\n tokenBudget: number;\n /** Decay configuration */\n decay: {\n defaultTTL: number;\n decayThreshold: number;\n };\n /** State multipliers */\n states: {\n activeThreshold: number;\n readyThreshold: number;\n };\n}\n\nexport interface BudgetPruner {\n /**\n * Prune entries to fit within token budget\n * @param entries - Memory entries to prune\n * @param budget - Optional override budget (uses config default if not provided)\n * @returns Result with kept/removed entries and budget utilization\n */\n pruneToFit(entries: MemoryEntry[], budget?: number): PruneResult & { budgetUtilization: number };\n\n /**\n * Calculate priority score for an entry\n * @param entry - Entry to score\n * @param allEntries - All entries for TF-IDF calculation\n * @returns Priority score (higher = more important)\n */\n priorityScore(entry: MemoryEntry, allEntries: MemoryEntry[]): number;\n}\n\n/**\n * Create a budget-aware pruner instance\n * @param config - Pruner configuration\n * @returns BudgetPruner instance\n */\nexport function createBudgetPruner(config: BudgetPrunerConfig): BudgetPruner {\n const { tokenBudget, decay } = config;\n const engramScorer = createEngramScorer(decay);\n\n function tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length > 0);\n }\n\n function calculateTF(term: string, tokens: string[]): number {\n const count = tokens.filter((t) => t === term).length;\n // Sqrt capping to prevent common words from dominating\n return Math.sqrt(count);\n }\n\n function calculateIDF(term: string, allEntries: MemoryEntry[]): number {\n const totalDocs = allEntries.length;\n const docsWithTerm = allEntries.filter((entry) => {\n const tokens = tokenize(entry.content);\n return tokens.includes(term);\n }).length;\n\n if (docsWithTerm === 0) return 0;\n\n return Math.log(totalDocs / docsWithTerm);\n }\n\n function calculateTFIDF(entry: MemoryEntry, allEntries: MemoryEntry[]): number {\n const tokens = tokenize(entry.content);\n if (tokens.length === 0) return 0;\n\n const uniqueTerms = [...new Set(tokens)];\n let totalScore = 0;\n\n for (const term of uniqueTerms) {\n const tf = calculateTF(term, tokens);\n const idf = calculateIDF(term, allEntries);\n totalScore += tf * idf;\n }\n\n // Normalize by entry length\n return totalScore / tokens.length;\n }\n\n function getStateMultiplier(entry: MemoryEntry): number {\n // BTSP entries get max priority (handled separately, but keep high multiplier)\n if (entry.isBTSP) return 2.0;\n\n // State-based multipliers\n switch (entry.state) {\n case 'active':\n return 2.0;\n case 'ready':\n return 1.0;\n case 'silent':\n return 0.5;\n default:\n return 1.0;\n }\n }\n\n function priorityScore(entry: MemoryEntry, allEntries: MemoryEntry[]): number {\n const tfidf = calculateTFIDF(entry, allEntries);\n const currentScore = engramScorer.calculateScore(entry);\n const engramDecay = 1 - currentScore; // Lower decay = higher priority\n const stateMultiplier = getStateMultiplier(entry);\n\n // Priority = TF-IDF * (1 - decay) * state_multiplier\n // This balances relevance, recency, and confidence state\n return tfidf * (1 - engramDecay) * stateMultiplier;\n }\n\n function pruneToFit(\n entries: MemoryEntry[],\n budget: number = tokenBudget,\n ): PruneResult & { budgetUtilization: number } {\n if (entries.length === 0) {\n return {\n kept: [],\n removed: [],\n originalTokens: 0,\n prunedTokens: 0,\n budgetUtilization: 0,\n };\n }\n\n // Calculate original token count\n const originalTokens = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Step 1: Separate BTSP entries (always included, bypass budget)\n const btspEntries = entries.filter((e) => e.isBTSP);\n const regularEntries = entries.filter((e) => !e.isBTSP);\n\n const btspTokens = btspEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Step 2: Score regular entries\n const scored = regularEntries.map((entry) => ({\n entry,\n score: priorityScore(entry, entries),\n tokens: estimateTokens(entry.content),\n }));\n\n // Step 3: Sort by priority score descending\n scored.sort((a, b) => b.score - a.score);\n\n // Step 4: Greedy fill until budget exceeded\n const kept: MemoryEntry[] = [...btspEntries];\n const removed: MemoryEntry[] = [];\n let currentTokens = btspTokens;\n\n for (const item of scored) {\n if (currentTokens + item.tokens <= budget) {\n kept.push(item.entry);\n currentTokens += item.tokens;\n } else {\n removed.push(item.entry);\n }\n }\n\n const budgetUtilization = budget > 0 ? currentTokens / budget : 0;\n\n return {\n kept,\n removed,\n originalTokens,\n prunedTokens: currentTokens,\n budgetUtilization,\n };\n }\n\n return {\n pruneToFit,\n priorityScore,\n };\n}\n\n/**\n * Helper to create budget pruner from RealtimeConfig\n * @param realtimeConfig - Realtime configuration\n * @param decayConfig - Decay configuration\n * @param statesConfig - States configuration\n * @returns BudgetPruner instance\n */\nexport function createBudgetPrunerFromConfig(\n realtimeConfig: RealtimeConfig,\n decayConfig: { defaultTTL: number; decayThreshold: number },\n statesConfig: { activeThreshold: number; readyThreshold: number },\n): BudgetPruner {\n return createBudgetPruner({\n tokenBudget: realtimeConfig.tokenBudget,\n decay: decayConfig,\n states: statesConfig,\n });\n}\n","/**\n * Metrics and Telemetry System\n *\n * Tracks performance metrics and optimization statistics:\n * - Optimization duration and throughput\n * - Token savings and reduction rates\n * - Memory usage and cache hit rates\n * - Daemon uptime and session counts\n */\n\nexport interface OptimizationMetric {\n timestamp: number;\n duration: number;\n tokensBefore: number;\n tokensAfter: number;\n entriesProcessed: number;\n entriesKept: number;\n cacheHitRate: number;\n memoryUsage: number;\n}\n\nexport interface DaemonMetric {\n startTime: number;\n sessionsWatched: number;\n totalOptimizations: number;\n totalTokensSaved: number;\n averageLatency: number;\n memoryUsage: number;\n}\n\nexport interface MetricsSnapshot {\n timestamp: number;\n optimization: {\n totalRuns: number;\n totalDuration: number;\n totalTokensSaved: number;\n averageReduction: number;\n p50Latency: number;\n p95Latency: number;\n p99Latency: number;\n };\n cache: {\n hitRate: number;\n totalHits: number;\n totalMisses: number;\n size: number;\n };\n daemon: {\n uptime: number;\n sessionsWatched: number;\n memoryUsage: number;\n };\n}\n\nexport interface MetricsCollector {\n /**\n * Record an optimization metric\n */\n recordOptimization(metric: OptimizationMetric): void;\n\n /**\n * Update daemon metrics\n */\n updateDaemon(metric: Partial<DaemonMetric>): void;\n\n /**\n * Get current metrics snapshot\n */\n getSnapshot(): MetricsSnapshot;\n\n /**\n * Export metrics as JSON\n */\n export(): string;\n\n /**\n * Reset all metrics\n */\n reset(): void;\n}\n\n/**\n * Create a metrics collector instance\n */\nexport function createMetricsCollector(): MetricsCollector {\n const optimizations: OptimizationMetric[] = [];\n let daemonMetrics: DaemonMetric = {\n startTime: Date.now(),\n sessionsWatched: 0,\n totalOptimizations: 0,\n totalTokensSaved: 0,\n averageLatency: 0,\n memoryUsage: 0,\n };\n\n let cacheHits = 0;\n let cacheMisses = 0;\n\n function recordOptimization(metric: OptimizationMetric): void {\n optimizations.push(metric);\n\n // Update daemon totals\n daemonMetrics.totalOptimizations++;\n daemonMetrics.totalTokensSaved += metric.tokensBefore - metric.tokensAfter;\n\n // Update cache stats\n if (metric.cacheHitRate > 0) {\n const hits = Math.round(metric.entriesProcessed * metric.cacheHitRate);\n cacheHits += hits;\n cacheMisses += metric.entriesProcessed - hits;\n }\n\n // Update average latency (moving average)\n daemonMetrics.averageLatency =\n (daemonMetrics.averageLatency * (daemonMetrics.totalOptimizations - 1) + metric.duration) /\n daemonMetrics.totalOptimizations;\n\n // Keep only last 1000 metrics in memory\n if (optimizations.length > 1000) {\n optimizations.shift();\n }\n }\n\n function updateDaemon(metric: Partial<DaemonMetric>): void {\n daemonMetrics = {\n ...daemonMetrics,\n ...metric,\n };\n }\n\n function calculatePercentile(values: number[], percentile: number): number {\n if (values.length === 0) return 0;\n\n const sorted = [...values].sort((a, b) => a - b);\n const index = Math.ceil((percentile / 100) * sorted.length) - 1;\n return sorted[index] || 0;\n }\n\n function getSnapshot(): MetricsSnapshot {\n const totalRuns = optimizations.length;\n const totalDuration = optimizations.reduce((sum, m) => sum + m.duration, 0);\n const totalTokensSaved = optimizations.reduce(\n (sum, m) => sum + (m.tokensBefore - m.tokensAfter),\n 0,\n );\n\n const totalTokensBefore = optimizations.reduce((sum, m) => sum + m.tokensBefore, 0);\n const averageReduction = totalTokensBefore > 0 ? totalTokensSaved / totalTokensBefore : 0;\n\n const durations = optimizations.map((m) => m.duration);\n\n const totalCacheQueries = cacheHits + cacheMisses;\n const hitRate = totalCacheQueries > 0 ? cacheHits / totalCacheQueries : 0;\n\n return {\n timestamp: Date.now(),\n optimization: {\n totalRuns,\n totalDuration,\n totalTokensSaved,\n averageReduction,\n p50Latency: calculatePercentile(durations, 50),\n p95Latency: calculatePercentile(durations, 95),\n p99Latency: calculatePercentile(durations, 99),\n },\n cache: {\n hitRate,\n totalHits: cacheHits,\n totalMisses: cacheMisses,\n size: optimizations.reduce((sum, m) => sum + m.entriesKept, 0),\n },\n daemon: {\n uptime: Date.now() - daemonMetrics.startTime,\n sessionsWatched: daemonMetrics.sessionsWatched,\n memoryUsage: daemonMetrics.memoryUsage,\n },\n };\n }\n\n function exportMetrics(): string {\n return JSON.stringify(getSnapshot(), null, 2);\n }\n\n function reset(): void {\n optimizations.length = 0;\n cacheHits = 0;\n cacheMisses = 0;\n daemonMetrics = {\n startTime: Date.now(),\n sessionsWatched: 0,\n totalOptimizations: 0,\n totalTokensSaved: 0,\n averageLatency: 0,\n memoryUsage: 0,\n };\n }\n\n return {\n recordOptimization,\n updateDaemon,\n getSnapshot,\n export: exportMetrics,\n reset,\n };\n}\n\n// Global metrics instance\nlet globalMetrics: MetricsCollector | null = null;\n\n/**\n * Get or create the global metrics collector\n */\nexport function getMetrics(): MetricsCollector {\n if (!globalMetrics) {\n globalMetrics = createMetricsCollector();\n }\n return globalMetrics;\n}\n","/**\n * Incremental Optimizer - Cache-based delta processing\n *\n * Optimizes performance for real-time scenarios by:\n * - Caching entry scores by content hash\n * - Only recomputing scores for new/changed entries\n * - Pre-computing and caching document frequency tables\n * - Periodically forcing full re-optimization to prevent drift\n *\n * Target: <50ms for incremental updates on 100K token contexts\n */\n\nimport type { MemoryEntry } from '../types/memory.js';\nimport type { PruneResult } from '../types/pruner.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\nimport { type BudgetPrunerConfig, createBudgetPruner } from './budget-pruner.js';\nimport { getMetrics } from './metrics.js';\n\nexport interface IncrementalOptimizerConfig extends BudgetPrunerConfig {\n /** Force full re-optimization every N incremental updates */\n fullOptimizationInterval: number;\n}\n\nexport interface IncrementalOptimizerState {\n /** Entry cache keyed by content hash */\n entryCache: Map<string, { entry: MemoryEntry; score: number; timestamp: number }>;\n /** Document frequency table for IDF calculation */\n documentFrequency: Map<string, number>;\n /** Total document count for IDF */\n totalDocuments: number;\n /** Incremental update counter */\n updateCount: number;\n /** Last full optimization timestamp */\n lastFullOptimization: number;\n}\n\nexport interface IncrementalOptimizer {\n /**\n * Optimize incrementally (only process new/changed entries)\n * @param newEntries - New entries to add\n * @param budget - Optional budget override\n * @returns Prune result with budget utilization\n */\n optimizeIncremental(\n newEntries: MemoryEntry[],\n budget?: number,\n ): PruneResult & { budgetUtilization: number };\n\n /**\n * Optimize fully (recompute all scores)\n * @param allEntries - All entries to optimize\n * @param budget - Optional budget override\n * @returns Prune result with budget utilization\n */\n optimizeFull(\n allEntries: MemoryEntry[],\n budget?: number,\n ): PruneResult & { budgetUtilization: number };\n\n /**\n * Get current optimizer state (for serialization)\n * @returns Serializable state object\n */\n getState(): IncrementalOptimizerState;\n\n /**\n * Restore optimizer state (from serialization)\n * @param state - State to restore\n */\n restoreState(state: IncrementalOptimizerState): void;\n\n /**\n * Reset optimizer state (clear all caches)\n */\n reset(): void;\n\n /**\n * Get cache statistics\n * @returns Cache stats\n */\n getStats(): {\n cachedEntries: number;\n uniqueTerms: number;\n totalDocuments: number;\n updateCount: number;\n lastFullOptimization: number;\n };\n}\n\n/**\n * Create an incremental optimizer instance\n * @param config - Optimizer configuration\n * @returns IncrementalOptimizer instance\n */\nexport function createIncrementalOptimizer(\n config: IncrementalOptimizerConfig,\n): IncrementalOptimizer {\n const pruner = createBudgetPruner(config);\n const { fullOptimizationInterval } = config;\n\n // Internal state\n let state: IncrementalOptimizerState = {\n entryCache: new Map(),\n documentFrequency: new Map(),\n totalDocuments: 0,\n updateCount: 0,\n lastFullOptimization: Date.now(),\n };\n\n function tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length > 0);\n }\n\n /**\n * Update document frequency table incrementally\n */\n function updateDocumentFrequency(entries: MemoryEntry[], remove = false): void {\n for (const entry of entries) {\n const tokens = tokenize(entry.content);\n const uniqueTerms = [...new Set(tokens)];\n\n for (const term of uniqueTerms) {\n const current = state.documentFrequency.get(term) || 0;\n const updated = remove ? Math.max(0, current - 1) : current + 1;\n\n if (updated === 0) {\n state.documentFrequency.delete(term);\n } else {\n state.documentFrequency.set(term, updated);\n }\n }\n }\n\n state.totalDocuments += remove ? -entries.length : entries.length;\n state.totalDocuments = Math.max(0, state.totalDocuments);\n }\n\n /**\n * Check if entry is cached and still valid\n */\n function getCachedEntry(hash: string): MemoryEntry | null {\n const cached = state.entryCache.get(hash);\n if (!cached) return null;\n\n // Entry is valid if found in cache\n return cached.entry;\n }\n\n /**\n * Cache entry with score\n */\n function cacheEntry(entry: MemoryEntry, score: number): void {\n state.entryCache.set(entry.hash, {\n entry,\n score,\n timestamp: Date.now(),\n });\n }\n\n function optimizeIncremental(\n newEntries: MemoryEntry[],\n budget?: number,\n ): PruneResult & { budgetUtilization: number } {\n const startTime = Date.now();\n state.updateCount++;\n\n // Force full optimization if interval reached\n if (state.updateCount >= fullOptimizationInterval) {\n // Get all cached entries\n const allEntries = Array.from(state.entryCache.values()).map((c) => c.entry);\n return optimizeFull([...allEntries, ...newEntries], budget);\n }\n\n // Filter out already-cached entries\n const uncachedEntries: MemoryEntry[] = [];\n const cachedEntries: MemoryEntry[] = [];\n\n for (const entry of newEntries) {\n const cached = getCachedEntry(entry.hash);\n if (cached) {\n cachedEntries.push(cached);\n } else {\n uncachedEntries.push(entry);\n }\n }\n\n // Update document frequency for new entries only\n if (uncachedEntries.length > 0) {\n updateDocumentFrequency(uncachedEntries, false);\n }\n\n // Combine with cached entries for scoring context\n const allEntries = [...cachedEntries, ...uncachedEntries];\n\n // Score only uncached entries (reuse cached scores)\n for (const entry of uncachedEntries) {\n const score = pruner.priorityScore(entry, allEntries);\n cacheEntry(entry, score);\n }\n\n // Get all current entries (from cache + new)\n const currentEntries = Array.from(state.entryCache.values()).map((c) => c.entry);\n\n // Calculate tokens before\n const tokensBefore = currentEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Prune to fit budget\n const result = pruner.pruneToFit(currentEntries, budget);\n\n // Calculate tokens after\n const tokensAfter = result.kept.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Update cache: remove pruned entries\n for (const removed of result.removed) {\n state.entryCache.delete(removed.hash);\n }\n\n // Update document frequency to reflect removal\n if (result.removed.length > 0) {\n updateDocumentFrequency(result.removed, true);\n }\n\n // Record metrics\n const duration = Date.now() - startTime;\n const cacheHitRate = newEntries.length > 0 ? cachedEntries.length / newEntries.length : 0;\n\n getMetrics().recordOptimization({\n timestamp: Date.now(),\n duration,\n tokensBefore,\n tokensAfter,\n entriesProcessed: newEntries.length,\n entriesKept: result.kept.length,\n cacheHitRate,\n memoryUsage: process.memoryUsage().heapUsed,\n });\n\n return result;\n }\n\n function optimizeFull(\n allEntries: MemoryEntry[],\n budget?: number,\n ): PruneResult & { budgetUtilization: number } {\n const startTime = Date.now();\n\n // Calculate tokens before\n const tokensBefore = allEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Reset state\n state.entryCache.clear();\n state.documentFrequency.clear();\n state.totalDocuments = 0;\n state.updateCount = 0;\n state.lastFullOptimization = Date.now();\n\n // Rebuild document frequency table\n updateDocumentFrequency(allEntries, false);\n\n // Score and cache all entries\n for (const entry of allEntries) {\n const score = pruner.priorityScore(entry, allEntries);\n cacheEntry(entry, score);\n }\n\n // Prune to fit budget\n const result = pruner.pruneToFit(allEntries, budget);\n\n // Calculate tokens after\n const tokensAfter = result.kept.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Update cache: remove pruned entries\n for (const removed of result.removed) {\n state.entryCache.delete(removed.hash);\n }\n\n // Update document frequency to reflect removal\n if (result.removed.length > 0) {\n updateDocumentFrequency(result.removed, true);\n }\n\n // Record metrics\n const duration = Date.now() - startTime;\n\n getMetrics().recordOptimization({\n timestamp: Date.now(),\n duration,\n tokensBefore,\n tokensAfter,\n entriesProcessed: allEntries.length,\n entriesKept: result.kept.length,\n cacheHitRate: 0, // Full optimization has no cache hits\n memoryUsage: process.memoryUsage().heapUsed,\n });\n\n return result;\n }\n\n function getState(): IncrementalOptimizerState {\n return {\n entryCache: new Map(state.entryCache),\n documentFrequency: new Map(state.documentFrequency),\n totalDocuments: state.totalDocuments,\n updateCount: state.updateCount,\n lastFullOptimization: state.lastFullOptimization,\n };\n }\n\n function restoreState(restoredState: IncrementalOptimizerState): void {\n state = {\n entryCache: new Map(restoredState.entryCache),\n documentFrequency: new Map(restoredState.documentFrequency),\n totalDocuments: restoredState.totalDocuments,\n updateCount: restoredState.updateCount,\n lastFullOptimization: restoredState.lastFullOptimization,\n };\n }\n\n function reset(): void {\n state = {\n entryCache: new Map(),\n documentFrequency: new Map(),\n totalDocuments: 0,\n updateCount: 0,\n lastFullOptimization: Date.now(),\n };\n }\n\n function getStats() {\n return {\n cachedEntries: state.entryCache.size,\n uniqueTerms: state.documentFrequency.size,\n totalDocuments: state.totalDocuments,\n updateCount: state.updateCount,\n lastFullOptimization: state.lastFullOptimization,\n };\n }\n\n return {\n optimizeIncremental,\n optimizeFull,\n getState,\n restoreState,\n reset,\n getStats,\n };\n}\n","/**\n * Streaming Context Pipeline - Real-time sliding window buffer\n *\n * Maintains an optimized context in real-time by:\n * - Ingesting new content as it arrives\n * - Storing entries by priority internally (for eviction decisions)\n * - Outputting in chronological order (for conversation coherence)\n * - Evicting lowest-priority entries when budget exceeded\n * - Using IncrementalOptimizer for fast delta processing\n */\n\nimport type { MemoryEntry } from '../types/memory.js';\nimport { parseClaudeCodeContext } from '../utils/context-parser.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\nimport {\n createIncrementalOptimizer,\n type IncrementalOptimizerConfig,\n} from './incremental-optimizer.js';\n\nexport interface ContextPipelineConfig extends IncrementalOptimizerConfig {\n /** Sliding window size (max entries to keep) */\n windowSize: number;\n}\n\nexport interface ContextPipelineStats {\n /** Total entries ingested */\n totalIngested: number;\n /** Current entry count */\n currentEntries: number;\n /** Current token count */\n currentTokens: number;\n /** Budget utilization (0.0-1.0) */\n budgetUtilization: number;\n /** Evicted entry count */\n evictedEntries: number;\n /** Optimizer stats */\n optimizer: {\n cachedEntries: number;\n uniqueTerms: number;\n updateCount: number;\n };\n}\n\nexport interface ContextPipeline {\n /**\n * Ingest new content into the pipeline\n * @param content - Raw content string\n * @param metadata - Optional metadata to attach to entries\n * @returns Number of entries ingested\n */\n ingest(content: string, metadata?: Record<string, unknown>): number;\n\n /**\n * Get current optimized context (chronologically ordered)\n * @returns Optimized context string\n */\n getContext(): string;\n\n /**\n * Get current entries (chronologically ordered)\n * @returns Array of memory entries\n */\n getEntries(): MemoryEntry[];\n\n /**\n * Get pipeline statistics\n * @returns Pipeline stats\n */\n getStats(): ContextPipelineStats;\n\n /**\n * Clear all entries and reset state\n */\n clear(): void;\n}\n\n/**\n * Create a context pipeline instance\n * @param config - Pipeline configuration\n * @returns ContextPipeline instance\n */\nexport function createContextPipeline(config: ContextPipelineConfig): ContextPipeline {\n const optimizer = createIncrementalOptimizer(config);\n const { windowSize, tokenBudget } = config;\n\n // Internal state\n let totalIngested = 0;\n let evictedEntries = 0;\n let currentEntries: MemoryEntry[] = [];\n let budgetUtilization = 0;\n\n function ingest(content: string, metadata: Record<string, unknown> = {}): number {\n // Parse content into entries\n const newEntries = parseClaudeCodeContext(content);\n\n if (newEntries.length === 0) return 0;\n\n // Attach metadata to entries\n const entriesWithMetadata = newEntries.map((entry) => ({\n ...entry,\n metadata: { ...entry.metadata, ...metadata },\n }));\n\n // Optimize incrementally\n const result = optimizer.optimizeIncremental(entriesWithMetadata, tokenBudget);\n\n // Update statistics\n totalIngested += newEntries.length;\n evictedEntries += result.removed.length;\n currentEntries = result.kept;\n budgetUtilization = result.budgetUtilization;\n\n // Enforce window size limit (keep most recent if exceeded)\n if (currentEntries.length > windowSize) {\n // Sort by timestamp descending (newest first)\n const sorted = [...currentEntries].sort((a, b) => b.timestamp - a.timestamp);\n const toKeep = sorted.slice(0, windowSize);\n const toRemove = sorted.slice(windowSize);\n\n currentEntries = toKeep;\n evictedEntries += toRemove.length;\n }\n\n return newEntries.length;\n }\n\n function getContext(): string {\n // Sort entries chronologically (oldest first)\n const sorted = [...currentEntries].sort((a, b) => a.timestamp - b.timestamp);\n return sorted.map((e) => e.content).join('\\n\\n');\n }\n\n function getEntries(): MemoryEntry[] {\n // Return entries chronologically (oldest first)\n return [...currentEntries].sort((a, b) => a.timestamp - b.timestamp);\n }\n\n function getStats(): ContextPipelineStats {\n const optimizerStats = optimizer.getStats();\n const currentTokens = currentEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n return {\n totalIngested,\n currentEntries: currentEntries.length,\n currentTokens,\n budgetUtilization,\n evictedEntries,\n optimizer: {\n cachedEntries: optimizerStats.cachedEntries,\n uniqueTerms: optimizerStats.uniqueTerms,\n updateCount: optimizerStats.updateCount,\n },\n };\n }\n\n function clear(): void {\n totalIngested = 0;\n evictedEntries = 0;\n currentEntries = [];\n budgetUtilization = 0;\n optimizer.reset();\n }\n\n return {\n ingest,\n getContext,\n getEntries,\n getStats,\n clear,\n };\n}\n","/**\n * KV Memory Store Module\n * Implements hippocampal key-value storage with dual index/value tables.\n * Maps to: Hippocampal Key-Value — the hippocampus separates what to store from how to retrieve it.\n */\n\nimport { copyFileSync, existsSync } from 'node:fs';\nimport Database from 'better-sqlite3';\nimport type { MemoryEntry, MemoryQueryFilters } from '../types/memory.js';\n\n/**\n * Optimization statistics record.\n */\nexport interface OptimizationStats {\n id: number;\n timestamp: number;\n tokens_before: number;\n tokens_after: number;\n entries_pruned: number;\n duration_ms: number;\n}\n\n/**\n * KV Memory interface.\n */\nexport interface KVMemory {\n /** Store a memory entry */\n put(entry: MemoryEntry): Promise<void>;\n\n /** Retrieve a memory entry by ID */\n get(id: string): Promise<MemoryEntry | null>;\n\n /** Query entries by filters */\n query(filters: MemoryQueryFilters): Promise<MemoryEntry[]>;\n\n /** Delete a memory entry */\n delete(id: string): Promise<void>;\n\n /** List all entry IDs */\n list(): Promise<string[]>;\n\n /** Compact database (remove expired entries) */\n compact(): Promise<number>;\n\n /** Close database connection */\n close(): Promise<void>;\n\n /** Record optimization statistics */\n recordOptimization(stats: Omit<OptimizationStats, 'id'>): Promise<void>;\n\n /** Get all optimization statistics */\n getOptimizationStats(): Promise<OptimizationStats[]>;\n\n /** Clear all optimization statistics */\n clearOptimizationStats(): Promise<void>;\n}\n\n/**\n * Create a timestamped backup of the database\n * @param dbPath - Path to database file\n * @returns Path to backup file\n */\nfunction createBackup(dbPath: string): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n const backupPath = `${dbPath}.backup-${timestamp}`;\n\n try {\n copyFileSync(dbPath, backupPath);\n console.log(`✓ Database backed up to: ${backupPath}`);\n return backupPath;\n } catch (error) {\n console.error(`Warning: Could not create backup: ${error}`);\n return '';\n }\n}\n\n/**\n * Create KV Memory store with SQLite backend.\n *\n * Initializes database with dual table schema:\n * - entries_index: Fast lookups (id, hash, timestamp, score, ttl, state, accessCount, isBTSP)\n * - entries_value: Content storage (id, content, tags, metadata)\n *\n * @param dbPath - Path to SQLite database file\n * @returns KVMemory instance\n */\nexport async function createKVMemory(dbPath: string): Promise<KVMemory> {\n // Detect database corruption and create backup\n let db: Database.Database;\n try {\n db = new Database(dbPath);\n\n // Quick integrity check\n const integrityCheck = db.pragma('quick_check', { simple: true });\n if (integrityCheck !== 'ok') {\n console.error('⚠ Database corruption detected!');\n\n // Create backup before attempting recovery\n if (existsSync(dbPath)) {\n const backupPath = createBackup(dbPath);\n if (backupPath) {\n console.log(`Backup created at: ${backupPath}`);\n }\n }\n\n // Try to recover\n console.log('Attempting database recovery...');\n db.close();\n db = new Database(dbPath);\n }\n } catch (error) {\n console.error('⚠ Database error detected:', error);\n\n // Create backup if database exists\n if (existsSync(dbPath)) {\n createBackup(dbPath);\n console.log('Creating new database...');\n }\n\n db = new Database(dbPath);\n }\n\n // Enable WAL mode for better concurrency\n db.pragma('journal_mode = WAL');\n\n // Create entries_index table\n db.exec(`\n CREATE TABLE IF NOT EXISTS entries_index (\n id TEXT PRIMARY KEY NOT NULL,\n hash TEXT UNIQUE NOT NULL,\n timestamp INTEGER NOT NULL,\n score REAL NOT NULL DEFAULT 0.0 CHECK(score >= 0.0 AND score <= 1.0),\n ttl INTEGER NOT NULL CHECK(ttl >= 0),\n state TEXT NOT NULL CHECK(state IN ('silent', 'ready', 'active')),\n accessCount INTEGER NOT NULL DEFAULT 0 CHECK(accessCount >= 0),\n isBTSP INTEGER NOT NULL DEFAULT 0 CHECK(isBTSP IN (0, 1)),\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\n );\n `);\n\n // Create entries_value table\n db.exec(`\n CREATE TABLE IF NOT EXISTS entries_value (\n id TEXT PRIMARY KEY NOT NULL,\n content TEXT NOT NULL,\n tags TEXT,\n metadata TEXT,\n FOREIGN KEY (id) REFERENCES entries_index(id) ON DELETE CASCADE\n );\n `);\n\n // Create optimization_stats table\n db.exec(`\n CREATE TABLE IF NOT EXISTS optimization_stats (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\n tokens_before INTEGER NOT NULL,\n tokens_after INTEGER NOT NULL,\n entries_pruned INTEGER NOT NULL,\n duration_ms INTEGER NOT NULL\n );\n `);\n\n // Create indexes\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_entries_state ON entries_index(state);\n CREATE INDEX IF NOT EXISTS idx_entries_score ON entries_index(score DESC);\n CREATE INDEX IF NOT EXISTS idx_entries_hash ON entries_index(hash);\n CREATE INDEX IF NOT EXISTS idx_entries_timestamp ON entries_index(timestamp DESC);\n CREATE INDEX IF NOT EXISTS idx_stats_timestamp ON optimization_stats(timestamp DESC);\n `);\n\n // Prepare statements for better performance\n const putIndexStmt = db.prepare(`\n INSERT OR REPLACE INTO entries_index\n (id, hash, timestamp, score, ttl, state, accessCount, isBTSP)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const putValueStmt = db.prepare(`\n INSERT OR REPLACE INTO entries_value\n (id, content, tags, metadata)\n VALUES (?, ?, ?, ?)\n `);\n\n const getStmt = db.prepare(`\n SELECT\n i.id, i.hash, i.timestamp, i.score, i.ttl, i.state, i.accessCount, i.isBTSP,\n v.content, v.tags, v.metadata\n FROM entries_index i\n JOIN entries_value v ON i.id = v.id\n WHERE i.id = ?\n `);\n\n const deleteIndexStmt = db.prepare('DELETE FROM entries_index WHERE id = ?');\n const deleteValueStmt = db.prepare('DELETE FROM entries_value WHERE id = ?');\n\n return {\n async put(entry: MemoryEntry): Promise<void> {\n const transaction = db.transaction(() => {\n putIndexStmt.run(\n entry.id,\n entry.hash,\n entry.timestamp,\n entry.score,\n entry.ttl,\n entry.state,\n entry.accessCount,\n entry.isBTSP ? 1 : 0,\n );\n\n putValueStmt.run(\n entry.id,\n entry.content,\n JSON.stringify(entry.tags),\n JSON.stringify(entry.metadata),\n );\n });\n\n transaction();\n },\n\n async get(id: string): Promise<MemoryEntry | null> {\n const row = getStmt.get(id) as unknown;\n\n if (!row) {\n return null;\n }\n\n const r = row as {\n id: string;\n hash: string;\n timestamp: number;\n score: number;\n ttl: number;\n state: string;\n accessCount: number;\n isBTSP: number;\n content: string;\n tags: string | null;\n metadata: string | null;\n };\n\n return {\n id: r.id,\n content: r.content,\n hash: r.hash,\n timestamp: r.timestamp,\n score: r.score,\n ttl: r.ttl,\n state: r.state as 'silent' | 'ready' | 'active',\n accessCount: r.accessCount,\n tags: r.tags ? JSON.parse(r.tags) : [],\n metadata: r.metadata ? JSON.parse(r.metadata) : {},\n isBTSP: r.isBTSP === 1,\n };\n },\n\n async query(filters: MemoryQueryFilters): Promise<MemoryEntry[]> {\n let sql = `\n SELECT\n i.id, i.hash, i.timestamp, i.score, i.ttl, i.state, i.accessCount, i.isBTSP,\n v.content, v.tags, v.metadata\n FROM entries_index i\n JOIN entries_value v ON i.id = v.id\n WHERE 1=1\n `;\n\n const params: unknown[] = [];\n\n if (filters.state) {\n sql += ' AND i.state = ?';\n params.push(filters.state);\n }\n\n if (filters.minScore !== undefined) {\n sql += ' AND i.score >= ?';\n params.push(filters.minScore);\n }\n\n if (filters.maxScore !== undefined) {\n sql += ' AND i.score <= ?';\n params.push(filters.maxScore);\n }\n\n if (filters.isBTSP !== undefined) {\n sql += ' AND i.isBTSP = ?';\n params.push(filters.isBTSP ? 1 : 0);\n }\n\n sql += ' ORDER BY i.score DESC';\n\n if (filters.limit) {\n sql += ' LIMIT ?';\n params.push(filters.limit);\n }\n\n if (filters.offset) {\n sql += ' OFFSET ?';\n params.push(filters.offset);\n }\n\n const stmt = db.prepare(sql);\n const rows = stmt.all(...params) as unknown[];\n\n return rows.map((row) => {\n const r = row as {\n id: string;\n hash: string;\n timestamp: number;\n score: number;\n ttl: number;\n state: string;\n accessCount: number;\n isBTSP: number;\n content: string;\n tags: string | null;\n metadata: string | null;\n };\n\n return {\n id: r.id,\n content: r.content,\n hash: r.hash,\n timestamp: r.timestamp,\n score: r.score,\n ttl: r.ttl,\n state: r.state as 'silent' | 'ready' | 'active',\n accessCount: r.accessCount,\n tags: r.tags ? JSON.parse(r.tags) : [],\n metadata: r.metadata ? JSON.parse(r.metadata) : {},\n isBTSP: r.isBTSP === 1,\n };\n });\n },\n\n async delete(id: string): Promise<void> {\n const transaction = db.transaction(() => {\n deleteIndexStmt.run(id);\n deleteValueStmt.run(id);\n });\n\n transaction();\n },\n\n async list(): Promise<string[]> {\n const stmt = db.prepare('SELECT id FROM entries_index');\n const rows = stmt.all() as { id: string }[];\n return rows.map((r) => r.id);\n },\n\n async compact(): Promise<number> {\n const before = db.prepare('SELECT COUNT(*) as count FROM entries_index').get() as {\n count: number;\n };\n\n // Remove fully decayed entries (this will be enhanced in sleep-compressor)\n db.exec('DELETE FROM entries_index WHERE ttl <= 0');\n\n db.exec('VACUUM');\n\n const after = db.prepare('SELECT COUNT(*) as count FROM entries_index').get() as {\n count: number;\n };\n\n return before.count - after.count;\n },\n\n async close(): Promise<void> {\n db.close();\n },\n\n async recordOptimization(stats: Omit<OptimizationStats, 'id'>): Promise<void> {\n const stmt = db.prepare(`\n INSERT INTO optimization_stats (timestamp, tokens_before, tokens_after, entries_pruned, duration_ms)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n stmt.run(\n stats.timestamp,\n stats.tokens_before,\n stats.tokens_after,\n stats.entries_pruned,\n stats.duration_ms,\n );\n },\n\n async getOptimizationStats(): Promise<OptimizationStats[]> {\n const stmt = db.prepare(`\n SELECT id, timestamp, tokens_before, tokens_after, entries_pruned, duration_ms\n FROM optimization_stats\n ORDER BY timestamp DESC\n `);\n\n const rows = stmt.all() as OptimizationStats[];\n return rows;\n },\n\n async clearOptimizationStats(): Promise<void> {\n db.exec('DELETE FROM optimization_stats');\n },\n };\n}\n","/**\n * Sleep Compressor - Implements sleep replay principle\n *\n * Neuroscience: During sleep, the brain consolidates memories by replaying important ones\n * and discarding irrelevant information.\n * Application: Periodic consolidation removes decayed entries and merges duplicates.\n */\n\nimport type { ConsolidateResult, DuplicateGroup } from '../types/consolidate.js';\nimport type { MemoryEntry } from '../types/memory.js';\nimport { createEngramScorer } from './engram-scorer.js';\n\nexport interface SleepCompressor {\n /**\n * Consolidate entries: remove decayed, merge duplicates\n * @param entries - All memory entries\n * @returns Consolidation result\n */\n consolidate(entries: MemoryEntry[]): ConsolidateResult;\n\n /**\n * Find duplicate entries (exact hash or near-duplicate by similarity)\n * @param entries - Memory entries\n * @returns Groups of duplicates\n */\n findDuplicates(entries: MemoryEntry[]): DuplicateGroup[];\n\n /**\n * Merge duplicate entries, keeping highest score\n * @param groups - Duplicate groups\n * @returns Merged entries\n */\n mergeDuplicates(groups: DuplicateGroup[]): MemoryEntry[];\n}\n\n/**\n * Create a sleep compressor instance\n * @returns SleepCompressor instance\n */\nexport function createSleepCompressor(): SleepCompressor {\n const scorer = createEngramScorer({ defaultTTL: 24, decayThreshold: 0.95 });\n\n function consolidate(entries: MemoryEntry[]): ConsolidateResult {\n const startTime = Date.now();\n const originalCount = entries.length;\n\n // Step 1: Remove fully decayed entries (decay ≥ 0.95)\n const now = Date.now();\n const nonDecayed = entries.filter((entry) => {\n const ageInSeconds = (now - entry.timestamp) / 1000;\n const decay = scorer.calculateDecay(ageInSeconds, entry.ttl);\n return decay < 0.95; // Keep entries with decay < 0.95\n });\n\n const decayedRemoved = originalCount - nonDecayed.length;\n\n // Step 2: Find and merge duplicates\n const duplicateGroups = findDuplicates(nonDecayed);\n const merged = mergeDuplicates(duplicateGroups);\n\n // Step 3: Keep non-duplicates\n const duplicateIds = new Set(duplicateGroups.flatMap((g) => g.entries.map((e) => e.id)));\n const nonDuplicates = nonDecayed.filter((e) => !duplicateIds.has(e.id));\n\n // Combine merged duplicates with non-duplicates\n const kept = [...merged, ...nonDuplicates];\n const removed = entries.filter((e) => !kept.some((k) => k.id === e.id));\n\n const duplicatesRemoved = duplicateGroups.reduce((sum, g) => sum + (g.entries.length - 1), 0);\n\n return {\n kept,\n removed,\n entriesBefore: originalCount,\n entriesAfter: kept.length,\n decayedRemoved,\n duplicatesRemoved,\n compressionRatio: originalCount > 0 ? kept.length / originalCount : 0,\n durationMs: Date.now() - startTime,\n };\n }\n\n function findDuplicates(entries: MemoryEntry[]): DuplicateGroup[] {\n const groups: DuplicateGroup[] = [];\n const processed = new Set<string>();\n\n // Find exact hash matches\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n if (!entry || processed.has(entry.id)) continue;\n\n const duplicates = entries.filter((e, idx) => idx !== i && e.hash === entry.hash);\n\n if (duplicates.length > 0) {\n const group: DuplicateGroup = {\n entries: [entry, ...duplicates],\n similarity: 1.0, // Exact match\n };\n groups.push(group);\n\n // Mark as processed\n processed.add(entry.id);\n for (const dup of duplicates) {\n processed.add(dup.id);\n }\n }\n }\n\n // Find near-duplicates (cosine similarity ≥ 0.85)\n for (let i = 0; i < entries.length; i++) {\n const entryI = entries[i];\n if (!entryI || processed.has(entryI.id)) continue;\n\n for (let j = i + 1; j < entries.length; j++) {\n const entryJ = entries[j];\n if (!entryJ || processed.has(entryJ.id)) continue;\n\n const similarity = cosineSimilarity(entryI.content, entryJ.content);\n\n if (similarity >= 0.85) {\n const group: DuplicateGroup = {\n entries: [entryI, entryJ],\n similarity,\n };\n groups.push(group);\n\n processed.add(entryI.id);\n processed.add(entryJ.id);\n break; // Move to next i\n }\n }\n }\n\n return groups;\n }\n\n function mergeDuplicates(groups: DuplicateGroup[]): MemoryEntry[] {\n const merged: MemoryEntry[] = [];\n\n for (const group of groups) {\n // Keep entry with highest score\n const sorted = [...group.entries].sort((a, b) => b.score - a.score);\n const best = sorted[0];\n if (!best) continue; // Skip empty groups\n\n // Sum access counts\n const totalAccessCount = group.entries.reduce((sum, e) => sum + e.accessCount, 0);\n\n // Merge tags\n const allTags = new Set(group.entries.flatMap((e) => e.tags));\n\n merged.push({\n ...best,\n accessCount: totalAccessCount,\n tags: Array.from(allTags),\n });\n }\n\n return merged;\n }\n\n /**\n * Calculate cosine similarity between two text strings\n * @param text1 - First text\n * @param text2 - Second text\n * @returns Similarity score (0.0-1.0)\n */\n function cosineSimilarity(text1: string, text2: string): number {\n const words1 = tokenize(text1);\n const words2 = tokenize(text2);\n\n // Build vocabulary\n const vocab = new Set([...words1, ...words2]);\n\n // Build word frequency vectors\n const vec1: Record<string, number> = {};\n const vec2: Record<string, number> = {};\n\n for (const word of vocab) {\n vec1[word] = words1.filter((w) => w === word).length;\n vec2[word] = words2.filter((w) => w === word).length;\n }\n\n // Calculate dot product and magnitudes\n let dotProduct = 0;\n let mag1 = 0;\n let mag2 = 0;\n\n for (const word of vocab) {\n const count1 = vec1[word] ?? 0;\n const count2 = vec2[word] ?? 0;\n dotProduct += count1 * count2;\n mag1 += count1 * count1;\n mag2 += count2 * count2;\n }\n\n mag1 = Math.sqrt(mag1);\n mag2 = Math.sqrt(mag2);\n\n if (mag1 === 0 || mag2 === 0) return 0;\n\n return dotProduct / (mag1 * mag2);\n }\n\n function tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length > 0);\n }\n\n return {\n consolidate,\n findDuplicates,\n mergeDuplicates,\n };\n}\n","/**\n * Daemon Process Manager - Background process lifecycle management\n *\n * Handles:\n * - Process forking and detachment\n * - PID file management\n * - Signal handling (SIGTERM, SIGINT)\n * - Daemon start/stop/status commands\n */\n\nimport { fork } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { getMetrics } from '../core/metrics.js';\nimport type { SparnConfig } from '../types/config.js';\n\nexport interface DaemonCommand {\n /** Start the daemon */\n start(config: SparnConfig): Promise<DaemonStartResult>;\n\n /** Stop the daemon */\n stop(config: SparnConfig): Promise<DaemonStopResult>;\n\n /** Get daemon status */\n status(config: SparnConfig): Promise<DaemonStatusResult>;\n}\n\nexport interface DaemonStartResult {\n success: boolean;\n pid?: number;\n message: string;\n error?: string;\n}\n\nexport interface DaemonStopResult {\n success: boolean;\n message: string;\n error?: string;\n}\n\nexport interface DaemonStatusResult {\n running: boolean;\n pid?: number;\n uptime?: number;\n sessionsWatched?: number;\n tokensSaved?: number;\n message: string;\n}\n\n/**\n * Create daemon command interface\n * @returns DaemonCommand instance\n */\nexport function createDaemonCommand(): DaemonCommand {\n /**\n * Check if daemon is running\n */\n function isDaemonRunning(pidFile: string): { running: boolean; pid?: number } {\n if (!existsSync(pidFile)) {\n return { running: false };\n }\n\n try {\n const pidStr = readFileSync(pidFile, 'utf-8').trim();\n const pid = Number.parseInt(pidStr, 10);\n\n if (Number.isNaN(pid)) {\n return { running: false };\n }\n\n // Check if process exists (cross-platform)\n try {\n process.kill(pid, 0); // Signal 0 checks existence without killing\n return { running: true, pid };\n } catch {\n // Process doesn't exist, clean up stale PID file\n unlinkSync(pidFile);\n return { running: false };\n }\n } catch {\n return { running: false };\n }\n }\n\n /**\n * Write PID file\n */\n function writePidFile(pidFile: string, pid: number): void {\n // Ensure directory exists\n const dir = dirname(pidFile);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n writeFileSync(pidFile, String(pid), 'utf-8');\n }\n\n /**\n * Remove PID file\n */\n function removePidFile(pidFile: string): void {\n if (existsSync(pidFile)) {\n unlinkSync(pidFile);\n }\n }\n\n async function start(config: SparnConfig): Promise<DaemonStartResult> {\n const { pidFile, logFile } = config.realtime;\n\n // Check if already running\n const status = isDaemonRunning(pidFile);\n if (status.running) {\n return {\n success: false,\n pid: status.pid,\n message: `Daemon already running (PID ${status.pid})`,\n error: 'Already running',\n };\n }\n\n try {\n // Fork child process (daemon entry point)\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const daemonPath = join(__dirname, 'index.js');\n\n const child = fork(daemonPath, [], {\n detached: true,\n stdio: 'ignore',\n env: {\n ...process.env,\n SPARN_CONFIG: JSON.stringify(config),\n SPARN_PID_FILE: pidFile,\n SPARN_LOG_FILE: logFile,\n },\n });\n\n // Detach from parent\n child.unref();\n\n // Write PID file\n if (child.pid) {\n writePidFile(pidFile, child.pid);\n\n return {\n success: true,\n pid: child.pid,\n message: `Daemon started (PID ${child.pid})`,\n };\n }\n\n return {\n success: false,\n message: 'Failed to start daemon (no PID)',\n error: 'No PID',\n };\n } catch (error) {\n return {\n success: false,\n message: 'Failed to start daemon',\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n async function stop(config: SparnConfig): Promise<DaemonStopResult> {\n const { pidFile } = config.realtime;\n\n const status = isDaemonRunning(pidFile);\n\n if (!status.running || !status.pid) {\n return {\n success: true,\n message: 'Daemon not running',\n };\n }\n\n try {\n // Send SIGTERM\n process.kill(status.pid, 'SIGTERM');\n\n // Wait for process to exit (timeout after 5s)\n const maxWait = 5000;\n const interval = 100;\n let waited = 0;\n\n while (waited < maxWait) {\n try {\n process.kill(status.pid, 0);\n // Still running, wait\n await new Promise((resolve) => setTimeout(resolve, interval));\n waited += interval;\n } catch {\n // Process exited\n removePidFile(pidFile);\n return {\n success: true,\n message: `Daemon stopped (PID ${status.pid})`,\n };\n }\n }\n\n // Timeout, force kill\n try {\n process.kill(status.pid, 'SIGKILL');\n removePidFile(pidFile);\n return {\n success: true,\n message: `Daemon force killed (PID ${status.pid})`,\n };\n } catch {\n removePidFile(pidFile);\n return {\n success: true,\n message: `Daemon stopped (PID ${status.pid})`,\n };\n }\n } catch (error) {\n return {\n success: false,\n message: 'Failed to stop daemon',\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n async function status(config: SparnConfig): Promise<DaemonStatusResult> {\n const { pidFile } = config.realtime;\n\n const daemonStatus = isDaemonRunning(pidFile);\n\n if (!daemonStatus.running || !daemonStatus.pid) {\n return {\n running: false,\n message: 'Daemon not running',\n };\n }\n\n // Get metrics snapshot\n const metrics = getMetrics().getSnapshot();\n\n return {\n running: true,\n pid: daemonStatus.pid,\n uptime: metrics.daemon.uptime,\n sessionsWatched: metrics.daemon.sessionsWatched,\n tokensSaved: metrics.optimization.totalTokensSaved,\n message: `Daemon running (PID ${daemonStatus.pid})`,\n };\n }\n\n return {\n start,\n stop,\n status,\n };\n}\n","/**\n * File Tracker - Incremental file reading with byte position tracking\n *\n * Tracks read positions for files to enable efficient incremental reading.\n * Handles JSONL partial line buffering for incomplete writes.\n *\n * Use case: Monitor Claude Code session JSONL files and only read new lines\n * as they're appended, without re-reading the entire file.\n */\n\nimport { readFileSync, statSync } from 'node:fs';\n\nexport interface FilePosition {\n /** File path */\n path: string;\n /** Last read byte position */\n position: number;\n /** Partial line buffer (for JSONL incomplete writes) */\n partialLine: string;\n /** Last modification time */\n lastModified: number;\n /** File size at last read */\n lastSize: number;\n}\n\nexport interface FileTracker {\n /**\n * Read new content from file since last read\n * @param filePath - File to read\n * @returns New content as array of lines (empty if no new content)\n */\n readNewLines(filePath: string): string[];\n\n /**\n * Get current position for a file\n * @param filePath - File path\n * @returns File position or null if not tracked\n */\n getPosition(filePath: string): FilePosition | null;\n\n /**\n * Reset position for a file (start from beginning on next read)\n * @param filePath - File path\n */\n resetPosition(filePath: string): void;\n\n /**\n * Clear all tracked positions\n */\n clearAll(): void;\n\n /**\n * Get all tracked file paths\n * @returns Array of tracked file paths\n */\n getTrackedFiles(): string[];\n}\n\n/**\n * Create a file tracker instance\n * @returns FileTracker instance\n */\nexport function createFileTracker(): FileTracker {\n // Track positions by file path\n const positions = new Map<string, FilePosition>();\n\n function readNewLines(filePath: string): string[] {\n try {\n // Get current file stats\n const stats = statSync(filePath);\n const currentSize = stats.size;\n const currentModified = stats.mtimeMs;\n\n // Get or initialize position\n let pos = positions.get(filePath);\n\n if (!pos) {\n // First read: start from beginning\n pos = {\n path: filePath,\n position: 0,\n partialLine: '',\n lastModified: currentModified,\n lastSize: 0,\n };\n positions.set(filePath, pos);\n }\n\n // Check if file was truncated or is same size\n if (currentSize < pos.lastSize || currentSize === pos.position) {\n // File truncated or no new content\n if (currentSize < pos.lastSize) {\n // Reset position if truncated\n pos.position = 0;\n pos.partialLine = '';\n }\n return [];\n }\n\n // Read new content from last position\n const buffer = Buffer.alloc(currentSize - pos.position);\n const fd = readFileSync(filePath);\n fd.copy(buffer, 0, pos.position, currentSize);\n\n // Convert to string and combine with partial line\n const newContent = (pos.partialLine + buffer.toString('utf-8')).split('\\n');\n\n // Last element might be incomplete (no trailing newline yet)\n const partialLine = newContent.pop() || '';\n\n // Update position\n pos.position = currentSize;\n pos.partialLine = partialLine;\n pos.lastModified = currentModified;\n pos.lastSize = currentSize;\n\n // Return complete lines (filter empty)\n return newContent.filter((line) => line.trim().length > 0);\n } catch (_error) {\n // File doesn't exist or can't be read\n // Return empty array (fail silently for watcher use case)\n return [];\n }\n }\n\n function getPosition(filePath: string): FilePosition | null {\n return positions.get(filePath) || null;\n }\n\n function resetPosition(filePath: string): void {\n positions.delete(filePath);\n }\n\n function clearAll(): void {\n positions.clear();\n }\n\n function getTrackedFiles(): string[] {\n return Array.from(positions.keys());\n }\n\n return {\n readNewLines,\n getPosition,\n resetPosition,\n clearAll,\n getTrackedFiles,\n };\n}\n","/**\n * Session Watcher - Monitor Claude Code session files for changes\n *\n * Uses Node.js fs.watch to monitor ~/.claude/projects/**\\/*.jsonl files.\n * Debounces events and triggers optimization when token threshold exceeded.\n * Maintains per-session ContextPipeline instances.\n */\n\nimport { type FSWatcher, readdirSync, statSync, watch } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { type ContextPipeline, createContextPipeline } from '../core/context-pipeline.js';\nimport { getMetrics } from '../core/metrics.js';\nimport type { SparnConfig } from '../types/config.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\nimport { createFileTracker } from './file-tracker.js';\n\nexport interface SessionWatcherConfig {\n /** Sparn configuration */\n config: SparnConfig;\n /** Callback when optimization triggered */\n onOptimize?: (sessionId: string, stats: SessionStats) => void;\n /** Callback on error */\n onError?: (error: Error) => void;\n}\n\nexport interface SessionStats {\n /** Session ID */\n sessionId: string;\n /** Total tokens ingested */\n totalTokens: number;\n /** Current optimized tokens */\n optimizedTokens: number;\n /** Reduction percentage */\n reduction: number;\n /** Entry count */\n entryCount: number;\n /** Budget utilization */\n budgetUtilization: number;\n}\n\nexport interface SessionWatcher {\n /**\n * Start watching Claude Code session files\n * @returns Promise that resolves when watcher is ready\n */\n start(): Promise<void>;\n\n /**\n * Stop watching and cleanup\n */\n stop(): void;\n\n /**\n * Get statistics for all sessions\n * @returns Array of session stats\n */\n getStats(): SessionStats[];\n\n /**\n * Get statistics for a specific session\n * @param sessionId - Session ID\n * @returns Session stats or null if not found\n */\n getSessionStats(sessionId: string): SessionStats | null;\n\n /**\n * Manually trigger optimization for a session\n * @param sessionId - Session ID\n */\n optimizeSession(sessionId: string): void;\n}\n\n/**\n * Create a session watcher instance\n * @param config - Watcher configuration\n * @returns SessionWatcher instance\n */\nexport function createSessionWatcher(config: SessionWatcherConfig): SessionWatcher {\n const { config: sparnConfig, onOptimize, onError } = config;\n const { realtime, decay, states } = sparnConfig;\n\n // Per-session pipelines and trackers\n const pipelines = new Map<string, ContextPipeline>();\n const fileTracker = createFileTracker();\n\n // File system watchers\n const watchers: FSWatcher[] = [];\n\n // Debounce timers per file\n const debounceTimers = new Map<string, NodeJS.Timeout>();\n\n /**\n * Get Claude Code projects directory\n */\n function getProjectsDir(): string {\n return join(homedir(), '.claude', 'projects');\n }\n\n /**\n * Extract session ID from file path\n * Example: ~/.claude/projects/my-project/abc123.jsonl -> abc123\n */\n function getSessionId(filePath: string): string {\n const filename = filePath.split(/[/\\\\]/).pop() || '';\n return filename.replace(/\\.jsonl$/, '');\n }\n\n /**\n * Get or create pipeline for session\n */\n function getPipeline(sessionId: string): ContextPipeline {\n let pipeline = pipelines.get(sessionId);\n\n if (!pipeline) {\n pipeline = createContextPipeline({\n tokenBudget: realtime.tokenBudget,\n decay,\n states,\n windowSize: realtime.windowSize,\n fullOptimizationInterval: 50, // Full re-optimization every 50 incremental updates\n });\n pipelines.set(sessionId, pipeline);\n }\n\n return pipeline;\n }\n\n /**\n * Handle file change event (debounced)\n */\n function handleFileChange(filePath: string): void {\n // Clear existing timer\n const existingTimer = debounceTimers.get(filePath);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n\n // Set new debounced timer\n const timer = setTimeout(() => {\n try {\n // Read new lines from file\n const newLines = fileTracker.readNewLines(filePath);\n\n if (newLines.length === 0) return;\n\n // Parse JSONL content\n const content = newLines.join('\\n');\n const sessionId = getSessionId(filePath);\n const pipeline = getPipeline(sessionId);\n\n // Ingest into pipeline\n pipeline.ingest(content, { sessionId, filePath });\n\n // Check if we should trigger optimization\n const stats = pipeline.getStats();\n if (stats.currentTokens >= realtime.autoOptimizeThreshold) {\n // Update daemon metrics\n getMetrics().updateDaemon({\n sessionsWatched: pipelines.size,\n memoryUsage: process.memoryUsage().heapUsed,\n });\n\n // Trigger optimization callback\n if (onOptimize) {\n const sessionStats = computeSessionStats(sessionId, pipeline);\n onOptimize(sessionId, sessionStats);\n }\n }\n } catch (error) {\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n } finally {\n debounceTimers.delete(filePath);\n }\n }, realtime.debounceMs);\n\n debounceTimers.set(filePath, timer);\n }\n\n /**\n * Recursively find all JSONL files in directory\n */\n function findJsonlFiles(dir: string): string[] {\n const files: string[] = [];\n\n try {\n const entries = readdirSync(dir);\n\n for (const entry of entries) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n\n if (stat.isDirectory()) {\n // Recurse into subdirectories\n files.push(...findJsonlFiles(fullPath));\n } else if (entry.endsWith('.jsonl')) {\n // Match pattern\n const matches = realtime.watchPatterns.some((pattern) => {\n // Simple glob matching (supports **/*.jsonl)\n const regex = new RegExp(\n pattern.replace(/\\*\\*/g, '.*').replace(/\\*/g, '[^/\\\\\\\\]*').replace(/\\./g, '\\\\.'),\n );\n return regex.test(fullPath);\n });\n\n if (matches) {\n files.push(fullPath);\n }\n }\n }\n } catch (_error) {\n // Ignore errors (directory might not exist yet)\n }\n\n return files;\n }\n\n /**\n * Compute session statistics\n */\n function computeSessionStats(sessionId: string, pipeline: ContextPipeline): SessionStats {\n const stats = pipeline.getStats();\n const entries = pipeline.getEntries();\n const totalTokens = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n return {\n sessionId,\n totalTokens: stats.totalIngested,\n optimizedTokens: stats.currentTokens,\n reduction: totalTokens > 0 ? (totalTokens - stats.currentTokens) / totalTokens : 0,\n entryCount: stats.currentEntries,\n budgetUtilization: stats.budgetUtilization,\n };\n }\n\n async function start(): Promise<void> {\n const projectsDir = getProjectsDir();\n\n // Find all existing JSONL files\n const jsonlFiles = findJsonlFiles(projectsDir);\n\n // Watch each file's parent directory (fs.watch is directory-based)\n const watchedDirs = new Set<string>();\n\n for (const file of jsonlFiles) {\n const dir = dirname(file);\n\n if (!watchedDirs.has(dir)) {\n const watcher = watch(dir, { recursive: false }, (_eventType, filename) => {\n if (filename?.endsWith('.jsonl')) {\n const fullPath = join(dir, filename);\n handleFileChange(fullPath);\n }\n });\n\n watchers.push(watcher);\n watchedDirs.add(dir);\n }\n }\n\n // Also watch projects directory for new subdirectories\n const projectsWatcher = watch(projectsDir, { recursive: true }, (_eventType, filename) => {\n if (filename?.endsWith('.jsonl')) {\n const fullPath = join(projectsDir, filename);\n handleFileChange(fullPath);\n }\n });\n\n watchers.push(projectsWatcher);\n\n // Update daemon metrics\n getMetrics().updateDaemon({\n startTime: Date.now(),\n sessionsWatched: jsonlFiles.length,\n memoryUsage: process.memoryUsage().heapUsed,\n });\n }\n\n function stop(): void {\n // Close all watchers\n for (const watcher of watchers) {\n watcher.close();\n }\n watchers.length = 0;\n\n // Clear all timers\n for (const timer of debounceTimers.values()) {\n clearTimeout(timer);\n }\n debounceTimers.clear();\n\n // Clear pipelines\n pipelines.clear();\n\n // Clear file tracker\n fileTracker.clearAll();\n }\n\n function getStats(): SessionStats[] {\n const stats: SessionStats[] = [];\n\n for (const [sessionId, pipeline] of pipelines.entries()) {\n stats.push(computeSessionStats(sessionId, pipeline));\n }\n\n return stats;\n }\n\n function getSessionStats(sessionId: string): SessionStats | null {\n const pipeline = pipelines.get(sessionId);\n if (!pipeline) return null;\n\n return computeSessionStats(sessionId, pipeline);\n }\n\n function optimizeSession(sessionId: string): void {\n const pipeline = pipelines.get(sessionId);\n if (!pipeline) return;\n\n // Get entries and force full optimization\n const entries = pipeline.getEntries();\n pipeline.clear();\n pipeline.ingest(entries.map((e) => e.content).join('\\n\\n'));\n\n // Trigger callback\n if (onOptimize) {\n const stats = computeSessionStats(sessionId, pipeline);\n onOptimize(sessionId, stats);\n }\n }\n\n return {\n start,\n stop,\n getStats,\n getSessionStats,\n optimizeSession,\n };\n}\n","/**\n * Sparn MCP Server - Model Context Protocol server implementation\n *\n * Exposes Sparn's neuroscience-inspired context optimization as MCP tools,\n * enabling integration with Claude Desktop, VS Code, and other MCP clients.\n *\n * Tools:\n * - sparn_optimize: Optimize context with configurable options\n * - sparn_stats: Get optimization statistics\n * - sparn_consolidate: Run memory consolidation (sleep replay)\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { createGenericAdapter } from '../adapters/generic.js';\nimport type { KVMemory } from '../core/kv-memory.js';\nimport { createSleepCompressor } from '../core/sleep-compressor.js';\nimport type { SparnConfig } from '../types/config.js';\nimport { DEFAULT_CONFIG } from '../types/config.js';\n\n/**\n * Options for creating the Sparn MCP server.\n */\nexport interface SparnMcpServerOptions {\n /** KV memory store instance */\n memory: KVMemory;\n /** Sparn configuration (defaults to DEFAULT_CONFIG) */\n config?: SparnConfig;\n}\n\n/**\n * Create and configure the Sparn MCP server with all tools registered.\n *\n * @param options - Server options including memory store and config\n * @returns Configured McpServer instance ready to connect to a transport\n */\nexport function createSparnMcpServer(options: SparnMcpServerOptions): McpServer {\n const { memory, config = DEFAULT_CONFIG } = options;\n\n const server = new McpServer({\n name: 'sparn',\n version: '1.1.1',\n });\n\n registerOptimizeTool(server, memory, config);\n registerStatsTool(server, memory);\n registerConsolidateTool(server, memory);\n\n return server;\n}\n\n/**\n * Register the sparn_optimize tool.\n *\n * Optimizes input context using the neuroscience-inspired pipeline:\n * BTSP detection, engram scoring, confidence states, and sparse pruning.\n */\nfunction registerOptimizeTool(server: McpServer, memory: KVMemory, config: SparnConfig): void {\n server.registerTool(\n 'sparn_optimize',\n {\n title: 'Sparn Optimize',\n description:\n 'Optimize context using neuroscience-inspired pruning. ' +\n 'Applies BTSP detection, engram scoring, confidence states, ' +\n 'and sparse pruning to reduce token usage while preserving important information.',\n inputSchema: {\n context: z.string().describe('The context text to optimize'),\n dryRun: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, do not persist changes to the memory store'),\n verbose: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, include per-entry details in the response'),\n threshold: z\n .number()\n .min(0)\n .max(100)\n .optional()\n .describe('Custom pruning threshold (1-100, overrides config)'),\n },\n },\n async ({ context, dryRun, verbose, threshold }) => {\n try {\n const effectiveConfig = threshold\n ? { ...config, pruning: { ...config.pruning, threshold } }\n : config;\n\n const adapter = createGenericAdapter(memory, effectiveConfig);\n const result = await adapter.optimize(context, {\n dryRun,\n verbose,\n threshold,\n });\n\n const response = {\n optimizedContext: result.optimizedContext,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n reduction: `${(result.reduction * 100).toFixed(1)}%`,\n entriesProcessed: result.entriesProcessed,\n entriesKept: result.entriesKept,\n durationMs: result.durationMs,\n stateDistribution: result.stateDistribution,\n ...(verbose && result.details ? { details: result.details } : {}),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ error: message }),\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n\n/**\n * Register the sparn_stats tool.\n *\n * Returns optimization statistics from the memory store, including\n * total commands run, tokens saved, and average reduction.\n */\nfunction registerStatsTool(server: McpServer, memory: KVMemory): void {\n server.registerTool(\n 'sparn_stats',\n {\n title: 'Sparn Stats',\n description:\n 'Get optimization statistics including total commands run, ' +\n 'tokens saved, and average reduction percentage.',\n inputSchema: {\n reset: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, reset all optimization statistics'),\n },\n },\n async ({ reset }) => {\n try {\n if (reset) {\n await memory.clearOptimizationStats();\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(\n {\n message: 'Optimization statistics have been reset.',\n totalCommands: 0,\n totalTokensSaved: 0,\n averageReduction: '0.0%',\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n const stats = await memory.getOptimizationStats();\n const totalCommands = stats.length;\n\n const totalTokensSaved = stats.reduce(\n (sum, s) => sum + (s.tokens_before - s.tokens_after),\n 0,\n );\n\n const averageReduction =\n totalCommands > 0\n ? stats.reduce((sum, s) => {\n const reduction =\n s.tokens_before > 0 ? (s.tokens_before - s.tokens_after) / s.tokens_before : 0;\n return sum + reduction;\n }, 0) / totalCommands\n : 0;\n\n const recentOptimizations = stats.slice(0, 10).map((s) => ({\n timestamp: new Date(s.timestamp).toISOString(),\n tokensBefore: s.tokens_before,\n tokensAfter: s.tokens_after,\n entriesPruned: s.entries_pruned,\n durationMs: s.duration_ms,\n reduction: `${(\n ((s.tokens_before - s.tokens_after) / Math.max(s.tokens_before, 1)) * 100\n ).toFixed(1)}%`,\n }));\n\n const response = {\n totalCommands,\n totalTokensSaved,\n averageReduction: `${(averageReduction * 100).toFixed(1)}%`,\n recentOptimizations,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ error: message }),\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n\n/**\n * Register the sparn_consolidate tool.\n *\n * Runs the sleep-compressor consolidation process, which removes\n * decayed entries and merges duplicates in the memory store.\n */\nfunction registerConsolidateTool(server: McpServer, memory: KVMemory): void {\n server.registerTool(\n 'sparn_consolidate',\n {\n title: 'Sparn Consolidate',\n description:\n 'Run memory consolidation (sleep replay). ' +\n 'Removes decayed entries and merges duplicates to reclaim space. ' +\n 'Inspired by the neuroscience principle of sleep-based memory consolidation.',\n },\n async () => {\n try {\n const allIds = await memory.list();\n const allEntries = await Promise.all(\n allIds.map(async (id) => {\n const entry = await memory.get(id);\n return entry;\n }),\n );\n\n const entries = allEntries.filter((e) => e !== null);\n\n const compressor = createSleepCompressor();\n const result = compressor.consolidate(entries);\n\n // Apply changes to memory store\n for (const removed of result.removed) {\n await memory.delete(removed.id);\n }\n\n for (const kept of result.kept) {\n await memory.put(kept);\n }\n\n // Run VACUUM to reclaim disk space\n await memory.compact();\n\n const response = {\n entriesBefore: result.entriesBefore,\n entriesAfter: result.entriesAfter,\n decayedRemoved: result.decayedRemoved,\n duplicatesRemoved: result.duplicatesRemoved,\n compressionRatio: `${(result.compressionRatio * 100).toFixed(1)}%`,\n durationMs: result.durationMs,\n vacuumCompleted: true,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ error: message }),\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n","/**\n * Configuration types for Sparn behavior customization.\n */\n\n/**\n * Agent adapter type.\n */\nexport type AgentType = 'claude-code' | 'generic';\n\n/**\n * Pruning configuration.\n */\nexport interface PruningConfig {\n /** Percentage of top-scored entries to keep (1-100, default: 5) */\n threshold: number;\n\n /** Aggressiveness scale 0-100 (affects TF-IDF weighting, default: 50) */\n aggressiveness: number;\n}\n\n/**\n * Decay configuration.\n */\nexport interface DecayConfig {\n /** Default TTL in hours (default: 24) */\n defaultTTL: number;\n\n /** Decay threshold for pruning (0.0-1.0, default: 0.95) */\n decayThreshold: number;\n}\n\n/**\n * Confidence state threshold configuration.\n */\nexport interface StatesConfig {\n /** Score threshold for active state (default: 0.7) */\n activeThreshold: number;\n\n /** Score threshold for ready state (default: 0.3) */\n readyThreshold: number;\n}\n\n/**\n * UI configuration.\n */\nexport interface UIConfig {\n /** Enable colored output (default: true) */\n colors: boolean;\n\n /** Enable sound effects (default: false) */\n sounds: boolean;\n\n /** Verbose logging (default: false) */\n verbose: boolean;\n}\n\n/**\n * Real-time optimization configuration.\n */\nexport interface RealtimeConfig {\n /** Target token budget for optimized context (default: 50000) */\n tokenBudget: number;\n\n /** Token threshold that triggers auto-optimization (default: 80000) */\n autoOptimizeThreshold: number;\n\n /** File patterns to watch for changes (default: ['**\\/*.jsonl']) */\n watchPatterns: string[];\n\n /** Daemon PID file path (default: '.sparn/daemon.pid') */\n pidFile: string;\n\n /** Daemon log file path (default: '.sparn/daemon.log') */\n logFile: string;\n\n /** Debounce delay in milliseconds for file changes (default: 5000) */\n debounceMs: number;\n\n /** Enable incremental optimization (default: true) */\n incremental: boolean;\n\n /** Sliding window size for context entries (default: 500) */\n windowSize: number;\n\n /** Consolidation interval in hours, or null for disabled (default: null) */\n consolidationInterval: number | null;\n}\n\n/**\n * Complete Sparn configuration.\n */\nexport interface SparnConfig {\n pruning: PruningConfig;\n decay: DecayConfig;\n states: StatesConfig;\n agent: AgentType;\n ui: UIConfig;\n /** Auto-consolidation interval in hours, or null for manual */\n autoConsolidate: number | null;\n /** Real-time optimization settings */\n realtime: RealtimeConfig;\n}\n\n/**\n * Default configuration values.\n */\nexport const DEFAULT_CONFIG: SparnConfig = {\n pruning: {\n threshold: 5,\n aggressiveness: 50,\n },\n decay: {\n defaultTTL: 24,\n decayThreshold: 0.95,\n },\n states: {\n activeThreshold: 0.7,\n readyThreshold: 0.3,\n },\n agent: 'generic',\n ui: {\n colors: true,\n sounds: false,\n verbose: false,\n },\n autoConsolidate: null,\n realtime: {\n tokenBudget: 50000,\n autoOptimizeThreshold: 80000,\n watchPatterns: ['**/*.jsonl'],\n pidFile: '.sparn/daemon.pid',\n logFile: '.sparn/daemon.log',\n debounceMs: 5000,\n incremental: true,\n windowSize: 500,\n consolidationInterval: null,\n },\n};\n","/**\n * Logging utility.\n * Simple console wrapper with log levels.\n */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Logger interface.\n */\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\n/**\n * Create a logger with optional verbosity control.\n *\n * @param verbose - Enable debug-level logging\n * @returns Logger instance\n */\nexport function createLogger(verbose = false): Logger {\n return {\n debug(message: string, ...args: unknown[]): void {\n if (verbose) {\n console.debug(`[DEBUG] ${message}`, ...args);\n }\n },\n info(message: string, ...args: unknown[]): void {\n console.info(`[INFO] ${message}`, ...args);\n },\n warn(message: string, ...args: unknown[]): void {\n console.warn(`[WARN] ${message}`, ...args);\n },\n error(message: string, ...args: unknown[]): void {\n console.error(`[ERROR] ${message}`, ...args);\n },\n };\n}\n"],"mappings":"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","names":["randomUUID","randomUUID","randomUUID","randomUUID","allEntries","existsSync","existsSync","status","__filename","__dirname","readFileSync","statSync","dirname","join","join","statSync","dirname"]}
1
+ {"version":3,"sources":["../src/core/btsp-embedder.ts","../src/utils/hash.ts","../src/utils/tfidf.ts","../src/utils/tokenizer.ts","../src/core/engram-scorer.ts","../src/core/budget-pruner.ts","../src/core/confidence-states.ts","../src/utils/context-parser.ts","../src/adapters/claude-code.ts","../src/adapters/generic.ts","../src/core/sparse-pruner.ts","../src/core/metrics.ts","../src/core/incremental-optimizer.ts","../src/core/context-pipeline.ts","../src/core/debt-tracker.ts","../src/core/dependency-graph.ts","../src/core/docs-generator.ts","../src/core/kv-memory.ts","../src/core/search-engine.ts","../src/core/sleep-compressor.ts","../src/core/workflow-planner.ts","../src/daemon/daemon-process.ts","../src/daemon/file-tracker.ts","../src/daemon/session-watcher.ts","../src/mcp/server.ts","../src/types/config.ts","../src/utils/logger.ts"],"sourcesContent":["/**\n * BTSP Embedder - Implements behavioral timescale synaptic plasticity\n *\n * Application: Detect high-importance patterns and mark for permanent retention.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { MemoryEntry } from '../types/memory.js';\nimport { hashContent } from '../utils/hash.js';\n\nexport interface BTSPEmbedder {\n /**\n * Detect if content contains BTSP patterns (errors, stack traces, conflicts, git diffs)\n * @param content - Content to analyze\n * @returns True if BTSP pattern detected\n */\n detectBTSP(content: string): boolean;\n\n /**\n * Create a new memory entry marked as BTSP (one-shot learned)\n * @param content - Entry content\n * @param tags - Optional tags\n * @param metadata - Optional metadata\n * @returns BTSP-marked memory entry\n */\n createBTSPEntry(\n content: string,\n tags?: string[],\n metadata?: Record<string, unknown>,\n ): MemoryEntry;\n}\n\n/**\n * Create a BTSP embedder instance\n * @returns BTSPEmbedder instance\n */\nexport interface BTSPEmbedderConfig {\n /** Additional regex pattern strings to detect BTSP events */\n customPatterns?: string[];\n}\n\nexport function createBTSPEmbedder(config?: BTSPEmbedderConfig): BTSPEmbedder {\n // Patterns that indicate critical events\n const BTSP_PATTERNS: RegExp[] = [\n // Error patterns\n /\\b(error|exception|failure|fatal|critical|panic)\\b/i,\n /\\b(TypeError|ReferenceError|SyntaxError|RangeError|URIError)\\b/,\n /\\bENOENT|EACCES|ECONNREFUSED|ETIMEDOUT\\b/,\n\n // Stack trace patterns\n /^\\s+at\\s+.*\\(.*:\\d+:\\d+\\)/m, // JavaScript stack trace\n /^\\s+at\\s+.*\\.[a-zA-Z]+:\\d+/m, // Python/Ruby stack trace\n\n // Git diff new files\n /^new file mode \\d+$/m,\n /^--- \\/dev\\/null$/m,\n\n // Merge conflict markers\n /^<<<<<<< /m,\n /^=======/m,\n /^>>>>>>> /m,\n ];\n\n // Merge custom patterns (silently skip invalid regex)\n if (config?.customPatterns) {\n for (const pattern of config.customPatterns) {\n try {\n BTSP_PATTERNS.push(new RegExp(pattern));\n } catch {\n // Invalid regex — silently ignore\n }\n }\n }\n\n function detectBTSP(content: string): boolean {\n return BTSP_PATTERNS.some((pattern) => pattern.test(content));\n }\n\n function createBTSPEntry(\n content: string,\n tags: string[] = [],\n metadata: Record<string, unknown> = {},\n ): MemoryEntry {\n return {\n id: randomUUID(),\n content,\n hash: hashContent(content),\n timestamp: Date.now(),\n score: 1.0, // Maximum initial score\n ttl: 365 * 24 * 3600, // 1 year in seconds (long retention)\n state: 'active', // Always active\n accessCount: 0,\n tags: [...tags, 'btsp'],\n metadata,\n isBTSP: true,\n };\n }\n\n return {\n detectBTSP,\n createBTSPEntry,\n };\n}\n","/**\n * Content hashing utilities.\n * Uses SHA-256 for deduplication.\n */\n\nimport { createHash } from 'node:crypto';\n\n/**\n * Generate SHA-256 hash of content for deduplication.\n *\n * @param content - Content to hash\n * @returns 64-character hex string (SHA-256)\n *\n * @example\n * ```typescript\n * const hash = hashContent('Hello world');\n * console.log(hash.length); // 64\n * ```\n */\nexport function hashContent(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n","/**\n * Shared TF-IDF utilities\n *\n * Centralized text tokenization and TF-IDF scoring used by\n * sparse-pruner, budget-pruner, incremental-optimizer, and sleep-compressor.\n */\n\nimport type { MemoryEntry } from '../types/memory.js';\n\n/**\n * Tokenize text into lowercase words\n */\nexport function tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length > 0);\n}\n\n/**\n * Calculate term frequency with sqrt capping\n */\nexport function calculateTF(term: string, tokens: string[]): number {\n const count = tokens.filter((t) => t === term).length;\n return Math.sqrt(count);\n}\n\n/**\n * Calculate inverse document frequency across entries\n */\nexport function calculateIDF(term: string, allEntries: MemoryEntry[]): number {\n const totalDocs = allEntries.length;\n const docsWithTerm = allEntries.filter((entry) => {\n const tokens = tokenize(entry.content);\n return tokens.includes(term);\n }).length;\n\n if (docsWithTerm === 0) return 0;\n\n return Math.log(totalDocs / docsWithTerm);\n}\n\n/**\n * Calculate TF-IDF score for an entry relative to a corpus\n */\nexport function calculateTFIDF(entry: MemoryEntry, allEntries: MemoryEntry[]): number {\n const tokens = tokenize(entry.content);\n if (tokens.length === 0) return 0;\n\n const uniqueTerms = [...new Set(tokens)];\n let totalScore = 0;\n\n for (const term of uniqueTerms) {\n const tf = calculateTF(term, tokens);\n const idf = calculateIDF(term, allEntries);\n totalScore += tf * idf;\n }\n\n // Normalize by entry length\n return totalScore / tokens.length;\n}\n\n/**\n * Pre-computed TF-IDF index for O(1) document frequency lookups.\n * Eliminates O(n^2) bottleneck when scoring multiple entries.\n */\nexport interface TFIDFIndex {\n /** Map of term -> number of documents containing the term */\n documentFrequency: Map<string, number>;\n /** Total number of documents in the corpus */\n totalDocuments: number;\n}\n\n/**\n * Build a pre-computed TF-IDF index from a set of entries.\n * Iterates all entries once to build document frequency map.\n *\n * @param entries - Corpus of memory entries\n * @returns Pre-computed index for use with scoreTFIDF()\n */\nexport function createTFIDFIndex(entries: MemoryEntry[]): TFIDFIndex {\n const documentFrequency = new Map<string, number>();\n\n for (const entry of entries) {\n const tokens = tokenize(entry.content);\n const uniqueTerms = new Set(tokens);\n\n for (const term of uniqueTerms) {\n documentFrequency.set(term, (documentFrequency.get(term) || 0) + 1);\n }\n }\n\n return {\n documentFrequency,\n totalDocuments: entries.length,\n };\n}\n\n/**\n * Score an entry using a pre-computed TF-IDF index.\n * Uses pre-computed document frequencies instead of re-tokenizing all entries.\n *\n * @param entry - Entry to score\n * @param index - Pre-computed TF-IDF index from createTFIDFIndex()\n * @returns TF-IDF score (higher = more distinctive)\n */\nexport function scoreTFIDF(entry: MemoryEntry, index: TFIDFIndex): number {\n const tokens = tokenize(entry.content);\n if (tokens.length === 0) return 0;\n\n const uniqueTerms = new Set(tokens);\n let totalScore = 0;\n\n for (const term of uniqueTerms) {\n const tf = calculateTF(term, tokens);\n const docsWithTerm = index.documentFrequency.get(term) || 0;\n\n if (docsWithTerm === 0) continue;\n\n const idf = Math.log(index.totalDocuments / docsWithTerm);\n totalScore += tf * idf;\n }\n\n // Normalize by entry length\n return totalScore / tokens.length;\n}\n","/**\n * Token estimation utilities.\n * Supports both heuristic (~90% accuracy) and precise (GPT tokenizer, ~95%+ accuracy) modes.\n */\n\nimport { encode } from 'gpt-tokenizer';\n\n/** Module-level flag for precise token counting */\nlet usePrecise = false;\n\n/**\n * Enable or disable precise token counting using GPT tokenizer.\n * When enabled, estimateTokens() uses gpt-tokenizer for ~95%+ accuracy on code.\n * When disabled (default), uses fast whitespace heuristic.\n *\n * @param enabled - Whether to use precise counting\n */\nexport function setPreciseTokenCounting(enabled: boolean): void {\n usePrecise = enabled;\n}\n\n/**\n * Count tokens precisely using GPT tokenizer.\n *\n * @param text - Text to count\n * @returns Exact token count\n */\nexport function countTokensPrecise(text: string): number {\n if (!text || text.length === 0) {\n return 0;\n }\n return encode(text).length;\n}\n\n/**\n * Estimate token count for text.\n *\n * In default (heuristic) mode: ~90% accuracy, very fast.\n * In precise mode: ~95%+ accuracy using GPT tokenizer.\n *\n * @param text - Text to count\n * @returns Estimated token count\n */\nexport function estimateTokens(text: string): number {\n if (!text || text.length === 0) {\n return 0;\n }\n\n if (usePrecise) {\n return encode(text).length;\n }\n\n // Split on whitespace to get words\n const words = text.split(/\\s+/).filter((w) => w.length > 0);\n const wordCount = words.length;\n\n // Character-based estimate\n const charCount = text.length;\n const charEstimate = Math.ceil(charCount / 4);\n\n // Word-based estimate\n const wordEstimate = Math.ceil(wordCount * 0.75);\n\n // Return the maximum of both estimates (more conservative)\n return Math.max(wordEstimate, charEstimate);\n}\n","/**\n * Engram Scorer - Implements time-based memory decay\n *\n * Older entries fade over time unless reinforced by access.\n * Applies exponential decay formula to memory scores based on age and access count.\n *\n * Formula: decay = 1 - e^(-age/TTL)\n * Score adjustment: score_new = score_old * (1 - decay) + (accessCount bonus)\n */\n\nimport type { MemoryEntry } from '../types/memory.js';\n\nexport interface EngramScorerConfig {\n /** Default TTL in hours for new entries */\n defaultTTL: number;\n /** Decay threshold (0.0-1.0) above which entries are marked for pruning */\n decayThreshold: number;\n}\n\nexport interface EngramScorer {\n /**\n * Calculate current score for an entry based on decay and access count\n * @param entry - Memory entry to score\n * @param currentTime - Current timestamp in milliseconds (for testing)\n * @returns Updated score (0.0-1.0)\n */\n calculateScore(entry: MemoryEntry, currentTime?: number): number;\n\n /**\n * Refresh TTL to default value\n * @param entry - Entry to refresh\n * @returns Entry with refreshed TTL and timestamp\n */\n refreshTTL(entry: MemoryEntry): MemoryEntry;\n\n /**\n * Calculate decay factor (0.0-1.0) based on age and TTL\n * @param ageInSeconds - Age of entry in seconds\n * @param ttlInSeconds - TTL in seconds\n * @returns Decay factor (0.0 = fresh, 1.0 = fully decayed)\n */\n calculateDecay(ageInSeconds: number, ttlInSeconds: number): number;\n}\n\n/**\n * Create an engram scorer instance\n * @param config - Scorer configuration\n * @returns EngramScorer instance\n */\nexport function createEngramScorer(\n config: EngramScorerConfig & { recencyBoostMinutes?: number; recencyBoostMultiplier?: number },\n): EngramScorer {\n const { defaultTTL } = config;\n const recencyWindowMs = (config.recencyBoostMinutes ?? 30) * 60 * 1000;\n const recencyMultiplier = config.recencyBoostMultiplier ?? 1.3;\n\n function calculateDecay(ageInSeconds: number, ttlInSeconds: number): number {\n if (ttlInSeconds === 0) return 1.0; // Instant decay\n if (ageInSeconds <= 0) return 0.0; // Fresh entry\n\n // Exponential decay: 1 - e^(-age/TTL)\n const ratio = ageInSeconds / ttlInSeconds;\n const decay = 1 - Math.exp(-ratio);\n\n // Clamp to [0.0, 1.0]\n return Math.max(0, Math.min(1, decay));\n }\n\n function calculateScore(entry: MemoryEntry, currentTime: number = Date.now()): number {\n // Calculate age in seconds\n const ageInMilliseconds = currentTime - entry.timestamp;\n const ageInSeconds = Math.max(0, ageInMilliseconds / 1000);\n\n // Calculate decay factor\n const decay = calculateDecay(ageInSeconds, entry.ttl);\n\n // Base score reduced by decay\n let score = entry.score * (1 - decay);\n\n // Access count bonus (diminishing returns via log)\n if (entry.accessCount > 0) {\n const accessBonus = Math.log(entry.accessCount + 1) * 0.1;\n score = Math.min(1.0, score + accessBonus);\n }\n\n // BTSP entries maintain high score\n if (entry.isBTSP) {\n score = Math.max(score, 0.9);\n }\n\n // Recency boost for non-BTSP entries within the recency window\n if (!entry.isBTSP && recencyWindowMs > 0) {\n const ageMs = currentTime - entry.timestamp;\n if (ageMs >= 0 && ageMs < recencyWindowMs) {\n const boostFactor = 1 + (recencyMultiplier - 1) * (1 - ageMs / recencyWindowMs);\n score = score * boostFactor;\n }\n }\n\n return Math.max(0, Math.min(1, score));\n }\n\n function refreshTTL(entry: MemoryEntry): MemoryEntry {\n return {\n ...entry,\n ttl: defaultTTL * 3600, // Convert hours to seconds\n timestamp: Date.now(),\n };\n }\n\n return {\n calculateScore,\n refreshTTL,\n calculateDecay,\n };\n}\n","/**\n * Budget-Aware Pruner - Token budget optimization\n *\n * Unlike SparsePruner which keeps top N% entries, BudgetPruner fits entries\n * within a target token budget using priority scoring that combines:\n * - TF-IDF relevance\n * - Time-based decay\n * - Confidence state multipliers\n * - BTSP bypass (always included)\n *\n * Target use case: Real-time optimization for Opus model (~50K token budget)\n */\n\nimport type { RealtimeConfig } from '../types/config.js';\nimport type { MemoryEntry } from '../types/memory.js';\nimport type { PruneResult } from '../types/pruner.js';\nimport { createTFIDFIndex, scoreTFIDF, type TFIDFIndex } from '../utils/tfidf.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\nimport { createEngramScorer } from './engram-scorer.js';\n\nexport interface BudgetPrunerConfig {\n /** Target token budget */\n tokenBudget: number;\n /** Decay configuration */\n decay: {\n defaultTTL: number;\n decayThreshold: number;\n };\n /** State multipliers */\n states: {\n activeThreshold: number;\n readyThreshold: number;\n };\n}\n\nexport interface BudgetPruner {\n /**\n * Prune entries to fit within token budget\n * @param entries - Memory entries to prune\n * @param budget - Optional override budget (uses config default if not provided)\n * @returns Result with kept/removed entries and budget utilization\n */\n pruneToFit(entries: MemoryEntry[], budget?: number): PruneResult & { budgetUtilization: number };\n\n /**\n * Calculate priority score for an entry\n * @param entry - Entry to score\n * @param allEntries - All entries for TF-IDF calculation\n * @param index - Optional pre-computed TF-IDF index\n * @returns Priority score (higher = more important)\n */\n priorityScore(entry: MemoryEntry, allEntries: MemoryEntry[], index?: TFIDFIndex): number;\n}\n\n/**\n * Create a budget-aware pruner instance\n * @param config - Pruner configuration\n * @returns BudgetPruner instance\n */\nexport function createBudgetPruner(config: BudgetPrunerConfig): BudgetPruner {\n const { tokenBudget, decay } = config;\n const engramScorer = createEngramScorer(decay);\n\n function getStateMultiplier(entry: MemoryEntry): number {\n // BTSP entries get max priority (handled separately, but keep high multiplier)\n if (entry.isBTSP) return 2.0;\n\n // State-based multipliers\n switch (entry.state) {\n case 'active':\n return 2.0;\n case 'ready':\n return 1.0;\n case 'silent':\n return 0.5;\n default:\n return 1.0;\n }\n }\n\n function priorityScore(\n entry: MemoryEntry,\n allEntries: MemoryEntry[],\n index?: TFIDFIndex,\n ): number {\n const tfidf = index\n ? scoreTFIDF(entry, index)\n : scoreTFIDF(entry, createTFIDFIndex(allEntries));\n const currentScore = engramScorer.calculateScore(entry);\n const engramDecay = 1 - currentScore; // Lower decay = higher priority\n const stateMultiplier = getStateMultiplier(entry);\n\n // Priority = TF-IDF * (1 - decay) * state_multiplier\n // This balances relevance, recency, and confidence state\n return tfidf * (1 - engramDecay) * stateMultiplier;\n }\n\n function pruneToFit(\n entries: MemoryEntry[],\n budget: number = tokenBudget,\n ): PruneResult & { budgetUtilization: number } {\n if (entries.length === 0) {\n return {\n kept: [],\n removed: [],\n originalTokens: 0,\n prunedTokens: 0,\n budgetUtilization: 0,\n };\n }\n\n // Calculate original token count\n const originalTokens = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Step 1: Separate BTSP entries (high priority but still within budget)\n const btspEntries = entries.filter((e) => e.isBTSP);\n const regularEntries = entries.filter((e) => !e.isBTSP);\n\n // Guard: if BTSP entries alone exceed budget, only include most recent ones\n let includedBtsp: MemoryEntry[] = [];\n let btspTokens = 0;\n const sortedBtsp = [...btspEntries].sort((a, b) => b.timestamp - a.timestamp);\n for (const entry of sortedBtsp) {\n const tokens = estimateTokens(entry.content);\n if (btspTokens + tokens <= budget * 0.8) {\n // Reserve 20% for regular entries\n includedBtsp.push(entry);\n btspTokens += tokens;\n }\n }\n // If no BTSP fits, include at least the most recent one\n if (includedBtsp.length === 0 && sortedBtsp.length > 0) {\n const firstBtsp = sortedBtsp[0];\n if (firstBtsp) {\n includedBtsp = [firstBtsp];\n btspTokens = estimateTokens(firstBtsp.content);\n }\n }\n\n // Track BTSP entries excluded by the guard\n const excludedBtsp = btspEntries.filter((e) => !includedBtsp.includes(e));\n\n // Step 2: Build TF-IDF index once and score regular entries\n const tfidfIndex = createTFIDFIndex(entries);\n const scored = regularEntries.map((entry) => ({\n entry,\n score: priorityScore(entry, entries, tfidfIndex),\n tokens: estimateTokens(entry.content),\n }));\n\n // Step 3: Sort by priority score descending\n scored.sort((a, b) => b.score - a.score);\n\n // Step 4: Greedy fill until budget exceeded\n const kept: MemoryEntry[] = [...includedBtsp];\n const removed: MemoryEntry[] = [...excludedBtsp];\n let currentTokens = btspTokens;\n\n for (const item of scored) {\n if (currentTokens + item.tokens <= budget) {\n kept.push(item.entry);\n currentTokens += item.tokens;\n } else {\n removed.push(item.entry);\n }\n }\n\n const budgetUtilization = budget > 0 ? currentTokens / budget : 0;\n\n return {\n kept,\n removed,\n originalTokens,\n prunedTokens: currentTokens,\n budgetUtilization,\n };\n }\n\n return {\n pruneToFit,\n priorityScore,\n };\n}\n\n/**\n * Helper to create budget pruner from RealtimeConfig\n * @param realtimeConfig - Realtime configuration\n * @param decayConfig - Decay configuration\n * @param statesConfig - States configuration\n * @returns BudgetPruner instance\n */\nexport function createBudgetPrunerFromConfig(\n realtimeConfig: RealtimeConfig,\n decayConfig: { defaultTTL: number; decayThreshold: number },\n statesConfig: { activeThreshold: number; readyThreshold: number },\n): BudgetPruner {\n return createBudgetPruner({\n tokenBudget: realtimeConfig.tokenBudget,\n decay: decayConfig,\n states: statesConfig,\n });\n}\n","/**\n * Confidence States - Entry classification by score\n *\n * Entries exist in three states: silent, ready, active.\n * Classifies memory entries by score into silent/ready/active states.\n */\n\nimport type { ConfidenceState, MemoryEntry, StateDistribution } from '../types/memory.js';\n\nexport interface ConfidenceStatesConfig {\n /** Score threshold for active state (e.g., 0.7) */\n activeThreshold: number;\n /** Score threshold for ready state (e.g., 0.3) */\n readyThreshold: number;\n}\n\nexport interface ConfidenceStates {\n /**\n * Calculate state based on entry score and BTSP flag\n * @param entry - Memory entry\n * @returns Confidence state\n */\n calculateState(entry: MemoryEntry): ConfidenceState;\n\n /**\n * Transition entry to correct state based on its score\n * @param entry - Entry to transition\n * @returns Entry with updated state\n */\n transition(entry: MemoryEntry): MemoryEntry;\n\n /**\n * Get distribution of states across all entries\n * @param entries - All memory entries\n * @returns State distribution with counts\n */\n getDistribution(entries: MemoryEntry[]): StateDistribution;\n}\n\n/**\n * Create a confidence states manager\n * @param config - States configuration\n * @returns ConfidenceStates instance\n */\nexport function createConfidenceStates(config: ConfidenceStatesConfig): ConfidenceStates {\n const { activeThreshold, readyThreshold } = config;\n\n function calculateState(entry: MemoryEntry): ConfidenceState {\n // BTSP entries are always active\n if (entry.isBTSP) {\n return 'active';\n }\n\n // State based on score thresholds\n // Active: score >= 0.7\n if (entry.score >= activeThreshold) {\n return 'active';\n }\n\n // Ready: 0.3 <= score < 0.7\n if (entry.score >= readyThreshold) {\n return 'ready';\n }\n\n // Silent: score < 0.3\n return 'silent';\n }\n\n function transition(entry: MemoryEntry): MemoryEntry {\n const newState = calculateState(entry);\n\n return {\n ...entry,\n state: newState,\n };\n }\n\n function getDistribution(entries: MemoryEntry[]): StateDistribution {\n const distribution: StateDistribution = {\n silent: 0,\n ready: 0,\n active: 0,\n total: entries.length,\n };\n\n for (const entry of entries) {\n const state = calculateState(entry);\n distribution[state]++;\n }\n\n return distribution;\n }\n\n return {\n calculateState,\n transition,\n getDistribution,\n };\n}\n","/**\n * Context Parser - Shared utilities for parsing agent contexts into memory entries\n *\n * Extracted from claude-code adapter to enable reuse across:\n * - Adapters (claude-code, generic)\n * - Real-time pipeline (streaming context)\n * - Hooks (pre-prompt, post-tool-result)\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { MemoryEntry } from '../types/memory.js';\nimport { hashContent } from './hash.js';\n\n/**\n * Block type classification for Claude Code context\n */\nexport type BlockType = 'conversation' | 'tool' | 'result' | 'other';\n\n/**\n * Parse Claude Code context into memory entries\n * Handles conversation turns, tool uses, and results\n * @param context - Raw context string\n * @returns Array of memory entries\n */\nexport function parseClaudeCodeContext(context: string): MemoryEntry[] {\n // Auto-detect JSONL format: check if first non-empty line starts with '{'\n const firstNonEmpty = context.split('\\n').find((line) => line.trim().length > 0);\n if (firstNonEmpty?.trim().startsWith('{')) {\n const jsonlEntries = parseJSONLContext(context);\n if (jsonlEntries.length > 0) return jsonlEntries;\n // Fall through to text parser if JSONL parse returned empty\n }\n\n const entries: MemoryEntry[] = [];\n const now = Date.now();\n\n // Split by conversation turns and tool boundaries\n const lines = context.split('\\n');\n let currentBlock: string[] = [];\n let blockType: BlockType = 'other';\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Detect conversation turns\n if (trimmed.startsWith('User:') || trimmed.startsWith('Assistant:')) {\n if (currentBlock.length > 0) {\n entries.push(createEntry(currentBlock.join('\\n'), blockType, now));\n currentBlock = [];\n }\n blockType = 'conversation';\n currentBlock.push(line);\n }\n // Detect tool calls\n else if (\n trimmed.includes('<function_calls>') ||\n trimmed.includes('<invoke>') ||\n trimmed.includes('<tool_use>')\n ) {\n if (currentBlock.length > 0) {\n entries.push(createEntry(currentBlock.join('\\n'), blockType, now));\n currentBlock = [];\n }\n blockType = 'tool';\n currentBlock.push(line);\n }\n // Detect tool results\n else if (trimmed.includes('<function_results>') || trimmed.includes('</function_results>')) {\n if (currentBlock.length > 0 && blockType !== 'result') {\n entries.push(createEntry(currentBlock.join('\\n'), blockType, now));\n currentBlock = [];\n }\n blockType = 'result';\n currentBlock.push(line);\n }\n // Continue current block\n else if (currentBlock.length > 0) {\n currentBlock.push(line);\n }\n // Start new block if line has content\n else if (trimmed.length > 0) {\n currentBlock.push(line);\n blockType = 'other';\n }\n }\n\n // Add final block\n if (currentBlock.length > 0) {\n entries.push(createEntry(currentBlock.join('\\n'), blockType, now));\n }\n\n return entries.filter((e) => e.content.trim().length > 0);\n}\n\n/**\n * Create a memory entry from a content block\n * @param content - Block content\n * @param type - Block type\n * @param baseTime - Base timestamp\n * @returns Memory entry\n */\nexport function createEntry(content: string, type: BlockType, baseTime: number): MemoryEntry {\n const tags: string[] = [type];\n\n // Assign initial score based on type\n let initialScore = 0.5;\n if (type === 'conversation') initialScore = 0.8; // Prioritize conversation\n if (type === 'tool') initialScore = 0.7; // Tool calls are important\n if (type === 'result') initialScore = 0.4; // Results can be verbose\n\n return {\n id: randomUUID(),\n content,\n hash: hashContent(content),\n timestamp: baseTime,\n score: initialScore,\n state: initialScore >= 0.7 ? 'active' : initialScore >= 0.3 ? 'ready' : 'silent',\n ttl: 24 * 3600, // 24 hours default\n accessCount: 0,\n tags,\n metadata: { type },\n isBTSP: false,\n };\n}\n\n/**\n * Parsed JSONL message structure\n */\nexport interface JSONLMessage {\n role?: string;\n content?:\n | string\n | Array<{\n type: string;\n text?: string;\n name?: string;\n input?: unknown;\n content?: string | Array<{ type: string; text?: string }>;\n }>;\n type?: string;\n tool_use?: { name: string; input: unknown };\n tool_result?: { content: string | Array<{ type: string; text?: string }> };\n}\n\n/**\n * Parse a single JSONL line into a message\n * @param line - Single JSON line\n * @returns Parsed message or null on failure\n */\nexport function parseJSONLLine(line: string): JSONLMessage | null {\n const trimmed = line.trim();\n if (trimmed.length === 0) return null;\n\n try {\n return JSON.parse(trimmed) as JSONLMessage;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract text content from a JSONL message content field\n */\nfunction extractContent(content: JSONLMessage['content']): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .map((block) => {\n if (block.type === 'text' && block.text) return block.text;\n if (block.type === 'tool_use' && block.name) return `[tool_use: ${block.name}]`;\n if (block.type === 'tool_result') {\n if (typeof block.content === 'string') return block.content;\n if (Array.isArray(block.content)) {\n return block.content\n .filter((c) => c.type === 'text' && c.text)\n .map((c) => c.text)\n .join('\\n');\n }\n }\n return '';\n })\n .filter((s) => s.length > 0)\n .join('\\n');\n }\n return '';\n}\n\n/**\n * Classify a JSONL message into a BlockType\n */\nfunction classifyJSONLMessage(msg: JSONLMessage): BlockType {\n // Check for tool_use blocks in content array\n if (Array.isArray(msg.content)) {\n const hasToolUse = msg.content.some((b) => b.type === 'tool_use');\n const hasToolResult = msg.content.some((b) => b.type === 'tool_result');\n if (hasToolUse) return 'tool';\n if (hasToolResult) return 'result';\n }\n\n if (msg.type === 'tool_use' || msg.tool_use) return 'tool';\n if (msg.type === 'tool_result' || msg.tool_result) return 'result';\n\n if (msg.role === 'user' || msg.role === 'assistant') return 'conversation';\n\n return 'other';\n}\n\n/**\n * Parse JSONL context into memory entries\n * Handles Claude Code transcript format (one JSON object per line)\n *\n * @param context - Raw JSONL context string\n * @returns Array of memory entries, or empty array if parsing fails\n */\nexport function parseJSONLContext(context: string): MemoryEntry[] {\n const entries: MemoryEntry[] = [];\n const now = Date.now();\n const lines = context.split('\\n');\n\n for (const line of lines) {\n const msg = parseJSONLLine(line);\n if (!msg) continue;\n\n const content = extractContent(msg.content);\n if (!content || content.trim().length === 0) continue;\n\n const blockType = classifyJSONLMessage(msg);\n entries.push(createEntry(content, blockType, now));\n }\n\n return entries;\n}\n\n/**\n * Parse generic context (fallback for non-Claude-Code agents)\n * Splits on double newlines, treats as paragraphs\n * @param context - Raw context string\n * @returns Array of memory entries\n */\nexport function parseGenericContext(context: string): MemoryEntry[] {\n const entries: MemoryEntry[] = [];\n const now = Date.now();\n\n // Split on double newlines (paragraph boundaries)\n const blocks = context.split(/\\n\\n+/);\n\n for (const block of blocks) {\n const trimmed = block.trim();\n if (trimmed.length === 0) continue;\n\n entries.push(createEntry(trimmed, 'other', now));\n }\n\n return entries;\n}\n","/**\n * Claude Code Adapter - Claude Code-specific optimization pipeline\n *\n * Optimized for Claude Code's conversation patterns, tool use, and context management.\n * Implements the same AgentAdapter interface as GenericAdapter but with Claude-specific tuning.\n */\n\nimport { createBTSPEmbedder } from '../core/btsp-embedder.js';\nimport { createBudgetPruner } from '../core/budget-pruner.js';\nimport { createConfidenceStates } from '../core/confidence-states.js';\nimport { createEngramScorer } from '../core/engram-scorer.js';\nimport type { KVMemory } from '../core/kv-memory.js';\nimport type { AgentAdapter, OptimizationResult, OptimizeOptions } from '../types/adapter.js';\nimport type { SparnConfig } from '../types/config.js';\nimport { parseClaudeCodeContext } from '../utils/context-parser.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\n\n/**\n * Claude Code-specific optimization profile\n * Tuned for Claude's conversation patterns and tool use\n */\nconst CLAUDE_CODE_PROFILE = {\n // Preserve conversation turns more aggressively\n conversationBoost: 1.5, // 50% boost for User/Assistant exchanges\n\n // BTSP patterns specific to Claude Code\n btspPatterns: [\n // Error patterns\n /\\b(error|exception|failure|fatal|critical|panic)\\b/i,\n /^\\s+at\\s+.*\\(.*:\\d+:\\d+\\)/m, // Stack traces\n /^Error:/m,\n\n // Git conflict markers\n /^<<<<<<< /m,\n /^=======/m,\n /^>>>>>>> /m,\n\n // Tool use patterns (important for context)\n /<function_calls>/,\n /<invoke>/,\n /<tool_use>/,\n\n // File operation results (often critical)\n /ENOENT|EACCES|EISDIR|EEXIST/,\n ],\n};\n\n/**\n * Create a Claude Code adapter instance\n * @param memory - KV memory store\n * @param config - Sparn configuration\n * @returns AgentAdapter instance optimized for Claude Code\n */\nexport function createClaudeCodeAdapter(memory: KVMemory, config: SparnConfig): AgentAdapter {\n // Create core modules with Claude Code-optimized settings\n const pruner = createBudgetPruner({\n tokenBudget: config.realtime.tokenBudget,\n decay: config.decay,\n states: config.states,\n });\n\n const scorer = createEngramScorer(config.decay);\n const states = createConfidenceStates(config.states);\n const btsp = createBTSPEmbedder({ customPatterns: config.btspPatterns });\n\n async function optimize(\n context: string,\n options: OptimizeOptions = {},\n ): Promise<OptimizationResult> {\n const startTime = Date.now();\n\n // Parse context into entries\n // For Claude Code, we parse by conversation turns and tool uses\n const entries = parseClaudeCodeContext(context);\n\n // Apply BTSP detection with Claude Code-specific patterns\n const entriesWithBTSP = entries.map((entry) => {\n const isBTSP = CLAUDE_CODE_PROFILE.btspPatterns.some((pattern) =>\n pattern.test(entry.content),\n );\n\n if (isBTSP) {\n const btspEntry = btsp.createBTSPEntry(entry.content, [...entry.tags, 'claude-code'], {\n originalTimestamp: entry.timestamp,\n });\n // Preserve original timestamp\n return {\n ...btspEntry,\n timestamp: entry.timestamp,\n };\n }\n\n return entry;\n });\n\n // Apply conversation boost to User/Assistant exchanges\n const boostedEntries = entriesWithBTSP.map((entry) => {\n const isConversationTurn =\n entry.content.trim().startsWith('User:') || entry.content.trim().startsWith('Assistant:');\n\n if (isConversationTurn) {\n return {\n ...entry,\n score: entry.score * CLAUDE_CODE_PROFILE.conversationBoost,\n };\n }\n\n return entry;\n });\n\n // Score entries with decay, preserving conversation boost\n const scoredEntries = boostedEntries.map((entry) => {\n const decayScore = scorer.calculateScore(entry);\n const isConversationTurn =\n entry.content.trim().startsWith('User:') || entry.content.trim().startsWith('Assistant:');\n\n // For conversation turns, apply boost on top of decay score instead of losing it\n const finalScore = isConversationTurn\n ? Math.min(1.0, decayScore * CLAUDE_CODE_PROFILE.conversationBoost)\n : decayScore;\n\n return {\n ...entry,\n score: finalScore,\n };\n });\n\n // Calculate states\n const entriesWithStates = scoredEntries.map((entry) => {\n const state = states.calculateState(entry);\n return {\n ...entry,\n state,\n };\n });\n\n // Prune entries to fit within token budget\n const pruneResult = pruner.pruneToFit(entriesWithStates);\n\n // Store kept entries in memory (if not dry-run)\n if (!options.dryRun) {\n for (const entry of pruneResult.kept) {\n await memory.put(entry);\n }\n\n // Record optimization stats\n await memory.recordOptimization({\n timestamp: Date.now(),\n tokens_before: pruneResult.originalTokens,\n tokens_after: pruneResult.prunedTokens,\n entries_pruned: pruneResult.removed.length,\n duration_ms: Date.now() - startTime,\n });\n }\n\n // Build optimized context from kept entries\n const optimizedContext = pruneResult.kept.map((entry) => entry.content).join('\\n');\n\n // Calculate state distribution\n const stateDistribution = states.getDistribution(pruneResult.kept);\n\n // Build result\n const result: OptimizationResult = {\n optimizedContext,\n tokensBefore: pruneResult.originalTokens,\n tokensAfter: pruneResult.prunedTokens,\n reduction:\n pruneResult.originalTokens > 0\n ? (pruneResult.originalTokens - pruneResult.prunedTokens) / pruneResult.originalTokens\n : 0,\n entriesProcessed: entries.length,\n entriesKept: pruneResult.kept.length,\n durationMs: Date.now() - startTime,\n stateDistribution,\n };\n\n // Add verbose details if requested\n if (options.verbose) {\n result.details = pruneResult.kept.map((entry) => ({\n id: entry.id,\n score: entry.score,\n state: entry.state || 'unknown',\n isBTSP: entry.tags.includes('btsp'),\n tokens: estimateTokens(entry.content),\n }));\n }\n\n return result;\n }\n\n return {\n optimize,\n };\n}\n","/**\n * Generic Adapter - Agent-agnostic optimization pipeline\n *\n * Orchestrates all optimization modules to process context memory.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { createBTSPEmbedder } from '../core/btsp-embedder.js';\nimport { createConfidenceStates } from '../core/confidence-states.js';\nimport { createEngramScorer } from '../core/engram-scorer.js';\nimport type { KVMemory } from '../core/kv-memory.js';\nimport { createSparsePruner } from '../core/sparse-pruner.js';\nimport type { AgentAdapter, OptimizationResult, OptimizeOptions } from '../types/adapter.js';\nimport type { SparnConfig } from '../types/config.js';\nimport type { MemoryEntry } from '../types/memory.js';\nimport { hashContent } from '../utils/hash.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\n\n/**\n * Create a generic adapter instance\n * @param memory - KV memory store\n * @param config - Sparn configuration\n * @returns AgentAdapter instance\n */\nexport function createGenericAdapter(memory: KVMemory, config: SparnConfig): AgentAdapter {\n const pruner = createSparsePruner(config.pruning);\n const scorer = createEngramScorer(config.decay);\n const states = createConfidenceStates(config.states);\n const btsp = createBTSPEmbedder({ customPatterns: config.btspPatterns });\n\n async function optimize(\n context: string,\n options: OptimizeOptions = {},\n ): Promise<OptimizationResult> {\n const startTime = Date.now();\n\n // Parse context into entries (line-based for simplicity)\n const lines = context.split('\\n').filter((line) => line.trim().length > 0);\n const now = Date.now();\n const entries: MemoryEntry[] = lines.map((content, index) => {\n const isBTSP = btsp.detectBTSP(content);\n return {\n id: randomUUID(),\n content,\n hash: hashContent(content),\n timestamp: now + index, // Unique timestamps preserve ordering\n score: isBTSP ? 1.0 : 0.5,\n ttl: config.decay.defaultTTL * 3600,\n state: 'ready' as const,\n accessCount: 0,\n tags: [],\n metadata: {},\n isBTSP,\n };\n });\n\n // Calculate original token count\n const tokensBefore = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Step 1: Update scores with decay\n const scoredEntries = entries.map((entry) => ({\n ...entry,\n score: scorer.calculateScore(entry),\n }));\n\n // Step 2: Transition states based on scores\n const statedEntries = scoredEntries.map((entry) => states.transition(entry));\n\n // Step 3: Apply sparse pruning\n const pruneResult = pruner.prune(statedEntries);\n\n // Step 4: Keep active and ready entries, discard silent\n const optimizedEntries = pruneResult.kept.filter(\n (e) => e.state === 'active' || e.state === 'ready',\n );\n\n // Calculate final token count\n const tokensAfter = optimizedEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Reconstruct optimized context\n const optimizedContext = optimizedEntries.map((e) => e.content).join('\\n');\n\n // Store entries in memory (if not dry run)\n if (!options.dryRun) {\n for (const entry of optimizedEntries) {\n await memory.put(entry);\n }\n\n // Record optimization statistics\n await memory.recordOptimization({\n timestamp: Date.now(),\n tokens_before: tokensBefore,\n tokens_after: tokensAfter,\n entries_pruned: entries.length - optimizedEntries.length,\n duration_ms: Date.now() - startTime,\n });\n }\n\n // Get state distribution\n const distribution = states.getDistribution(optimizedEntries);\n\n const result: OptimizationResult = {\n optimizedContext,\n tokensBefore,\n tokensAfter,\n reduction: tokensBefore > 0 ? (tokensBefore - tokensAfter) / tokensBefore : 0,\n entriesProcessed: entries.length,\n entriesKept: optimizedEntries.length,\n stateDistribution: distribution,\n durationMs: Date.now() - startTime,\n };\n\n // Add verbose details if requested\n if (options.verbose) {\n result.details = optimizedEntries.map((e) => ({\n id: e.id,\n score: e.score,\n state: e.state,\n isBTSP: e.isBTSP,\n tokens: estimateTokens(e.content),\n }));\n }\n\n return result;\n }\n\n return {\n optimize,\n };\n}\n","/**\n * Sparse Pruner - Relevance filtering\n *\n * Keeps only the top 2-5% most relevant context entries by TF-IDF score.\n * Low-scoring entries are pruned to reduce token usage.\n */\n\nimport type { MemoryEntry } from '../types/memory.js';\nimport type { PruneResult } from '../types/pruner.js';\nimport { createTFIDFIndex, scoreTFIDF } from '../utils/tfidf.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\n\nexport interface SparsePrunerConfig {\n /** Percentage threshold for pruning (e.g., 5 = keep top 5%) */\n threshold: number;\n}\n\nexport interface SparsePruner {\n /**\n * Prune entries to keep only top N% by relevance score\n * @param entries - Memory entries to prune\n * @returns Result with kept/removed entries and token counts\n */\n prune(entries: MemoryEntry[]): PruneResult;\n\n /**\n * Calculate TF-IDF relevance score for a single entry\n * @param entry - Entry to score\n * @param allEntries - All entries for IDF calculation\n * @returns Relevance score (0.0-1.0)\n */\n scoreEntry(entry: MemoryEntry, allEntries: MemoryEntry[]): number;\n}\n\n/**\n * Create a sparse pruner instance\n * @param config - Pruner configuration\n * @returns SparsePruner instance\n */\nexport function createSparsePruner(config: SparsePrunerConfig): SparsePruner {\n const { threshold } = config;\n\n function scoreEntry(entry: MemoryEntry, allEntries: MemoryEntry[]): number {\n return scoreTFIDF(entry, createTFIDFIndex(allEntries));\n }\n\n function prune(entries: MemoryEntry[]): PruneResult {\n if (entries.length === 0) {\n return {\n kept: [],\n removed: [],\n originalTokens: 0,\n prunedTokens: 0,\n };\n }\n\n // Calculate original token count\n const originalTokens = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Build TF-IDF index once for all entries\n const tfidfIndex = createTFIDFIndex(entries);\n\n // Score all entries using pre-computed index\n const scored = entries.map((entry) => ({\n entry,\n score: scoreTFIDF(entry, tfidfIndex),\n }));\n\n // Sort by score descending\n scored.sort((a, b) => b.score - a.score);\n\n // Keep top N% (minimum 1 entry)\n const keepCount = Math.max(1, Math.ceil(entries.length * (threshold / 100)));\n const kept = scored.slice(0, keepCount).map((s) => s.entry);\n const removed = scored.slice(keepCount).map((s) => s.entry);\n\n // Calculate pruned token count\n const prunedTokens = kept.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n return {\n kept,\n removed,\n originalTokens,\n prunedTokens,\n };\n }\n\n return {\n prune,\n scoreEntry,\n };\n}\n","/**\n * Metrics and Telemetry System\n *\n * Tracks performance metrics and optimization statistics:\n * - Optimization duration and throughput\n * - Token savings and reduction rates\n * - Memory usage and cache hit rates\n * - Daemon uptime and session counts\n */\n\nexport interface OptimizationMetric {\n timestamp: number;\n duration: number;\n tokensBefore: number;\n tokensAfter: number;\n entriesProcessed: number;\n entriesKept: number;\n cacheHitRate: number;\n memoryUsage: number;\n}\n\nexport interface DaemonMetric {\n startTime: number;\n sessionsWatched: number;\n totalOptimizations: number;\n totalTokensSaved: number;\n averageLatency: number;\n memoryUsage: number;\n}\n\nexport interface MetricsSnapshot {\n timestamp: number;\n optimization: {\n totalRuns: number;\n totalDuration: number;\n totalTokensSaved: number;\n averageReduction: number;\n p50Latency: number;\n p95Latency: number;\n p99Latency: number;\n };\n cache: {\n hitRate: number;\n totalHits: number;\n totalMisses: number;\n size: number;\n };\n daemon: {\n uptime: number;\n sessionsWatched: number;\n memoryUsage: number;\n };\n}\n\nexport interface MetricsCollector {\n /**\n * Record an optimization metric\n */\n recordOptimization(metric: OptimizationMetric): void;\n\n /**\n * Update daemon metrics\n */\n updateDaemon(metric: Partial<DaemonMetric>): void;\n\n /**\n * Get current metrics snapshot\n */\n getSnapshot(): MetricsSnapshot;\n\n /**\n * Export metrics as JSON\n */\n export(): string;\n\n /**\n * Reset all metrics\n */\n reset(): void;\n}\n\n/**\n * Create a metrics collector instance\n */\nexport function createMetricsCollector(): MetricsCollector {\n const optimizations: OptimizationMetric[] = [];\n let daemonMetrics: DaemonMetric = {\n startTime: Date.now(),\n sessionsWatched: 0,\n totalOptimizations: 0,\n totalTokensSaved: 0,\n averageLatency: 0,\n memoryUsage: 0,\n };\n\n let cacheHits = 0;\n let cacheMisses = 0;\n\n function recordOptimization(metric: OptimizationMetric): void {\n optimizations.push(metric);\n\n // Update daemon totals\n daemonMetrics.totalOptimizations++;\n daemonMetrics.totalTokensSaved += metric.tokensBefore - metric.tokensAfter;\n\n // Update cache stats\n if (metric.cacheHitRate > 0) {\n const hits = Math.round(metric.entriesProcessed * metric.cacheHitRate);\n cacheHits += hits;\n cacheMisses += metric.entriesProcessed - hits;\n }\n\n // Update average latency (moving average)\n daemonMetrics.averageLatency =\n (daemonMetrics.averageLatency * (daemonMetrics.totalOptimizations - 1) + metric.duration) /\n daemonMetrics.totalOptimizations;\n\n // Keep only last 1000 metrics in memory\n if (optimizations.length > 1000) {\n optimizations.shift();\n }\n }\n\n function updateDaemon(metric: Partial<DaemonMetric>): void {\n daemonMetrics = {\n ...daemonMetrics,\n ...metric,\n };\n }\n\n function calculatePercentile(sortedValues: number[], percentile: number): number {\n if (sortedValues.length === 0) return 0;\n const index = Math.ceil((percentile / 100) * sortedValues.length) - 1;\n return sortedValues[index] || 0;\n }\n\n function getSnapshot(): MetricsSnapshot {\n const totalRuns = optimizations.length;\n const totalDuration = optimizations.reduce((sum, m) => sum + m.duration, 0);\n const totalTokensSaved = optimizations.reduce(\n (sum, m) => sum + (m.tokensBefore - m.tokensAfter),\n 0,\n );\n\n const totalTokensBefore = optimizations.reduce((sum, m) => sum + m.tokensBefore, 0);\n const averageReduction = totalTokensBefore > 0 ? totalTokensSaved / totalTokensBefore : 0;\n\n // Sort durations once, reuse for all percentile calculations\n const sortedDurations = optimizations.map((m) => m.duration).sort((a, b) => a - b);\n\n const totalCacheQueries = cacheHits + cacheMisses;\n const hitRate = totalCacheQueries > 0 ? cacheHits / totalCacheQueries : 0;\n\n return {\n timestamp: Date.now(),\n optimization: {\n totalRuns,\n totalDuration,\n totalTokensSaved,\n averageReduction,\n p50Latency: calculatePercentile(sortedDurations, 50),\n p95Latency: calculatePercentile(sortedDurations, 95),\n p99Latency: calculatePercentile(sortedDurations, 99),\n },\n cache: {\n hitRate,\n totalHits: cacheHits,\n totalMisses: cacheMisses,\n size: optimizations.reduce((sum, m) => sum + m.entriesKept, 0),\n },\n daemon: {\n uptime: Date.now() - daemonMetrics.startTime,\n sessionsWatched: daemonMetrics.sessionsWatched,\n memoryUsage: daemonMetrics.memoryUsage,\n },\n };\n }\n\n function exportMetrics(): string {\n return JSON.stringify(getSnapshot(), null, 2);\n }\n\n function reset(): void {\n optimizations.length = 0;\n cacheHits = 0;\n cacheMisses = 0;\n daemonMetrics = {\n startTime: Date.now(),\n sessionsWatched: 0,\n totalOptimizations: 0,\n totalTokensSaved: 0,\n averageLatency: 0,\n memoryUsage: 0,\n };\n }\n\n return {\n recordOptimization,\n updateDaemon,\n getSnapshot,\n export: exportMetrics,\n reset,\n };\n}\n\n// Global metrics instance\nlet globalMetrics: MetricsCollector | null = null;\n\n/**\n * Get or create the global metrics collector\n */\nexport function getMetrics(): MetricsCollector {\n if (!globalMetrics) {\n globalMetrics = createMetricsCollector();\n }\n return globalMetrics;\n}\n","/**\n * Incremental Optimizer - Cache-based delta processing\n *\n * Optimizes performance for real-time scenarios by:\n * - Caching entry scores by content hash\n * - Only recomputing scores for new/changed entries\n * - Pre-computing and caching document frequency tables\n * - Periodically forcing full re-optimization to prevent drift\n *\n * Target: <50ms for incremental updates on 100K token contexts\n */\n\nimport type { MemoryEntry } from '../types/memory.js';\nimport type { PruneResult } from '../types/pruner.js';\nimport { tokenize } from '../utils/tfidf.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\nimport { type BudgetPrunerConfig, createBudgetPruner } from './budget-pruner.js';\nimport { getMetrics } from './metrics.js';\n\nexport interface IncrementalOptimizerConfig extends BudgetPrunerConfig {\n /** Force full re-optimization every N incremental updates */\n fullOptimizationInterval: number;\n}\n\nexport interface IncrementalOptimizerState {\n /** Entry cache keyed by content hash */\n entryCache: Map<string, { entry: MemoryEntry; score: number; timestamp: number }>;\n /** Document frequency table for IDF calculation */\n documentFrequency: Map<string, number>;\n /** Total document count for IDF */\n totalDocuments: number;\n /** Incremental update counter */\n updateCount: number;\n /** Last full optimization timestamp */\n lastFullOptimization: number;\n}\n\nexport interface IncrementalOptimizer {\n /**\n * Optimize incrementally (only process new/changed entries)\n * @param newEntries - New entries to add\n * @param budget - Optional budget override\n * @returns Prune result with budget utilization\n */\n optimizeIncremental(\n newEntries: MemoryEntry[],\n budget?: number,\n ): PruneResult & { budgetUtilization: number };\n\n /**\n * Optimize fully (recompute all scores)\n * @param allEntries - All entries to optimize\n * @param budget - Optional budget override\n * @returns Prune result with budget utilization\n */\n optimizeFull(\n allEntries: MemoryEntry[],\n budget?: number,\n ): PruneResult & { budgetUtilization: number };\n\n /**\n * Get current optimizer state (for serialization)\n * @returns Serializable state object\n */\n getState(): IncrementalOptimizerState;\n\n /**\n * Restore optimizer state (from serialization)\n * @param state - State to restore\n */\n restoreState(state: IncrementalOptimizerState): void;\n\n /**\n * Reset optimizer state (clear all caches)\n */\n reset(): void;\n\n /**\n * Get cache statistics\n * @returns Cache stats\n */\n getStats(): {\n cachedEntries: number;\n uniqueTerms: number;\n totalDocuments: number;\n updateCount: number;\n lastFullOptimization: number;\n };\n\n /**\n * Serialize optimizer state to JSON string for persistence\n * @returns JSON string of the state\n */\n serializeState(): string;\n\n /**\n * Deserialize optimizer state from JSON string\n * @param json - JSON string to restore from\n * @returns true if successful, false on error\n */\n deserializeState(json: string): boolean;\n}\n\n/**\n * Create an incremental optimizer instance\n * @param config - Optimizer configuration\n * @returns IncrementalOptimizer instance\n */\nexport function createIncrementalOptimizer(\n config: IncrementalOptimizerConfig,\n): IncrementalOptimizer {\n const pruner = createBudgetPruner(config);\n const { fullOptimizationInterval } = config;\n\n // Internal state\n let state: IncrementalOptimizerState = {\n entryCache: new Map(),\n documentFrequency: new Map(),\n totalDocuments: 0,\n updateCount: 0,\n lastFullOptimization: Date.now(),\n };\n\n /**\n * Update document frequency table incrementally\n */\n function updateDocumentFrequency(entries: MemoryEntry[], remove = false): void {\n for (const entry of entries) {\n const tokens = tokenize(entry.content);\n const uniqueTerms = [...new Set(tokens)];\n\n for (const term of uniqueTerms) {\n const current = state.documentFrequency.get(term) || 0;\n const updated = remove ? Math.max(0, current - 1) : current + 1;\n\n if (updated === 0) {\n state.documentFrequency.delete(term);\n } else {\n state.documentFrequency.set(term, updated);\n }\n }\n }\n\n state.totalDocuments += remove ? -entries.length : entries.length;\n state.totalDocuments = Math.max(0, state.totalDocuments);\n }\n\n /**\n * Check if entry is cached and still valid\n */\n function getCachedEntry(hash: string): MemoryEntry | null {\n const cached = state.entryCache.get(hash);\n if (!cached) return null;\n\n // Entry is valid if found in cache\n return cached.entry;\n }\n\n /** Max cache entries to prevent unbounded growth */\n const MAX_CACHE_SIZE = 10000;\n\n /**\n * Cache entry with score\n */\n function cacheEntry(entry: MemoryEntry, score: number): void {\n // Evict oldest entries if cache is full\n if (state.entryCache.size >= MAX_CACHE_SIZE) {\n const entries = Array.from(state.entryCache.entries());\n entries.sort((a, b) => a[1].timestamp - b[1].timestamp);\n // Remove oldest 20%\n const toRemove = Math.floor(MAX_CACHE_SIZE * 0.2);\n for (let i = 0; i < toRemove && i < entries.length; i++) {\n const entry = entries[i];\n if (entry) {\n state.entryCache.delete(entry[0]);\n }\n }\n }\n\n state.entryCache.set(entry.hash, {\n entry,\n score,\n timestamp: Date.now(),\n });\n }\n\n function optimizeIncremental(\n newEntries: MemoryEntry[],\n budget?: number,\n ): PruneResult & { budgetUtilization: number } {\n const startTime = Date.now();\n state.updateCount++;\n\n // Force full optimization if interval reached\n if (state.updateCount >= fullOptimizationInterval) {\n // Get all cached entries\n const allEntries = Array.from(state.entryCache.values()).map((c) => c.entry);\n return optimizeFull([...allEntries, ...newEntries], budget);\n }\n\n // Filter out already-cached entries\n const uncachedEntries: MemoryEntry[] = [];\n const cachedEntries: MemoryEntry[] = [];\n\n for (const entry of newEntries) {\n const cached = getCachedEntry(entry.hash);\n if (cached) {\n cachedEntries.push(cached);\n } else {\n uncachedEntries.push(entry);\n }\n }\n\n // Update document frequency for new entries only\n if (uncachedEntries.length > 0) {\n updateDocumentFrequency(uncachedEntries, false);\n }\n\n // Combine with cached entries for scoring context\n const allEntries = [...cachedEntries, ...uncachedEntries];\n\n // Score only uncached entries (reuse cached scores)\n for (const entry of uncachedEntries) {\n const score = pruner.priorityScore(entry, allEntries);\n cacheEntry(entry, score);\n }\n\n // Get all current entries (from cache + new)\n const currentEntries = Array.from(state.entryCache.values()).map((c) => c.entry);\n\n // Calculate tokens before\n const tokensBefore = currentEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Prune to fit budget\n const result = pruner.pruneToFit(currentEntries, budget);\n\n // Calculate tokens after\n const tokensAfter = result.kept.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Update cache: remove pruned entries\n for (const removed of result.removed) {\n state.entryCache.delete(removed.hash);\n }\n\n // Update document frequency to reflect removal\n if (result.removed.length > 0) {\n updateDocumentFrequency(result.removed, true);\n }\n\n // Record metrics\n const duration = Date.now() - startTime;\n const cacheHitRate = newEntries.length > 0 ? cachedEntries.length / newEntries.length : 0;\n\n getMetrics().recordOptimization({\n timestamp: Date.now(),\n duration,\n tokensBefore,\n tokensAfter,\n entriesProcessed: newEntries.length,\n entriesKept: result.kept.length,\n cacheHitRate,\n memoryUsage: process.memoryUsage().heapUsed,\n });\n\n return result;\n }\n\n function optimizeFull(\n allEntries: MemoryEntry[],\n budget?: number,\n ): PruneResult & { budgetUtilization: number } {\n const startTime = Date.now();\n\n // Calculate tokens before\n const tokensBefore = allEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Reset state\n state.entryCache.clear();\n state.documentFrequency.clear();\n state.totalDocuments = 0;\n state.updateCount = 0;\n state.lastFullOptimization = Date.now();\n\n // Rebuild document frequency table\n updateDocumentFrequency(allEntries, false);\n\n // Score and cache all entries\n for (const entry of allEntries) {\n const score = pruner.priorityScore(entry, allEntries);\n cacheEntry(entry, score);\n }\n\n // Prune to fit budget\n const result = pruner.pruneToFit(allEntries, budget);\n\n // Calculate tokens after\n const tokensAfter = result.kept.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n // Update cache: remove pruned entries\n for (const removed of result.removed) {\n state.entryCache.delete(removed.hash);\n }\n\n // Update document frequency to reflect removal\n if (result.removed.length > 0) {\n updateDocumentFrequency(result.removed, true);\n }\n\n // Record metrics\n const duration = Date.now() - startTime;\n\n getMetrics().recordOptimization({\n timestamp: Date.now(),\n duration,\n tokensBefore,\n tokensAfter,\n entriesProcessed: allEntries.length,\n entriesKept: result.kept.length,\n cacheHitRate: 0, // Full optimization has no cache hits\n memoryUsage: process.memoryUsage().heapUsed,\n });\n\n return result;\n }\n\n function getState(): IncrementalOptimizerState {\n return {\n entryCache: new Map(state.entryCache),\n documentFrequency: new Map(state.documentFrequency),\n totalDocuments: state.totalDocuments,\n updateCount: state.updateCount,\n lastFullOptimization: state.lastFullOptimization,\n };\n }\n\n function restoreState(restoredState: IncrementalOptimizerState): void {\n state = {\n entryCache: new Map(restoredState.entryCache),\n documentFrequency: new Map(restoredState.documentFrequency),\n totalDocuments: restoredState.totalDocuments,\n updateCount: restoredState.updateCount,\n lastFullOptimization: restoredState.lastFullOptimization,\n };\n }\n\n function reset(): void {\n state = {\n entryCache: new Map(),\n documentFrequency: new Map(),\n totalDocuments: 0,\n updateCount: 0,\n lastFullOptimization: Date.now(),\n };\n }\n\n function getStats() {\n return {\n cachedEntries: state.entryCache.size,\n uniqueTerms: state.documentFrequency.size,\n totalDocuments: state.totalDocuments,\n updateCount: state.updateCount,\n lastFullOptimization: state.lastFullOptimization,\n };\n }\n\n function serializeState(): string {\n const s = getState();\n return JSON.stringify({\n entryCache: Array.from(s.entryCache.entries()),\n documentFrequency: Array.from(s.documentFrequency.entries()),\n totalDocuments: s.totalDocuments,\n updateCount: s.updateCount,\n lastFullOptimization: s.lastFullOptimization,\n });\n }\n\n function deserializeState(json: string): boolean {\n try {\n const parsed = JSON.parse(json);\n restoreState({\n entryCache: new Map(parsed.entryCache),\n documentFrequency: new Map(parsed.documentFrequency),\n totalDocuments: parsed.totalDocuments,\n updateCount: parsed.updateCount,\n lastFullOptimization: parsed.lastFullOptimization,\n });\n return true;\n } catch {\n return false;\n }\n }\n\n return {\n optimizeIncremental,\n optimizeFull,\n getState,\n restoreState,\n reset,\n getStats,\n serializeState,\n deserializeState,\n };\n}\n","/**\n * Streaming Context Pipeline - Real-time sliding window buffer\n *\n * Maintains an optimized context in real-time by:\n * - Ingesting new content as it arrives\n * - Storing entries by priority internally (for eviction decisions)\n * - Outputting in chronological order (for conversation coherence)\n * - Evicting lowest-priority entries when budget exceeded\n * - Using IncrementalOptimizer for fast delta processing\n */\n\nimport type { MemoryEntry } from '../types/memory.js';\nimport { parseClaudeCodeContext } from '../utils/context-parser.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\nimport {\n createIncrementalOptimizer,\n type IncrementalOptimizerConfig,\n} from './incremental-optimizer.js';\n\nexport interface ContextPipelineConfig extends IncrementalOptimizerConfig {\n /** Sliding window size (max entries to keep) */\n windowSize: number;\n}\n\nexport interface ContextPipelineStats {\n /** Total entries ingested */\n totalIngested: number;\n /** Current entry count */\n currentEntries: number;\n /** Current token count */\n currentTokens: number;\n /** Budget utilization (0.0-1.0) */\n budgetUtilization: number;\n /** Evicted entry count */\n evictedEntries: number;\n /** Optimizer stats */\n optimizer: {\n cachedEntries: number;\n uniqueTerms: number;\n updateCount: number;\n };\n}\n\nexport interface ContextPipeline {\n /**\n * Serialize optimizer state for persistence\n * @returns JSON string of the optimizer state\n */\n serializeOptimizerState(): string;\n\n /**\n * Restore optimizer state from persistence\n * @param json - JSON string to restore from\n * @returns true if successful\n */\n deserializeOptimizerState(json: string): boolean;\n /**\n * Ingest new content into the pipeline\n * @param content - Raw content string\n * @param metadata - Optional metadata to attach to entries\n * @returns Number of entries ingested\n */\n ingest(content: string, metadata?: Record<string, unknown>): number;\n\n /**\n * Get current optimized context (chronologically ordered)\n * @returns Optimized context string\n */\n getContext(): string;\n\n /**\n * Get current entries (chronologically ordered)\n * @returns Array of memory entries\n */\n getEntries(): MemoryEntry[];\n\n /**\n * Get pipeline statistics\n * @returns Pipeline stats\n */\n getStats(): ContextPipelineStats;\n\n /**\n * Clear all entries and reset state\n */\n clear(): void;\n}\n\n/**\n * Create a context pipeline instance\n * @param config - Pipeline configuration\n * @returns ContextPipeline instance\n */\nexport function createContextPipeline(config: ContextPipelineConfig): ContextPipeline {\n const optimizer = createIncrementalOptimizer(config);\n const { windowSize, tokenBudget } = config;\n\n // Internal state\n let totalIngested = 0;\n let evictedEntries = 0;\n let currentEntries: MemoryEntry[] = [];\n let budgetUtilization = 0;\n\n function ingest(content: string, metadata: Record<string, unknown> = {}): number {\n // Parse content into entries\n const newEntries = parseClaudeCodeContext(content);\n\n if (newEntries.length === 0) return 0;\n\n // Attach metadata to entries\n const entriesWithMetadata = newEntries.map((entry) => ({\n ...entry,\n metadata: { ...entry.metadata, ...metadata },\n }));\n\n // Optimize incrementally\n const result = optimizer.optimizeIncremental(entriesWithMetadata, tokenBudget);\n\n // Update statistics\n totalIngested += newEntries.length;\n evictedEntries += result.removed.length;\n currentEntries = result.kept;\n budgetUtilization = result.budgetUtilization;\n\n // Enforce window size limit using hybrid scoring\n if (currentEntries.length > windowSize) {\n // Calculate hybrid eviction score: ageNormalized * 0.4 + score * 0.6\n const timestamps = currentEntries.map((e) => e.timestamp);\n const minTs = Math.min(...timestamps);\n const maxTs = Math.max(...timestamps);\n const tsRange = maxTs - minTs || 1;\n\n const scored = currentEntries.map((entry) => {\n // BTSP entries always survive\n if (entry.isBTSP) return { entry, hybridScore: 2.0 };\n\n // ageNormalized: 1.0 = newest, 0.0 = oldest\n const ageNormalized = (entry.timestamp - minTs) / tsRange;\n const hybridScore = ageNormalized * 0.4 + entry.score * 0.6;\n return { entry, hybridScore };\n });\n\n // Sort by hybrid score descending (highest = keep)\n scored.sort((a, b) => {\n if (b.hybridScore !== a.hybridScore) return b.hybridScore - a.hybridScore;\n // Tiebreak: newer entries first\n return b.entry.timestamp - a.entry.timestamp;\n });\n\n const toKeep = scored.slice(0, windowSize).map((s) => s.entry);\n const toRemove = scored.slice(windowSize);\n\n currentEntries = toKeep;\n evictedEntries += toRemove.length;\n }\n\n return newEntries.length;\n }\n\n function getContext(): string {\n // Sort entries chronologically (oldest first)\n const sorted = [...currentEntries].sort((a, b) => a.timestamp - b.timestamp);\n return sorted.map((e) => e.content).join('\\n\\n');\n }\n\n function getEntries(): MemoryEntry[] {\n // Return entries chronologically (oldest first)\n return [...currentEntries].sort((a, b) => a.timestamp - b.timestamp);\n }\n\n function getStats(): ContextPipelineStats {\n const optimizerStats = optimizer.getStats();\n const currentTokens = currentEntries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n return {\n totalIngested,\n currentEntries: currentEntries.length,\n currentTokens,\n budgetUtilization,\n evictedEntries,\n optimizer: {\n cachedEntries: optimizerStats.cachedEntries,\n uniqueTerms: optimizerStats.uniqueTerms,\n updateCount: optimizerStats.updateCount,\n },\n };\n }\n\n function clear(): void {\n totalIngested = 0;\n evictedEntries = 0;\n currentEntries = [];\n budgetUtilization = 0;\n optimizer.reset();\n }\n\n function serializeOptimizerState(): string {\n return optimizer.serializeState();\n }\n\n function deserializeOptimizerState(json: string): boolean {\n return optimizer.deserializeState(json);\n }\n\n return {\n serializeOptimizerState,\n deserializeOptimizerState,\n ingest,\n getContext,\n getEntries,\n getStats,\n clear,\n };\n}\n","/**\n * Debt Tracker - Technical debt management\n *\n * Tracks technical debt with mandatory repayment dates,\n * severity levels, and token cost estimates.\n * Stored in SQLite alongside the main memory.db.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport Database from 'better-sqlite3';\n\nexport type DebtSeverity = 'P0' | 'P1' | 'P2';\nexport type DebtStatus = 'open' | 'in_progress' | 'resolved';\n\nexport interface TechDebt {\n id: string;\n description: string;\n created_at: number;\n repayment_date: number;\n severity: DebtSeverity;\n token_cost: number;\n files_affected: string[];\n status: DebtStatus;\n resolution_tokens?: number;\n resolved_at?: number;\n}\n\nexport interface DebtStats {\n total: number;\n open: number;\n in_progress: number;\n resolved: number;\n overdue: number;\n totalTokenCost: number;\n resolvedTokenCost: number;\n repaymentRate: number;\n}\n\nexport interface DebtTracker {\n /** Add a new tech debt item */\n add(debt: Omit<TechDebt, 'id' | 'created_at' | 'status'>): Promise<TechDebt>;\n\n /** List all debts, optionally filtered */\n list(filter?: {\n status?: DebtStatus;\n severity?: DebtSeverity;\n overdue?: boolean;\n }): Promise<TechDebt[]>;\n\n /** Get a specific debt by ID */\n get(id: string): Promise<TechDebt | null>;\n\n /** Update debt status */\n resolve(id: string, resolutionTokens?: number): Promise<void>;\n\n /** Update debt status to in_progress */\n start(id: string): Promise<void>;\n\n /** Delete a debt item */\n remove(id: string): Promise<void>;\n\n /** Get debt statistics */\n stats(): Promise<DebtStats>;\n\n /** Get P0 debts for CLAUDE.md inclusion */\n getCritical(): Promise<TechDebt[]>;\n\n /** Close database */\n close(): Promise<void>;\n}\n\n/**\n * Create a debt tracker instance\n */\nexport function createDebtTracker(dbPath: string): DebtTracker {\n const db = new Database(dbPath);\n db.pragma('journal_mode = WAL');\n\n // Create debt table\n db.exec(`\n CREATE TABLE IF NOT EXISTS tech_debt (\n id TEXT PRIMARY KEY NOT NULL,\n description TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n repayment_date INTEGER NOT NULL,\n severity TEXT NOT NULL CHECK(severity IN ('P0', 'P1', 'P2')),\n token_cost INTEGER NOT NULL DEFAULT 0,\n files_affected TEXT NOT NULL DEFAULT '[]',\n status TEXT NOT NULL DEFAULT 'open' CHECK(status IN ('open', 'in_progress', 'resolved')),\n resolution_tokens INTEGER,\n resolved_at INTEGER\n );\n `);\n\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_debt_status ON tech_debt(status);\n CREATE INDEX IF NOT EXISTS idx_debt_severity ON tech_debt(severity);\n CREATE INDEX IF NOT EXISTS idx_debt_repayment ON tech_debt(repayment_date);\n `);\n\n const insertStmt = db.prepare(`\n INSERT INTO tech_debt (id, description, created_at, repayment_date, severity, token_cost, files_affected, status)\n VALUES (?, ?, ?, ?, ?, ?, ?, 'open')\n `);\n\n const getStmt = db.prepare('SELECT * FROM tech_debt WHERE id = ?');\n\n function rowToDebt(row: Record<string, unknown>): TechDebt {\n return {\n id: row['id'] as string,\n description: row['description'] as string,\n created_at: row['created_at'] as number,\n repayment_date: row['repayment_date'] as number,\n severity: row['severity'] as DebtSeverity,\n token_cost: row['token_cost'] as number,\n files_affected: JSON.parse((row['files_affected'] as string) || '[]'),\n status: row['status'] as DebtStatus,\n resolution_tokens: row['resolution_tokens'] as number | undefined,\n resolved_at: row['resolved_at'] as number | undefined,\n };\n }\n\n async function add(debt: Omit<TechDebt, 'id' | 'created_at' | 'status'>): Promise<TechDebt> {\n const id = randomUUID().split('-')[0] || 'debt';\n const created_at = Date.now();\n\n insertStmt.run(\n id,\n debt.description,\n created_at,\n debt.repayment_date,\n debt.severity,\n debt.token_cost,\n JSON.stringify(debt.files_affected),\n );\n\n return {\n id,\n created_at,\n status: 'open',\n description: debt.description,\n repayment_date: debt.repayment_date,\n severity: debt.severity,\n token_cost: debt.token_cost,\n files_affected: debt.files_affected,\n };\n }\n\n async function list(\n filter: { status?: DebtStatus; severity?: DebtSeverity; overdue?: boolean } = {},\n ): Promise<TechDebt[]> {\n let sql = 'SELECT * FROM tech_debt WHERE 1=1';\n const params: unknown[] = [];\n\n if (filter.status) {\n sql += ' AND status = ?';\n params.push(filter.status);\n }\n\n if (filter.severity) {\n sql += ' AND severity = ?';\n params.push(filter.severity);\n }\n\n if (filter.overdue) {\n sql += ' AND repayment_date < ? AND status != ?';\n params.push(Date.now());\n params.push('resolved');\n }\n\n sql += ' ORDER BY severity ASC, repayment_date ASC';\n\n const rows = db.prepare(sql).all(...params) as Array<Record<string, unknown>>;\n return rows.map(rowToDebt);\n }\n\n async function get(id: string): Promise<TechDebt | null> {\n const row = getStmt.get(id) as Record<string, unknown> | undefined;\n if (!row) return null;\n return rowToDebt(row);\n }\n\n async function resolve(id: string, resolutionTokens?: number): Promise<void> {\n const result = db\n .prepare(\n 'UPDATE tech_debt SET status = ?, resolution_tokens = ?, resolved_at = ? WHERE id = ?',\n )\n .run('resolved', resolutionTokens ?? null, Date.now(), id);\n if (result.changes === 0) {\n throw new Error(`Debt not found: ${id}`);\n }\n }\n\n async function start(id: string): Promise<void> {\n const result = db\n .prepare('UPDATE tech_debt SET status = ? WHERE id = ?')\n .run('in_progress', id);\n if (result.changes === 0) {\n throw new Error(`Debt not found: ${id}`);\n }\n }\n\n async function remove(id: string): Promise<void> {\n db.prepare('DELETE FROM tech_debt WHERE id = ?').run(id);\n }\n\n async function stats(): Promise<DebtStats> {\n const all = db.prepare('SELECT * FROM tech_debt').all() as Array<Record<string, unknown>>;\n const debts = all.map(rowToDebt);\n\n const now = Date.now();\n const open = debts.filter((d) => d.status === 'open');\n const inProgress = debts.filter((d) => d.status === 'in_progress');\n const resolved = debts.filter((d) => d.status === 'resolved');\n const overdue = debts.filter((d) => d.status !== 'resolved' && d.repayment_date < now);\n\n const totalTokenCost = debts.reduce((sum, d) => sum + d.token_cost, 0);\n const resolvedTokenCost = resolved.reduce(\n (sum, d) => sum + (d.resolution_tokens || d.token_cost),\n 0,\n );\n\n // Repayment rate: resolved on time / total resolved\n const resolvedOnTime = resolved.filter(\n (d) => d.resolved_at && d.resolved_at <= d.repayment_date,\n ).length;\n const repaymentRate = resolved.length > 0 ? resolvedOnTime / resolved.length : 0;\n\n return {\n total: debts.length,\n open: open.length,\n in_progress: inProgress.length,\n resolved: resolved.length,\n overdue: overdue.length,\n totalTokenCost,\n resolvedTokenCost,\n repaymentRate,\n };\n }\n\n async function getCritical(): Promise<TechDebt[]> {\n const rows = db\n .prepare(\n \"SELECT * FROM tech_debt WHERE severity = 'P0' AND status != 'resolved' ORDER BY repayment_date ASC\",\n )\n .all() as Array<Record<string, unknown>>;\n return rows.map(rowToDebt);\n }\n\n async function close(): Promise<void> {\n db.close();\n }\n\n return {\n add,\n list,\n get,\n resolve,\n start,\n remove,\n stats,\n getCritical,\n close,\n };\n}\n","/**\n * Dependency Graph Analyzer\n *\n * Analyzes TypeScript/JavaScript import/export relationships to build\n * a dependency graph. Uses regex-based parsing (no AST dependency needed)\n * for lightweight, fast analysis.\n *\n * Integrates with engram scoring to identify hot paths and prioritize\n * files for context loading.\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { extname, join, relative, resolve } from 'node:path';\nimport { estimateTokens } from '../utils/tokenizer.js';\n\nexport interface DependencyNode {\n filePath: string;\n exports: string[];\n imports: DependencyEdge[];\n callers: string[];\n engram_score: number;\n lastModified: number;\n tokenEstimate: number;\n}\n\nexport interface DependencyEdge {\n source: string;\n target: string;\n symbols: string[];\n}\n\nexport interface GraphAnalysis {\n entryPoints: string[];\n hotPaths: string[];\n orphans: string[];\n totalTokens: number;\n optimizedTokens: number;\n}\n\nexport interface DependencyGraphConfig {\n /** Project root directory */\n projectRoot: string;\n /** Maximum depth for traversal (default: Infinity) */\n maxDepth?: number;\n /** File extensions to analyze (default: ['.ts', '.tsx', '.js', '.jsx']) */\n extensions?: string[];\n /** Directories to ignore (default: ['node_modules', 'dist', '.git', '.sparn']) */\n ignoreDirs?: string[];\n}\n\nexport interface DependencyGraph {\n /** Build the full dependency graph */\n build(): Promise<Map<string, DependencyNode>>;\n\n /** Get graph analysis with entry points, hot paths, orphans */\n analyze(): Promise<GraphAnalysis>;\n\n /** Get subgraph focused on a specific module/pattern */\n focus(pattern: string): Promise<Map<string, DependencyNode>>;\n\n /** Get files needed starting from an entry point, up to maxDepth */\n getFilesFromEntry(entryPoint: string, maxDepth?: number): Promise<string[]>;\n\n /** Get the full node map (after build) */\n getNodes(): Map<string, DependencyNode>;\n}\n\n// Import/export parsing patterns\nconst IMPORT_PATTERNS = [\n // import { Foo, Bar } from './module'\n /import\\s+\\{([^}]+)\\}\\s+from\\s+['\"]([^'\"]+)['\"]/g,\n // import Foo from './module'\n /import\\s+(\\w+)\\s+from\\s+['\"]([^'\"]+)['\"]/g,\n // import * as Foo from './module'\n /import\\s+\\*\\s+as\\s+(\\w+)\\s+from\\s+['\"]([^'\"]+)['\"]/g,\n // import './module' (side-effect)\n /import\\s+['\"]([^'\"]+)['\"]/g,\n // require('./module')\n /require\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g,\n];\n\nconst EXPORT_PATTERNS = [\n // export { Foo, Bar }\n /export\\s+\\{([^}]+)\\}/g,\n // export function/class/const/let/var/type/interface\n /export\\s+(?:default\\s+)?(?:function|class|const|let|var|type|interface|enum)\\s+(\\w+)/g,\n // export default\n /export\\s+default\\s+/g,\n];\n\n/**\n * Parse imports from file content\n */\nfunction parseImports(content: string, filePath: string): DependencyEdge[] {\n const edges: DependencyEdge[] = [];\n const seen = new Set<string>();\n\n for (const pattern of IMPORT_PATTERNS) {\n const regex = new RegExp(pattern.source, pattern.flags);\n const matches = [...content.matchAll(regex)];\n\n for (const match of matches) {\n if (pattern.source.includes('from')) {\n // Named/default imports with from clause\n const symbolsRaw = match[1] || '';\n const target = match[2] || '';\n\n if (!target || (target.startsWith('.') === false && !target.startsWith('/'))) {\n continue; // Skip external packages\n }\n\n const symbols = symbolsRaw\n .split(',')\n .map(\n (s) =>\n s\n .trim()\n .split(/\\s+as\\s+/)[0]\n ?.trim() || '',\n )\n .filter(Boolean);\n\n const key = `${filePath}->${target}`;\n if (!seen.has(key)) {\n seen.add(key);\n edges.push({ source: filePath, target, symbols });\n }\n } else if (pattern.source.includes('require')) {\n const target = match[1] || '';\n if (!target || (!target.startsWith('.') && !target.startsWith('/'))) {\n continue;\n }\n const key = `${filePath}->${target}`;\n if (!seen.has(key)) {\n seen.add(key);\n edges.push({ source: filePath, target, symbols: [] });\n }\n } else {\n const target = match[1] || '';\n if (!target || (!target.startsWith('.') && !target.startsWith('/'))) {\n continue;\n }\n const key = `${filePath}->${target}`;\n if (!seen.has(key)) {\n seen.add(key);\n edges.push({ source: filePath, target, symbols: [] });\n }\n }\n }\n }\n\n return edges;\n}\n\n/**\n * Parse exports from file content\n */\nfunction parseExports(content: string): string[] {\n const exportsList: string[] = [];\n\n for (const pattern of EXPORT_PATTERNS) {\n const regex = new RegExp(pattern.source, pattern.flags);\n const matches = [...content.matchAll(regex)];\n\n for (const match of matches) {\n if (match[1]) {\n const symbols = match[1]\n .split(',')\n .map(\n (s) =>\n s\n .trim()\n .split(/\\s+as\\s+/)[0]\n ?.trim() || '',\n )\n .filter(Boolean);\n exportsList.push(...symbols);\n } else {\n exportsList.push('default');\n }\n }\n }\n\n return [...new Set(exportsList)];\n}\n\n/**\n * Resolve a relative import path to an absolute file path\n */\nfunction resolveImportPath(\n importPath: string,\n fromFile: string,\n projectRoot: string,\n extensions: string[],\n): string | null {\n // Remove .js/.ts extension from import if present\n const cleanImport = importPath.replace(/\\.(js|ts|tsx|jsx)$/, '');\n\n const baseDir = join(projectRoot, fromFile, '..');\n const candidates = [\n ...extensions.map((ext) => resolve(baseDir, `${cleanImport}${ext}`)),\n ...extensions.map((ext) => resolve(baseDir, cleanImport, `index${ext}`)),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return relative(projectRoot, candidate).replace(/\\\\/g, '/');\n }\n }\n\n return null;\n}\n\n/**\n * Recursively collect all source files\n */\nfunction collectFiles(\n dir: string,\n projectRoot: string,\n extensions: string[],\n ignoreDirs: string[],\n): string[] {\n const files: string[] = [];\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if (!ignoreDirs.includes(entry.name)) {\n files.push(...collectFiles(fullPath, projectRoot, extensions, ignoreDirs));\n }\n } else if (entry.isFile() && extensions.includes(extname(entry.name))) {\n files.push(relative(projectRoot, fullPath).replace(/\\\\/g, '/'));\n }\n }\n } catch {\n // Skip inaccessible directories\n }\n\n return files;\n}\n\n/**\n * Create a dependency graph analyzer\n */\nexport function createDependencyGraph(config: DependencyGraphConfig): DependencyGraph {\n const {\n projectRoot,\n maxDepth = 50,\n extensions = ['.ts', '.tsx', '.js', '.jsx'],\n ignoreDirs = ['node_modules', 'dist', '.git', '.sparn', 'coverage'],\n } = config;\n\n const nodes = new Map<string, DependencyNode>();\n let built = false;\n\n async function build(): Promise<Map<string, DependencyNode>> {\n nodes.clear();\n\n // Collect all source files\n const files = collectFiles(projectRoot, projectRoot, extensions, ignoreDirs);\n\n // Parse each file\n for (const filePath of files) {\n const fullPath = join(projectRoot, filePath);\n\n try {\n const content = readFileSync(fullPath, 'utf-8');\n const stat = statSync(fullPath);\n\n const exports = parseExports(content);\n const imports = parseImports(content, filePath);\n\n // Resolve import targets to actual file paths\n const resolvedImports: DependencyEdge[] = [];\n for (const imp of imports) {\n const resolved = resolveImportPath(imp.target, filePath, projectRoot, extensions);\n if (resolved) {\n resolvedImports.push({ ...imp, target: resolved });\n }\n }\n\n nodes.set(filePath, {\n filePath,\n exports,\n imports: resolvedImports,\n callers: [], // Populated in second pass\n engram_score: 0,\n lastModified: stat.mtimeMs,\n tokenEstimate: estimateTokens(content),\n });\n } catch {\n // Skip files that can't be read\n }\n }\n\n // Second pass: populate callers\n for (const [filePath, node] of nodes) {\n for (const imp of node.imports) {\n const targetNode = nodes.get(imp.target);\n if (targetNode && !targetNode.callers.includes(filePath)) {\n targetNode.callers.push(filePath);\n }\n }\n }\n\n built = true;\n return nodes;\n }\n\n async function analyze(): Promise<GraphAnalysis> {\n if (!built) await build();\n\n const entryPoints: string[] = [];\n const orphans: string[] = [];\n const callerCounts = new Map<string, number>();\n\n for (const [filePath, node] of nodes) {\n // Entry points: files with no callers (typically index.ts, CLI entry, etc.)\n if (node.callers.length === 0 && node.imports.length > 0) {\n entryPoints.push(filePath);\n }\n\n // Orphans: files with no callers AND no imports (truly isolated)\n if (node.callers.length === 0 && node.imports.length === 0) {\n orphans.push(filePath);\n }\n\n // Count how many files import each module\n callerCounts.set(filePath, node.callers.length);\n }\n\n // Hot paths: files imported by the most other files\n const sortedByCallers = [...callerCounts.entries()]\n .sort((a, b) => b[1] - a[1])\n .filter(([, count]) => count > 0);\n\n const hotPaths = sortedByCallers.slice(0, 10).map(([path]) => path);\n\n // Token calculations\n const totalTokens = [...nodes.values()].reduce((sum, n) => sum + n.tokenEstimate, 0);\n const hotPathTokens = hotPaths.reduce(\n (sum, path) => sum + (nodes.get(path)?.tokenEstimate || 0),\n 0,\n );\n\n return {\n entryPoints,\n hotPaths,\n orphans,\n totalTokens,\n optimizedTokens: hotPathTokens,\n };\n }\n\n async function focus(pattern: string): Promise<Map<string, DependencyNode>> {\n if (!built) await build();\n\n const matching = new Map<string, DependencyNode>();\n const lowerPattern = pattern.toLowerCase();\n\n for (const [filePath, node] of nodes) {\n if (filePath.toLowerCase().includes(lowerPattern)) {\n matching.set(filePath, node);\n\n // Also include direct dependencies and callers\n for (const imp of node.imports) {\n const depNode = nodes.get(imp.target);\n if (depNode) {\n matching.set(imp.target, depNode);\n }\n }\n\n for (const caller of node.callers) {\n const callerNode = nodes.get(caller);\n if (callerNode) {\n matching.set(caller, callerNode);\n }\n }\n }\n }\n\n return matching;\n }\n\n async function getFilesFromEntry(\n entryPoint: string,\n depth: number = maxDepth,\n ): Promise<string[]> {\n if (!built) await build();\n\n const visited = new Set<string>();\n const queue: Array<{ path: string; depth: number }> = [{ path: entryPoint, depth: 0 }];\n\n while (queue.length > 0) {\n const item = queue.shift();\n if (!item) break;\n\n if (visited.has(item.path) || item.depth > depth) continue;\n visited.add(item.path);\n\n const node = nodes.get(item.path);\n if (node) {\n for (const imp of node.imports) {\n if (!visited.has(imp.target)) {\n queue.push({ path: imp.target, depth: item.depth + 1 });\n }\n }\n }\n }\n\n return [...visited];\n }\n\n function getNodes(): Map<string, DependencyNode> {\n return nodes;\n }\n\n return {\n build,\n analyze,\n focus,\n getFilesFromEntry,\n getNodes,\n };\n}\n","/**\n * Docs Generator - Auto-generate CLAUDE.md\n *\n * Scans repo structure, uses dependency graph data, and generates\n * a compact CLAUDE.md optimized for AI agent context loading.\n */\n\nimport { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { extname, join, relative } from 'node:path';\nimport type { DependencyGraph, GraphAnalysis } from './dependency-graph.js';\n\nexport interface DocsGeneratorConfig {\n projectRoot: string;\n /** Include dependency graph summary */\n includeGraph?: boolean;\n /** Include debt tracker info */\n includeDebt?: boolean;\n /** Custom sections to append */\n customSections?: string[];\n}\n\nexport interface DocsGenerator {\n /** Generate CLAUDE.md content */\n generate(graph?: DependencyGraph): Promise<string>;\n}\n\n/**\n * Detect entry points by looking for common patterns\n */\nfunction detectEntryPoints(projectRoot: string): Array<{ path: string; description: string }> {\n const entries: Array<{ path: string; description: string }> = [];\n const candidates = [\n { path: 'src/index.ts', desc: 'Library API' },\n { path: 'src/cli/index.ts', desc: 'CLI entry point' },\n { path: 'src/daemon/index.ts', desc: 'Daemon process' },\n { path: 'src/mcp/index.ts', desc: 'MCP server' },\n { path: 'src/main.ts', desc: 'Main entry' },\n { path: 'src/app.ts', desc: 'App entry' },\n { path: 'src/server.ts', desc: 'Server entry' },\n { path: 'index.ts', desc: 'Root entry' },\n { path: 'index.js', desc: 'Root entry' },\n ];\n\n for (const c of candidates) {\n if (existsSync(join(projectRoot, c.path))) {\n entries.push({ path: c.path, description: c.desc });\n }\n }\n\n return entries;\n}\n\n/**\n * Scan directory structure for module summary\n */\nfunction scanModules(\n dir: string,\n projectRoot: string,\n ignoreDirs = ['node_modules', 'dist', '.git', '.sparn', 'coverage'],\n): Array<{ path: string; lines: number }> {\n const modules: Array<{ path: string; lines: number }> = [];\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n\n if (entry.isDirectory() && !ignoreDirs.includes(entry.name)) {\n modules.push(...scanModules(fullPath, projectRoot, ignoreDirs));\n } else if (entry.isFile() && ['.ts', '.tsx', '.js', '.jsx'].includes(extname(entry.name))) {\n try {\n const content = readFileSync(fullPath, 'utf-8');\n modules.push({\n path: relative(projectRoot, fullPath).replace(/\\\\/g, '/'),\n lines: content.split('\\n').length,\n });\n } catch {\n // Skip\n }\n }\n }\n } catch {\n // Skip\n }\n\n return modules;\n}\n\n/**\n * Read package.json for project info\n */\nfunction readPackageJson(\n projectRoot: string,\n): { name: string; version: string; scripts: Record<string, string> } | null {\n const pkgPath = join(projectRoot, 'package.json');\n if (!existsSync(pkgPath)) return null;\n\n try {\n return JSON.parse(readFileSync(pkgPath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Detect tech stack from dependencies\n */\nfunction detectStack(projectRoot: string): string[] {\n const stack: string[] = [];\n const pkg = readPackageJson(projectRoot);\n if (!pkg) return stack;\n\n const allDeps = {\n ...(pkg as unknown as { dependencies?: Record<string, string> }).dependencies,\n ...(pkg as unknown as { devDependencies?: Record<string, string> }).devDependencies,\n };\n\n if (allDeps['typescript']) stack.push('TypeScript');\n if (allDeps['vitest']) stack.push('Vitest');\n if (allDeps['@biomejs/biome']) stack.push('Biome');\n if (allDeps['eslint']) stack.push('ESLint');\n if (allDeps['prettier']) stack.push('Prettier');\n if (allDeps['react']) stack.push('React');\n if (allDeps['next']) stack.push('Next.js');\n if (allDeps['express']) stack.push('Express');\n if (allDeps['commander']) stack.push('Commander.js CLI');\n if (allDeps['better-sqlite3']) stack.push('SQLite (better-sqlite3)');\n if (allDeps['zod']) stack.push('Zod validation');\n\n return stack;\n}\n\n/**\n * Create a docs generator\n */\nexport function createDocsGenerator(config: DocsGeneratorConfig): DocsGenerator {\n const { projectRoot, includeGraph = true } = config;\n\n async function generate(graph?: DependencyGraph): Promise<string> {\n const lines: string[] = [];\n const pkg = readPackageJson(projectRoot);\n const projectName = pkg?.name || 'Project';\n const now = new Date().toISOString();\n\n // Header\n lines.push(`# ${projectName} — Developer Guide`);\n lines.push(`<!-- Auto-generated by Sparn v1.3.0 — ${now} -->`);\n lines.push('');\n\n // Tech stack\n const stack = detectStack(projectRoot);\n if (stack.length > 0) {\n lines.push(`**Stack**: ${stack.join(', ')}`);\n lines.push('');\n }\n\n // Commands\n if (pkg?.scripts) {\n lines.push('## Commands');\n lines.push('');\n const important = ['build', 'dev', 'test', 'lint', 'typecheck', 'start'];\n for (const cmd of important) {\n if (pkg.scripts[cmd]) {\n lines.push(`- \\`npm run ${cmd}\\` — \\`${pkg.scripts[cmd]}\\``);\n }\n }\n lines.push('');\n }\n\n // Entry points\n const entryPoints = detectEntryPoints(projectRoot);\n if (entryPoints.length > 0) {\n lines.push('## Entry Points');\n lines.push('');\n for (const ep of entryPoints) {\n lines.push(`- \\`${ep.path}\\` — ${ep.description}`);\n }\n lines.push('');\n }\n\n // Module summary\n const srcDir = join(projectRoot, 'src');\n if (existsSync(srcDir)) {\n const modules = scanModules(srcDir, projectRoot);\n\n // Group by directory\n const dirGroups = new Map<string, Array<{ file: string; lines: number }>>();\n for (const mod of modules) {\n const parts = mod.path.split('/');\n const dir = parts.length > 2 ? parts.slice(0, 2).join('/') : parts[0] || '';\n if (!dirGroups.has(dir)) {\n dirGroups.set(dir, []);\n }\n dirGroups.get(dir)?.push({\n file: parts[parts.length - 1] || mod.path,\n lines: mod.lines,\n });\n }\n\n lines.push('## Structure');\n lines.push('');\n for (const [dir, files] of dirGroups) {\n lines.push(`### ${dir}/ (${files.length} files)`);\n // Show up to 8 files per dir\n const shown = files.slice(0, 8);\n for (const f of shown) {\n lines.push(`- \\`${f.file}\\` (${f.lines}L)`);\n }\n if (files.length > 8) {\n lines.push(`- ... and ${files.length - 8} more`);\n }\n lines.push('');\n }\n }\n\n // Dependency graph analysis\n if (includeGraph && graph) {\n try {\n const analysis: GraphAnalysis = await graph.analyze();\n\n lines.push('## Hot Dependencies (most imported)');\n lines.push('');\n for (const path of analysis.hotPaths.slice(0, 5)) {\n const node = graph.getNodes().get(path);\n const callerCount = node?.callers.length || 0;\n lines.push(`- \\`${path}\\` (imported by ${callerCount} modules)`);\n }\n lines.push('');\n\n if (analysis.orphans.length > 0) {\n lines.push(\n `**Orphaned files** (${analysis.orphans.length}): ${analysis.orphans.slice(0, 3).join(', ')}${analysis.orphans.length > 3 ? '...' : ''}`,\n );\n lines.push('');\n }\n\n lines.push(\n `**Total tokens**: ${analysis.totalTokens.toLocaleString()} | **Hot path tokens**: ${analysis.optimizedTokens.toLocaleString()}`,\n );\n lines.push('');\n } catch {\n // Skip graph section on error\n }\n }\n\n // Sparn config\n const sparnConfigPath = join(projectRoot, '.sparn', 'config.yaml');\n if (existsSync(sparnConfigPath)) {\n lines.push('## Sparn Optimization');\n lines.push('');\n lines.push('Sparn is active in this project. Key features:');\n lines.push('- Context optimization (60-70% token reduction)');\n lines.push('- Use `sparn search` before reading files');\n lines.push('- Use `sparn graph` to understand dependencies');\n lines.push('- Use `sparn plan` for planning, `sparn exec` for execution');\n lines.push('');\n }\n\n // Custom sections\n if (config.customSections) {\n for (const section of config.customSections) {\n lines.push(section);\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n }\n\n return { generate };\n}\n","/**\n * KV Memory Store Module\n * Key-value storage with dual index/value tables.\n * Separates what to store (content) from how to retrieve it (index with scores and state).\n */\n\nimport { copyFileSync, existsSync } from 'node:fs';\nimport Database from 'better-sqlite3';\nimport type { MemoryEntry, MemoryQueryFilters } from '../types/memory.js';\n\n/**\n * Optimization statistics record.\n */\nexport interface OptimizationStats {\n id: number;\n timestamp: number;\n tokens_before: number;\n tokens_after: number;\n entries_pruned: number;\n duration_ms: number;\n}\n\n/**\n * KV Memory interface.\n */\n/**\n * FTS5 search result with rank score.\n */\nexport interface FTSResult {\n entry: MemoryEntry;\n rank: number;\n}\n\nexport interface KVMemory {\n /** Store a memory entry */\n put(entry: MemoryEntry): Promise<void>;\n\n /** Retrieve a memory entry by ID */\n get(id: string): Promise<MemoryEntry | null>;\n\n /** Query entries by filters */\n query(filters: MemoryQueryFilters): Promise<MemoryEntry[]>;\n\n /** Delete a memory entry */\n delete(id: string): Promise<void>;\n\n /** List all entry IDs */\n list(): Promise<string[]>;\n\n /** Compact database (remove expired entries) */\n compact(): Promise<number>;\n\n /** Close database connection */\n close(): Promise<void>;\n\n /** Record optimization statistics */\n recordOptimization(stats: Omit<OptimizationStats, 'id'>): Promise<void>;\n\n /** Get all optimization statistics */\n getOptimizationStats(): Promise<OptimizationStats[]>;\n\n /** Clear all optimization statistics */\n clearOptimizationStats(): Promise<void>;\n\n /** Full-text search using FTS5 */\n searchFTS(query: string, limit?: number): Promise<FTSResult[]>;\n}\n\n/**\n * Create a timestamped backup of the database\n * @param dbPath - Path to database file\n * @returns Path to backup file\n */\nfunction createBackup(dbPath: string): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n const backupPath = `${dbPath}.backup-${timestamp}`;\n\n try {\n copyFileSync(dbPath, backupPath);\n console.log(`✓ Database backed up to: ${backupPath}`);\n return backupPath;\n } catch (error) {\n console.error(`Warning: Could not create backup: ${error}`);\n return '';\n }\n}\n\n/**\n * Create KV Memory store with SQLite backend.\n *\n * Initializes database with dual table schema:\n * - entries_index: Fast lookups (id, hash, timestamp, score, ttl, state, accessCount, isBTSP)\n * - entries_value: Content storage (id, content, tags, metadata)\n *\n * @param dbPath - Path to SQLite database file\n * @returns KVMemory instance\n */\nexport async function createKVMemory(dbPath: string): Promise<KVMemory> {\n // Detect database corruption and create backup\n let db: Database.Database;\n try {\n db = new Database(dbPath);\n\n // Quick integrity check\n const integrityCheck = db.pragma('quick_check', { simple: true });\n if (integrityCheck !== 'ok') {\n console.error('⚠ Database corruption detected!');\n\n // Close corrupted db before backup/recovery\n db.close();\n\n // Create backup before attempting recovery\n if (existsSync(dbPath)) {\n const backupPath = createBackup(dbPath);\n if (backupPath) {\n console.log(`Backup created at: ${backupPath}`);\n }\n }\n\n // Try to recover\n console.log('Attempting database recovery...');\n db = new Database(dbPath);\n }\n } catch (error) {\n console.error('⚠ Database error detected:', error);\n\n // Create backup if database exists\n if (existsSync(dbPath)) {\n createBackup(dbPath);\n console.log('Creating new database...');\n }\n\n db = new Database(dbPath);\n }\n\n // Enable WAL mode for better concurrency\n db.pragma('journal_mode = WAL');\n\n // Enable foreign key enforcement (SQLite disables by default)\n db.pragma('foreign_keys = ON');\n\n // Create entries_index table\n db.exec(`\n CREATE TABLE IF NOT EXISTS entries_index (\n id TEXT PRIMARY KEY NOT NULL,\n hash TEXT UNIQUE NOT NULL,\n timestamp INTEGER NOT NULL,\n score REAL NOT NULL DEFAULT 0.0 CHECK(score >= 0.0 AND score <= 1.0),\n ttl INTEGER NOT NULL CHECK(ttl >= 0),\n state TEXT NOT NULL CHECK(state IN ('silent', 'ready', 'active')),\n accessCount INTEGER NOT NULL DEFAULT 0 CHECK(accessCount >= 0),\n isBTSP INTEGER NOT NULL DEFAULT 0 CHECK(isBTSP IN (0, 1)),\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\n );\n `);\n\n // Create entries_value table\n db.exec(`\n CREATE TABLE IF NOT EXISTS entries_value (\n id TEXT PRIMARY KEY NOT NULL,\n content TEXT NOT NULL,\n tags TEXT,\n metadata TEXT,\n FOREIGN KEY (id) REFERENCES entries_index(id) ON DELETE CASCADE\n );\n `);\n\n // Create optimization_stats table\n db.exec(`\n CREATE TABLE IF NOT EXISTS optimization_stats (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\n tokens_before INTEGER NOT NULL,\n tokens_after INTEGER NOT NULL,\n entries_pruned INTEGER NOT NULL,\n duration_ms INTEGER NOT NULL\n );\n `);\n\n // Create indexes\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_entries_state ON entries_index(state);\n CREATE INDEX IF NOT EXISTS idx_entries_score ON entries_index(score DESC);\n CREATE INDEX IF NOT EXISTS idx_entries_hash ON entries_index(hash);\n CREATE INDEX IF NOT EXISTS idx_entries_timestamp ON entries_index(timestamp DESC);\n CREATE INDEX IF NOT EXISTS idx_stats_timestamp ON optimization_stats(timestamp DESC);\n `);\n\n // Create FTS5 virtual table for full-text search\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS entries_fts USING fts5(id, content, tokenize='porter');\n `);\n\n // Create triggers to keep FTS in sync\n // Note: triggers use INSERT OR REPLACE pattern since FTS5 doesn't support UPSERT\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS entries_fts_insert\n AFTER INSERT ON entries_value\n BEGIN\n INSERT OR REPLACE INTO entries_fts(id, content) VALUES (NEW.id, NEW.content);\n END;\n `);\n\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS entries_fts_delete\n AFTER DELETE ON entries_value\n BEGIN\n DELETE FROM entries_fts WHERE id = OLD.id;\n END;\n `);\n\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS entries_fts_update\n AFTER UPDATE ON entries_value\n BEGIN\n DELETE FROM entries_fts WHERE id = OLD.id;\n INSERT INTO entries_fts(id, content) VALUES (NEW.id, NEW.content);\n END;\n `);\n\n // Backfill existing data into FTS table\n db.exec(`\n INSERT OR IGNORE INTO entries_fts(id, content)\n SELECT id, content FROM entries_value\n WHERE id NOT IN (SELECT id FROM entries_fts);\n `);\n\n // Prepare statements for better performance\n const putIndexStmt = db.prepare(`\n INSERT OR REPLACE INTO entries_index\n (id, hash, timestamp, score, ttl, state, accessCount, isBTSP)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const putValueStmt = db.prepare(`\n INSERT OR REPLACE INTO entries_value\n (id, content, tags, metadata)\n VALUES (?, ?, ?, ?)\n `);\n\n const getStmt = db.prepare(`\n SELECT\n i.id, i.hash, i.timestamp, i.score, i.ttl, i.state, i.accessCount, i.isBTSP,\n v.content, v.tags, v.metadata\n FROM entries_index i\n JOIN entries_value v ON i.id = v.id\n WHERE i.id = ?\n `);\n\n const deleteIndexStmt = db.prepare('DELETE FROM entries_index WHERE id = ?');\n const deleteValueStmt = db.prepare('DELETE FROM entries_value WHERE id = ?');\n\n return {\n async put(entry: MemoryEntry): Promise<void> {\n const transaction = db.transaction(() => {\n putIndexStmt.run(\n entry.id,\n entry.hash,\n entry.timestamp,\n entry.score,\n entry.ttl,\n entry.state,\n entry.accessCount,\n entry.isBTSP ? 1 : 0,\n );\n\n putValueStmt.run(\n entry.id,\n entry.content,\n JSON.stringify(entry.tags),\n JSON.stringify(entry.metadata),\n );\n });\n\n transaction();\n },\n\n async get(id: string): Promise<MemoryEntry | null> {\n const row = getStmt.get(id) as unknown;\n\n if (!row) {\n return null;\n }\n\n const r = row as {\n id: string;\n hash: string;\n timestamp: number;\n score: number;\n ttl: number;\n state: string;\n accessCount: number;\n isBTSP: number;\n content: string;\n tags: string | null;\n metadata: string | null;\n };\n\n return {\n id: r.id,\n content: r.content,\n hash: r.hash,\n timestamp: r.timestamp,\n score: r.score,\n ttl: r.ttl,\n state: r.state as 'silent' | 'ready' | 'active',\n accessCount: r.accessCount,\n tags: r.tags ? JSON.parse(r.tags) : [],\n metadata: r.metadata ? JSON.parse(r.metadata) : {},\n isBTSP: r.isBTSP === 1,\n };\n },\n\n async query(filters: MemoryQueryFilters): Promise<MemoryEntry[]> {\n let sql = `\n SELECT\n i.id, i.hash, i.timestamp, i.score, i.ttl, i.state, i.accessCount, i.isBTSP,\n v.content, v.tags, v.metadata\n FROM entries_index i\n JOIN entries_value v ON i.id = v.id\n WHERE 1=1\n `;\n\n const params: unknown[] = [];\n\n if (filters.state) {\n sql += ' AND i.state = ?';\n params.push(filters.state);\n }\n\n if (filters.minScore !== undefined) {\n sql += ' AND i.score >= ?';\n params.push(filters.minScore);\n }\n\n if (filters.maxScore !== undefined) {\n sql += ' AND i.score <= ?';\n params.push(filters.maxScore);\n }\n\n if (filters.isBTSP !== undefined) {\n sql += ' AND i.isBTSP = ?';\n params.push(filters.isBTSP ? 1 : 0);\n }\n\n if (filters.tags && filters.tags.length > 0) {\n for (const tag of filters.tags) {\n sql += ' AND v.tags LIKE ?';\n params.push(`%\"${tag}\"%`);\n }\n }\n\n sql += ' ORDER BY i.score DESC';\n\n if (filters.limit) {\n sql += ' LIMIT ?';\n params.push(filters.limit);\n\n if (filters.offset) {\n sql += ' OFFSET ?';\n params.push(filters.offset);\n }\n }\n\n const stmt = db.prepare(sql);\n const rows = stmt.all(...params) as unknown[];\n\n return rows.map((row) => {\n const r = row as {\n id: string;\n hash: string;\n timestamp: number;\n score: number;\n ttl: number;\n state: string;\n accessCount: number;\n isBTSP: number;\n content: string;\n tags: string | null;\n metadata: string | null;\n };\n\n return {\n id: r.id,\n content: r.content,\n hash: r.hash,\n timestamp: r.timestamp,\n score: r.score,\n ttl: r.ttl,\n state: r.state as 'silent' | 'ready' | 'active',\n accessCount: r.accessCount,\n tags: r.tags ? JSON.parse(r.tags) : [],\n metadata: r.metadata ? JSON.parse(r.metadata) : {},\n isBTSP: r.isBTSP === 1,\n };\n });\n },\n\n async delete(id: string): Promise<void> {\n const transaction = db.transaction(() => {\n deleteIndexStmt.run(id);\n deleteValueStmt.run(id);\n });\n\n transaction();\n },\n\n async list(): Promise<string[]> {\n const stmt = db.prepare('SELECT id FROM entries_index');\n const rows = stmt.all() as { id: string }[];\n return rows.map((r) => r.id);\n },\n\n async compact(): Promise<number> {\n const before = db.prepare('SELECT COUNT(*) as count FROM entries_index').get() as {\n count: number;\n };\n\n // Remove expired non-BTSP entries: timestamp (ms) + ttl (seconds)*1000 < now\n const now = Date.now();\n db.prepare('DELETE FROM entries_index WHERE isBTSP = 0 AND (timestamp + ttl * 1000) < ?').run(\n now,\n );\n\n // Also remove non-BTSP entries with zero TTL\n db.exec('DELETE FROM entries_index WHERE isBTSP = 0 AND ttl <= 0');\n\n // Decay-based removal: remove non-BTSP entries with decay >= 0.95\n const candidates = db\n .prepare('SELECT id, timestamp, ttl FROM entries_index WHERE isBTSP = 0')\n .all() as Array<{ id: string; timestamp: number; ttl: number }>;\n\n for (const row of candidates) {\n const ageSeconds = Math.max(0, (now - row.timestamp) / 1000);\n const ttlSeconds = row.ttl;\n if (ttlSeconds <= 0) continue;\n const decay = 1 - Math.exp(-ageSeconds / ttlSeconds);\n if (decay >= 0.95) {\n db.prepare('DELETE FROM entries_index WHERE id = ?').run(row.id);\n }\n }\n\n // Clean up orphaned value entries\n db.exec('DELETE FROM entries_value WHERE id NOT IN (SELECT id FROM entries_index)');\n\n db.exec('VACUUM');\n\n const after = db.prepare('SELECT COUNT(*) as count FROM entries_index').get() as {\n count: number;\n };\n\n return before.count - after.count;\n },\n\n async close(): Promise<void> {\n db.close();\n },\n\n async recordOptimization(stats: Omit<OptimizationStats, 'id'>): Promise<void> {\n const stmt = db.prepare(`\n INSERT INTO optimization_stats (timestamp, tokens_before, tokens_after, entries_pruned, duration_ms)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n stmt.run(\n stats.timestamp,\n stats.tokens_before,\n stats.tokens_after,\n stats.entries_pruned,\n stats.duration_ms,\n );\n\n // Retain only last 1000 stats to prevent unbounded growth\n db.prepare(\n 'DELETE FROM optimization_stats WHERE id NOT IN (SELECT id FROM optimization_stats ORDER BY timestamp DESC LIMIT 1000)',\n ).run();\n },\n\n async getOptimizationStats(): Promise<OptimizationStats[]> {\n const stmt = db.prepare(`\n SELECT id, timestamp, tokens_before, tokens_after, entries_pruned, duration_ms\n FROM optimization_stats\n ORDER BY timestamp DESC\n `);\n\n const rows = stmt.all() as OptimizationStats[];\n return rows;\n },\n\n async clearOptimizationStats(): Promise<void> {\n db.exec('DELETE FROM optimization_stats');\n },\n\n async searchFTS(query: string, limit = 10): Promise<FTSResult[]> {\n if (!query || query.trim().length === 0) return [];\n\n // Sanitize query: strip FTS5 special characters to prevent syntax errors\n const sanitized = query.replace(/[{}()[\\]\"':*^~]/g, ' ').trim();\n if (sanitized.length === 0) return [];\n\n const stmt = db.prepare(`\n SELECT\n f.id, f.content, rank,\n i.hash, i.timestamp, i.score, i.ttl, i.state, i.accessCount, i.isBTSP,\n v.tags, v.metadata\n FROM entries_fts f\n JOIN entries_index i ON f.id = i.id\n JOIN entries_value v ON f.id = v.id\n WHERE entries_fts MATCH ?\n ORDER BY rank\n LIMIT ?\n `);\n\n try {\n const rows = stmt.all(sanitized, limit) as Array<{\n id: string;\n content: string;\n rank: number;\n hash: string;\n timestamp: number;\n score: number;\n ttl: number;\n state: string;\n accessCount: number;\n isBTSP: number;\n tags: string | null;\n metadata: string | null;\n }>;\n\n return rows.map((r) => ({\n entry: {\n id: r.id,\n content: r.content,\n hash: r.hash,\n timestamp: r.timestamp,\n score: r.score,\n ttl: r.ttl,\n state: r.state as 'silent' | 'ready' | 'active',\n accessCount: r.accessCount,\n tags: r.tags ? JSON.parse(r.tags) : [],\n metadata: r.metadata ? JSON.parse(r.metadata) : {},\n isBTSP: r.isBTSP === 1,\n },\n rank: r.rank,\n }));\n } catch {\n // FTS query error (bad syntax despite sanitization) — return empty\n return [];\n }\n },\n };\n}\n","/**\n * Search Engine - Hybrid FTS5 + ripgrep search\n *\n * Deterministic search without embeddings:\n * 1. FTS5 for full-text search with stemming (porter tokenizer)\n * 2. ripgrep fallback for exact pattern/regex matching\n * 3. Fusion scoring with dedup across both sources\n */\n\nimport { execFileSync, execSync } from 'node:child_process';\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { extname, join, relative } from 'node:path';\nimport Database from 'better-sqlite3';\n\nexport interface SearchResult {\n filePath: string;\n lineNumber: number;\n content: string;\n score: number;\n context: string[];\n engram_score: number;\n}\n\nexport interface SearchOpts {\n maxResults?: number;\n fileGlob?: string;\n useRipgrep?: boolean;\n includeContext?: boolean;\n}\n\nexport interface IndexStats {\n filesIndexed: number;\n totalLines: number;\n duration: number;\n}\n\nexport interface SearchEngine {\n /** Initialize the search database */\n init(projectRoot: string): Promise<void>;\n\n /** Index files into FTS5 */\n index(paths?: string[]): Promise<IndexStats>;\n\n /** Search using hybrid FTS5 + ripgrep */\n search(query: string, opts?: SearchOpts): Promise<SearchResult[]>;\n\n /** Re-index all files */\n refresh(): Promise<IndexStats>;\n\n /** Close the database */\n close(): Promise<void>;\n}\n\n/**\n * Check if ripgrep is available\n */\nfunction hasRipgrep(): boolean {\n try {\n execSync('rg --version', { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Run ripgrep search\n */\nfunction ripgrepSearch(query: string, projectRoot: string, opts: SearchOpts = {}): SearchResult[] {\n try {\n const args = ['--line-number', '--no-heading', '--color=never'];\n\n if (opts.fileGlob) {\n args.push('--glob', opts.fileGlob);\n }\n\n // Ignore common dirs\n args.push(\n '--glob',\n '!node_modules',\n '--glob',\n '!dist',\n '--glob',\n '!.git',\n '--glob',\n '!.sparn',\n '--glob',\n '!coverage',\n );\n\n const maxResults = opts.maxResults || 20;\n args.push('--max-count', String(maxResults));\n\n // Include context lines\n if (opts.includeContext) {\n args.push('-C', '2');\n }\n\n // Use execFileSync to avoid shell injection - args passed as array\n args.push('--', query, projectRoot);\n const output = execFileSync('rg', args, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });\n\n const results: SearchResult[] = [];\n const lines = output.split('\\n').filter(Boolean);\n\n for (const line of lines) {\n // Parse rg output: file:line:content\n const match = line.match(/^(.+?):(\\d+):(.*)/);\n if (match) {\n const filePath = relative(projectRoot, match[1] || '').replace(/\\\\/g, '/');\n const lineNumber = Number.parseInt(match[2] || '0', 10);\n const content = (match[3] || '').trim();\n\n results.push({\n filePath,\n lineNumber,\n content,\n score: 0.8, // Exact match gets high base score\n context: [],\n engram_score: 0,\n });\n }\n }\n\n return results.slice(0, maxResults);\n } catch {\n return [];\n }\n}\n\n/**\n * Collect indexable files from a directory\n */\nfunction collectIndexableFiles(\n dir: string,\n projectRoot: string,\n ignoreDirs = ['node_modules', 'dist', '.git', '.sparn', 'coverage'],\n exts = ['.ts', '.tsx', '.js', '.jsx', '.json', '.md', '.yaml', '.yml'],\n): string[] {\n const files: string[] = [];\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if (!ignoreDirs.includes(entry.name)) {\n files.push(...collectIndexableFiles(fullPath, projectRoot, ignoreDirs, exts));\n }\n } else if (entry.isFile() && exts.includes(extname(entry.name))) {\n // Skip large files (>100KB)\n try {\n const stat = statSync(fullPath);\n if (stat.size < 100 * 1024) {\n files.push(relative(projectRoot, fullPath).replace(/\\\\/g, '/'));\n }\n } catch {\n // Skip\n }\n }\n }\n } catch {\n // Skip inaccessible directories\n }\n\n return files;\n}\n\n/**\n * Create a search engine instance\n */\nexport function createSearchEngine(dbPath: string): SearchEngine {\n let db: Database.Database | null = null;\n let projectRoot = '';\n const rgAvailable = hasRipgrep();\n\n async function init(root: string): Promise<void> {\n // Close existing connection if re-initializing\n if (db) {\n try {\n db.close();\n } catch {\n /* ignore */\n }\n }\n projectRoot = root;\n db = new Database(dbPath);\n db.pragma('journal_mode = WAL');\n\n // Create FTS5 virtual table\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS search_index USING fts5(\n filepath, line_number, content, tokenize='porter'\n );\n `);\n\n // Create metadata table for tracking index state\n db.exec(`\n CREATE TABLE IF NOT EXISTS search_meta (\n filepath TEXT PRIMARY KEY,\n mtime INTEGER NOT NULL,\n indexed_at INTEGER NOT NULL\n );\n `);\n }\n\n async function index(paths?: string[]): Promise<IndexStats> {\n if (!db) throw new Error('Search engine not initialized. Call init() first.');\n\n const startTime = Date.now();\n\n const filesToIndex = paths || collectIndexableFiles(projectRoot, projectRoot);\n\n let filesIndexed = 0;\n let totalLines = 0;\n\n const insertStmt = db.prepare(\n 'INSERT INTO search_index(filepath, line_number, content) VALUES (?, ?, ?)',\n );\n const metaStmt = db.prepare(\n 'INSERT OR REPLACE INTO search_meta(filepath, mtime, indexed_at) VALUES (?, ?, ?)',\n );\n const checkMeta = db.prepare('SELECT mtime FROM search_meta WHERE filepath = ?');\n const deleteFile = db.prepare('DELETE FROM search_index WHERE filepath = ?');\n\n const transaction = db.transaction(() => {\n for (const filePath of filesToIndex) {\n const fullPath = join(projectRoot, filePath);\n\n if (!existsSync(fullPath)) continue;\n\n try {\n const stat = statSync(fullPath);\n const existing = checkMeta.get(filePath) as { mtime: number } | undefined;\n\n // Skip if file hasn't changed\n if (existing && existing.mtime >= stat.mtimeMs) {\n continue;\n }\n\n // Remove old index entries for this file\n deleteFile.run(filePath);\n\n const content = readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line && line.trim().length > 0) {\n insertStmt.run(filePath, i + 1, line);\n totalLines++;\n }\n }\n\n metaStmt.run(filePath, stat.mtimeMs, Date.now());\n filesIndexed++;\n } catch {\n // Skip problematic files\n }\n }\n });\n\n transaction();\n\n return {\n filesIndexed,\n totalLines,\n duration: Date.now() - startTime,\n };\n }\n\n async function search(query: string, opts: SearchOpts = {}): Promise<SearchResult[]> {\n if (!db) throw new Error('Search engine not initialized. Call init() first.');\n\n const maxResults = opts.maxResults || 10;\n const results: SearchResult[] = [];\n const seen = new Set<string>(); // Dedup key: filepath:lineNumber\n\n // 1. FTS5 search\n try {\n // Escape FTS5 special characters and scope to content column\n const ftsQuery = query\n .replace(/['\"*(){}[\\]^~\\\\:]/g, ' ')\n .trim()\n .split(/\\s+/)\n .filter((w) => w.length > 0)\n .map((w) => `content:${w}`)\n .join(' ');\n\n if (ftsQuery.length > 0) {\n let sql = `\n SELECT filepath, line_number, content, rank\n FROM search_index\n WHERE search_index MATCH ?\n `;\n const params: unknown[] = [ftsQuery];\n\n if (opts.fileGlob) {\n // Convert glob to LIKE pattern\n const likePattern = opts.fileGlob.replace(/\\*/g, '%').replace(/\\?/g, '_');\n sql += ' AND filepath LIKE ?';\n params.push(likePattern);\n }\n\n sql += ' ORDER BY rank LIMIT ?';\n params.push(maxResults * 2); // Fetch extra for dedup\n\n const rows = db.prepare(sql).all(...params) as Array<{\n filepath: string;\n line_number: number;\n content: string;\n rank: number;\n }>;\n\n for (const row of rows) {\n const key = `${row.filepath}:${row.line_number}`;\n if (!seen.has(key)) {\n seen.add(key);\n\n // FTS5 rank is negative (lower = better match)\n const score = Math.min(1, Math.max(0, 1 + row.rank / 10));\n\n const context: string[] = [];\n if (opts.includeContext) {\n // Get surrounding lines using CAST for numeric comparison\n const contextRows = db\n .prepare(\n `SELECT content FROM search_index WHERE filepath = ? AND CAST(line_number AS INTEGER) BETWEEN ? AND ? ORDER BY CAST(line_number AS INTEGER)`,\n )\n .all(row.filepath, row.line_number - 2, row.line_number + 2) as Array<{\n content: string;\n }>;\n context.push(...contextRows.map((r) => r.content));\n }\n\n results.push({\n filePath: row.filepath,\n lineNumber: row.line_number,\n content: row.content,\n score,\n context,\n engram_score: 0,\n });\n }\n }\n }\n } catch {\n // FTS5 query failed, fall through to ripgrep\n }\n\n // 2. ripgrep search (if available and requested or as supplement)\n if (rgAvailable && opts.useRipgrep !== false) {\n const rgResults = ripgrepSearch(query, projectRoot, opts);\n\n for (const result of rgResults) {\n const key = `${result.filePath}:${result.lineNumber}`;\n if (!seen.has(key)) {\n seen.add(key);\n results.push(result);\n }\n }\n }\n\n // Sort by score descending and limit\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, maxResults);\n }\n\n async function refresh(): Promise<IndexStats> {\n if (!db) throw new Error('Search engine not initialized. Call init() first.');\n\n // Clear all index data\n db.exec('DELETE FROM search_index');\n db.exec('DELETE FROM search_meta');\n\n return index();\n }\n\n async function close(): Promise<void> {\n if (db) {\n db.close();\n db = null;\n }\n }\n\n return {\n init,\n index,\n search,\n refresh,\n close,\n };\n}\n","/**\n * Sleep Compressor - Periodic consolidation\n *\n * Removes decayed entries and merges duplicates to keep the memory store lean.\n * Runs on demand or on a scheduled interval via the daemon.\n */\n\nimport type { ConsolidateResult, DuplicateGroup } from '../types/consolidate.js';\nimport type { MemoryEntry } from '../types/memory.js';\nimport { tokenize } from '../utils/tfidf.js';\nimport { createEngramScorer } from './engram-scorer.js';\n\nexport interface SleepCompressor {\n /**\n * Consolidate entries: remove decayed, merge duplicates\n * @param entries - All memory entries\n * @returns Consolidation result\n */\n consolidate(entries: MemoryEntry[]): ConsolidateResult;\n\n /**\n * Find duplicate entries (exact hash or near-duplicate by similarity)\n * @param entries - Memory entries\n * @returns Groups of duplicates\n */\n findDuplicates(entries: MemoryEntry[]): DuplicateGroup[];\n\n /**\n * Merge duplicate entries, keeping highest score\n * @param groups - Duplicate groups\n * @returns Merged entries\n */\n mergeDuplicates(groups: DuplicateGroup[]): MemoryEntry[];\n}\n\n/**\n * Create a sleep compressor instance\n * @returns SleepCompressor instance\n */\nexport function createSleepCompressor(): SleepCompressor {\n const scorer = createEngramScorer({ defaultTTL: 24, decayThreshold: 0.95 });\n\n function consolidate(entries: MemoryEntry[]): ConsolidateResult {\n const startTime = Date.now();\n const originalCount = entries.length;\n\n // Step 1: Remove fully decayed entries (decay ≥ 0.95)\n const now = Date.now();\n const nonDecayed = entries.filter((entry) => {\n const ageInSeconds = (now - entry.timestamp) / 1000;\n const decay = scorer.calculateDecay(ageInSeconds, entry.ttl);\n return decay < 0.95; // Keep entries with decay < 0.95\n });\n\n const decayedRemoved = originalCount - nonDecayed.length;\n\n // Step 2: Find and merge duplicates\n const duplicateGroups = findDuplicates(nonDecayed);\n const merged = mergeDuplicates(duplicateGroups);\n\n // Step 3: Keep non-duplicates\n const duplicateIds = new Set(duplicateGroups.flatMap((g) => g.entries.map((e) => e.id)));\n const nonDuplicates = nonDecayed.filter((e) => !duplicateIds.has(e.id));\n\n // Combine merged duplicates with non-duplicates\n const kept = [...merged, ...nonDuplicates];\n const removed = entries.filter((e) => !kept.some((k) => k.id === e.id));\n\n const duplicatesRemoved = duplicateGroups.reduce((sum, g) => sum + (g.entries.length - 1), 0);\n\n return {\n kept,\n removed,\n entriesBefore: originalCount,\n entriesAfter: kept.length,\n decayedRemoved,\n duplicatesRemoved,\n compressionRatio: originalCount > 0 ? kept.length / originalCount : 0,\n durationMs: Date.now() - startTime,\n };\n }\n\n function findDuplicates(entries: MemoryEntry[]): DuplicateGroup[] {\n const groups: DuplicateGroup[] = [];\n const processed = new Set<string>();\n\n // Find exact hash matches\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n if (!entry || processed.has(entry.id)) continue;\n\n const duplicates = entries.filter((e, idx) => idx !== i && e.hash === entry.hash);\n\n if (duplicates.length > 0) {\n const group: DuplicateGroup = {\n entries: [entry, ...duplicates],\n similarity: 1.0, // Exact match\n };\n groups.push(group);\n\n // Mark as processed\n processed.add(entry.id);\n for (const dup of duplicates) {\n processed.add(dup.id);\n }\n }\n }\n\n // Find near-duplicates (cosine similarity ≥ 0.85)\n for (let i = 0; i < entries.length; i++) {\n const entryI = entries[i];\n if (!entryI || processed.has(entryI.id)) continue;\n\n for (let j = i + 1; j < entries.length; j++) {\n const entryJ = entries[j];\n if (!entryJ || processed.has(entryJ.id)) continue;\n\n const similarity = cosineSimilarity(entryI.content, entryJ.content);\n\n if (similarity >= 0.85) {\n const group: DuplicateGroup = {\n entries: [entryI, entryJ],\n similarity,\n };\n groups.push(group);\n\n processed.add(entryI.id);\n processed.add(entryJ.id);\n break; // Move to next i\n }\n }\n }\n\n return groups;\n }\n\n function mergeDuplicates(groups: DuplicateGroup[]): MemoryEntry[] {\n const merged: MemoryEntry[] = [];\n\n for (const group of groups) {\n // Keep entry with highest score\n const sorted = [...group.entries].sort((a, b) => b.score - a.score);\n const best = sorted[0];\n if (!best) continue; // Skip empty groups\n\n // Sum access counts\n const totalAccessCount = group.entries.reduce((sum, e) => sum + e.accessCount, 0);\n\n // Merge tags\n const allTags = new Set(group.entries.flatMap((e) => e.tags));\n\n merged.push({\n ...best,\n accessCount: totalAccessCount,\n tags: Array.from(allTags),\n });\n }\n\n return merged;\n }\n\n /**\n * Calculate cosine similarity between two text strings\n * @param text1 - First text\n * @param text2 - Second text\n * @returns Similarity score (0.0-1.0)\n */\n function cosineSimilarity(text1: string, text2: string): number {\n const words1 = tokenize(text1);\n const words2 = tokenize(text2);\n\n // Build word frequency vectors in single pass each\n const vec1: Record<string, number> = {};\n const vec2: Record<string, number> = {};\n\n for (const word of words1) {\n vec1[word] = (vec1[word] ?? 0) + 1;\n }\n for (const word of words2) {\n vec2[word] = (vec2[word] ?? 0) + 1;\n }\n\n const vocab = new Set([...words1, ...words2]);\n\n // Calculate dot product and magnitudes\n let dotProduct = 0;\n let mag1 = 0;\n let mag2 = 0;\n\n for (const word of vocab) {\n const count1 = vec1[word] ?? 0;\n const count2 = vec2[word] ?? 0;\n dotProduct += count1 * count2;\n mag1 += count1 * count1;\n mag2 += count2 * count2;\n }\n\n mag1 = Math.sqrt(mag1);\n mag2 = Math.sqrt(mag2);\n\n if (mag1 === 0 || mag2 === 0) return 0;\n\n return dotProduct / (mag1 * mag2);\n }\n\n return {\n consolidate,\n findDuplicates,\n mergeDuplicates,\n };\n}\n","/**\n * Workflow Planner - Plan/Exec/Verify separation\n *\n * Separates AI agent workflows into discrete phases:\n * - Planning: Identify files needed, search queries, and steps\n * - Execution: Apply constraints (max reads, token budget)\n * - Verification: Check step completion and run tests\n *\n * Reduces token waste by preventing re-planning loops.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport interface SparnPlan {\n id: string;\n created_at: number;\n task_description: string;\n steps: PlanStep[];\n token_budget: {\n planning: number;\n estimated_execution: number;\n max_file_reads: number;\n };\n files_needed: string[];\n search_queries: string[];\n status: 'draft' | 'ready' | 'executing' | 'completed' | 'failed';\n}\n\nexport interface PlanStep {\n order: number;\n action: 'read' | 'write' | 'search' | 'test' | 'verify';\n target: string;\n description: string;\n dependencies: number[];\n estimated_tokens: number;\n status: 'pending' | 'in_progress' | 'completed' | 'skipped' | 'failed';\n result?: string;\n}\n\nexport interface PlanExecConstraints {\n maxFileReads: number;\n tokenBudget: number;\n allowReplan: boolean;\n}\n\nexport interface PlanVerifyResult {\n planId: string;\n stepsCompleted: number;\n stepsFailed: number;\n stepsSkipped: number;\n totalSteps: number;\n tokensBudgeted: number;\n tokensUsed: number;\n success: boolean;\n details: Array<{\n step: number;\n action: string;\n target: string;\n status: string;\n }>;\n}\n\nexport interface WorkflowPlanner {\n /** Create a new plan */\n createPlan(\n taskDescription: string,\n filesNeeded: string[],\n searchQueries: string[],\n steps: Omit<PlanStep, 'status' | 'result'>[],\n tokenBudget?: { planning: number; estimated_execution: number; max_file_reads: number },\n ): Promise<SparnPlan>;\n\n /** Load an existing plan */\n loadPlan(planId: string): Promise<SparnPlan | null>;\n\n /** List all plans */\n listPlans(): Promise<Array<{ id: string; task: string; status: string; created: number }>>;\n\n /** Update a plan step status */\n updateStep(\n planId: string,\n stepOrder: number,\n status: PlanStep['status'],\n result?: string,\n ): Promise<void>;\n\n /** Start execution of a plan */\n startExec(planId: string): Promise<PlanExecConstraints>;\n\n /** Verify plan completion */\n verify(planId: string): Promise<PlanVerifyResult>;\n\n /** Get the plans directory */\n getPlansDir(): string;\n}\n\n/**\n * Create a workflow planner\n */\nexport function createWorkflowPlanner(projectRoot: string): WorkflowPlanner {\n const plansDir = join(projectRoot, '.sparn', 'plans');\n\n // Ensure plans directory exists\n if (!existsSync(plansDir)) {\n mkdirSync(plansDir, { recursive: true });\n }\n\n function sanitizeId(id: string): string {\n // Strip path separators and traversal sequences to prevent path injection\n return id.replace(/[/\\\\:.]/g, '').replace(/\\.\\./g, '');\n }\n\n function planPath(planId: string): string {\n const safeId = sanitizeId(planId);\n if (!safeId) throw new Error('Invalid plan ID');\n return join(plansDir, `plan-${safeId}.json`);\n }\n\n async function createPlan(\n taskDescription: string,\n filesNeeded: string[],\n searchQueries: string[],\n steps: Omit<PlanStep, 'status' | 'result'>[],\n tokenBudget = { planning: 0, estimated_execution: 0, max_file_reads: 5 },\n ): Promise<SparnPlan> {\n const id = randomUUID().split('-')[0] || 'plan';\n\n const plan: SparnPlan = {\n id,\n created_at: Date.now(),\n task_description: taskDescription,\n steps: steps.map((s) => ({ ...s, status: 'pending' as const })),\n token_budget: tokenBudget,\n files_needed: filesNeeded,\n search_queries: searchQueries,\n status: 'draft',\n };\n\n writeFileSync(planPath(id), JSON.stringify(plan, null, 2), 'utf-8');\n return plan;\n }\n\n async function loadPlan(planId: string): Promise<SparnPlan | null> {\n const path = planPath(planId);\n if (!existsSync(path)) return null;\n\n try {\n return JSON.parse(readFileSync(path, 'utf-8')) as SparnPlan;\n } catch {\n return null;\n }\n }\n\n async function listPlans(): Promise<\n Array<{ id: string; task: string; status: string; created: number }>\n > {\n if (!existsSync(plansDir)) return [];\n\n const files = readdirSync(plansDir).filter((f) => f.startsWith('plan-') && f.endsWith('.json'));\n\n const plans: Array<{ id: string; task: string; status: string; created: number }> = [];\n\n for (const file of files) {\n try {\n const plan = JSON.parse(readFileSync(join(plansDir, file), 'utf-8')) as SparnPlan;\n plans.push({\n id: plan.id,\n task: plan.task_description,\n status: plan.status,\n created: plan.created_at,\n });\n } catch {\n // Skip corrupt plan files\n }\n }\n\n return plans.sort((a, b) => b.created - a.created);\n }\n\n async function updateStep(\n planId: string,\n stepOrder: number,\n status: PlanStep['status'],\n result?: string,\n ): Promise<void> {\n const plan = await loadPlan(planId);\n if (!plan) throw new Error(`Plan ${planId} not found`);\n\n const step = plan.steps.find((s) => s.order === stepOrder);\n if (!step) throw new Error(`Step ${stepOrder} not found in plan ${planId}`);\n\n step.status = status;\n if (result !== undefined) {\n step.result = result;\n }\n\n writeFileSync(planPath(planId), JSON.stringify(plan, null, 2), 'utf-8');\n }\n\n async function startExec(planId: string): Promise<PlanExecConstraints> {\n const plan = await loadPlan(planId);\n if (!plan) throw new Error(`Plan ${planId} not found`);\n\n plan.status = 'executing';\n writeFileSync(planPath(planId), JSON.stringify(plan, null, 2), 'utf-8');\n\n return {\n maxFileReads: plan.token_budget.max_file_reads,\n tokenBudget: plan.token_budget.estimated_execution,\n allowReplan: false,\n };\n }\n\n async function verify(planId: string): Promise<PlanVerifyResult> {\n const plan = await loadPlan(planId);\n if (!plan) throw new Error(`Plan ${planId} not found`);\n\n let stepsCompleted = 0;\n let stepsFailed = 0;\n let stepsSkipped = 0;\n let tokensUsed = 0;\n\n const details: PlanVerifyResult['details'] = [];\n\n for (const step of plan.steps) {\n switch (step.status) {\n case 'completed':\n stepsCompleted++;\n tokensUsed += step.estimated_tokens;\n break;\n case 'failed':\n stepsFailed++;\n break;\n case 'skipped':\n stepsSkipped++;\n break;\n default:\n // pending or in_progress = not done yet\n break;\n }\n\n details.push({\n step: step.order,\n action: step.action,\n target: step.target,\n status: step.status,\n });\n }\n\n const totalSteps = plan.steps.length;\n const success = stepsFailed === 0 && stepsCompleted === totalSteps;\n\n // Update plan status - only mark completed/failed if no steps are still pending/in_progress\n const hasInProgress = plan.steps.some(\n (s) => s.status === 'pending' || s.status === 'in_progress',\n );\n if (!hasInProgress) {\n plan.status = success ? 'completed' : 'failed';\n writeFileSync(planPath(planId), JSON.stringify(plan, null, 2), 'utf-8');\n }\n\n return {\n planId,\n stepsCompleted,\n stepsFailed,\n stepsSkipped,\n totalSteps,\n tokensBudgeted: plan.token_budget.estimated_execution,\n tokensUsed,\n success,\n details,\n };\n }\n\n function getPlansDir(): string {\n return plansDir;\n }\n\n return {\n createPlan,\n loadPlan,\n listPlans,\n updateStep,\n startExec,\n verify,\n getPlansDir,\n };\n}\n","/**\n * Daemon Process Manager - Background process lifecycle management\n *\n * Handles:\n * - Process forking and detachment\n * - PID file management\n * - Signal handling (SIGTERM, SIGINT)\n * - Daemon start/stop/status commands\n */\n\nimport { spawn } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { SparnConfig } from '../types/config.js';\n\nexport interface DaemonCommand {\n /** Start the daemon */\n start(config: SparnConfig): Promise<DaemonStartResult>;\n\n /** Stop the daemon */\n stop(config: SparnConfig): Promise<DaemonStopResult>;\n\n /** Get daemon status */\n status(config: SparnConfig): Promise<DaemonStatusResult>;\n}\n\nexport interface DaemonStartResult {\n success: boolean;\n pid?: number;\n message: string;\n error?: string;\n}\n\nexport interface DaemonStopResult {\n success: boolean;\n message: string;\n error?: string;\n}\n\nexport interface DaemonStatusResult {\n running: boolean;\n pid?: number;\n uptime?: number;\n sessionsWatched?: number;\n tokensSaved?: number;\n message: string;\n}\n\n/**\n * Create daemon command interface\n * @returns DaemonCommand instance\n */\nexport function createDaemonCommand(): DaemonCommand {\n /**\n * Check if daemon is running\n */\n function isDaemonRunning(pidFile: string): { running: boolean; pid?: number } {\n if (!existsSync(pidFile)) {\n return { running: false };\n }\n\n try {\n const pidStr = readFileSync(pidFile, 'utf-8').trim();\n const pid = Number.parseInt(pidStr, 10);\n\n if (Number.isNaN(pid)) {\n return { running: false };\n }\n\n // Check if process exists (cross-platform)\n try {\n process.kill(pid, 0); // Signal 0 checks existence without killing\n return { running: true, pid };\n } catch {\n // Process doesn't exist, clean up stale PID file\n unlinkSync(pidFile);\n return { running: false };\n }\n } catch {\n return { running: false };\n }\n }\n\n /**\n * Write PID file\n */\n function writePidFile(pidFile: string, pid: number): void {\n // Ensure directory exists\n const dir = dirname(pidFile);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n writeFileSync(pidFile, String(pid), 'utf-8');\n }\n\n /**\n * Remove PID file\n */\n function removePidFile(pidFile: string): void {\n if (existsSync(pidFile)) {\n unlinkSync(pidFile);\n }\n }\n\n async function start(config: SparnConfig): Promise<DaemonStartResult> {\n const { pidFile, logFile } = config.realtime;\n\n // Check if already running\n const status = isDaemonRunning(pidFile);\n if (status.running) {\n return {\n success: false,\n pid: status.pid,\n message: `Daemon already running (PID ${status.pid})`,\n error: 'Already running',\n };\n }\n\n try {\n // Resolve daemon entry point path\n // daemon-process.ts is bundled into dist/cli/index.js by tsup,\n // so we navigate from dist/cli/ to dist/daemon/index.js\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const daemonPath = join(__dirname, '..', 'daemon', 'index.js');\n const isWindows = process.platform === 'win32';\n\n const childEnv = {\n ...process.env,\n SPARN_CONFIG: JSON.stringify(config),\n SPARN_PID_FILE: pidFile,\n SPARN_LOG_FILE: logFile,\n };\n\n // On Windows with Git Bash/MINGW, Node's detached:true doesn't\n // survive parent exit. Write a launcher script and run it with\n // PowerShell Start-Process which truly detaches.\n if (isWindows) {\n const configFile = join(dirname(pidFile), 'daemon-config.json');\n writeFileSync(configFile, JSON.stringify({ config, pidFile, logFile }), 'utf-8');\n\n // Create a tiny launcher script that sets env vars and runs the daemon\n const launcherFile = join(dirname(pidFile), 'daemon-launcher.mjs');\n const launcherCode = [\n `import { readFileSync } from 'node:fs';`,\n `const cfg = JSON.parse(readFileSync(${JSON.stringify(configFile)}, 'utf-8'));`,\n `process.env.SPARN_CONFIG = JSON.stringify(cfg.config);`,\n `process.env.SPARN_PID_FILE = cfg.pidFile;`,\n `process.env.SPARN_LOG_FILE = cfg.logFile;`,\n `await import(${JSON.stringify(`file:///${daemonPath.replace(/\\\\/g, '/')}`)});`,\n ].join('\\n');\n writeFileSync(launcherFile, launcherCode, 'utf-8');\n\n const ps = spawn(\n 'powershell.exe',\n [\n '-NoProfile',\n '-WindowStyle',\n 'Hidden',\n '-Command',\n `Start-Process -FilePath '${process.execPath}' -ArgumentList '${launcherFile}' -WindowStyle Hidden`,\n ],\n { stdio: 'ignore', windowsHide: true },\n );\n\n ps.unref();\n\n // Wait for daemon to write its own PID file\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n if (existsSync(pidFile)) {\n const pid = Number.parseInt(readFileSync(pidFile, 'utf-8').trim(), 10);\n if (!Number.isNaN(pid)) {\n return {\n success: true,\n pid,\n message: `Daemon started (PID ${pid})`,\n };\n }\n }\n\n return {\n success: false,\n message: 'Daemon failed to start (no PID file written)',\n error: 'Timeout waiting for daemon PID',\n };\n }\n\n // Unix: standard detached spawn\n const child = spawn(process.execPath, [daemonPath], {\n detached: true,\n stdio: 'ignore',\n env: childEnv,\n });\n\n // Detach from parent\n child.unref();\n\n // Write PID file\n if (child.pid) {\n writePidFile(pidFile, child.pid);\n\n return {\n success: true,\n pid: child.pid,\n message: `Daemon started (PID ${child.pid})`,\n };\n }\n\n return {\n success: false,\n message: 'Failed to start daemon (no PID)',\n error: 'No PID',\n };\n } catch (error) {\n return {\n success: false,\n message: 'Failed to start daemon',\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n async function stop(config: SparnConfig): Promise<DaemonStopResult> {\n const { pidFile } = config.realtime;\n\n const status = isDaemonRunning(pidFile);\n\n if (!status.running || !status.pid) {\n return {\n success: true,\n message: 'Daemon not running',\n };\n }\n\n try {\n // On Windows, SIGTERM is not supported by process.kill - it terminates immediately.\n // On Unix, SIGTERM allows graceful shutdown.\n const isWindows = process.platform === 'win32';\n\n if (isWindows) {\n // Windows: process.kill with any signal terminates the process\n process.kill(status.pid);\n } else {\n process.kill(status.pid, 'SIGTERM');\n }\n\n // Wait for process to exit (timeout after 5s)\n const maxWait = 5000;\n const interval = 100;\n let waited = 0;\n\n while (waited < maxWait) {\n try {\n process.kill(status.pid, 0);\n // Still running, wait\n await new Promise((resolve) => setTimeout(resolve, interval));\n waited += interval;\n } catch {\n // Process exited\n removePidFile(pidFile);\n return {\n success: true,\n message: `Daemon stopped (PID ${status.pid})`,\n };\n }\n }\n\n // Timeout, force kill\n try {\n if (!isWindows) {\n process.kill(status.pid, 'SIGKILL');\n }\n removePidFile(pidFile);\n return {\n success: true,\n message: `Daemon force killed (PID ${status.pid})`,\n };\n } catch {\n removePidFile(pidFile);\n return {\n success: true,\n message: `Daemon stopped (PID ${status.pid})`,\n };\n }\n } catch (error) {\n return {\n success: false,\n message: 'Failed to stop daemon',\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n async function status(config: SparnConfig): Promise<DaemonStatusResult> {\n const { pidFile } = config.realtime;\n\n const daemonStatus = isDaemonRunning(pidFile);\n\n if (!daemonStatus.running || !daemonStatus.pid) {\n return {\n running: false,\n message: 'Daemon not running',\n };\n }\n\n // Note: getMetrics() returns this process's metrics, not the daemon's.\n // For accurate daemon metrics, we'd need IPC. For now, report basic status.\n return {\n running: true,\n pid: daemonStatus.pid,\n message: `Daemon running (PID ${daemonStatus.pid})`,\n };\n }\n\n return {\n start,\n stop,\n status,\n };\n}\n","/**\n * File Tracker - Incremental file reading with byte position tracking\n *\n * Tracks read positions for files to enable efficient incremental reading.\n * Handles JSONL partial line buffering for incomplete writes.\n *\n * Use case: Monitor Claude Code session JSONL files and only read new lines\n * as they're appended, without re-reading the entire file.\n */\n\nimport { closeSync, openSync, readSync, statSync } from 'node:fs';\n\nexport interface FilePosition {\n /** File path */\n path: string;\n /** Last read byte position */\n position: number;\n /** Partial line buffer (for JSONL incomplete writes) */\n partialLine: string;\n /** Last modification time */\n lastModified: number;\n /** File size at last read */\n lastSize: number;\n}\n\nexport interface FileTracker {\n /**\n * Read new content from file since last read\n * @param filePath - File to read\n * @returns New content as array of lines (empty if no new content)\n */\n readNewLines(filePath: string): string[];\n\n /**\n * Get current position for a file\n * @param filePath - File path\n * @returns File position or null if not tracked\n */\n getPosition(filePath: string): FilePosition | null;\n\n /**\n * Reset position for a file (start from beginning on next read)\n * @param filePath - File path\n */\n resetPosition(filePath: string): void;\n\n /**\n * Clear all tracked positions\n */\n clearAll(): void;\n\n /**\n * Get all tracked file paths\n * @returns Array of tracked file paths\n */\n getTrackedFiles(): string[];\n}\n\n/**\n * Create a file tracker instance\n * @returns FileTracker instance\n */\nexport function createFileTracker(): FileTracker {\n // Track positions by file path\n const positions = new Map<string, FilePosition>();\n\n function readNewLines(filePath: string): string[] {\n try {\n // Get current file stats\n const stats = statSync(filePath);\n const currentSize = stats.size;\n const currentModified = stats.mtimeMs;\n\n // Get or initialize position\n let pos = positions.get(filePath);\n\n if (!pos) {\n // First read: start from beginning\n pos = {\n path: filePath,\n position: 0,\n partialLine: '',\n lastModified: currentModified,\n lastSize: 0,\n };\n positions.set(filePath, pos);\n }\n\n // Check if file was truncated or is same size\n if (currentSize < pos.lastSize || currentSize === pos.position) {\n // File truncated or no new content\n if (currentSize < pos.lastSize) {\n // Reset position if truncated\n pos.position = 0;\n pos.partialLine = '';\n }\n return [];\n }\n\n // Read only new bytes from last position (delta read)\n const bytesToRead = currentSize - pos.position;\n const buffer = Buffer.alloc(bytesToRead);\n const fd = openSync(filePath, 'r');\n try {\n readSync(fd, buffer, 0, bytesToRead, pos.position);\n } finally {\n closeSync(fd);\n }\n\n // Convert to string and combine with partial line\n const newContent = (pos.partialLine + buffer.toString('utf-8')).split('\\n');\n\n // Last element might be incomplete (no trailing newline yet)\n const partialLine = newContent.pop() || '';\n\n // Update position\n pos.position = currentSize;\n pos.partialLine = partialLine;\n pos.lastModified = currentModified;\n pos.lastSize = currentSize;\n\n // Return complete lines (filter empty)\n return newContent.filter((line) => line.trim().length > 0);\n } catch (_error) {\n // File doesn't exist or can't be read\n // Return empty array (fail silently for watcher use case)\n return [];\n }\n }\n\n function getPosition(filePath: string): FilePosition | null {\n return positions.get(filePath) || null;\n }\n\n function resetPosition(filePath: string): void {\n positions.delete(filePath);\n }\n\n function clearAll(): void {\n positions.clear();\n }\n\n function getTrackedFiles(): string[] {\n return Array.from(positions.keys());\n }\n\n return {\n readNewLines,\n getPosition,\n resetPosition,\n clearAll,\n getTrackedFiles,\n };\n}\n","/**\n * Session Watcher - Monitor Claude Code session files for changes\n *\n * Uses Node.js fs.watch to monitor ~/.claude/projects/**\\/*.jsonl files.\n * Debounces events and triggers optimization when token threshold exceeded.\n * Maintains per-session ContextPipeline instances.\n */\n\nimport {\n existsSync,\n type FSWatcher,\n mkdirSync,\n readdirSync,\n readFileSync,\n statSync,\n watch,\n writeFileSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { type ContextPipeline, createContextPipeline } from '../core/context-pipeline.js';\nimport { getMetrics } from '../core/metrics.js';\nimport type { SparnConfig } from '../types/config.js';\nimport { estimateTokens } from '../utils/tokenizer.js';\nimport { createFileTracker } from './file-tracker.js';\n\nexport interface SessionWatcherConfig {\n /** Sparn configuration */\n config: SparnConfig;\n /** Callback when optimization triggered */\n onOptimize?: (sessionId: string, stats: SessionStats) => void;\n /** Callback on error */\n onError?: (error: Error) => void;\n}\n\nexport interface SessionStats {\n /** Session ID */\n sessionId: string;\n /** Total tokens ingested */\n totalTokens: number;\n /** Current optimized tokens */\n optimizedTokens: number;\n /** Reduction percentage */\n reduction: number;\n /** Entry count */\n entryCount: number;\n /** Budget utilization */\n budgetUtilization: number;\n}\n\nexport interface SessionWatcher {\n /**\n * Start watching Claude Code session files\n * @returns Promise that resolves when watcher is ready\n */\n start(): Promise<void>;\n\n /**\n * Stop watching and cleanup\n */\n stop(): void;\n\n /**\n * Get statistics for all sessions\n * @returns Array of session stats\n */\n getStats(): SessionStats[];\n\n /**\n * Get statistics for a specific session\n * @param sessionId - Session ID\n * @returns Session stats or null if not found\n */\n getSessionStats(sessionId: string): SessionStats | null;\n\n /**\n * Manually trigger optimization for a session\n * @param sessionId - Session ID\n */\n optimizeSession(sessionId: string): void;\n}\n\n/**\n * Create a session watcher instance\n * @param config - Watcher configuration\n * @returns SessionWatcher instance\n */\nexport function createSessionWatcher(config: SessionWatcherConfig): SessionWatcher {\n const { config: sparnConfig, onOptimize, onError } = config;\n const { realtime, decay, states } = sparnConfig;\n\n // Per-session pipelines and trackers\n const pipelines = new Map<string, ContextPipeline>();\n const fileTracker = createFileTracker();\n\n // File system watchers\n const watchers: FSWatcher[] = [];\n\n // Debounce timers per file\n const debounceTimers = new Map<string, NodeJS.Timeout>();\n\n /**\n * Get Claude Code projects directory\n */\n function getProjectsDir(): string {\n return join(homedir(), '.claude', 'projects');\n }\n\n /**\n * Extract session ID from file path\n * Example: ~/.claude/projects/my-project/abc123.jsonl -> abc123\n */\n function getSessionId(filePath: string): string {\n const filename = filePath.split(/[/\\\\]/).pop() || '';\n return filename.replace(/\\.jsonl$/, '');\n }\n\n /**\n * Get or create pipeline for session\n */\n function getPipeline(sessionId: string): ContextPipeline {\n let pipeline = pipelines.get(sessionId);\n\n if (!pipeline) {\n pipeline = createContextPipeline({\n tokenBudget: realtime.tokenBudget,\n decay,\n states,\n windowSize: realtime.windowSize,\n fullOptimizationInterval: 50, // Full re-optimization every 50 incremental updates\n });\n // Restore persisted optimizer state if available\n loadState(sessionId, pipeline);\n pipelines.set(sessionId, pipeline);\n }\n\n return pipeline;\n }\n\n /**\n * Handle file change event (debounced)\n */\n function handleFileChange(filePath: string): void {\n // Clear existing timer\n const existingTimer = debounceTimers.get(filePath);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n\n // Set new debounced timer\n const timer = setTimeout(() => {\n try {\n // Read new lines from file\n const newLines = fileTracker.readNewLines(filePath);\n\n if (newLines.length === 0) return;\n\n // Parse JSONL content\n const content = newLines.join('\\n');\n const sessionId = getSessionId(filePath);\n const pipeline = getPipeline(sessionId);\n\n // Ingest into pipeline\n pipeline.ingest(content, { sessionId, filePath });\n\n // Check if we should trigger optimization\n const stats = pipeline.getStats();\n if (stats.currentTokens >= realtime.autoOptimizeThreshold) {\n // Update daemon metrics\n getMetrics().updateDaemon({\n sessionsWatched: pipelines.size,\n memoryUsage: process.memoryUsage().heapUsed,\n });\n\n // Trigger optimization callback\n if (onOptimize) {\n const sessionStats = computeSessionStats(sessionId, pipeline);\n onOptimize(sessionId, sessionStats);\n }\n }\n } catch (error) {\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n } finally {\n debounceTimers.delete(filePath);\n }\n }, realtime.debounceMs);\n\n debounceTimers.set(filePath, timer);\n }\n\n /**\n * Recursively find all JSONL files in directory\n */\n function findJsonlFiles(dir: string): string[] {\n const files: string[] = [];\n\n try {\n const entries = readdirSync(dir);\n\n for (const entry of entries) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n\n if (stat.isDirectory()) {\n // Recurse into subdirectories\n files.push(...findJsonlFiles(fullPath));\n } else if (entry.endsWith('.jsonl')) {\n // Match pattern\n const matches = realtime.watchPatterns.some((pattern) => {\n // Simple glob matching (supports **/*.jsonl)\n const regex = new RegExp(\n pattern\n .replace(/\\./g, '\\\\.')\n .replace(/\\*\\*/g, '.*')\n .replace(/(?<!\\.)(\\*)/g, '[^/\\\\\\\\]*'),\n );\n return regex.test(fullPath);\n });\n\n if (matches) {\n files.push(fullPath);\n }\n }\n }\n } catch (_error) {\n // Ignore errors (directory might not exist yet)\n }\n\n return files;\n }\n\n /**\n * Compute session statistics\n */\n function computeSessionStats(sessionId: string, pipeline: ContextPipeline): SessionStats {\n const stats = pipeline.getStats();\n const entries = pipeline.getEntries();\n const totalTokens = entries.reduce((sum, e) => sum + estimateTokens(e.content), 0);\n\n return {\n sessionId,\n totalTokens: stats.totalIngested,\n optimizedTokens: stats.currentTokens,\n reduction: totalTokens > 0 ? (totalTokens - stats.currentTokens) / totalTokens : 0,\n entryCount: stats.currentEntries,\n budgetUtilization: stats.budgetUtilization,\n };\n }\n\n async function start(): Promise<void> {\n const projectsDir = getProjectsDir();\n\n // Find all existing JSONL files (for initial metrics count)\n const jsonlFiles = findJsonlFiles(projectsDir);\n\n // Use a single recursive watcher on the projects dir to avoid duplicate events\n // from both per-dir watchers and the recursive watcher firing for the same file\n try {\n const projectsWatcher = watch(projectsDir, { recursive: true }, (_eventType, filename) => {\n if (filename?.endsWith('.jsonl')) {\n const fullPath = join(projectsDir, filename);\n handleFileChange(fullPath);\n }\n });\n\n watchers.push(projectsWatcher);\n } catch {\n // Recursive watch not supported (some Linux kernels) - fall back to per-dir\n const watchedDirs = new Set<string>();\n\n for (const file of jsonlFiles) {\n const dir = dirname(file);\n\n if (!watchedDirs.has(dir)) {\n const watcher = watch(dir, { recursive: false }, (_eventType, filename) => {\n if (filename?.endsWith('.jsonl')) {\n const fullPath = join(dir, filename);\n handleFileChange(fullPath);\n }\n });\n\n watchers.push(watcher);\n watchedDirs.add(dir);\n }\n }\n }\n\n // Update daemon metrics\n getMetrics().updateDaemon({\n startTime: Date.now(),\n sessionsWatched: jsonlFiles.length,\n memoryUsage: process.memoryUsage().heapUsed,\n });\n }\n\n /**\n * State persistence path\n */\n function getStatePath(): string {\n return join(homedir(), '.sparn', 'optimizer-state.json');\n }\n\n /**\n * Save optimizer state for all sessions\n */\n function saveState(): void {\n try {\n const stateMap: Record<string, string> = {};\n for (const [sessionId, pipeline] of pipelines.entries()) {\n stateMap[sessionId] = pipeline.serializeOptimizerState();\n }\n const statePath = getStatePath();\n const dir = dirname(statePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(statePath, JSON.stringify(stateMap), 'utf-8');\n } catch {\n // Best-effort — fail silently\n }\n }\n\n /**\n * Load optimizer state for a session\n */\n function loadState(sessionId: string, pipeline: ReturnType<typeof createContextPipeline>): void {\n try {\n const statePath = getStatePath();\n if (!existsSync(statePath)) return;\n const raw = readFileSync(statePath, 'utf-8');\n const stateMap = JSON.parse(raw) as Record<string, string>;\n const sessionState = stateMap[sessionId];\n if (sessionState) {\n pipeline.deserializeOptimizerState(sessionState);\n }\n } catch {\n // Best-effort — fail silently\n }\n }\n\n function stop(): void {\n // Save optimizer state before stopping\n saveState();\n\n // Close all watchers\n for (const watcher of watchers) {\n watcher.close();\n }\n watchers.length = 0;\n\n // Clear all timers\n for (const timer of debounceTimers.values()) {\n clearTimeout(timer);\n }\n debounceTimers.clear();\n\n // Clear pipelines\n pipelines.clear();\n\n // Clear file tracker\n fileTracker.clearAll();\n }\n\n function getStats(): SessionStats[] {\n const stats: SessionStats[] = [];\n\n for (const [sessionId, pipeline] of pipelines.entries()) {\n stats.push(computeSessionStats(sessionId, pipeline));\n }\n\n return stats;\n }\n\n function getSessionStats(sessionId: string): SessionStats | null {\n const pipeline = pipelines.get(sessionId);\n if (!pipeline) return null;\n\n return computeSessionStats(sessionId, pipeline);\n }\n\n function optimizeSession(sessionId: string): void {\n const pipeline = pipelines.get(sessionId);\n if (!pipeline) return;\n\n // Get entries and force full optimization\n const entries = pipeline.getEntries();\n pipeline.clear();\n pipeline.ingest(entries.map((e) => e.content).join('\\n\\n'));\n\n // Trigger callback\n if (onOptimize) {\n const stats = computeSessionStats(sessionId, pipeline);\n onOptimize(sessionId, stats);\n }\n }\n\n return {\n start,\n stop,\n getStats,\n getSessionStats,\n optimizeSession,\n };\n}\n","/**\n * Sparn MCP Server - Model Context Protocol server implementation\n *\n * Exposes Sparn context optimization as MCP tools, enabling integration\n * with Claude Desktop, VS Code, and other MCP clients.\n *\n * Tools:\n * - sparn_optimize: Optimize context with configurable options\n * - sparn_stats: Get optimization statistics\n * - sparn_consolidate: Run memory consolidation\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { createGenericAdapter } from '../adapters/generic.js';\nimport type { KVMemory } from '../core/kv-memory.js';\nimport { createSleepCompressor } from '../core/sleep-compressor.js';\nimport type { SparnConfig } from '../types/config.js';\nimport { DEFAULT_CONFIG } from '../types/config.js';\n\n/**\n * Options for creating the Sparn MCP server.\n */\nexport interface SparnMcpServerOptions {\n /** KV memory store instance */\n memory: KVMemory;\n /** Sparn configuration (defaults to DEFAULT_CONFIG) */\n config?: SparnConfig;\n}\n\n/**\n * Create and configure the Sparn MCP server with all tools registered.\n *\n * @param options - Server options including memory store and config\n * @returns Configured McpServer instance ready to connect to a transport\n */\nexport function createSparnMcpServer(options: SparnMcpServerOptions): McpServer {\n const { memory, config = DEFAULT_CONFIG } = options;\n\n const server = new McpServer({\n name: 'sparn',\n version: '1.4.0',\n });\n\n registerOptimizeTool(server, memory, config);\n registerStatsTool(server, memory);\n registerConsolidateTool(server, memory);\n registerSearchTool(server, memory);\n\n return server;\n}\n\n/**\n * Register the sparn_optimize tool.\n *\n * Optimizes input context using the multi-stage pipeline:\n * critical event detection, relevance scoring, entry classification, and sparse pruning.\n */\nfunction registerOptimizeTool(server: McpServer, memory: KVMemory, config: SparnConfig): void {\n server.registerTool(\n 'sparn_optimize',\n {\n title: 'Sparn Optimize',\n description:\n 'Optimize context using multi-stage pruning. ' +\n 'Applies critical event detection, relevance scoring, entry classification, ' +\n 'and sparse pruning to reduce token usage while preserving important information.',\n inputSchema: {\n context: z.string().describe('The context text to optimize'),\n dryRun: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, do not persist changes to the memory store'),\n verbose: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, include per-entry details in the response'),\n threshold: z\n .number()\n .min(0)\n .max(100)\n .optional()\n .describe('Custom pruning threshold (1-100, overrides config)'),\n },\n },\n async ({ context, dryRun, verbose, threshold }) => {\n try {\n const effectiveConfig = threshold\n ? { ...config, pruning: { ...config.pruning, threshold } }\n : config;\n\n const adapter = createGenericAdapter(memory, effectiveConfig);\n const result = await adapter.optimize(context, {\n dryRun,\n verbose,\n threshold,\n });\n\n const response = {\n optimizedContext: result.optimizedContext,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n reduction: `${(result.reduction * 100).toFixed(1)}%`,\n entriesProcessed: result.entriesProcessed,\n entriesKept: result.entriesKept,\n durationMs: result.durationMs,\n stateDistribution: result.stateDistribution,\n ...(verbose && result.details ? { details: result.details } : {}),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ error: message }),\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n\n/**\n * Register the sparn_stats tool.\n *\n * Returns optimization statistics from the memory store, including\n * total commands run, tokens saved, and average reduction.\n */\nfunction registerStatsTool(server: McpServer, memory: KVMemory): void {\n server.registerTool(\n 'sparn_stats',\n {\n title: 'Sparn Stats',\n description:\n 'Get optimization statistics including total commands run, ' +\n 'tokens saved, and average reduction percentage.',\n inputSchema: {\n reset: z\n .boolean()\n .optional()\n .default(false)\n .describe('If true, reset all optimization statistics'),\n },\n },\n async ({ reset }) => {\n try {\n if (reset) {\n await memory.clearOptimizationStats();\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(\n {\n message: 'Optimization statistics have been reset.',\n totalCommands: 0,\n totalTokensSaved: 0,\n averageReduction: '0.0%',\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n\n const stats = await memory.getOptimizationStats();\n const totalCommands = stats.length;\n\n const totalTokensSaved = stats.reduce(\n (sum, s) => sum + (s.tokens_before - s.tokens_after),\n 0,\n );\n\n const averageReduction =\n totalCommands > 0\n ? stats.reduce((sum, s) => {\n const reduction =\n s.tokens_before > 0 ? (s.tokens_before - s.tokens_after) / s.tokens_before : 0;\n return sum + reduction;\n }, 0) / totalCommands\n : 0;\n\n const recentOptimizations = stats.slice(0, 10).map((s) => ({\n timestamp: new Date(s.timestamp).toISOString(),\n tokensBefore: s.tokens_before,\n tokensAfter: s.tokens_after,\n entriesPruned: s.entries_pruned,\n durationMs: s.duration_ms,\n reduction: `${(\n ((s.tokens_before - s.tokens_after) / Math.max(s.tokens_before, 1)) * 100\n ).toFixed(1)}%`,\n }));\n\n const response = {\n totalCommands,\n totalTokensSaved,\n averageReduction: `${(averageReduction * 100).toFixed(1)}%`,\n recentOptimizations,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ error: message }),\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n\n/**\n * Register the sparn_search tool.\n *\n * Searches memory entries using FTS5 full-text search.\n * Returns matching entries with score, state, and rank info.\n */\nfunction registerSearchTool(server: McpServer, memory: KVMemory): void {\n server.registerTool(\n 'sparn_search',\n {\n title: 'Sparn Search',\n description:\n 'Search memory entries using full-text search. ' +\n 'Returns matching entries with relevance ranking, score, and state information.',\n inputSchema: {\n query: z.string().describe('Search query text'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .default(10)\n .describe('Maximum number of results (1-100, default 10)'),\n },\n },\n async ({ query, limit }) => {\n try {\n const results = await memory.searchFTS(query, limit);\n\n const response = results.map((r) => ({\n id: r.entry.id,\n content:\n r.entry.content.length > 500 ? `${r.entry.content.slice(0, 500)}...` : r.entry.content,\n score: r.entry.score,\n state: r.entry.state,\n rank: r.rank,\n tags: r.entry.tags,\n isBTSP: r.entry.isBTSP,\n }));\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ results: response, total: response.length }, null, 2),\n },\n ],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ error: message }),\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n\n/**\n * Register the sparn_consolidate tool.\n *\n * Runs the consolidation process, which removes decayed entries\n * and merges duplicates in the memory store.\n */\nfunction registerConsolidateTool(server: McpServer, memory: KVMemory): void {\n server.registerTool(\n 'sparn_consolidate',\n {\n title: 'Sparn Consolidate',\n description:\n 'Run memory consolidation. ' +\n 'Removes decayed entries and merges duplicates to reclaim space.',\n },\n async () => {\n try {\n const allIds = await memory.list();\n const allEntries = await Promise.all(\n allIds.map(async (id) => {\n const entry = await memory.get(id);\n return entry;\n }),\n );\n\n const entries = allEntries.filter((e) => e !== null);\n\n const compressor = createSleepCompressor();\n const result = compressor.consolidate(entries);\n\n // Apply changes to memory store\n for (const removed of result.removed) {\n await memory.delete(removed.id);\n }\n\n for (const kept of result.kept) {\n await memory.put(kept);\n }\n\n // Run VACUUM to reclaim disk space\n await memory.compact();\n\n const response = {\n entriesBefore: result.entriesBefore,\n entriesAfter: result.entriesAfter,\n decayedRemoved: result.decayedRemoved,\n duplicatesRemoved: result.duplicatesRemoved,\n compressionRatio: `${(result.compressionRatio * 100).toFixed(1)}%`,\n durationMs: result.durationMs,\n vacuumCompleted: true,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ error: message }),\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n","/**\n * Configuration types for Sparn behavior customization.\n */\n\n/**\n * Agent adapter type.\n */\nexport type AgentType = 'claude-code' | 'generic';\n\n/**\n * Pruning configuration.\n */\nexport interface PruningConfig {\n /** Percentage of top-scored entries to keep (1-100, default: 5) */\n threshold: number;\n\n /** Aggressiveness scale 0-100 (affects TF-IDF weighting, default: 50) */\n aggressiveness: number;\n}\n\n/**\n * Decay configuration.\n */\nexport interface DecayConfig {\n /** Default TTL in hours (default: 24) */\n defaultTTL: number;\n\n /** Decay threshold for pruning (0.0-1.0, default: 0.95) */\n decayThreshold: number;\n\n /** Minutes within which entries get a recency boost (default: 30) */\n recencyBoostMinutes?: number;\n\n /** Multiplier for recency boost at age 0 (default: 1.3) */\n recencyBoostMultiplier?: number;\n}\n\n/**\n * Confidence state threshold configuration.\n */\nexport interface StatesConfig {\n /** Score threshold for active state (default: 0.7) */\n activeThreshold: number;\n\n /** Score threshold for ready state (default: 0.3) */\n readyThreshold: number;\n}\n\n/**\n * UI configuration.\n */\nexport interface UIConfig {\n /** Enable colored output (default: true) */\n colors: boolean;\n\n /** Enable sound effects (default: false) */\n sounds: boolean;\n\n /** Verbose logging (default: false) */\n verbose: boolean;\n}\n\n/**\n * Real-time optimization configuration.\n */\nexport interface RealtimeConfig {\n /** Target token budget for optimized context (default: 50000) */\n tokenBudget: number;\n\n /** Token threshold that triggers auto-optimization (default: 60000) */\n autoOptimizeThreshold: number;\n\n /** File patterns to watch for changes (default: ['**\\/*.jsonl']) */\n watchPatterns: string[];\n\n /** Daemon PID file path (default: '.sparn/daemon.pid') */\n pidFile: string;\n\n /** Daemon log file path (default: '.sparn/daemon.log') */\n logFile: string;\n\n /** Debounce delay in milliseconds for file changes (default: 5000) */\n debounceMs: number;\n\n /** Enable incremental optimization (default: true) */\n incremental: boolean;\n\n /** Sliding window size for context entries (default: 500) */\n windowSize: number;\n\n /** Consolidation interval in hours, or null for disabled (default: null) */\n consolidationInterval: number | null;\n\n /** Use precise GPT tokenizer for token counting (default: false) */\n preciseTokenCounting?: boolean;\n}\n\n/**\n * Complete Sparn configuration.\n */\nexport interface SparnConfig {\n pruning: PruningConfig;\n decay: DecayConfig;\n states: StatesConfig;\n agent: AgentType;\n ui: UIConfig;\n /** Auto-consolidation interval in hours, or null for manual */\n autoConsolidate: number | null;\n /** Real-time optimization settings */\n realtime: RealtimeConfig;\n /** Additional BTSP pattern regex strings (default: []) */\n btspPatterns?: string[];\n}\n\n/**\n * Default configuration values.\n */\nexport const DEFAULT_CONFIG: SparnConfig = {\n pruning: {\n threshold: 5,\n aggressiveness: 50,\n },\n decay: {\n defaultTTL: 24,\n decayThreshold: 0.95,\n },\n states: {\n activeThreshold: 0.7,\n readyThreshold: 0.3,\n },\n agent: 'generic',\n ui: {\n colors: true,\n sounds: false,\n verbose: false,\n },\n autoConsolidate: null,\n realtime: {\n tokenBudget: 40000,\n autoOptimizeThreshold: 60000,\n watchPatterns: ['**/*.jsonl'],\n pidFile: '.sparn/daemon.pid',\n logFile: '.sparn/daemon.log',\n debounceMs: 5000,\n incremental: true,\n windowSize: 500,\n consolidationInterval: null,\n },\n};\n","/**\n * Logging utility.\n * Simple console wrapper with log levels.\n */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Logger interface.\n */\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\n/**\n * Create a logger with optional verbosity control.\n *\n * @param verbose - Enable debug-level logging\n * @returns Logger instance\n */\nexport function createLogger(verbose = false): Logger {\n return {\n debug(message: string, ...args: unknown[]): void {\n if (verbose) {\n console.debug(`[DEBUG] ${message}`, ...args);\n }\n },\n info(message: string, ...args: unknown[]): void {\n console.info(`[INFO] ${message}`, ...args);\n },\n warn(message: string, ...args: unknown[]): void {\n console.warn(`[WARN] ${message}`, ...args);\n },\n error(message: string, ...args: unknown[]): void {\n console.error(`[ERROR] ${message}`, ...args);\n },\n };\n}\n"],"mappings":"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","names":["randomUUID","randomUUID","randomUUID","randomUUID","entry","allEntries","randomUUID","resolve","existsSync","readdirSync","readFileSync","extname","join","relative","existsSync","Database","existsSync","readdirSync","readFileSync","statSync","extname","join","relative","Database","randomUUID","existsSync","readdirSync","readFileSync","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","status","__filename","__dirname","resolve","statSync","existsSync","mkdirSync","readdirSync","readFileSync","statSync","writeFileSync","dirname","join","join","readdirSync","statSync","dirname","existsSync","mkdirSync","writeFileSync","readFileSync"]}