@stackmemoryai/stackmemory 0.5.31 → 0.5.34
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.
- package/dist/agents/core/agent-task-manager.js.map +1 -1
- package/dist/cli/claude-sm.js +199 -16
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/commands/clear.js +1 -1
- package/dist/cli/commands/clear.js.map +1 -1
- package/dist/cli/commands/context.js +1 -12
- package/dist/cli/commands/context.js.map +2 -2
- package/dist/cli/commands/dashboard.js.map +1 -1
- package/dist/cli/commands/discovery.js +1 -1
- package/dist/cli/commands/discovery.js.map +1 -1
- package/dist/cli/commands/handoff.js +1 -1
- package/dist/cli/commands/handoff.js.map +1 -1
- package/dist/cli/commands/linear.js +1 -14
- package/dist/cli/commands/linear.js.map +2 -2
- package/dist/cli/commands/login.js +32 -10
- package/dist/cli/commands/login.js.map +2 -2
- package/dist/cli/commands/migrate.js +80 -22
- package/dist/cli/commands/migrate.js.map +2 -2
- package/dist/cli/commands/model.js +533 -0
- package/dist/cli/commands/model.js.map +7 -0
- package/dist/cli/commands/monitor.js +1 -1
- package/dist/cli/commands/monitor.js.map +1 -1
- package/dist/cli/commands/quality.js +1 -1
- package/dist/cli/commands/quality.js.map +1 -1
- package/dist/cli/commands/ralph.js +93 -28
- package/dist/cli/commands/ralph.js.map +2 -2
- package/dist/cli/commands/service.js +10 -3
- package/dist/cli/commands/service.js.map +2 -2
- package/dist/cli/commands/skills.js +61 -11
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/sms-notify.js +342 -22
- package/dist/cli/commands/sms-notify.js.map +3 -3
- package/dist/cli/commands/workflow.js +1 -1
- package/dist/cli/commands/workflow.js.map +1 -1
- package/dist/cli/commands/worktree.js +1 -1
- package/dist/cli/commands/worktree.js.map +1 -1
- package/dist/cli/index.js +3 -1
- package/dist/cli/index.js.map +2 -2
- package/dist/core/context/auto-context.js.map +1 -1
- package/dist/core/context/compaction-handler.js.map +2 -2
- package/dist/core/context/context-bridge.js.map +2 -2
- package/dist/core/context/dual-stack-manager.js +24 -8
- package/dist/core/context/dual-stack-manager.js.map +2 -2
- package/dist/core/context/enhanced-rehydration.js.map +1 -1
- package/dist/core/context/frame-database.js +41 -5
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-digest.js +6 -1
- package/dist/core/context/frame-digest.js.map +2 -2
- package/dist/core/context/frame-handoff-manager.js.map +1 -1
- package/dist/core/context/frame-lifecycle-hooks.js +119 -0
- package/dist/core/context/frame-lifecycle-hooks.js.map +7 -0
- package/dist/core/context/frame-manager.js +56 -9
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/frame-stack.js +29 -0
- package/dist/core/context/frame-stack.js.map +2 -2
- package/dist/core/context/incremental-gc.js.map +2 -2
- package/dist/core/context/index.js +4 -22
- package/dist/core/context/index.js.map +2 -2
- package/dist/core/context/permission-manager.js +0 -11
- package/dist/core/context/permission-manager.js.map +2 -2
- package/dist/core/context/recursive-context-manager.js +15 -9
- package/dist/core/context/recursive-context-manager.js.map +2 -2
- package/dist/core/context/refactored-frame-manager.js +140 -34
- package/dist/core/context/refactored-frame-manager.js.map +3 -3
- package/dist/core/context/shared-context-layer.js +0 -11
- package/dist/core/context/shared-context-layer.js.map +2 -2
- package/dist/core/context/stack-merge-resolver.js.map +1 -1
- package/dist/core/context/validation.js +6 -1
- package/dist/core/context/validation.js.map +2 -2
- package/dist/core/database/database-adapter.js.map +1 -1
- package/dist/core/database/paradedb-adapter.js.map +1 -1
- package/dist/core/database/query-router.js.map +1 -1
- package/dist/core/database/sqlite-adapter.js.map +1 -1
- package/dist/core/digest/frame-digest-integration.js.map +1 -1
- package/dist/core/digest/hybrid-digest-generator.js.map +1 -1
- package/dist/core/digest/types.js.map +1 -1
- package/dist/core/errors/index.js +249 -0
- package/dist/core/errors/index.js.map +2 -2
- package/dist/core/frame/workflow-templates.js.map +2 -2
- package/dist/core/merge/conflict-detector.js.map +1 -1
- package/dist/core/merge/resolution-engine.js.map +1 -1
- package/dist/core/merge/stack-diff.js.map +1 -1
- package/dist/core/models/fallback-monitor.js +229 -0
- package/dist/core/models/fallback-monitor.js.map +7 -0
- package/dist/core/models/model-router.js +340 -0
- package/dist/core/models/model-router.js.map +7 -0
- package/dist/core/monitoring/error-handler.js +37 -270
- package/dist/core/monitoring/error-handler.js.map +3 -3
- package/dist/core/monitoring/session-monitor.js.map +1 -1
- package/dist/core/performance/lazy-context-loader.js.map +1 -1
- package/dist/core/performance/optimized-frame-context.js.map +1 -1
- package/dist/core/retrieval/context-retriever.js.map +1 -1
- package/dist/core/retrieval/graph-retrieval.js.map +1 -1
- package/dist/core/retrieval/hierarchical-retrieval.js.map +1 -1
- package/dist/core/retrieval/llm-context-retrieval.js.map +1 -1
- package/dist/core/retrieval/retrieval-benchmarks.js.map +1 -1
- package/dist/core/retrieval/summary-generator.js.map +1 -1
- package/dist/core/retrieval/types.js.map +1 -1
- package/dist/core/storage/chromadb-adapter.js.map +1 -1
- package/dist/core/storage/infinite-storage.js.map +1 -1
- package/dist/core/storage/two-tier-storage.js.map +1 -1
- package/dist/features/tasks/task-aware-context.js.map +1 -1
- package/dist/features/web/server/index.js +1 -1
- package/dist/features/web/server/index.js.map +1 -1
- package/dist/hooks/claude-code-whatsapp-hook.js +197 -0
- package/dist/hooks/claude-code-whatsapp-hook.js.map +7 -0
- package/dist/hooks/linear-task-picker.js +1 -1
- package/dist/hooks/linear-task-picker.js.map +2 -2
- package/dist/hooks/schemas.js +105 -1
- package/dist/hooks/schemas.js.map +2 -2
- package/dist/hooks/session-summary.js +5 -1
- package/dist/hooks/session-summary.js.map +2 -2
- package/dist/hooks/sms-action-runner.js +16 -1
- package/dist/hooks/sms-action-runner.js.map +2 -2
- package/dist/hooks/sms-notify.js +4 -2
- package/dist/hooks/sms-notify.js.map +2 -2
- package/dist/hooks/sms-webhook.js +23 -2
- package/dist/hooks/sms-webhook.js.map +2 -2
- package/dist/hooks/whatsapp-commands.js +516 -0
- package/dist/hooks/whatsapp-commands.js.map +7 -0
- package/dist/hooks/whatsapp-scheduler.js +317 -0
- package/dist/hooks/whatsapp-scheduler.js.map +7 -0
- package/dist/hooks/whatsapp-sync.js +409 -0
- package/dist/hooks/whatsapp-sync.js.map +7 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/mcp/handlers/context-handlers.js.map +1 -1
- package/dist/integrations/mcp/handlers/discovery-handlers.js.map +1 -1
- package/dist/integrations/mcp/server.js +1 -1
- package/dist/integrations/mcp/server.js.map +1 -1
- package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js +1 -1
- package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js.map +1 -1
- package/dist/integrations/ralph/context/stackmemory-context-loader.js +1 -1
- package/dist/integrations/ralph/context/stackmemory-context-loader.js.map +1 -1
- package/dist/integrations/ralph/learning/pattern-learner.js +1 -1
- package/dist/integrations/ralph/learning/pattern-learner.js.map +1 -1
- package/dist/integrations/ralph/orchestration/multi-loop-orchestrator.js +1 -1
- package/dist/integrations/ralph/orchestration/multi-loop-orchestrator.js.map +1 -1
- package/dist/integrations/ralph/swarm/swarm-coordinator.js +1 -1
- package/dist/integrations/ralph/swarm/swarm-coordinator.js.map +1 -1
- package/dist/integrations/ralph/visualization/ralph-debugger.js +1 -1
- package/dist/integrations/ralph/visualization/ralph-debugger.js.map +1 -1
- package/dist/mcp/stackmemory-mcp-server.js +1 -1
- package/dist/mcp/stackmemory-mcp-server.js.map +1 -1
- package/dist/skills/claude-skills.js.map +1 -1
- package/dist/skills/recursive-agent-orchestrator.js.map +1 -1
- package/dist/skills/unified-rlm-orchestrator.js.map +1 -1
- package/package.json +2 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/integrations/mcp/handlers/discovery-handlers.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Discovery MCP Tool Handlers\n * Intelligently discovers relevant files based on current context\n */\n\nimport { FrameManager } from '../../../core/context/frame-manager.js';\nimport { LLMContextRetrieval } from '../../../core/retrieval/index.js';\nimport { logger } from '../../../core/monitoring/logger.js';\nimport { execSync } from 'child_process';\nimport { existsSync, readFileSync, readdirSync, statSync } from 'fs';\nimport { join, relative, extname } from 'path';\nimport Database from 'better-sqlite3';\n\nexport interface DiscoveryDependencies {\n frameManager: FrameManager;\n contextRetrieval: LLMContextRetrieval;\n db: Database.Database;\n projectRoot: string;\n}\n\ninterface DiscoveredFile {\n path: string;\n relevance: 'high' | 'medium' | 'low';\n reason: string;\n matchedKeywords?: string[];\n excerpt?: string;\n}\n\ninterface DiscoveryResult {\n files: DiscoveredFile[];\n keywords: string[];\n contextSummary: string;\n mdContext: Record<string, string>;\n}\n\nexport class DiscoveryHandlers {\n constructor(private deps: DiscoveryDependencies) {}\n\n /**\n * Discover relevant files based on current context\n */\n async handleDiscover(args: {\n query?: string;\n depth?: 'shallow' | 'medium' | 'deep';\n includePatterns?: string[];\n excludePatterns?: string[];\n maxFiles?: number;\n }): Promise<any> {\n try {\n const {\n query,\n depth = 'medium',\n includePatterns = ['*.ts', '*.tsx', '*.js', '*.md', '*.json'],\n excludePatterns = ['node_modules', 'dist', '.git', '*.min.js'],\n maxFiles = 20,\n } = args;\n\n logger.info('Starting discovery', { query, depth });\n\n // Step 1: Extract keywords from current context\n const keywords = this.extractContextKeywords(query);\n\n // Step 2: Parse .md files for additional context\n const mdContext = this.parseMdFiles();\n\n // Step 3: Get recently touched files from frames\n const recentFiles = this.getRecentFilesFromContext();\n\n // Step 4: Search codebase for relevant files\n const discoveredFiles = await this.searchCodebase(\n keywords,\n includePatterns,\n excludePatterns,\n depth,\n maxFiles\n );\n\n // Step 5: Merge and rank results\n const rankedFiles = this.rankFiles(\n discoveredFiles,\n recentFiles,\n keywords\n );\n\n // Step 6: Generate context summary\n const contextSummary = this.generateContextSummary(keywords, rankedFiles);\n\n const result: DiscoveryResult = {\n files: rankedFiles.slice(0, maxFiles),\n keywords,\n contextSummary,\n mdContext,\n };\n\n return {\n content: [\n {\n type: 'text',\n text: this.formatDiscoveryResult(result),\n },\n ],\n metadata: result,\n };\n } catch (error) {\n logger.error('Discovery failed', error);\n throw error;\n }\n }\n\n /**\n * Get related files to a specific file or concept\n */\n async handleRelatedFiles(args: {\n file?: string;\n concept?: string;\n maxFiles?: number;\n }): Promise<any> {\n try {\n const { file, concept, maxFiles = 10 } = args;\n\n if (!file && !concept) {\n throw new Error('Either file or concept is required');\n }\n\n let relatedFiles: DiscoveredFile[] = [];\n\n if (file) {\n // Find files that import/reference this file\n relatedFiles = this.findFileReferences(file, maxFiles);\n }\n\n if (concept) {\n // Search for files mentioning this concept\n const conceptFiles = this.searchForConcept(concept, maxFiles);\n relatedFiles = this.mergeAndDedupe(relatedFiles, conceptFiles);\n }\n\n return {\n content: [\n {\n type: 'text',\n text: this.formatRelatedFiles(relatedFiles, file, concept),\n },\n ],\n metadata: { relatedFiles },\n };\n } catch (error) {\n logger.error('Related files search failed', error);\n throw error;\n }\n }\n\n /**\n * Get session summary with actionable context\n */\n async handleSessionSummary(args: {\n includeFiles?: boolean;\n includeDecisions?: boolean;\n }): Promise<any> {\n try {\n const { includeFiles = true, includeDecisions = true } = args;\n\n const hotStack = this.deps.frameManager.getHotStackContext(50);\n const recentFiles = includeFiles ? this.getRecentFilesFromContext() : [];\n const decisions = includeDecisions ? this.getRecentDecisions() : [];\n\n const summary = {\n activeFrames: hotStack.length,\n currentGoal:\n hotStack[hotStack.length - 1]?.header?.goal || 'No active task',\n recentFiles: recentFiles.slice(0, 10),\n decisions: decisions.slice(0, 5),\n stackDepth: this.deps.frameManager.getStackDepth(),\n };\n\n return {\n content: [\n {\n type: 'text',\n text: this.formatSessionSummary(summary),\n },\n ],\n metadata: summary,\n };\n } catch (error) {\n logger.error('Session summary failed', error);\n throw error;\n }\n }\n\n // ===============================\n // Private helper methods\n // ===============================\n\n private extractContextKeywords(query?: string): string[] {\n const keywords: Set<string> = new Set();\n\n // Add query terms\n if (query) {\n const queryWords = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((w) => w.length > 2);\n queryWords.forEach((w) => keywords.add(w));\n }\n\n // Extract from current frames\n const hotStack = this.deps.frameManager.getHotStackContext(20);\n for (const frame of hotStack) {\n // Frame name/goal\n if (frame.header?.goal) {\n const goalWords = frame.header.goal\n .toLowerCase()\n .split(/[\\s\\-_]+/)\n .filter((w) => w.length > 2);\n goalWords.forEach((w) => keywords.add(w));\n }\n\n // Constraints\n frame.header?.constraints?.forEach((c: string) => {\n const words = c\n .toLowerCase()\n .split(/[\\s\\-_]+/)\n .filter((w) => w.length > 2);\n words.forEach((w) => keywords.add(w));\n });\n\n // Recent events\n frame.recentEvents?.forEach((evt: any) => {\n if (evt.data?.content) {\n const words = String(evt.data.content)\n .toLowerCase()\n .split(/[\\s\\-_]+/)\n .filter((w) => w.length > 3)\n .slice(0, 5);\n words.forEach((w) => keywords.add(w));\n }\n });\n }\n\n // Extract from recent files in events\n try {\n const fileEvents = this.deps.db\n .prepare(\n `\n SELECT DISTINCT data FROM events e\n JOIN frames f ON e.frame_id = f.frame_id\n WHERE e.type IN ('file_read', 'file_write', 'file_edit')\n ORDER BY e.timestamp DESC\n LIMIT 20\n `\n )\n .all() as any[];\n\n for (const evt of fileEvents) {\n try {\n const data = JSON.parse(evt.data || '{}');\n if (data.path) {\n // Extract meaningful parts from file path\n const pathParts = data.path.split('/').slice(-2);\n pathParts.forEach((part: string) => {\n const words = part\n .replace(/\\.[^.]+$/, '')\n .split(/[\\-_]+/)\n .filter((w) => w.length > 2);\n words.forEach((w) => keywords.add(w.toLowerCase()));\n });\n }\n } catch {}\n }\n } catch {}\n\n // Remove common stopwords\n const stopwords = new Set([\n 'the',\n 'and',\n 'for',\n 'with',\n 'this',\n 'that',\n 'from',\n 'have',\n 'has',\n 'been',\n 'will',\n 'can',\n 'should',\n 'would',\n 'could',\n 'function',\n 'const',\n 'let',\n 'var',\n 'import',\n 'export',\n 'return',\n 'async',\n 'await',\n ]);\n\n return Array.from(keywords).filter((k) => !stopwords.has(k));\n }\n\n private parseMdFiles(): Record<string, string> {\n const mdContext: Record<string, string> = {};\n const mdFiles = ['CLAUDE.md', 'README.md', '.stackmemory/context.md'];\n\n for (const mdFile of mdFiles) {\n const fullPath = join(this.deps.projectRoot, mdFile);\n if (existsSync(fullPath)) {\n try {\n const content = readFileSync(fullPath, 'utf8');\n // Extract key sections\n const sections = this.extractMdSections(content);\n mdContext[mdFile] = sections;\n } catch {}\n }\n }\n\n // Also check ~/.claude/CLAUDE.md\n const homeClaude = join(process.env['HOME'] || '', '.claude', 'CLAUDE.md');\n if (existsSync(homeClaude)) {\n try {\n const content = readFileSync(homeClaude, 'utf8');\n mdContext['~/.claude/CLAUDE.md'] = this.extractMdSections(content);\n } catch {}\n }\n\n return mdContext;\n }\n\n private extractMdSections(content: string): string {\n // Extract meaningful sections (headers and their content)\n const lines = content.split('\\n');\n const sections: string[] = [];\n let currentSection = '';\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.startsWith('```')) {\n inCodeBlock = !inCodeBlock;\n continue;\n }\n if (inCodeBlock) continue;\n\n if (line.startsWith('#')) {\n if (currentSection) sections.push(currentSection.trim());\n currentSection = line + '\\n';\n } else if (currentSection && line.trim()) {\n currentSection += line + '\\n';\n }\n }\n if (currentSection) sections.push(currentSection.trim());\n\n // Return condensed version (first 500 chars of each section)\n return sections\n .map((s) => (s.length > 500 ? s.slice(0, 500) + '...' : s))\n .join('\\n\\n');\n }\n\n private getRecentFilesFromContext(): string[] {\n const files: Set<string> = new Set();\n\n try {\n const fileEvents = this.deps.db\n .prepare(\n `\n SELECT DISTINCT data FROM events e\n JOIN frames f ON e.frame_id = f.frame_id\n WHERE e.type IN ('file_read', 'file_write', 'file_edit', 'tool_call')\n AND e.timestamp > ?\n ORDER BY e.timestamp DESC\n LIMIT 50\n `\n )\n .all(Math.floor(Date.now() / 1000) - 3600) as any[]; // Last hour\n\n for (const evt of fileEvents) {\n try {\n const data = JSON.parse(evt.data || '{}');\n if (data.path) files.add(data.path);\n if (data.file) files.add(data.file);\n if (data.file_path) files.add(data.file_path);\n } catch {}\n }\n } catch {}\n\n // Also get from git status\n try {\n const gitStatus = execSync('git status --porcelain', {\n cwd: this.deps.projectRoot,\n encoding: 'utf8',\n });\n const modifiedFiles = gitStatus\n .split('\\n')\n .filter((l) => l.trim())\n .map((l) => l.slice(3).trim())\n .filter((f) => f);\n modifiedFiles.forEach((f) => files.add(f));\n } catch {}\n\n return Array.from(files);\n }\n\n private async searchCodebase(\n keywords: string[],\n includePatterns: string[],\n excludePatterns: string[],\n depth: 'shallow' | 'medium' | 'deep',\n maxFiles: number\n ): Promise<DiscoveredFile[]> {\n const files: DiscoveredFile[] = [];\n const maxResults = depth === 'shallow' ? 10 : depth === 'medium' ? 25 : 50;\n\n // Build grep command for each keyword\n for (const keyword of keywords.slice(0, 10)) {\n try {\n const excludeArgs = excludePatterns\n .map((p) => `--exclude-dir=${p}`)\n .join(' ');\n const includeArgs = includePatterns\n .map((p) => `--include=${p}`)\n .join(' ');\n\n const cmd = `grep -ril ${excludeArgs} ${includeArgs} \"${keyword}\" . 2>/dev/null | head -${maxResults}`;\n const result = execSync(cmd, {\n cwd: this.deps.projectRoot,\n encoding: 'utf8',\n timeout: 5000,\n });\n\n const matchedFiles = result.split('\\n').filter((f) => f.trim());\n for (const file of matchedFiles) {\n const cleanPath = file.replace(/^\\.\\//, '');\n const existing = files.find((f) => f.path === cleanPath);\n if (existing) {\n existing.matchedKeywords = existing.matchedKeywords || [];\n if (!existing.matchedKeywords.includes(keyword)) {\n existing.matchedKeywords.push(keyword);\n }\n } else {\n files.push({\n path: cleanPath,\n relevance: 'medium',\n reason: `Contains keyword: ${keyword}`,\n matchedKeywords: [keyword],\n });\n }\n }\n } catch {\n // Grep failed for this keyword, continue\n }\n }\n\n // Boost relevance for files with multiple keyword matches\n for (const file of files) {\n const matchCount = file.matchedKeywords?.length || 0;\n if (matchCount >= 3) {\n file.relevance = 'high';\n file.reason = `Matches ${matchCount} keywords: ${file.matchedKeywords?.slice(0, 3).join(', ')}`;\n }\n }\n\n return files;\n }\n\n private rankFiles(\n discovered: DiscoveredFile[],\n recent: string[],\n keywords: string[]\n ): DiscoveredFile[] {\n const recentSet = new Set(recent);\n\n // Add recent files with high relevance\n for (const recentFile of recent) {\n const existing = discovered.find((f) => f.path === recentFile);\n if (existing) {\n existing.relevance = 'high';\n existing.reason = 'Recently accessed + ' + existing.reason;\n } else {\n discovered.push({\n path: recentFile,\n relevance: 'high',\n reason: 'Recently accessed in context',\n });\n }\n }\n\n // Sort by relevance and match count\n return discovered.sort((a, b) => {\n const relevanceOrder = { high: 3, medium: 2, low: 1 };\n const relDiff = relevanceOrder[b.relevance] - relevanceOrder[a.relevance];\n if (relDiff !== 0) return relDiff;\n\n const aMatches = a.matchedKeywords?.length || 0;\n const bMatches = b.matchedKeywords?.length || 0;\n return bMatches - aMatches;\n });\n }\n\n private findFileReferences(file: string, maxFiles: number): DiscoveredFile[] {\n const results: DiscoveredFile[] = [];\n\n try {\n // Search for imports of this file\n const basename = file.replace(/\\.[^.]+$/, '');\n const cmd = `grep -ril \"from.*${basename}\" . --include=\"*.ts\" --include=\"*.tsx\" --include=\"*.js\" --exclude-dir=node_modules --exclude-dir=dist 2>/dev/null | head -${maxFiles}`;\n const result = execSync(cmd, {\n cwd: this.deps.projectRoot,\n encoding: 'utf8',\n timeout: 5000,\n });\n\n const files = result.split('\\n').filter((f) => f.trim());\n for (const f of files) {\n results.push({\n path: f.replace(/^\\.\\//, ''),\n relevance: 'high',\n reason: `Imports ${file}`,\n });\n }\n } catch {}\n\n return results;\n }\n\n private searchForConcept(\n concept: string,\n maxFiles: number\n ): DiscoveredFile[] {\n const results: DiscoveredFile[] = [];\n\n try {\n const cmd = `grep -ril \"${concept}\" . --include=\"*.ts\" --include=\"*.tsx\" --include=\"*.md\" --exclude-dir=node_modules --exclude-dir=dist 2>/dev/null | head -${maxFiles}`;\n const result = execSync(cmd, {\n cwd: this.deps.projectRoot,\n encoding: 'utf8',\n timeout: 5000,\n });\n\n const files = result.split('\\n').filter((f) => f.trim());\n for (const f of files) {\n results.push({\n path: f.replace(/^\\.\\//, ''),\n relevance: 'medium',\n reason: `Contains \"${concept}\"`,\n });\n }\n } catch {}\n\n return results;\n }\n\n private mergeAndDedupe(\n a: DiscoveredFile[],\n b: DiscoveredFile[]\n ): DiscoveredFile[] {\n const pathSet = new Set(a.map((f) => f.path));\n const merged = [...a];\n\n for (const file of b) {\n if (!pathSet.has(file.path)) {\n merged.push(file);\n pathSet.add(file.path);\n }\n }\n\n return merged;\n }\n\n private getRecentDecisions(): any[] {\n try {\n const decisions = this.deps.db\n .prepare(\n `\n SELECT a.text, a.type, a.priority, f.name as frame_name, a.created_at\n FROM anchors a\n JOIN frames f ON a.frame_id = f.frame_id\n WHERE a.type IN ('DECISION', 'CONSTRAINT', 'FACT')\n ORDER BY a.created_at DESC\n LIMIT 10\n `\n )\n .all();\n return decisions;\n } catch {\n return [];\n }\n }\n\n private generateContextSummary(\n keywords: string[],\n files: DiscoveredFile[]\n ): string {\n const hotStack = this.deps.frameManager.getHotStackContext(5);\n const currentGoal = hotStack[hotStack.length - 1]?.header?.goal;\n\n let summary = '';\n if (currentGoal) {\n summary += `Current task: ${currentGoal}\\n`;\n }\n summary += `Context keywords: ${keywords.slice(0, 10).join(', ')}\\n`;\n summary += `Relevant files found: ${files.length}\\n`;\n summary += `High relevance: ${files.filter((f) => f.relevance === 'high').length}`;\n\n return summary;\n }\n\n private formatDiscoveryResult(result: DiscoveryResult): string {\n let output = '# Discovery Results\\n\\n';\n\n output += '## Context Summary\\n';\n output += result.contextSummary + '\\n\\n';\n\n output += '## Relevant Files\\n\\n';\n for (const file of result.files.slice(0, 15)) {\n const icon =\n file.relevance === 'high'\n ? '[HIGH]'\n : file.relevance === 'medium'\n ? '[MED]'\n : '[LOW]';\n output += `${icon} ${file.path}\\n`;\n output += ` ${file.reason}\\n`;\n }\n\n if (result.keywords.length > 0) {\n output += '\\n## Keywords Used\\n';\n output += result.keywords.slice(0, 15).join(', ') + '\\n';\n }\n\n return output;\n }\n\n private formatRelatedFiles(\n files: DiscoveredFile[],\n file?: string,\n concept?: string\n ): string {\n let output = '# Related Files\\n\\n';\n\n if (file) output += `Related to file: ${file}\\n`;\n if (concept) output += `Related to concept: ${concept}\\n`;\n output += '\\n';\n\n for (const f of files) {\n output += `- ${f.path}\\n ${f.reason}\\n`;\n }\n\n return output;\n }\n\n private formatSessionSummary(summary: any): string {\n let output = '# Session Summary\\n\\n';\n\n output += `**Current Goal:** ${summary.currentGoal}\\n`;\n output += `**Active Frames:** ${summary.activeFrames}\\n`;\n output += `**Stack Depth:** ${summary.stackDepth}\\n\\n`;\n\n if (summary.recentFiles.length > 0) {\n output += '## Recent Files\\n';\n for (const f of summary.recentFiles) {\n output += `- ${f}\\n`;\n }\n output += '\\n';\n }\n\n if (summary.decisions.length > 0) {\n output += '## Recent Decisions\\n';\n for (const d of summary.decisions) {\n output += `- [${d.type}] ${d.text}\\n`;\n }\n }\n\n return output;\n }\n}\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * Discovery MCP Tool Handlers\n * Intelligently discovers relevant files based on current context\n */\n\nimport { FrameManager } from '../../../core/context/index.js';\nimport { LLMContextRetrieval } from '../../../core/retrieval/index.js';\nimport { logger } from '../../../core/monitoring/logger.js';\nimport { execSync } from 'child_process';\nimport { existsSync, readFileSync, readdirSync, statSync } from 'fs';\nimport { join, relative, extname } from 'path';\nimport Database from 'better-sqlite3';\n\nexport interface DiscoveryDependencies {\n frameManager: FrameManager;\n contextRetrieval: LLMContextRetrieval;\n db: Database.Database;\n projectRoot: string;\n}\n\ninterface DiscoveredFile {\n path: string;\n relevance: 'high' | 'medium' | 'low';\n reason: string;\n matchedKeywords?: string[];\n excerpt?: string;\n}\n\ninterface DiscoveryResult {\n files: DiscoveredFile[];\n keywords: string[];\n contextSummary: string;\n mdContext: Record<string, string>;\n}\n\nexport class DiscoveryHandlers {\n constructor(private deps: DiscoveryDependencies) {}\n\n /**\n * Discover relevant files based on current context\n */\n async handleDiscover(args: {\n query?: string;\n depth?: 'shallow' | 'medium' | 'deep';\n includePatterns?: string[];\n excludePatterns?: string[];\n maxFiles?: number;\n }): Promise<any> {\n try {\n const {\n query,\n depth = 'medium',\n includePatterns = ['*.ts', '*.tsx', '*.js', '*.md', '*.json'],\n excludePatterns = ['node_modules', 'dist', '.git', '*.min.js'],\n maxFiles = 20,\n } = args;\n\n logger.info('Starting discovery', { query, depth });\n\n // Step 1: Extract keywords from current context\n const keywords = this.extractContextKeywords(query);\n\n // Step 2: Parse .md files for additional context\n const mdContext = this.parseMdFiles();\n\n // Step 3: Get recently touched files from frames\n const recentFiles = this.getRecentFilesFromContext();\n\n // Step 4: Search codebase for relevant files\n const discoveredFiles = await this.searchCodebase(\n keywords,\n includePatterns,\n excludePatterns,\n depth,\n maxFiles\n );\n\n // Step 5: Merge and rank results\n const rankedFiles = this.rankFiles(\n discoveredFiles,\n recentFiles,\n keywords\n );\n\n // Step 6: Generate context summary\n const contextSummary = this.generateContextSummary(keywords, rankedFiles);\n\n const result: DiscoveryResult = {\n files: rankedFiles.slice(0, maxFiles),\n keywords,\n contextSummary,\n mdContext,\n };\n\n return {\n content: [\n {\n type: 'text',\n text: this.formatDiscoveryResult(result),\n },\n ],\n metadata: result,\n };\n } catch (error) {\n logger.error('Discovery failed', error);\n throw error;\n }\n }\n\n /**\n * Get related files to a specific file or concept\n */\n async handleRelatedFiles(args: {\n file?: string;\n concept?: string;\n maxFiles?: number;\n }): Promise<any> {\n try {\n const { file, concept, maxFiles = 10 } = args;\n\n if (!file && !concept) {\n throw new Error('Either file or concept is required');\n }\n\n let relatedFiles: DiscoveredFile[] = [];\n\n if (file) {\n // Find files that import/reference this file\n relatedFiles = this.findFileReferences(file, maxFiles);\n }\n\n if (concept) {\n // Search for files mentioning this concept\n const conceptFiles = this.searchForConcept(concept, maxFiles);\n relatedFiles = this.mergeAndDedupe(relatedFiles, conceptFiles);\n }\n\n return {\n content: [\n {\n type: 'text',\n text: this.formatRelatedFiles(relatedFiles, file, concept),\n },\n ],\n metadata: { relatedFiles },\n };\n } catch (error) {\n logger.error('Related files search failed', error);\n throw error;\n }\n }\n\n /**\n * Get session summary with actionable context\n */\n async handleSessionSummary(args: {\n includeFiles?: boolean;\n includeDecisions?: boolean;\n }): Promise<any> {\n try {\n const { includeFiles = true, includeDecisions = true } = args;\n\n const hotStack = this.deps.frameManager.getHotStackContext(50);\n const recentFiles = includeFiles ? this.getRecentFilesFromContext() : [];\n const decisions = includeDecisions ? this.getRecentDecisions() : [];\n\n const summary = {\n activeFrames: hotStack.length,\n currentGoal:\n hotStack[hotStack.length - 1]?.header?.goal || 'No active task',\n recentFiles: recentFiles.slice(0, 10),\n decisions: decisions.slice(0, 5),\n stackDepth: this.deps.frameManager.getStackDepth(),\n };\n\n return {\n content: [\n {\n type: 'text',\n text: this.formatSessionSummary(summary),\n },\n ],\n metadata: summary,\n };\n } catch (error) {\n logger.error('Session summary failed', error);\n throw error;\n }\n }\n\n // ===============================\n // Private helper methods\n // ===============================\n\n private extractContextKeywords(query?: string): string[] {\n const keywords: Set<string> = new Set();\n\n // Add query terms\n if (query) {\n const queryWords = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((w) => w.length > 2);\n queryWords.forEach((w) => keywords.add(w));\n }\n\n // Extract from current frames\n const hotStack = this.deps.frameManager.getHotStackContext(20);\n for (const frame of hotStack) {\n // Frame name/goal\n if (frame.header?.goal) {\n const goalWords = frame.header.goal\n .toLowerCase()\n .split(/[\\s\\-_]+/)\n .filter((w) => w.length > 2);\n goalWords.forEach((w) => keywords.add(w));\n }\n\n // Constraints\n frame.header?.constraints?.forEach((c: string) => {\n const words = c\n .toLowerCase()\n .split(/[\\s\\-_]+/)\n .filter((w) => w.length > 2);\n words.forEach((w) => keywords.add(w));\n });\n\n // Recent events\n frame.recentEvents?.forEach((evt: any) => {\n if (evt.data?.content) {\n const words = String(evt.data.content)\n .toLowerCase()\n .split(/[\\s\\-_]+/)\n .filter((w) => w.length > 3)\n .slice(0, 5);\n words.forEach((w) => keywords.add(w));\n }\n });\n }\n\n // Extract from recent files in events\n try {\n const fileEvents = this.deps.db\n .prepare(\n `\n SELECT DISTINCT data FROM events e\n JOIN frames f ON e.frame_id = f.frame_id\n WHERE e.type IN ('file_read', 'file_write', 'file_edit')\n ORDER BY e.timestamp DESC\n LIMIT 20\n `\n )\n .all() as any[];\n\n for (const evt of fileEvents) {\n try {\n const data = JSON.parse(evt.data || '{}');\n if (data.path) {\n // Extract meaningful parts from file path\n const pathParts = data.path.split('/').slice(-2);\n pathParts.forEach((part: string) => {\n const words = part\n .replace(/\\.[^.]+$/, '')\n .split(/[\\-_]+/)\n .filter((w) => w.length > 2);\n words.forEach((w) => keywords.add(w.toLowerCase()));\n });\n }\n } catch {}\n }\n } catch {}\n\n // Remove common stopwords\n const stopwords = new Set([\n 'the',\n 'and',\n 'for',\n 'with',\n 'this',\n 'that',\n 'from',\n 'have',\n 'has',\n 'been',\n 'will',\n 'can',\n 'should',\n 'would',\n 'could',\n 'function',\n 'const',\n 'let',\n 'var',\n 'import',\n 'export',\n 'return',\n 'async',\n 'await',\n ]);\n\n return Array.from(keywords).filter((k) => !stopwords.has(k));\n }\n\n private parseMdFiles(): Record<string, string> {\n const mdContext: Record<string, string> = {};\n const mdFiles = ['CLAUDE.md', 'README.md', '.stackmemory/context.md'];\n\n for (const mdFile of mdFiles) {\n const fullPath = join(this.deps.projectRoot, mdFile);\n if (existsSync(fullPath)) {\n try {\n const content = readFileSync(fullPath, 'utf8');\n // Extract key sections\n const sections = this.extractMdSections(content);\n mdContext[mdFile] = sections;\n } catch {}\n }\n }\n\n // Also check ~/.claude/CLAUDE.md\n const homeClaude = join(process.env['HOME'] || '', '.claude', 'CLAUDE.md');\n if (existsSync(homeClaude)) {\n try {\n const content = readFileSync(homeClaude, 'utf8');\n mdContext['~/.claude/CLAUDE.md'] = this.extractMdSections(content);\n } catch {}\n }\n\n return mdContext;\n }\n\n private extractMdSections(content: string): string {\n // Extract meaningful sections (headers and their content)\n const lines = content.split('\\n');\n const sections: string[] = [];\n let currentSection = '';\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.startsWith('```')) {\n inCodeBlock = !inCodeBlock;\n continue;\n }\n if (inCodeBlock) continue;\n\n if (line.startsWith('#')) {\n if (currentSection) sections.push(currentSection.trim());\n currentSection = line + '\\n';\n } else if (currentSection && line.trim()) {\n currentSection += line + '\\n';\n }\n }\n if (currentSection) sections.push(currentSection.trim());\n\n // Return condensed version (first 500 chars of each section)\n return sections\n .map((s) => (s.length > 500 ? s.slice(0, 500) + '...' : s))\n .join('\\n\\n');\n }\n\n private getRecentFilesFromContext(): string[] {\n const files: Set<string> = new Set();\n\n try {\n const fileEvents = this.deps.db\n .prepare(\n `\n SELECT DISTINCT data FROM events e\n JOIN frames f ON e.frame_id = f.frame_id\n WHERE e.type IN ('file_read', 'file_write', 'file_edit', 'tool_call')\n AND e.timestamp > ?\n ORDER BY e.timestamp DESC\n LIMIT 50\n `\n )\n .all(Math.floor(Date.now() / 1000) - 3600) as any[]; // Last hour\n\n for (const evt of fileEvents) {\n try {\n const data = JSON.parse(evt.data || '{}');\n if (data.path) files.add(data.path);\n if (data.file) files.add(data.file);\n if (data.file_path) files.add(data.file_path);\n } catch {}\n }\n } catch {}\n\n // Also get from git status\n try {\n const gitStatus = execSync('git status --porcelain', {\n cwd: this.deps.projectRoot,\n encoding: 'utf8',\n });\n const modifiedFiles = gitStatus\n .split('\\n')\n .filter((l) => l.trim())\n .map((l) => l.slice(3).trim())\n .filter((f) => f);\n modifiedFiles.forEach((f) => files.add(f));\n } catch {}\n\n return Array.from(files);\n }\n\n private async searchCodebase(\n keywords: string[],\n includePatterns: string[],\n excludePatterns: string[],\n depth: 'shallow' | 'medium' | 'deep',\n maxFiles: number\n ): Promise<DiscoveredFile[]> {\n const files: DiscoveredFile[] = [];\n const maxResults = depth === 'shallow' ? 10 : depth === 'medium' ? 25 : 50;\n\n // Build grep command for each keyword\n for (const keyword of keywords.slice(0, 10)) {\n try {\n const excludeArgs = excludePatterns\n .map((p) => `--exclude-dir=${p}`)\n .join(' ');\n const includeArgs = includePatterns\n .map((p) => `--include=${p}`)\n .join(' ');\n\n const cmd = `grep -ril ${excludeArgs} ${includeArgs} \"${keyword}\" . 2>/dev/null | head -${maxResults}`;\n const result = execSync(cmd, {\n cwd: this.deps.projectRoot,\n encoding: 'utf8',\n timeout: 5000,\n });\n\n const matchedFiles = result.split('\\n').filter((f) => f.trim());\n for (const file of matchedFiles) {\n const cleanPath = file.replace(/^\\.\\//, '');\n const existing = files.find((f) => f.path === cleanPath);\n if (existing) {\n existing.matchedKeywords = existing.matchedKeywords || [];\n if (!existing.matchedKeywords.includes(keyword)) {\n existing.matchedKeywords.push(keyword);\n }\n } else {\n files.push({\n path: cleanPath,\n relevance: 'medium',\n reason: `Contains keyword: ${keyword}`,\n matchedKeywords: [keyword],\n });\n }\n }\n } catch {\n // Grep failed for this keyword, continue\n }\n }\n\n // Boost relevance for files with multiple keyword matches\n for (const file of files) {\n const matchCount = file.matchedKeywords?.length || 0;\n if (matchCount >= 3) {\n file.relevance = 'high';\n file.reason = `Matches ${matchCount} keywords: ${file.matchedKeywords?.slice(0, 3).join(', ')}`;\n }\n }\n\n return files;\n }\n\n private rankFiles(\n discovered: DiscoveredFile[],\n recent: string[],\n keywords: string[]\n ): DiscoveredFile[] {\n const recentSet = new Set(recent);\n\n // Add recent files with high relevance\n for (const recentFile of recent) {\n const existing = discovered.find((f) => f.path === recentFile);\n if (existing) {\n existing.relevance = 'high';\n existing.reason = 'Recently accessed + ' + existing.reason;\n } else {\n discovered.push({\n path: recentFile,\n relevance: 'high',\n reason: 'Recently accessed in context',\n });\n }\n }\n\n // Sort by relevance and match count\n return discovered.sort((a, b) => {\n const relevanceOrder = { high: 3, medium: 2, low: 1 };\n const relDiff = relevanceOrder[b.relevance] - relevanceOrder[a.relevance];\n if (relDiff !== 0) return relDiff;\n\n const aMatches = a.matchedKeywords?.length || 0;\n const bMatches = b.matchedKeywords?.length || 0;\n return bMatches - aMatches;\n });\n }\n\n private findFileReferences(file: string, maxFiles: number): DiscoveredFile[] {\n const results: DiscoveredFile[] = [];\n\n try {\n // Search for imports of this file\n const basename = file.replace(/\\.[^.]+$/, '');\n const cmd = `grep -ril \"from.*${basename}\" . --include=\"*.ts\" --include=\"*.tsx\" --include=\"*.js\" --exclude-dir=node_modules --exclude-dir=dist 2>/dev/null | head -${maxFiles}`;\n const result = execSync(cmd, {\n cwd: this.deps.projectRoot,\n encoding: 'utf8',\n timeout: 5000,\n });\n\n const files = result.split('\\n').filter((f) => f.trim());\n for (const f of files) {\n results.push({\n path: f.replace(/^\\.\\//, ''),\n relevance: 'high',\n reason: `Imports ${file}`,\n });\n }\n } catch {}\n\n return results;\n }\n\n private searchForConcept(\n concept: string,\n maxFiles: number\n ): DiscoveredFile[] {\n const results: DiscoveredFile[] = [];\n\n try {\n const cmd = `grep -ril \"${concept}\" . --include=\"*.ts\" --include=\"*.tsx\" --include=\"*.md\" --exclude-dir=node_modules --exclude-dir=dist 2>/dev/null | head -${maxFiles}`;\n const result = execSync(cmd, {\n cwd: this.deps.projectRoot,\n encoding: 'utf8',\n timeout: 5000,\n });\n\n const files = result.split('\\n').filter((f) => f.trim());\n for (const f of files) {\n results.push({\n path: f.replace(/^\\.\\//, ''),\n relevance: 'medium',\n reason: `Contains \"${concept}\"`,\n });\n }\n } catch {}\n\n return results;\n }\n\n private mergeAndDedupe(\n a: DiscoveredFile[],\n b: DiscoveredFile[]\n ): DiscoveredFile[] {\n const pathSet = new Set(a.map((f) => f.path));\n const merged = [...a];\n\n for (const file of b) {\n if (!pathSet.has(file.path)) {\n merged.push(file);\n pathSet.add(file.path);\n }\n }\n\n return merged;\n }\n\n private getRecentDecisions(): any[] {\n try {\n const decisions = this.deps.db\n .prepare(\n `\n SELECT a.text, a.type, a.priority, f.name as frame_name, a.created_at\n FROM anchors a\n JOIN frames f ON a.frame_id = f.frame_id\n WHERE a.type IN ('DECISION', 'CONSTRAINT', 'FACT')\n ORDER BY a.created_at DESC\n LIMIT 10\n `\n )\n .all();\n return decisions;\n } catch {\n return [];\n }\n }\n\n private generateContextSummary(\n keywords: string[],\n files: DiscoveredFile[]\n ): string {\n const hotStack = this.deps.frameManager.getHotStackContext(5);\n const currentGoal = hotStack[hotStack.length - 1]?.header?.goal;\n\n let summary = '';\n if (currentGoal) {\n summary += `Current task: ${currentGoal}\\n`;\n }\n summary += `Context keywords: ${keywords.slice(0, 10).join(', ')}\\n`;\n summary += `Relevant files found: ${files.length}\\n`;\n summary += `High relevance: ${files.filter((f) => f.relevance === 'high').length}`;\n\n return summary;\n }\n\n private formatDiscoveryResult(result: DiscoveryResult): string {\n let output = '# Discovery Results\\n\\n';\n\n output += '## Context Summary\\n';\n output += result.contextSummary + '\\n\\n';\n\n output += '## Relevant Files\\n\\n';\n for (const file of result.files.slice(0, 15)) {\n const icon =\n file.relevance === 'high'\n ? '[HIGH]'\n : file.relevance === 'medium'\n ? '[MED]'\n : '[LOW]';\n output += `${icon} ${file.path}\\n`;\n output += ` ${file.reason}\\n`;\n }\n\n if (result.keywords.length > 0) {\n output += '\\n## Keywords Used\\n';\n output += result.keywords.slice(0, 15).join(', ') + '\\n';\n }\n\n return output;\n }\n\n private formatRelatedFiles(\n files: DiscoveredFile[],\n file?: string,\n concept?: string\n ): string {\n let output = '# Related Files\\n\\n';\n\n if (file) output += `Related to file: ${file}\\n`;\n if (concept) output += `Related to concept: ${concept}\\n`;\n output += '\\n';\n\n for (const f of files) {\n output += `- ${f.path}\\n ${f.reason}\\n`;\n }\n\n return output;\n }\n\n private formatSessionSummary(summary: any): string {\n let output = '# Session Summary\\n\\n';\n\n output += `**Current Goal:** ${summary.currentGoal}\\n`;\n output += `**Active Frames:** ${summary.activeFrames}\\n`;\n output += `**Stack Depth:** ${summary.stackDepth}\\n\\n`;\n\n if (summary.recentFiles.length > 0) {\n output += '## Recent Files\\n';\n for (const f of summary.recentFiles) {\n output += `- ${f}\\n`;\n }\n output += '\\n';\n }\n\n if (summary.decisions.length > 0) {\n output += '## Recent Decisions\\n';\n for (const d of summary.decisions) {\n output += `- [${d.type}] ${d.text}\\n`;\n }\n }\n\n return output;\n }\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import { readFileSync, existsSync, mkdirSync } from "fs";
|
|
17
17
|
import { join, dirname } from "path";
|
|
18
18
|
import { execSync } from "child_process";
|
|
19
|
-
import { FrameManager } from "../../core/context/
|
|
19
|
+
import { FrameManager } from "../../core/context/index.js";
|
|
20
20
|
import {
|
|
21
21
|
LinearTaskManager
|
|
22
22
|
} from "../../features/tasks/linear-task-manager.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/integrations/mcp/server.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n/**\n * StackMemory MCP Server - Local Instance\n * This runs locally and provides context to Claude Code\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport Database from 'better-sqlite3';\nimport {\n validateInput,\n StartFrameSchema,\n CloseFrameSchema,\n AddAnchorSchema,\n CreateTaskSchema,\n UpdateTaskStatusSchema,\n AddDecisionSchema,\n GetContextSchema,\n} from './schemas.js';\nimport { readFileSync, existsSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { execSync } from 'child_process';\nimport { FrameManager, FrameType } from '../../core/context/frame-manager.js';\nimport {\n LinearTaskManager,\n TaskPriority,\n TaskStatus,\n} from '../../features/tasks/linear-task-manager.js';\nimport { LinearAuthManager, LinearOAuthSetup } from '../linear/auth.js';\nimport { LinearSyncEngine, DEFAULT_SYNC_CONFIG } from '../linear/sync.js';\nimport { logger } from '../../core/monitoring/logger.js';\nimport { BrowserMCPIntegration } from '../../features/browser/browser-mcp.js';\nimport { TraceDetector } from '../../core/trace/trace-detector.js';\nimport { ToolCall, Trace } from '../../core/trace/types.js';\nimport { LLMContextRetrieval } from '../../core/retrieval/index.js';\nimport { DiscoveryHandlers } from './handlers/discovery-handlers.js';\nimport { v4 as uuidv4 } from 'uuid';\n// Type-safe environment variable access\nfunction getEnv(key: string, defaultValue?: string): string {\n const value = process.env[key];\n if (value === undefined) {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Environment variable ${key} is required`);\n }\n return value;\n}\n\nfunction getOptionalEnv(key: string): string | undefined {\n return process.env[key];\n}\n\n// ============================================\n// Simple Local MCP Server\n// ============================================\n\nclass LocalStackMemoryMCP {\n private server: Server;\n private db: Database.Database;\n private projectRoot: string;\n private frameManager: FrameManager;\n private taskStore: LinearTaskManager;\n private linearAuthManager: LinearAuthManager;\n private linearSync: LinearSyncEngine;\n private projectId: string;\n private contexts: Map<string, any> = new Map();\n private browserMCP: BrowserMCPIntegration;\n private traceDetector: TraceDetector;\n private contextRetrieval: LLMContextRetrieval;\n private discoveryHandlers: DiscoveryHandlers;\n\n constructor() {\n // Find project root (where .git is)\n this.projectRoot = this.findProjectRoot();\n this.projectId = this.getProjectId();\n\n // Ensure .stackmemory directory exists\n const dbDir = join(this.projectRoot, '.stackmemory');\n if (!existsSync(dbDir)) {\n mkdirSync(dbDir, { recursive: true });\n }\n\n // Initialize database\n const dbPath = join(dbDir, 'context.db');\n this.db = new Database(dbPath);\n this.initDB();\n\n // Initialize frame manager\n this.frameManager = new FrameManager(this.db, this.projectId);\n\n // Initialize task store\n this.taskStore = new LinearTaskManager(this.projectRoot, this.db);\n\n // Initialize Linear integration\n this.linearAuthManager = new LinearAuthManager(this.projectRoot);\n this.linearSync = new LinearSyncEngine(\n this.taskStore,\n this.linearAuthManager,\n DEFAULT_SYNC_CONFIG\n );\n\n // Initialize MCP server\n this.server = new Server(\n {\n name: 'stackmemory-local',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // Initialize Browser MCP integration\n this.browserMCP = new BrowserMCPIntegration({\n headless: process.env['BROWSER_HEADLESS'] !== 'false',\n defaultViewport: { width: 1280, height: 720 },\n });\n\n // Initialize Trace Detector with database persistence\n this.traceDetector = new TraceDetector({}, undefined, this.db);\n\n // Initialize LLM Context Retrieval\n this.contextRetrieval = new LLMContextRetrieval(\n this.db,\n this.frameManager,\n this.projectId\n );\n\n // Initialize Discovery Handlers\n this.discoveryHandlers = new DiscoveryHandlers({\n frameManager: this.frameManager,\n contextRetrieval: this.contextRetrieval,\n db: this.db,\n projectRoot: this.projectRoot,\n });\n\n this.setupHandlers();\n this.loadInitialContext();\n\n // Initialize Browser MCP with this server\n this.browserMCP.initialize(this.server).catch((error) => {\n logger.error('Failed to initialize Browser MCP', error);\n });\n\n logger.info('StackMemory MCP Server initialized', {\n projectRoot: this.projectRoot,\n projectId: this.projectId,\n });\n }\n\n private findProjectRoot(): string {\n let dir = process.cwd();\n while (dir !== '/') {\n if (existsSync(join(dir, '.git'))) {\n return dir;\n }\n dir = dirname(dir);\n }\n return process.cwd();\n }\n\n private initDB() {\n // Note: Don't create frames table here - FrameManager handles the schema\n // with the full run_id, project_id, parent_frame_id columns\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS contexts (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n content TEXT NOT NULL,\n importance REAL DEFAULT 0.5,\n created_at INTEGER DEFAULT (unixepoch()),\n last_accessed INTEGER DEFAULT (unixepoch()),\n access_count INTEGER DEFAULT 1\n );\n\n CREATE TABLE IF NOT EXISTS attention_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n context_id TEXT,\n query TEXT,\n response TEXT,\n influence_score REAL,\n timestamp INTEGER DEFAULT (unixepoch())\n );\n `);\n }\n\n private loadInitialContext() {\n // Load project information\n const projectInfo = this.getProjectInfo();\n this.addContext(\n 'project',\n `Project: ${projectInfo.name}\\nPath: ${projectInfo.path}`,\n 0.9\n );\n\n // Load recent git commits\n try {\n const recentCommits = execSync('git log --oneline -10', {\n cwd: this.projectRoot,\n }).toString();\n this.addContext('git_history', `Recent commits:\\n${recentCommits}`, 0.6);\n } catch {\n // Not a git repo or git not available\n }\n\n // Load README if exists\n const readmePath = join(this.projectRoot, 'README.md');\n if (existsSync(readmePath)) {\n const readme = readFileSync(readmePath, 'utf-8');\n const summary = readme.substring(0, 500);\n this.addContext('readme', `Project README:\\n${summary}...`, 0.8);\n }\n\n // Load any existing decisions from previous sessions\n this.loadStoredContexts();\n }\n\n private getProjectId(): string {\n // Use git remote or directory path as project ID\n // Algorithm must match session-manager and project-manager\n let identifier: string;\n try {\n identifier = execSync('git config --get remote.origin.url', {\n cwd: this.projectRoot,\n stdio: 'pipe',\n timeout: 5000,\n })\n .toString()\n .trim();\n } catch {\n identifier = this.projectRoot;\n }\n\n // Normalize: remove .git suffix, replace non-alphanumeric with dashes, take last 50 chars\n const cleaned = identifier\n .replace(/\\.git$/, '')\n .replace(/[^a-zA-Z0-9-]/g, '-')\n .toLowerCase();\n\n return cleaned.substring(cleaned.length - 50) || 'unknown';\n }\n\n private getProjectInfo() {\n const packageJsonPath = join(this.projectRoot, 'package.json');\n if (existsSync(packageJsonPath)) {\n const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n return {\n name: pkg.name || 'unknown',\n path: this.projectRoot,\n };\n }\n return {\n name: this.projectRoot.split('/').pop() || 'unknown',\n path: this.projectRoot,\n };\n }\n\n private addContext(type: string, content: string, importance: number = 0.5) {\n const id = `${type}_${Date.now()}`;\n\n this.db\n .prepare(\n `\n INSERT OR REPLACE INTO contexts (id, type, content, importance)\n VALUES (?, ?, ?, ?)\n `\n )\n .run(id, type, content, importance);\n\n this.contexts.set(id, { type, content, importance });\n return id;\n }\n\n private loadStoredContexts() {\n const stored = this.db\n .prepare(\n `\n SELECT * FROM contexts \n ORDER BY importance DESC, last_accessed DESC\n LIMIT 50\n `\n )\n .all() as any[];\n\n stored.forEach((ctx) => {\n this.contexts.set(ctx.id, ctx);\n });\n }\n\n private setupHandlers() {\n // Tool listing\n this.server.setRequestHandler(\n z.object({\n method: z.literal('tools/list'),\n }),\n async () => {\n return {\n tools: [\n {\n name: 'get_context',\n description: 'Get current project context',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'What you want to know',\n },\n limit: {\n type: 'number',\n description: 'Max contexts to return',\n },\n },\n },\n },\n {\n name: 'add_decision',\n description: 'Record a decision or important information',\n inputSchema: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description: 'The decision or information',\n },\n type: {\n type: 'string',\n enum: ['decision', 'constraint', 'learning'],\n },\n },\n required: ['content', 'type'],\n },\n },\n {\n name: 'start_frame',\n description: 'Start a new frame (task/subtask) on the call stack',\n inputSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Frame name/goal' },\n type: {\n type: 'string',\n enum: [\n 'task',\n 'subtask',\n 'tool_scope',\n 'review',\n 'write',\n 'debug',\n ],\n description: 'Frame type',\n },\n constraints: {\n type: 'array',\n items: { type: 'string' },\n description: 'Constraints for this frame',\n },\n },\n required: ['name', 'type'],\n },\n },\n {\n name: 'close_frame',\n description: 'Close current frame and generate digest',\n inputSchema: {\n type: 'object',\n properties: {\n result: {\n type: 'string',\n description: 'Frame completion result',\n },\n outputs: {\n type: 'object',\n description: 'Final outputs from frame',\n },\n },\n },\n },\n {\n name: 'add_anchor',\n description:\n 'Add anchored fact/decision/constraint to current frame',\n inputSchema: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n enum: [\n 'FACT',\n 'DECISION',\n 'CONSTRAINT',\n 'INTERFACE_CONTRACT',\n 'TODO',\n 'RISK',\n ],\n description: 'Anchor type',\n },\n text: { type: 'string', description: 'Anchor content' },\n priority: {\n type: 'number',\n description: 'Priority (0-10)',\n minimum: 0,\n maximum: 10,\n },\n },\n required: ['type', 'text'],\n },\n },\n {\n name: 'get_hot_stack',\n description: 'Get current active frames and context',\n inputSchema: {\n type: 'object',\n properties: {\n maxEvents: {\n type: 'number',\n description: 'Max recent events per frame',\n default: 20,\n },\n },\n },\n },\n {\n name: 'create_task',\n description: 'Create a new task in git-tracked JSONL storage',\n inputSchema: {\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Task title' },\n description: {\n type: 'string',\n description: 'Task description',\n },\n priority: {\n type: 'string',\n enum: ['low', 'medium', 'high', 'urgent'],\n description: 'Task priority',\n },\n estimatedEffort: {\n type: 'number',\n description: 'Estimated effort in minutes',\n },\n dependsOn: {\n type: 'array',\n items: { type: 'string' },\n description: 'Task IDs this depends on',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Tags for categorization',\n },\n },\n required: ['title'],\n },\n },\n {\n name: 'update_task_status',\n description: 'Update task status with automatic time tracking',\n inputSchema: {\n type: 'object',\n properties: {\n taskId: { type: 'string', description: 'Task ID to update' },\n status: {\n type: 'string',\n enum: [\n 'pending',\n 'in_progress',\n 'completed',\n 'blocked',\n 'cancelled',\n ],\n description: 'New status',\n },\n reason: {\n type: 'string',\n description:\n 'Reason for status change (especially for blocked)',\n },\n },\n required: ['taskId', 'status'],\n },\n },\n {\n name: 'get_active_tasks',\n description: 'Get currently active tasks synced from Linear',\n inputSchema: {\n type: 'object',\n properties: {\n frameId: {\n type: 'string',\n description: 'Filter by specific frame ID',\n },\n status: {\n type: 'string',\n enum: [\n 'pending',\n 'in_progress',\n 'completed',\n 'blocked',\n 'cancelled',\n ],\n description: 'Filter by status',\n },\n priority: {\n type: 'string',\n enum: ['low', 'medium', 'high', 'urgent'],\n description: 'Filter by priority',\n },\n search: {\n type: 'string',\n description: 'Search in task title or description',\n },\n limit: {\n type: 'number',\n description: 'Max number of tasks to return (default: 20)',\n },\n },\n },\n },\n {\n name: 'get_task_metrics',\n description: 'Get project task metrics and analytics',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'add_task_dependency',\n description: 'Add dependency relationship between tasks',\n inputSchema: {\n type: 'object',\n properties: {\n taskId: {\n type: 'string',\n description: 'Task that depends on another',\n },\n dependsOnId: {\n type: 'string',\n description: 'Task ID that this depends on',\n },\n },\n required: ['taskId', 'dependsOnId'],\n },\n },\n {\n name: 'linear_sync',\n description: 'Sync tasks with Linear',\n inputSchema: {\n type: 'object',\n properties: {\n direction: {\n type: 'string',\n enum: ['bidirectional', 'to_linear', 'from_linear'],\n description: 'Sync direction',\n },\n },\n },\n },\n {\n name: 'linear_update_task',\n description: 'Update a Linear task status',\n inputSchema: {\n type: 'object',\n properties: {\n issueId: {\n type: 'string',\n description: 'Linear issue ID or identifier (e.g., STA-34)',\n },\n status: {\n type: 'string',\n enum: ['todo', 'in-progress', 'done', 'canceled'],\n description: 'New status for the task',\n },\n title: {\n type: 'string',\n description: 'Update task title (optional)',\n },\n description: {\n type: 'string',\n description: 'Update task description (optional)',\n },\n priority: {\n type: 'number',\n enum: [1, 2, 3, 4],\n description: 'Priority (1=urgent, 2=high, 3=medium, 4=low)',\n },\n },\n required: ['issueId'],\n },\n },\n {\n name: 'linear_get_tasks',\n description: 'Get Linear tasks',\n inputSchema: {\n type: 'object',\n properties: {\n status: {\n type: 'string',\n enum: ['todo', 'in-progress', 'done', 'all'],\n description: 'Filter by status',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of tasks to return',\n },\n },\n },\n },\n {\n name: 'linear_status',\n description: 'Get Linear integration status',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'get_traces',\n description: 'Get detected traces (bundled tool call sequences)',\n inputSchema: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n enum: [\n 'search_driven',\n 'error_recovery',\n 'feature_implementation',\n 'refactoring',\n 'testing',\n 'exploration',\n 'debugging',\n 'documentation',\n 'build_deploy',\n 'unknown',\n ],\n description: 'Filter by trace type',\n },\n minScore: {\n type: 'number',\n description: 'Minimum importance score (0-1)',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of traces to return',\n },\n },\n },\n },\n {\n name: 'get_trace_statistics',\n description: 'Get statistics about detected traces',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'flush_traces',\n description: 'Flush any pending trace and finalize detection',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'compress_old_traces',\n description: 'Compress traces older than specified hours',\n inputSchema: {\n type: 'object',\n properties: {\n ageHours: {\n type: 'number',\n description: 'Age threshold in hours (default: 24)',\n },\n },\n },\n },\n {\n name: 'smart_context',\n description:\n 'LLM-driven context retrieval - intelligently selects relevant frames based on query',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description:\n 'Natural language query describing what context you need',\n },\n tokenBudget: {\n type: 'number',\n description:\n 'Maximum tokens to use for context (default: 4000)',\n },\n forceRefresh: {\n type: 'boolean',\n description: 'Force refresh of cached summaries',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'get_summary',\n description:\n 'Get compressed summary of project memory for analysis',\n inputSchema: {\n type: 'object',\n properties: {\n forceRefresh: {\n type: 'boolean',\n description: 'Force refresh of cached summary',\n },\n },\n },\n },\n // Discovery tools\n {\n name: 'sm_discover',\n description:\n 'Discover relevant files based on current context. Extracts keywords from active frames and searches codebase.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Optional query to focus the discovery',\n },\n depth: {\n type: 'string',\n enum: ['shallow', 'medium', 'deep'],\n description: 'Search depth',\n },\n maxFiles: {\n type: 'number',\n description: 'Maximum files to return',\n },\n },\n },\n },\n {\n name: 'sm_related_files',\n description: 'Find files related to a specific file or concept',\n inputSchema: {\n type: 'object',\n properties: {\n file: {\n type: 'string',\n description: 'File path to find related files for',\n },\n concept: {\n type: 'string',\n description: 'Concept to search for',\n },\n maxFiles: {\n type: 'number',\n description: 'Maximum files to return',\n },\n },\n },\n },\n {\n name: 'sm_session_summary',\n description:\n 'Get summary of current session with active tasks, files, and decisions',\n inputSchema: {\n type: 'object',\n properties: {\n includeFiles: {\n type: 'boolean',\n description: 'Include recently accessed files',\n },\n includeDecisions: {\n type: 'boolean',\n description: 'Include recent decisions',\n },\n },\n },\n },\n {\n name: 'sm_search',\n description:\n 'Search across StackMemory - frames, events, decisions, tasks',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query',\n },\n scope: {\n type: 'string',\n enum: ['all', 'frames', 'events', 'decisions', 'tasks'],\n description: 'Scope of search',\n },\n limit: {\n type: 'number',\n description: 'Maximum results',\n },\n },\n required: ['query'],\n },\n },\n ],\n };\n }\n );\n\n // Tool execution\n this.server.setRequestHandler(\n z.object({\n method: z.literal('tools/call'),\n params: z.object({\n name: z.string(),\n arguments: z.record(z.unknown()),\n }),\n }),\n async (request) => {\n const { name, arguments: args } = request.params;\n const callId = uuidv4();\n const startTime = Date.now();\n\n // Log tool call event before execution\n const currentFrameId = this.frameManager.getCurrentFrameId();\n if (currentFrameId) {\n this.frameManager.addEvent('tool_call', {\n tool_name: name,\n arguments: args,\n timestamp: startTime,\n });\n }\n\n // Create ToolCall for trace detection\n const toolCall: ToolCall = {\n id: callId,\n tool: name,\n arguments: args,\n timestamp: startTime,\n };\n\n let result;\n let error;\n\n try {\n switch (name) {\n case 'get_context':\n result = await this.handleGetContext(args);\n break;\n\n case 'add_decision':\n result = await this.handleAddDecision(args);\n break;\n\n case 'start_frame':\n result = await this.handleStartFrame(args);\n break;\n\n case 'close_frame':\n result = await this.handleCloseFrame(args);\n break;\n\n case 'add_anchor':\n result = await this.handleAddAnchor(args);\n break;\n\n case 'get_hot_stack':\n result = await this.handleGetHotStack(args);\n break;\n\n case 'create_task':\n result = await this.handleCreateTask(args);\n break;\n\n case 'update_task_status':\n result = await this.handleUpdateTaskStatus(args);\n break;\n\n case 'get_active_tasks':\n result = await this.handleGetActiveTasks(args);\n break;\n\n case 'get_task_metrics':\n result = await this.handleGetTaskMetrics(args);\n break;\n\n case 'add_task_dependency':\n result = await this.handleAddTaskDependency(args);\n break;\n\n case 'linear_sync':\n result = await this.handleLinearSync(args);\n break;\n\n case 'linear_update_task':\n result = await this.handleLinearUpdateTask(args);\n break;\n\n case 'linear_get_tasks':\n result = await this.handleLinearGetTasks(args);\n break;\n\n case 'linear_status':\n result = await this.handleLinearStatus(args);\n break;\n\n case 'get_traces':\n result = await this.handleGetTraces(args);\n break;\n\n case 'get_trace_statistics':\n result = await this.handleGetTraceStatistics(args);\n break;\n\n case 'flush_traces':\n result = await this.handleFlushTraces(args);\n break;\n\n case 'compress_old_traces':\n result = await this.handleCompressOldTraces(args);\n break;\n\n case 'smart_context':\n result = await this.handleSmartContext(args);\n break;\n\n case 'get_summary':\n result = await this.handleGetSummary(args);\n break;\n\n // Discovery tools\n case 'sm_discover':\n result = await this.handleSmDiscover(args);\n break;\n\n case 'sm_related_files':\n result = await this.handleSmRelatedFiles(args);\n break;\n\n case 'sm_session_summary':\n result = await this.handleSmSessionSummary(args);\n break;\n\n case 'sm_search':\n result = await this.handleSmSearch(args);\n break;\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (err: unknown) {\n error = err instanceof Error ? err : new Error(String(err));\n toolCall.error = error.message;\n throw err;\n } finally {\n const endTime = Date.now();\n\n // Log tool result event after execution (success or failure)\n // Skip for close_frame since the frame no longer exists after closing\n if (currentFrameId && name !== 'close_frame') {\n try {\n this.frameManager.addEvent('tool_result', {\n tool_name: name,\n success: !error,\n result: error ? { error: error.message } : result,\n timestamp: endTime,\n });\n } catch {\n // Frame may have been closed, ignore logging error\n }\n }\n\n // Update tool call with results and add to trace detector\n toolCall.result = error ? undefined : result;\n toolCall.duration = endTime - startTime;\n\n // Extract files affected if available from result or args\n if (args.file_path || args.path) {\n toolCall.filesAffected = [args.file_path || args.path].filter(\n Boolean\n ) as string[];\n } else if ((result as any)?.files) {\n const files = (result as any).files;\n toolCall.filesAffected = Array.isArray(files) ? files : [files];\n }\n\n // Add to trace detector\n this.traceDetector.addToolCall(toolCall);\n }\n\n return result;\n }\n );\n }\n\n private async handleGetContext(args: any) {\n const { query = '', limit = 10 } = args;\n\n // Get relevant contexts\n const contexts = Array.from(this.contexts.values())\n .sort((a, b) => b.importance - a.importance)\n .slice(0, limit);\n\n // Update access counts\n contexts.forEach((ctx) => {\n this.db\n .prepare(\n `\n UPDATE contexts \n SET last_accessed = unixepoch(), \n access_count = access_count + 1\n WHERE id = ?\n `\n )\n .run(ctx.id);\n });\n\n // Format response\n const response = contexts\n .map(\n (ctx) =>\n `[${ctx.type.toUpperCase()}] (importance: ${ctx.importance.toFixed(2)})\\n${ctx.content}`\n )\n .join('\\n\\n---\\n\\n');\n\n // Log for attention tracking\n this.logAttention(query, response);\n\n return {\n content: [\n {\n type: 'text',\n text:\n response ||\n 'No context available yet. Start adding decisions and information!',\n },\n ],\n };\n }\n\n private async handleAddDecision(args: any) {\n const { content, type = 'decision' } = args;\n\n const id = this.addContext(type, content, 0.8);\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2713 Added ${type}: ${content}\\nID: ${id}`,\n },\n ],\n };\n }\n\n private async handleStartFrame(args: unknown) {\n const { name, type, constraints } = validateInput(\n StartFrameSchema,\n args,\n 'start_frame'\n );\n\n const inputs: Record<string, any> = {};\n if (constraints) {\n inputs.constraints = constraints;\n }\n\n const frameId = this.frameManager.createFrame({\n type: type as FrameType,\n name,\n inputs,\n });\n\n // Log event\n this.frameManager.addEvent('user_message', {\n action: 'start_frame',\n name,\n type,\n constraints,\n });\n\n // Add as context\n this.addContext('active_frame', `Active frame: ${name} (${type})`, 0.9);\n\n const stackDepth = this.frameManager.getStackDepth();\n\n return {\n content: [\n {\n type: 'text',\n text: `\uD83D\uDE80 Started ${type}: ${name}\\nFrame ID: ${frameId}\\nStack depth: ${stackDepth}`,\n },\n ],\n };\n }\n\n private async handleCloseFrame(args: any) {\n const { result, outputs } = args;\n const currentFrameId = this.frameManager.getCurrentFrameId();\n\n if (!currentFrameId) {\n return {\n content: [\n {\n type: 'text',\n text: '\u26A0\uFE0F No active frame to close',\n },\n ],\n };\n }\n\n // Log completion event\n this.frameManager.addEvent('assistant_message', {\n action: 'close_frame',\n result,\n outputs,\n });\n\n this.frameManager.closeFrame(currentFrameId, outputs);\n\n const newStackDepth = this.frameManager.getStackDepth();\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 Closed frame: ${result || 'completed'}\\nStack depth: ${newStackDepth}`,\n },\n ],\n };\n }\n\n private async handleAddAnchor(args: unknown) {\n const { type, text, priority } = validateInput(\n AddAnchorSchema,\n args,\n 'add_anchor'\n );\n\n const anchorId = this.frameManager.addAnchor(type, text, priority);\n\n // Log anchor creation\n this.frameManager.addEvent('decision', {\n anchor_type: type,\n text,\n priority,\n anchor_id: anchorId,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `\uD83D\uDCCC Added ${type}: ${text}\\nAnchor ID: ${anchorId}`,\n },\n ],\n };\n }\n\n private async handleGetHotStack(args: any) {\n const { maxEvents = 20 } = args;\n\n const hotStack = this.frameManager.getHotStackContext(maxEvents);\n const activePath = this.frameManager.getActiveFramePath();\n\n if (hotStack.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: '\uD83D\uDCDA No active frames. Start a frame with start_frame tool.',\n },\n ],\n };\n }\n\n let response = '\uD83D\uDCDA **Active Call Stack:**\\n\\n';\n\n activePath.forEach((frame, index) => {\n const indent = ' '.repeat(index);\n const context = hotStack[index];\n\n response += `${indent}${index + 1}. **${frame.name}** (${frame.type})\\n`;\n\n if (context && context.anchors && context.anchors.length > 0) {\n response += `${indent} \uD83D\uDCCC ${context.anchors.length} anchors\\n`;\n }\n\n if (context && context.recentEvents && context.recentEvents.length > 0) {\n response += `${indent} \uD83D\uDCDD ${context.recentEvents.length} recent events\\n`;\n }\n\n response += '\\n';\n });\n\n response += `**Total stack depth:** ${hotStack.length}`;\n\n // Log stack access\n this.frameManager.addEvent('observation', {\n action: 'get_hot_stack',\n stack_depth: hotStack.length,\n total_anchors: hotStack.reduce(\n (sum, frame) => sum + frame.anchors.length,\n 0\n ),\n total_events: hotStack.reduce(\n (sum, frame) => sum + frame.recentEvents.length,\n 0\n ),\n });\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n }\n\n private logAttention(query: string, response: string) {\n // Simple attention logging for analysis\n this.db\n .prepare(\n `\n INSERT INTO attention_log (query, response)\n VALUES (?, ?)\n `\n )\n .run(query, response);\n }\n\n private async handleCreateTask(args: unknown) {\n const validated = validateInput(CreateTaskSchema, args, 'create_task');\n const { title, description, priority, tags } = validated;\n const { estimatedEffort, dependsOn } = args as any; // Legacy fields\n const currentFrameId = this.frameManager.getCurrentFrameId();\n\n if (!currentFrameId) {\n return {\n content: [\n {\n type: 'text',\n text: '\u26A0\uFE0F No active frame. Start a frame first with start_frame tool.',\n },\n ],\n };\n }\n\n const taskId = this.taskStore.createTask({\n title,\n description,\n priority: priority as TaskPriority,\n frameId: currentFrameId,\n dependsOn,\n tags,\n estimatedEffort,\n });\n\n // Log task creation event\n this.frameManager.addEvent('decision', {\n action: 'create_task',\n task_id: taskId,\n title,\n priority: priority || 'medium',\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 Created task: ${title}\\nID: ${taskId}\\nFrame: ${currentFrameId}\\nStored in: .stackmemory/tasks.jsonl`,\n },\n ],\n };\n }\n\n private async handleUpdateTaskStatus(args: any) {\n const { taskId, status, reason } = args;\n\n try {\n this.taskStore.updateTaskStatus(taskId, status as TaskStatus, reason);\n\n // Log status change event\n this.frameManager.addEvent('observation', {\n action: 'update_task_status',\n task_id: taskId,\n new_status: status,\n reason,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 Updated task ${taskId} to ${status}${reason ? `\\nReason: ${reason}` : ''}`,\n },\n ],\n };\n } catch (error: unknown) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to update task: ${error}`,\n },\n ],\n };\n }\n }\n\n private async handleGetActiveTasks(args: any) {\n const { frameId, status, priority, search, limit = 20 } = args;\n let tasks = this.taskStore.getActiveTasks(frameId);\n\n // Apply filters\n if (status) {\n tasks = tasks.filter((t) => t.status === status);\n }\n if (priority) {\n tasks = tasks.filter((t) => t.priority === priority);\n }\n if (search) {\n const searchLower = search.toLowerCase();\n tasks = tasks.filter(\n (t) =>\n t.title.toLowerCase().includes(searchLower) ||\n (t.description && t.description.toLowerCase().includes(searchLower))\n );\n }\n\n // Sort by priority (urgent first) then by created_at\n const priorityOrder = { urgent: 0, high: 1, medium: 2, low: 3 };\n tasks.sort((a, b) => {\n const pa = priorityOrder[a.priority] ?? 2;\n const pb = priorityOrder[b.priority] ?? 2;\n if (pa !== pb) return pa - pb;\n return b.created_at - a.created_at;\n });\n\n // Limit results\n tasks = tasks.slice(0, limit);\n\n if (tasks.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: search\n ? `\uD83D\uDCDD No tasks matching \"${search}\"`\n : '\uD83D\uDCDD No active tasks found',\n },\n ],\n };\n }\n\n let response = `\uD83D\uDCDD **Tasks** (${tasks.length} found)\\n\\n`;\n tasks.forEach((task) => {\n const priorityIcon =\n { urgent: '\uD83D\uDD34', high: '\uD83D\uDFE0', medium: '\uD83D\uDFE1', low: '\uD83D\uDFE2' }[task.priority] ||\n '\u26AA';\n const statusIcon =\n {\n pending: '\u23F3',\n in_progress: '\uD83D\uDD04',\n completed: '\u2705',\n blocked: '\uD83D\uDEAB',\n cancelled: '\u274C',\n }[task.status] || '\u26AA';\n const effort = task.estimated_effort\n ? ` (~${task.estimated_effort}m)`\n : '';\n\n // Extract Linear ID from title if present\n const linearMatch = task.title.match(/\\[ENG-\\d+\\]/);\n const linearId = linearMatch ? linearMatch[0] : '';\n const title = linearId\n ? task.title.replace(linearId, '').trim()\n : task.title;\n\n response += `${statusIcon} ${priorityIcon} **${linearId || task.id}** ${title}${effort}\\n`;\n if (task.description) {\n const desc = task.description.split('\\n')[0].slice(0, 100);\n response += ` ${desc}${task.description.length > 100 ? '...' : ''}\\n`;\n }\n if (task.tags && task.tags.length > 0) {\n response += ` \uD83C\uDFF7\uFE0F ${task.tags.join(', ')}\\n`;\n }\n response += '\\n';\n });\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n }\n\n private async handleGetTaskMetrics(_args: any) {\n const metrics = this.taskStore.getMetrics();\n\n let response = '\uD83D\uDCCA **Task Metrics**\\n\\n';\n response += `**Total Tasks:** ${metrics.total_tasks}\\n`;\n response += `**Completion Rate:** ${(metrics.completion_rate * 100).toFixed(1)}%\\n\\n`;\n\n response += '**By Status:**\\n';\n Object.entries(metrics.by_status).forEach(([status, count]) => {\n response += `- ${status}: ${count}\\n`;\n });\n\n response += '\\n**By Priority:**\\n';\n Object.entries(metrics.by_priority).forEach(([priority, count]) => {\n response += `- ${priority}: ${count}\\n`;\n });\n\n if (metrics.blocked_tasks > 0) {\n response += `\\n\u26A0\uFE0F **${metrics.blocked_tasks} blocked tasks**`;\n }\n\n if (metrics.avg_effort_accuracy > 0) {\n response += `\\n\uD83C\uDFAF **Effort Accuracy:** ${(metrics.avg_effort_accuracy * 100).toFixed(1)}%`;\n }\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n }\n\n private async handleAddTaskDependency(args: any) {\n const { taskId, dependsOnId } = args;\n\n try {\n this.taskStore.addDependency(taskId, dependsOnId);\n\n // Log dependency creation\n this.frameManager.addEvent('decision', {\n action: 'add_task_dependency',\n task_id: taskId,\n depends_on_id: dependsOnId,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `\uD83D\uDD17 Added dependency: ${taskId} depends on ${dependsOnId}`,\n },\n ],\n };\n } catch (error: unknown) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to add dependency: ${error}`,\n },\n ],\n };\n }\n }\n\n // Linear Integration Handlers\n private async handleLinearSync(args: any) {\n try {\n const tokens = this.linearAuthManager.loadTokens();\n\n if (!tokens) {\n return {\n content: [\n {\n type: 'text',\n text: '\u274C Linear not authenticated. Run: stackmemory linear setup',\n },\n ],\n };\n }\n\n const syncConfig = { ...DEFAULT_SYNC_CONFIG, enabled: true };\n if (args.direction) {\n syncConfig.direction = args.direction;\n }\n\n // Update sync engine configuration for this sync\n this.linearSync.updateConfig(syncConfig);\n const result = await this.linearSync.sync();\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 Linear sync completed\\n- To Linear: ${result.synced.toLinear} tasks\\n- From Linear: ${result.synced.fromLinear} tasks\\n- Updated: ${result.synced.updated} tasks`,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Linear sync failed: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleLinearUpdateTask(args: any) {\n try {\n const { LinearClient } = await import('../linear/client.js');\n\n const tokens = this.linearAuthManager.loadTokens();\n\n if (!tokens) {\n return {\n content: [\n {\n type: 'text',\n text: '\u274C Linear not authenticated. Run: stackmemory linear setup',\n },\n ],\n };\n }\n\n const client = new LinearClient({\n apiKey: tokens.accessToken,\n useBearer: true,\n onUnauthorized: async () => {\n const refreshed = await this.linearAuthManager.refreshAccessToken();\n return refreshed.accessToken;\n },\n });\n\n // Find the issue\n let issue = await client.getIssue(args.issueId);\n if (!issue) {\n issue = await client.findIssueByIdentifier(args.issueId);\n }\n\n if (!issue) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Linear issue ${args.issueId} not found`,\n },\n ],\n };\n }\n\n const updates: any = {};\n\n // Handle status update\n if (args.status) {\n const team = await client.getTeam();\n const states = await client.getWorkflowStates(team.id);\n\n const statusMap: Record<string, string> = {\n todo: 'unstarted',\n 'in-progress': 'started',\n done: 'completed',\n canceled: 'cancelled',\n };\n\n const targetType = statusMap[args.status] || args.status;\n const targetState = states.find((s: any) => s.type === targetType);\n\n if (!targetState) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Invalid status: ${args.status}`,\n },\n ],\n };\n }\n\n updates.stateId = targetState.id;\n }\n\n if (args.title) updates.title = args.title;\n if (args.description) updates.description = args.description;\n if (args.priority) updates.priority = args.priority;\n\n const updatedIssue = await client.updateIssue(issue.id, updates);\n\n // Auto-sync to local tasks after update\n this.linearSync.updateConfig({\n ...DEFAULT_SYNC_CONFIG,\n enabled: true,\n direction: 'from_linear',\n });\n const syncResult = await this.linearSync.sync();\n\n let response = `\u2705 Updated ${updatedIssue.identifier}: ${updatedIssue.title}\\n`;\n if (args.status) {\n response += `Status: ${updatedIssue.state.name}\\n`;\n }\n response += `URL: ${updatedIssue.url}\\n`;\n response += `\\n\uD83D\uDD04 Local sync: ${syncResult.synced.fromLinear} new, ${syncResult.synced.updated} updated`;\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to update Linear task: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleLinearGetTasks(args: any) {\n try {\n const { LinearClient } = await import('../linear/client.js');\n\n const tokens = this.linearAuthManager.loadTokens();\n\n if (!tokens) {\n return {\n content: [\n {\n type: 'text',\n text: '\u274C Linear not authenticated. Run: stackmemory linear setup',\n },\n ],\n };\n }\n\n const client = new LinearClient({\n apiKey: tokens.accessToken,\n useBearer: true,\n onUnauthorized: async () => {\n const refreshed = await this.linearAuthManager.refreshAccessToken();\n return refreshed.accessToken;\n },\n });\n\n let stateType: any = undefined;\n if (args.status && args.status !== 'all') {\n const statusMap: Record<string, string> = {\n todo: 'unstarted',\n 'in-progress': 'started',\n done: 'completed',\n };\n stateType = statusMap[args.status] || args.status;\n }\n\n const issues = await client.getIssues({\n stateType,\n limit: args.limit || 20,\n });\n\n if (!issues || issues.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No Linear tasks found',\n },\n ],\n };\n }\n\n let response = `\uD83D\uDCCB **Linear Tasks** (${issues.length} items)\\n\\n`;\n issues.forEach((issue: any) => {\n const priority = issue.priority ? `P${issue.priority}` : '-';\n response += `- **${issue.identifier}**: ${issue.title}\\n`;\n response += ` Status: ${issue.state.name} | Priority: ${priority}\\n`;\n if (issue.assignee) {\n response += ` Assignee: ${issue.assignee.name}\\n`;\n }\n response += ` ${issue.url}\\n\\n`;\n });\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to get Linear tasks: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleLinearStatus(_args: any) {\n try {\n const { LinearClient } = await import('../linear/client.js');\n\n const tokens = this.linearAuthManager.loadTokens();\n\n if (!tokens) {\n return {\n content: [\n {\n type: 'text',\n text: '\u274C Linear integration not configured\\nRun: stackmemory linear setup',\n },\n ],\n };\n }\n\n try {\n const client = new LinearClient({\n apiKey: tokens.accessToken,\n useBearer: true,\n onUnauthorized: async () => {\n const refreshed = await this.linearAuthManager.refreshAccessToken();\n return refreshed.accessToken;\n },\n });\n\n const viewer = await client.getViewer();\n const team = await client.getTeam();\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 **Linear Integration Status**\\n\\nConnected as: ${viewer.name} (${viewer.email})\\nTeam: ${team.name} (${team.key})\\nTokens: Valid`,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u26A0\uFE0F Linear configured but connection failed: ${error.message}`,\n },\n ],\n };\n }\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Linear status check failed: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleGetTraces(args: any) {\n const { type, minScore, limit = 20 } = args;\n\n // Flush pending traces first\n this.traceDetector.flush();\n\n let traces = this.traceDetector.getTraces();\n\n // Apply filters\n if (type) {\n traces = traces.filter((t) => t.type === type);\n }\n\n if (minScore !== undefined) {\n traces = traces.filter((t) => t.score >= minScore);\n }\n\n // Sort by score and limit\n traces = traces.sort((a, b) => b.score - a.score).slice(0, limit);\n\n // Format traces for display\n const formattedTraces = traces.map((trace) => ({\n id: trace.id,\n type: trace.type,\n score: trace.score.toFixed(2),\n summary: trace.summary,\n toolCount: trace.tools.length,\n duration: `${((trace.metadata.endTime - trace.metadata.startTime) / 1000).toFixed(1)}s`,\n filesModified: trace.metadata.filesModified.length,\n hasErrors: trace.metadata.errorsEncountered.length > 0,\n compressed: !!trace.compressed,\n }));\n\n return {\n content: [\n {\n type: 'text',\n text: `Found ${formattedTraces.length} traces:\\n\\n${formattedTraces\n .map(\n (t) =>\n `[${t.type}] Score: ${t.score} | Tools: ${t.toolCount} | Duration: ${t.duration}\\n ${t.summary}`\n )\n .join('\\n\\n')}`,\n },\n ],\n };\n }\n\n private async handleGetTraceStatistics(args: any) {\n this.traceDetector.flush();\n const stats = this.traceDetector.getStatistics();\n\n const typeBreakdown = Object.entries(stats.tracesByType)\n .map(([type, count]) => ` ${type}: ${count}`)\n .join('\\n');\n\n return {\n content: [\n {\n type: 'text',\n text: `**Trace Statistics**\\n\\nTotal Traces: ${stats.totalTraces}\nAverage Score: ${stats.averageScore.toFixed(2)}\nAverage Length: ${stats.averageLength.toFixed(1)} tools\nHigh Importance (>0.7): ${stats.highImportanceCount}\nCompressed: ${stats.compressedCount}\n\n**Trace Types:**\n${typeBreakdown}`,\n },\n ],\n };\n }\n\n private async handleFlushTraces(args: any) {\n this.traceDetector.flush();\n\n return {\n content: [\n {\n type: 'text',\n text: 'Pending traces have been flushed and finalized.',\n },\n ],\n };\n }\n\n private async handleCompressOldTraces(args: any) {\n const { ageHours = 24 } = args;\n\n const compressedCount = this.traceDetector.compressOldTraces(ageHours);\n\n return {\n content: [\n {\n type: 'text',\n text: `Compressed ${compressedCount} traces older than ${ageHours} hours.`,\n },\n ],\n };\n }\n\n private async handleSmartContext(args: any) {\n const { query, tokenBudget = 4000, forceRefresh = false } = args;\n\n try {\n const result = await this.contextRetrieval.retrieveContext(query, {\n tokenBudget,\n forceRefresh,\n });\n\n // Log the retrieval\n const currentFrameId = this.frameManager.getCurrentFrameId();\n if (currentFrameId) {\n this.frameManager.addEvent('observation', {\n action: 'smart_context',\n query,\n framesRetrieved: result.frames.length,\n tokenUsage: result.tokenUsage,\n confidence: result.analysis.confidenceScore,\n });\n }\n\n // Build response with metadata\n let response = result.context;\n response += `\\n\\n---\\n\uD83D\uDCCA **Retrieval Stats**\\n`;\n response += `- Frames included: ${result.frames.length}\\n`;\n response += `- Tokens used: ${result.tokenUsage.used}/${result.tokenUsage.budget}\\n`;\n response += `- Confidence: ${(result.analysis.confidenceScore * 100).toFixed(0)}%\\n`;\n response += `- Time: ${result.metadata.retrievalTimeMs}ms`;\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Context retrieval failed: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleGetSummary(args: any) {\n const { forceRefresh = false } = args;\n\n try {\n const summary = this.contextRetrieval.getSummary(forceRefresh);\n\n // Format the summary for display\n let response = '\uD83D\uDCCB **Compressed Memory Summary**\\n\\n';\n\n // Recent session\n response += '## Recent Session\\n';\n response += `- Frames: ${summary.recentSession.frames.length}\\n`;\n response += `- Time range: ${new Date(summary.recentSession.timeRange.start).toLocaleString()} - ${new Date(summary.recentSession.timeRange.end).toLocaleString()}\\n`;\n\n if (summary.recentSession.dominantOperations.length > 0) {\n response += `- Dominant ops: ${summary.recentSession.dominantOperations\n .slice(0, 5)\n .map((o) => `${o.operation}(${o.count})`)\n .join(', ')}\\n`;\n }\n\n if (summary.recentSession.filesTouched.length > 0) {\n response += `- Files touched: ${summary.recentSession.filesTouched\n .slice(0, 5)\n .map((f) => f.path)\n .join(', ')}\\n`;\n }\n\n if (summary.recentSession.errorsEncountered.length > 0) {\n response += `- Errors: ${summary.recentSession.errorsEncountered.length}\\n`;\n }\n\n // Historical patterns\n response += '\\n## Historical Patterns\\n';\n response += `- Topic counts: ${Object.keys(summary.historicalPatterns.topicFrameCounts).length} topics\\n`;\n\n if (summary.historicalPatterns.keyDecisions.length > 0) {\n response += `\\n### Key Decisions (${summary.historicalPatterns.keyDecisions.length})\\n`;\n summary.historicalPatterns.keyDecisions.slice(0, 5).forEach((d) => {\n response += `- ${d.text.substring(0, 80)}${d.text.length > 80 ? '...' : ''}\\n`;\n });\n }\n\n if (summary.historicalPatterns.recurringIssues.length > 0) {\n response += `\\n### Recurring Issues (${summary.historicalPatterns.recurringIssues.length})\\n`;\n summary.historicalPatterns.recurringIssues.slice(0, 3).forEach((i) => {\n response += `- ${i.issueType} (${i.occurrenceCount} times)\\n`;\n });\n }\n\n // Queryable indices\n response += '\\n## Available Indices\\n';\n response += `- By time: ${Object.keys(summary.queryableIndices.byTimeframe).length} periods\\n`;\n response += `- By file: ${Object.keys(summary.queryableIndices.byFile).length} files\\n`;\n response += `- By topic: ${Object.keys(summary.queryableIndices.byTopic).length} topics\\n`;\n response += `- By error: ${Object.keys(summary.queryableIndices.byErrorType).length} error types\\n`;\n\n // Stats\n response += `\\n## Stats\\n`;\n response += `- Total frames: ${summary.stats.totalFrames}\\n`;\n response += `- Total anchors: ${summary.stats.totalAnchors}\\n`;\n response += `- Total events: ${summary.stats.totalEvents}\\n`;\n response += `- Generated: ${new Date(summary.generatedAt).toLocaleString()}`;\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to get summary: ${error.message}`,\n },\n ],\n };\n }\n }\n\n // ============================================\n // Discovery Tools Handlers\n // ============================================\n\n private async handleSmDiscover(args: any) {\n return this.discoveryHandlers.handleDiscover(args);\n }\n\n private async handleSmRelatedFiles(args: any) {\n return this.discoveryHandlers.handleRelatedFiles(args);\n }\n\n private async handleSmSessionSummary(args: any) {\n return this.discoveryHandlers.handleSessionSummary(args);\n }\n\n private async handleSmSearch(args: any) {\n try {\n const { query, scope = 'all', limit = 20 } = args;\n\n if (!query) {\n throw new Error('Query is required');\n }\n\n const results: any[] = [];\n\n // Search frames\n if (scope === 'all' || scope === 'frames') {\n const frames = this.db\n .prepare(\n `\n SELECT frame_id, name, type, created_at, inputs, outputs\n FROM frames\n WHERE project_id = ? AND (name LIKE ? OR inputs LIKE ? OR outputs LIKE ?)\n ORDER BY created_at DESC\n LIMIT ?\n `\n )\n .all(\n this.projectId,\n `%${query}%`,\n `%${query}%`,\n `%${query}%`,\n limit\n ) as any[];\n\n frames.forEach((f) => {\n results.push({\n type: 'frame',\n id: f.frame_id,\n name: f.name,\n frameType: f.type,\n created: new Date(f.created_at * 1000).toISOString(),\n });\n });\n }\n\n // Search events\n if (scope === 'all' || scope === 'events') {\n const events = this.db\n .prepare(\n `\n SELECT e.event_id, e.type, e.data, e.timestamp, f.name as frame_name\n FROM events e\n JOIN frames f ON e.frame_id = f.frame_id\n WHERE f.project_id = ? AND e.data LIKE ?\n ORDER BY e.timestamp DESC\n LIMIT ?\n `\n )\n .all(this.projectId, `%${query}%`, limit) as any[];\n\n events.forEach((e) => {\n results.push({\n type: 'event',\n id: e.event_id,\n eventType: e.type,\n frame: e.frame_name,\n timestamp: new Date(e.timestamp * 1000).toISOString(),\n });\n });\n }\n\n // Search decisions/anchors\n if (scope === 'all' || scope === 'decisions') {\n const anchors = this.db\n .prepare(\n `\n SELECT a.anchor_id, a.type, a.text, a.priority, a.created_at, f.name as frame_name\n FROM anchors a\n JOIN frames f ON a.frame_id = f.frame_id\n WHERE f.project_id = ? AND a.text LIKE ?\n ORDER BY a.created_at DESC\n LIMIT ?\n `\n )\n .all(this.projectId, `%${query}%`, limit) as any[];\n\n anchors.forEach((a) => {\n results.push({\n type: 'decision',\n id: a.anchor_id,\n decisionType: a.type,\n text: a.text,\n priority: a.priority,\n frame: a.frame_name,\n });\n });\n }\n\n // Search tasks\n if (scope === 'all' || scope === 'tasks') {\n try {\n const tasks = this.db\n .prepare(\n `\n SELECT id, title, description, status, priority\n FROM task_cache\n WHERE title LIKE ? OR description LIKE ?\n ORDER BY created_at DESC\n LIMIT ?\n `\n )\n .all(`%${query}%`, `%${query}%`, limit) as any[];\n\n tasks.forEach((t) => {\n results.push({\n type: 'task',\n id: t.id,\n title: t.title,\n status: t.status,\n priority: t.priority,\n });\n });\n } catch {\n // Task table may not exist\n }\n }\n\n // Format results\n let response = `# Search Results for \"${query}\"\\n\\n`;\n response += `Found ${results.length} results\\n\\n`;\n\n const grouped = results.reduce(\n (acc, r) => {\n if (!acc[r.type]) acc[r.type] = [];\n acc[r.type].push(r);\n return acc;\n },\n {} as Record<string, any[]>\n );\n\n for (const [type, items] of Object.entries(grouped)) {\n response += `## ${type.charAt(0).toUpperCase() + type.slice(1)}s (${items.length})\\n`;\n for (const item of items.slice(0, 10)) {\n if (type === 'frame') {\n response += `- [${item.frameType}] ${item.name}\\n`;\n } else if (type === 'decision') {\n response += `- [${item.decisionType}] ${item.text.slice(0, 60)}...\\n`;\n } else if (type === 'task') {\n response += `- [${item.status}] ${item.title}\\n`;\n } else {\n response += `- ${JSON.stringify(item).slice(0, 80)}...\\n`;\n }\n }\n response += '\\n';\n }\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n metadata: { results, query, scope },\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Search failed: ${error.message}`,\n },\n ],\n };\n }\n }\n\n async start() {\n const transport = new StdioServerTransport();\n await this.server.connect(transport);\n console.error('StackMemory MCP Server started');\n }\n}\n\n// Export the class\nexport default LocalStackMemoryMCP;\n\n// Export function to run the server\nexport async function runMCPServer(): Promise<void> {\n const server = new LocalStackMemoryMCP();\n await server.start();\n}\n\n// Start the server\nif (import.meta.url === `file://${process.argv[1]}`) {\n const server = new LocalStackMemoryMCP();\n server.start().catch(console.error);\n}\n"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n/**\n * StackMemory MCP Server - Local Instance\n * This runs locally and provides context to Claude Code\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport Database from 'better-sqlite3';\nimport {\n validateInput,\n StartFrameSchema,\n CloseFrameSchema,\n AddAnchorSchema,\n CreateTaskSchema,\n UpdateTaskStatusSchema,\n AddDecisionSchema,\n GetContextSchema,\n} from './schemas.js';\nimport { readFileSync, existsSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { execSync } from 'child_process';\nimport { FrameManager, FrameType } from '../../core/context/index.js';\nimport {\n LinearTaskManager,\n TaskPriority,\n TaskStatus,\n} from '../../features/tasks/linear-task-manager.js';\nimport { LinearAuthManager, LinearOAuthSetup } from '../linear/auth.js';\nimport { LinearSyncEngine, DEFAULT_SYNC_CONFIG } from '../linear/sync.js';\nimport { logger } from '../../core/monitoring/logger.js';\nimport { BrowserMCPIntegration } from '../../features/browser/browser-mcp.js';\nimport { TraceDetector } from '../../core/trace/trace-detector.js';\nimport { ToolCall, Trace } from '../../core/trace/types.js';\nimport { LLMContextRetrieval } from '../../core/retrieval/index.js';\nimport { DiscoveryHandlers } from './handlers/discovery-handlers.js';\nimport { v4 as uuidv4 } from 'uuid';\n// Type-safe environment variable access\nfunction getEnv(key: string, defaultValue?: string): string {\n const value = process.env[key];\n if (value === undefined) {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Environment variable ${key} is required`);\n }\n return value;\n}\n\nfunction getOptionalEnv(key: string): string | undefined {\n return process.env[key];\n}\n\n// ============================================\n// Simple Local MCP Server\n// ============================================\n\nclass LocalStackMemoryMCP {\n private server: Server;\n private db: Database.Database;\n private projectRoot: string;\n private frameManager: FrameManager;\n private taskStore: LinearTaskManager;\n private linearAuthManager: LinearAuthManager;\n private linearSync: LinearSyncEngine;\n private projectId: string;\n private contexts: Map<string, any> = new Map();\n private browserMCP: BrowserMCPIntegration;\n private traceDetector: TraceDetector;\n private contextRetrieval: LLMContextRetrieval;\n private discoveryHandlers: DiscoveryHandlers;\n\n constructor() {\n // Find project root (where .git is)\n this.projectRoot = this.findProjectRoot();\n this.projectId = this.getProjectId();\n\n // Ensure .stackmemory directory exists\n const dbDir = join(this.projectRoot, '.stackmemory');\n if (!existsSync(dbDir)) {\n mkdirSync(dbDir, { recursive: true });\n }\n\n // Initialize database\n const dbPath = join(dbDir, 'context.db');\n this.db = new Database(dbPath);\n this.initDB();\n\n // Initialize frame manager\n this.frameManager = new FrameManager(this.db, this.projectId);\n\n // Initialize task store\n this.taskStore = new LinearTaskManager(this.projectRoot, this.db);\n\n // Initialize Linear integration\n this.linearAuthManager = new LinearAuthManager(this.projectRoot);\n this.linearSync = new LinearSyncEngine(\n this.taskStore,\n this.linearAuthManager,\n DEFAULT_SYNC_CONFIG\n );\n\n // Initialize MCP server\n this.server = new Server(\n {\n name: 'stackmemory-local',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // Initialize Browser MCP integration\n this.browserMCP = new BrowserMCPIntegration({\n headless: process.env['BROWSER_HEADLESS'] !== 'false',\n defaultViewport: { width: 1280, height: 720 },\n });\n\n // Initialize Trace Detector with database persistence\n this.traceDetector = new TraceDetector({}, undefined, this.db);\n\n // Initialize LLM Context Retrieval\n this.contextRetrieval = new LLMContextRetrieval(\n this.db,\n this.frameManager,\n this.projectId\n );\n\n // Initialize Discovery Handlers\n this.discoveryHandlers = new DiscoveryHandlers({\n frameManager: this.frameManager,\n contextRetrieval: this.contextRetrieval,\n db: this.db,\n projectRoot: this.projectRoot,\n });\n\n this.setupHandlers();\n this.loadInitialContext();\n\n // Initialize Browser MCP with this server\n this.browserMCP.initialize(this.server).catch((error) => {\n logger.error('Failed to initialize Browser MCP', error);\n });\n\n logger.info('StackMemory MCP Server initialized', {\n projectRoot: this.projectRoot,\n projectId: this.projectId,\n });\n }\n\n private findProjectRoot(): string {\n let dir = process.cwd();\n while (dir !== '/') {\n if (existsSync(join(dir, '.git'))) {\n return dir;\n }\n dir = dirname(dir);\n }\n return process.cwd();\n }\n\n private initDB() {\n // Note: Don't create frames table here - FrameManager handles the schema\n // with the full run_id, project_id, parent_frame_id columns\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS contexts (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n content TEXT NOT NULL,\n importance REAL DEFAULT 0.5,\n created_at INTEGER DEFAULT (unixepoch()),\n last_accessed INTEGER DEFAULT (unixepoch()),\n access_count INTEGER DEFAULT 1\n );\n\n CREATE TABLE IF NOT EXISTS attention_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n context_id TEXT,\n query TEXT,\n response TEXT,\n influence_score REAL,\n timestamp INTEGER DEFAULT (unixepoch())\n );\n `);\n }\n\n private loadInitialContext() {\n // Load project information\n const projectInfo = this.getProjectInfo();\n this.addContext(\n 'project',\n `Project: ${projectInfo.name}\\nPath: ${projectInfo.path}`,\n 0.9\n );\n\n // Load recent git commits\n try {\n const recentCommits = execSync('git log --oneline -10', {\n cwd: this.projectRoot,\n }).toString();\n this.addContext('git_history', `Recent commits:\\n${recentCommits}`, 0.6);\n } catch {\n // Not a git repo or git not available\n }\n\n // Load README if exists\n const readmePath = join(this.projectRoot, 'README.md');\n if (existsSync(readmePath)) {\n const readme = readFileSync(readmePath, 'utf-8');\n const summary = readme.substring(0, 500);\n this.addContext('readme', `Project README:\\n${summary}...`, 0.8);\n }\n\n // Load any existing decisions from previous sessions\n this.loadStoredContexts();\n }\n\n private getProjectId(): string {\n // Use git remote or directory path as project ID\n // Algorithm must match session-manager and project-manager\n let identifier: string;\n try {\n identifier = execSync('git config --get remote.origin.url', {\n cwd: this.projectRoot,\n stdio: 'pipe',\n timeout: 5000,\n })\n .toString()\n .trim();\n } catch {\n identifier = this.projectRoot;\n }\n\n // Normalize: remove .git suffix, replace non-alphanumeric with dashes, take last 50 chars\n const cleaned = identifier\n .replace(/\\.git$/, '')\n .replace(/[^a-zA-Z0-9-]/g, '-')\n .toLowerCase();\n\n return cleaned.substring(cleaned.length - 50) || 'unknown';\n }\n\n private getProjectInfo() {\n const packageJsonPath = join(this.projectRoot, 'package.json');\n if (existsSync(packageJsonPath)) {\n const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n return {\n name: pkg.name || 'unknown',\n path: this.projectRoot,\n };\n }\n return {\n name: this.projectRoot.split('/').pop() || 'unknown',\n path: this.projectRoot,\n };\n }\n\n private addContext(type: string, content: string, importance: number = 0.5) {\n const id = `${type}_${Date.now()}`;\n\n this.db\n .prepare(\n `\n INSERT OR REPLACE INTO contexts (id, type, content, importance)\n VALUES (?, ?, ?, ?)\n `\n )\n .run(id, type, content, importance);\n\n this.contexts.set(id, { type, content, importance });\n return id;\n }\n\n private loadStoredContexts() {\n const stored = this.db\n .prepare(\n `\n SELECT * FROM contexts \n ORDER BY importance DESC, last_accessed DESC\n LIMIT 50\n `\n )\n .all() as any[];\n\n stored.forEach((ctx) => {\n this.contexts.set(ctx.id, ctx);\n });\n }\n\n private setupHandlers() {\n // Tool listing\n this.server.setRequestHandler(\n z.object({\n method: z.literal('tools/list'),\n }),\n async () => {\n return {\n tools: [\n {\n name: 'get_context',\n description: 'Get current project context',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'What you want to know',\n },\n limit: {\n type: 'number',\n description: 'Max contexts to return',\n },\n },\n },\n },\n {\n name: 'add_decision',\n description: 'Record a decision or important information',\n inputSchema: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description: 'The decision or information',\n },\n type: {\n type: 'string',\n enum: ['decision', 'constraint', 'learning'],\n },\n },\n required: ['content', 'type'],\n },\n },\n {\n name: 'start_frame',\n description: 'Start a new frame (task/subtask) on the call stack',\n inputSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Frame name/goal' },\n type: {\n type: 'string',\n enum: [\n 'task',\n 'subtask',\n 'tool_scope',\n 'review',\n 'write',\n 'debug',\n ],\n description: 'Frame type',\n },\n constraints: {\n type: 'array',\n items: { type: 'string' },\n description: 'Constraints for this frame',\n },\n },\n required: ['name', 'type'],\n },\n },\n {\n name: 'close_frame',\n description: 'Close current frame and generate digest',\n inputSchema: {\n type: 'object',\n properties: {\n result: {\n type: 'string',\n description: 'Frame completion result',\n },\n outputs: {\n type: 'object',\n description: 'Final outputs from frame',\n },\n },\n },\n },\n {\n name: 'add_anchor',\n description:\n 'Add anchored fact/decision/constraint to current frame',\n inputSchema: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n enum: [\n 'FACT',\n 'DECISION',\n 'CONSTRAINT',\n 'INTERFACE_CONTRACT',\n 'TODO',\n 'RISK',\n ],\n description: 'Anchor type',\n },\n text: { type: 'string', description: 'Anchor content' },\n priority: {\n type: 'number',\n description: 'Priority (0-10)',\n minimum: 0,\n maximum: 10,\n },\n },\n required: ['type', 'text'],\n },\n },\n {\n name: 'get_hot_stack',\n description: 'Get current active frames and context',\n inputSchema: {\n type: 'object',\n properties: {\n maxEvents: {\n type: 'number',\n description: 'Max recent events per frame',\n default: 20,\n },\n },\n },\n },\n {\n name: 'create_task',\n description: 'Create a new task in git-tracked JSONL storage',\n inputSchema: {\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Task title' },\n description: {\n type: 'string',\n description: 'Task description',\n },\n priority: {\n type: 'string',\n enum: ['low', 'medium', 'high', 'urgent'],\n description: 'Task priority',\n },\n estimatedEffort: {\n type: 'number',\n description: 'Estimated effort in minutes',\n },\n dependsOn: {\n type: 'array',\n items: { type: 'string' },\n description: 'Task IDs this depends on',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Tags for categorization',\n },\n },\n required: ['title'],\n },\n },\n {\n name: 'update_task_status',\n description: 'Update task status with automatic time tracking',\n inputSchema: {\n type: 'object',\n properties: {\n taskId: { type: 'string', description: 'Task ID to update' },\n status: {\n type: 'string',\n enum: [\n 'pending',\n 'in_progress',\n 'completed',\n 'blocked',\n 'cancelled',\n ],\n description: 'New status',\n },\n reason: {\n type: 'string',\n description:\n 'Reason for status change (especially for blocked)',\n },\n },\n required: ['taskId', 'status'],\n },\n },\n {\n name: 'get_active_tasks',\n description: 'Get currently active tasks synced from Linear',\n inputSchema: {\n type: 'object',\n properties: {\n frameId: {\n type: 'string',\n description: 'Filter by specific frame ID',\n },\n status: {\n type: 'string',\n enum: [\n 'pending',\n 'in_progress',\n 'completed',\n 'blocked',\n 'cancelled',\n ],\n description: 'Filter by status',\n },\n priority: {\n type: 'string',\n enum: ['low', 'medium', 'high', 'urgent'],\n description: 'Filter by priority',\n },\n search: {\n type: 'string',\n description: 'Search in task title or description',\n },\n limit: {\n type: 'number',\n description: 'Max number of tasks to return (default: 20)',\n },\n },\n },\n },\n {\n name: 'get_task_metrics',\n description: 'Get project task metrics and analytics',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'add_task_dependency',\n description: 'Add dependency relationship between tasks',\n inputSchema: {\n type: 'object',\n properties: {\n taskId: {\n type: 'string',\n description: 'Task that depends on another',\n },\n dependsOnId: {\n type: 'string',\n description: 'Task ID that this depends on',\n },\n },\n required: ['taskId', 'dependsOnId'],\n },\n },\n {\n name: 'linear_sync',\n description: 'Sync tasks with Linear',\n inputSchema: {\n type: 'object',\n properties: {\n direction: {\n type: 'string',\n enum: ['bidirectional', 'to_linear', 'from_linear'],\n description: 'Sync direction',\n },\n },\n },\n },\n {\n name: 'linear_update_task',\n description: 'Update a Linear task status',\n inputSchema: {\n type: 'object',\n properties: {\n issueId: {\n type: 'string',\n description: 'Linear issue ID or identifier (e.g., STA-34)',\n },\n status: {\n type: 'string',\n enum: ['todo', 'in-progress', 'done', 'canceled'],\n description: 'New status for the task',\n },\n title: {\n type: 'string',\n description: 'Update task title (optional)',\n },\n description: {\n type: 'string',\n description: 'Update task description (optional)',\n },\n priority: {\n type: 'number',\n enum: [1, 2, 3, 4],\n description: 'Priority (1=urgent, 2=high, 3=medium, 4=low)',\n },\n },\n required: ['issueId'],\n },\n },\n {\n name: 'linear_get_tasks',\n description: 'Get Linear tasks',\n inputSchema: {\n type: 'object',\n properties: {\n status: {\n type: 'string',\n enum: ['todo', 'in-progress', 'done', 'all'],\n description: 'Filter by status',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of tasks to return',\n },\n },\n },\n },\n {\n name: 'linear_status',\n description: 'Get Linear integration status',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'get_traces',\n description: 'Get detected traces (bundled tool call sequences)',\n inputSchema: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n enum: [\n 'search_driven',\n 'error_recovery',\n 'feature_implementation',\n 'refactoring',\n 'testing',\n 'exploration',\n 'debugging',\n 'documentation',\n 'build_deploy',\n 'unknown',\n ],\n description: 'Filter by trace type',\n },\n minScore: {\n type: 'number',\n description: 'Minimum importance score (0-1)',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of traces to return',\n },\n },\n },\n },\n {\n name: 'get_trace_statistics',\n description: 'Get statistics about detected traces',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'flush_traces',\n description: 'Flush any pending trace and finalize detection',\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n {\n name: 'compress_old_traces',\n description: 'Compress traces older than specified hours',\n inputSchema: {\n type: 'object',\n properties: {\n ageHours: {\n type: 'number',\n description: 'Age threshold in hours (default: 24)',\n },\n },\n },\n },\n {\n name: 'smart_context',\n description:\n 'LLM-driven context retrieval - intelligently selects relevant frames based on query',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description:\n 'Natural language query describing what context you need',\n },\n tokenBudget: {\n type: 'number',\n description:\n 'Maximum tokens to use for context (default: 4000)',\n },\n forceRefresh: {\n type: 'boolean',\n description: 'Force refresh of cached summaries',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'get_summary',\n description:\n 'Get compressed summary of project memory for analysis',\n inputSchema: {\n type: 'object',\n properties: {\n forceRefresh: {\n type: 'boolean',\n description: 'Force refresh of cached summary',\n },\n },\n },\n },\n // Discovery tools\n {\n name: 'sm_discover',\n description:\n 'Discover relevant files based on current context. Extracts keywords from active frames and searches codebase.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Optional query to focus the discovery',\n },\n depth: {\n type: 'string',\n enum: ['shallow', 'medium', 'deep'],\n description: 'Search depth',\n },\n maxFiles: {\n type: 'number',\n description: 'Maximum files to return',\n },\n },\n },\n },\n {\n name: 'sm_related_files',\n description: 'Find files related to a specific file or concept',\n inputSchema: {\n type: 'object',\n properties: {\n file: {\n type: 'string',\n description: 'File path to find related files for',\n },\n concept: {\n type: 'string',\n description: 'Concept to search for',\n },\n maxFiles: {\n type: 'number',\n description: 'Maximum files to return',\n },\n },\n },\n },\n {\n name: 'sm_session_summary',\n description:\n 'Get summary of current session with active tasks, files, and decisions',\n inputSchema: {\n type: 'object',\n properties: {\n includeFiles: {\n type: 'boolean',\n description: 'Include recently accessed files',\n },\n includeDecisions: {\n type: 'boolean',\n description: 'Include recent decisions',\n },\n },\n },\n },\n {\n name: 'sm_search',\n description:\n 'Search across StackMemory - frames, events, decisions, tasks',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query',\n },\n scope: {\n type: 'string',\n enum: ['all', 'frames', 'events', 'decisions', 'tasks'],\n description: 'Scope of search',\n },\n limit: {\n type: 'number',\n description: 'Maximum results',\n },\n },\n required: ['query'],\n },\n },\n ],\n };\n }\n );\n\n // Tool execution\n this.server.setRequestHandler(\n z.object({\n method: z.literal('tools/call'),\n params: z.object({\n name: z.string(),\n arguments: z.record(z.unknown()),\n }),\n }),\n async (request) => {\n const { name, arguments: args } = request.params;\n const callId = uuidv4();\n const startTime = Date.now();\n\n // Log tool call event before execution\n const currentFrameId = this.frameManager.getCurrentFrameId();\n if (currentFrameId) {\n this.frameManager.addEvent('tool_call', {\n tool_name: name,\n arguments: args,\n timestamp: startTime,\n });\n }\n\n // Create ToolCall for trace detection\n const toolCall: ToolCall = {\n id: callId,\n tool: name,\n arguments: args,\n timestamp: startTime,\n };\n\n let result;\n let error;\n\n try {\n switch (name) {\n case 'get_context':\n result = await this.handleGetContext(args);\n break;\n\n case 'add_decision':\n result = await this.handleAddDecision(args);\n break;\n\n case 'start_frame':\n result = await this.handleStartFrame(args);\n break;\n\n case 'close_frame':\n result = await this.handleCloseFrame(args);\n break;\n\n case 'add_anchor':\n result = await this.handleAddAnchor(args);\n break;\n\n case 'get_hot_stack':\n result = await this.handleGetHotStack(args);\n break;\n\n case 'create_task':\n result = await this.handleCreateTask(args);\n break;\n\n case 'update_task_status':\n result = await this.handleUpdateTaskStatus(args);\n break;\n\n case 'get_active_tasks':\n result = await this.handleGetActiveTasks(args);\n break;\n\n case 'get_task_metrics':\n result = await this.handleGetTaskMetrics(args);\n break;\n\n case 'add_task_dependency':\n result = await this.handleAddTaskDependency(args);\n break;\n\n case 'linear_sync':\n result = await this.handleLinearSync(args);\n break;\n\n case 'linear_update_task':\n result = await this.handleLinearUpdateTask(args);\n break;\n\n case 'linear_get_tasks':\n result = await this.handleLinearGetTasks(args);\n break;\n\n case 'linear_status':\n result = await this.handleLinearStatus(args);\n break;\n\n case 'get_traces':\n result = await this.handleGetTraces(args);\n break;\n\n case 'get_trace_statistics':\n result = await this.handleGetTraceStatistics(args);\n break;\n\n case 'flush_traces':\n result = await this.handleFlushTraces(args);\n break;\n\n case 'compress_old_traces':\n result = await this.handleCompressOldTraces(args);\n break;\n\n case 'smart_context':\n result = await this.handleSmartContext(args);\n break;\n\n case 'get_summary':\n result = await this.handleGetSummary(args);\n break;\n\n // Discovery tools\n case 'sm_discover':\n result = await this.handleSmDiscover(args);\n break;\n\n case 'sm_related_files':\n result = await this.handleSmRelatedFiles(args);\n break;\n\n case 'sm_session_summary':\n result = await this.handleSmSessionSummary(args);\n break;\n\n case 'sm_search':\n result = await this.handleSmSearch(args);\n break;\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (err: unknown) {\n error = err instanceof Error ? err : new Error(String(err));\n toolCall.error = error.message;\n throw err;\n } finally {\n const endTime = Date.now();\n\n // Log tool result event after execution (success or failure)\n // Skip for close_frame since the frame no longer exists after closing\n if (currentFrameId && name !== 'close_frame') {\n try {\n this.frameManager.addEvent('tool_result', {\n tool_name: name,\n success: !error,\n result: error ? { error: error.message } : result,\n timestamp: endTime,\n });\n } catch {\n // Frame may have been closed, ignore logging error\n }\n }\n\n // Update tool call with results and add to trace detector\n toolCall.result = error ? undefined : result;\n toolCall.duration = endTime - startTime;\n\n // Extract files affected if available from result or args\n if (args.file_path || args.path) {\n toolCall.filesAffected = [args.file_path || args.path].filter(\n Boolean\n ) as string[];\n } else if ((result as any)?.files) {\n const files = (result as any).files;\n toolCall.filesAffected = Array.isArray(files) ? files : [files];\n }\n\n // Add to trace detector\n this.traceDetector.addToolCall(toolCall);\n }\n\n return result;\n }\n );\n }\n\n private async handleGetContext(args: any) {\n const { query = '', limit = 10 } = args;\n\n // Get relevant contexts\n const contexts = Array.from(this.contexts.values())\n .sort((a, b) => b.importance - a.importance)\n .slice(0, limit);\n\n // Update access counts\n contexts.forEach((ctx) => {\n this.db\n .prepare(\n `\n UPDATE contexts \n SET last_accessed = unixepoch(), \n access_count = access_count + 1\n WHERE id = ?\n `\n )\n .run(ctx.id);\n });\n\n // Format response\n const response = contexts\n .map(\n (ctx) =>\n `[${ctx.type.toUpperCase()}] (importance: ${ctx.importance.toFixed(2)})\\n${ctx.content}`\n )\n .join('\\n\\n---\\n\\n');\n\n // Log for attention tracking\n this.logAttention(query, response);\n\n return {\n content: [\n {\n type: 'text',\n text:\n response ||\n 'No context available yet. Start adding decisions and information!',\n },\n ],\n };\n }\n\n private async handleAddDecision(args: any) {\n const { content, type = 'decision' } = args;\n\n const id = this.addContext(type, content, 0.8);\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2713 Added ${type}: ${content}\\nID: ${id}`,\n },\n ],\n };\n }\n\n private async handleStartFrame(args: unknown) {\n const { name, type, constraints } = validateInput(\n StartFrameSchema,\n args,\n 'start_frame'\n );\n\n const inputs: Record<string, any> = {};\n if (constraints) {\n inputs.constraints = constraints;\n }\n\n const frameId = this.frameManager.createFrame({\n type: type as FrameType,\n name,\n inputs,\n });\n\n // Log event\n this.frameManager.addEvent('user_message', {\n action: 'start_frame',\n name,\n type,\n constraints,\n });\n\n // Add as context\n this.addContext('active_frame', `Active frame: ${name} (${type})`, 0.9);\n\n const stackDepth = this.frameManager.getStackDepth();\n\n return {\n content: [\n {\n type: 'text',\n text: `\uD83D\uDE80 Started ${type}: ${name}\\nFrame ID: ${frameId}\\nStack depth: ${stackDepth}`,\n },\n ],\n };\n }\n\n private async handleCloseFrame(args: any) {\n const { result, outputs } = args;\n const currentFrameId = this.frameManager.getCurrentFrameId();\n\n if (!currentFrameId) {\n return {\n content: [\n {\n type: 'text',\n text: '\u26A0\uFE0F No active frame to close',\n },\n ],\n };\n }\n\n // Log completion event\n this.frameManager.addEvent('assistant_message', {\n action: 'close_frame',\n result,\n outputs,\n });\n\n this.frameManager.closeFrame(currentFrameId, outputs);\n\n const newStackDepth = this.frameManager.getStackDepth();\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 Closed frame: ${result || 'completed'}\\nStack depth: ${newStackDepth}`,\n },\n ],\n };\n }\n\n private async handleAddAnchor(args: unknown) {\n const { type, text, priority } = validateInput(\n AddAnchorSchema,\n args,\n 'add_anchor'\n );\n\n const anchorId = this.frameManager.addAnchor(type, text, priority);\n\n // Log anchor creation\n this.frameManager.addEvent('decision', {\n anchor_type: type,\n text,\n priority,\n anchor_id: anchorId,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `\uD83D\uDCCC Added ${type}: ${text}\\nAnchor ID: ${anchorId}`,\n },\n ],\n };\n }\n\n private async handleGetHotStack(args: any) {\n const { maxEvents = 20 } = args;\n\n const hotStack = this.frameManager.getHotStackContext(maxEvents);\n const activePath = this.frameManager.getActiveFramePath();\n\n if (hotStack.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: '\uD83D\uDCDA No active frames. Start a frame with start_frame tool.',\n },\n ],\n };\n }\n\n let response = '\uD83D\uDCDA **Active Call Stack:**\\n\\n';\n\n activePath.forEach((frame, index) => {\n const indent = ' '.repeat(index);\n const context = hotStack[index];\n\n response += `${indent}${index + 1}. **${frame.name}** (${frame.type})\\n`;\n\n if (context && context.anchors && context.anchors.length > 0) {\n response += `${indent} \uD83D\uDCCC ${context.anchors.length} anchors\\n`;\n }\n\n if (context && context.recentEvents && context.recentEvents.length > 0) {\n response += `${indent} \uD83D\uDCDD ${context.recentEvents.length} recent events\\n`;\n }\n\n response += '\\n';\n });\n\n response += `**Total stack depth:** ${hotStack.length}`;\n\n // Log stack access\n this.frameManager.addEvent('observation', {\n action: 'get_hot_stack',\n stack_depth: hotStack.length,\n total_anchors: hotStack.reduce(\n (sum, frame) => sum + frame.anchors.length,\n 0\n ),\n total_events: hotStack.reduce(\n (sum, frame) => sum + frame.recentEvents.length,\n 0\n ),\n });\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n }\n\n private logAttention(query: string, response: string) {\n // Simple attention logging for analysis\n this.db\n .prepare(\n `\n INSERT INTO attention_log (query, response)\n VALUES (?, ?)\n `\n )\n .run(query, response);\n }\n\n private async handleCreateTask(args: unknown) {\n const validated = validateInput(CreateTaskSchema, args, 'create_task');\n const { title, description, priority, tags } = validated;\n const { estimatedEffort, dependsOn } = args as any; // Legacy fields\n const currentFrameId = this.frameManager.getCurrentFrameId();\n\n if (!currentFrameId) {\n return {\n content: [\n {\n type: 'text',\n text: '\u26A0\uFE0F No active frame. Start a frame first with start_frame tool.',\n },\n ],\n };\n }\n\n const taskId = this.taskStore.createTask({\n title,\n description,\n priority: priority as TaskPriority,\n frameId: currentFrameId,\n dependsOn,\n tags,\n estimatedEffort,\n });\n\n // Log task creation event\n this.frameManager.addEvent('decision', {\n action: 'create_task',\n task_id: taskId,\n title,\n priority: priority || 'medium',\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 Created task: ${title}\\nID: ${taskId}\\nFrame: ${currentFrameId}\\nStored in: .stackmemory/tasks.jsonl`,\n },\n ],\n };\n }\n\n private async handleUpdateTaskStatus(args: any) {\n const { taskId, status, reason } = args;\n\n try {\n this.taskStore.updateTaskStatus(taskId, status as TaskStatus, reason);\n\n // Log status change event\n this.frameManager.addEvent('observation', {\n action: 'update_task_status',\n task_id: taskId,\n new_status: status,\n reason,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 Updated task ${taskId} to ${status}${reason ? `\\nReason: ${reason}` : ''}`,\n },\n ],\n };\n } catch (error: unknown) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to update task: ${error}`,\n },\n ],\n };\n }\n }\n\n private async handleGetActiveTasks(args: any) {\n const { frameId, status, priority, search, limit = 20 } = args;\n let tasks = this.taskStore.getActiveTasks(frameId);\n\n // Apply filters\n if (status) {\n tasks = tasks.filter((t) => t.status === status);\n }\n if (priority) {\n tasks = tasks.filter((t) => t.priority === priority);\n }\n if (search) {\n const searchLower = search.toLowerCase();\n tasks = tasks.filter(\n (t) =>\n t.title.toLowerCase().includes(searchLower) ||\n (t.description && t.description.toLowerCase().includes(searchLower))\n );\n }\n\n // Sort by priority (urgent first) then by created_at\n const priorityOrder = { urgent: 0, high: 1, medium: 2, low: 3 };\n tasks.sort((a, b) => {\n const pa = priorityOrder[a.priority] ?? 2;\n const pb = priorityOrder[b.priority] ?? 2;\n if (pa !== pb) return pa - pb;\n return b.created_at - a.created_at;\n });\n\n // Limit results\n tasks = tasks.slice(0, limit);\n\n if (tasks.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: search\n ? `\uD83D\uDCDD No tasks matching \"${search}\"`\n : '\uD83D\uDCDD No active tasks found',\n },\n ],\n };\n }\n\n let response = `\uD83D\uDCDD **Tasks** (${tasks.length} found)\\n\\n`;\n tasks.forEach((task) => {\n const priorityIcon =\n { urgent: '\uD83D\uDD34', high: '\uD83D\uDFE0', medium: '\uD83D\uDFE1', low: '\uD83D\uDFE2' }[task.priority] ||\n '\u26AA';\n const statusIcon =\n {\n pending: '\u23F3',\n in_progress: '\uD83D\uDD04',\n completed: '\u2705',\n blocked: '\uD83D\uDEAB',\n cancelled: '\u274C',\n }[task.status] || '\u26AA';\n const effort = task.estimated_effort\n ? ` (~${task.estimated_effort}m)`\n : '';\n\n // Extract Linear ID from title if present\n const linearMatch = task.title.match(/\\[ENG-\\d+\\]/);\n const linearId = linearMatch ? linearMatch[0] : '';\n const title = linearId\n ? task.title.replace(linearId, '').trim()\n : task.title;\n\n response += `${statusIcon} ${priorityIcon} **${linearId || task.id}** ${title}${effort}\\n`;\n if (task.description) {\n const desc = task.description.split('\\n')[0].slice(0, 100);\n response += ` ${desc}${task.description.length > 100 ? '...' : ''}\\n`;\n }\n if (task.tags && task.tags.length > 0) {\n response += ` \uD83C\uDFF7\uFE0F ${task.tags.join(', ')}\\n`;\n }\n response += '\\n';\n });\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n }\n\n private async handleGetTaskMetrics(_args: any) {\n const metrics = this.taskStore.getMetrics();\n\n let response = '\uD83D\uDCCA **Task Metrics**\\n\\n';\n response += `**Total Tasks:** ${metrics.total_tasks}\\n`;\n response += `**Completion Rate:** ${(metrics.completion_rate * 100).toFixed(1)}%\\n\\n`;\n\n response += '**By Status:**\\n';\n Object.entries(metrics.by_status).forEach(([status, count]) => {\n response += `- ${status}: ${count}\\n`;\n });\n\n response += '\\n**By Priority:**\\n';\n Object.entries(metrics.by_priority).forEach(([priority, count]) => {\n response += `- ${priority}: ${count}\\n`;\n });\n\n if (metrics.blocked_tasks > 0) {\n response += `\\n\u26A0\uFE0F **${metrics.blocked_tasks} blocked tasks**`;\n }\n\n if (metrics.avg_effort_accuracy > 0) {\n response += `\\n\uD83C\uDFAF **Effort Accuracy:** ${(metrics.avg_effort_accuracy * 100).toFixed(1)}%`;\n }\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n }\n\n private async handleAddTaskDependency(args: any) {\n const { taskId, dependsOnId } = args;\n\n try {\n this.taskStore.addDependency(taskId, dependsOnId);\n\n // Log dependency creation\n this.frameManager.addEvent('decision', {\n action: 'add_task_dependency',\n task_id: taskId,\n depends_on_id: dependsOnId,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: `\uD83D\uDD17 Added dependency: ${taskId} depends on ${dependsOnId}`,\n },\n ],\n };\n } catch (error: unknown) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to add dependency: ${error}`,\n },\n ],\n };\n }\n }\n\n // Linear Integration Handlers\n private async handleLinearSync(args: any) {\n try {\n const tokens = this.linearAuthManager.loadTokens();\n\n if (!tokens) {\n return {\n content: [\n {\n type: 'text',\n text: '\u274C Linear not authenticated. Run: stackmemory linear setup',\n },\n ],\n };\n }\n\n const syncConfig = { ...DEFAULT_SYNC_CONFIG, enabled: true };\n if (args.direction) {\n syncConfig.direction = args.direction;\n }\n\n // Update sync engine configuration for this sync\n this.linearSync.updateConfig(syncConfig);\n const result = await this.linearSync.sync();\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 Linear sync completed\\n- To Linear: ${result.synced.toLinear} tasks\\n- From Linear: ${result.synced.fromLinear} tasks\\n- Updated: ${result.synced.updated} tasks`,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Linear sync failed: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleLinearUpdateTask(args: any) {\n try {\n const { LinearClient } = await import('../linear/client.js');\n\n const tokens = this.linearAuthManager.loadTokens();\n\n if (!tokens) {\n return {\n content: [\n {\n type: 'text',\n text: '\u274C Linear not authenticated. Run: stackmemory linear setup',\n },\n ],\n };\n }\n\n const client = new LinearClient({\n apiKey: tokens.accessToken,\n useBearer: true,\n onUnauthorized: async () => {\n const refreshed = await this.linearAuthManager.refreshAccessToken();\n return refreshed.accessToken;\n },\n });\n\n // Find the issue\n let issue = await client.getIssue(args.issueId);\n if (!issue) {\n issue = await client.findIssueByIdentifier(args.issueId);\n }\n\n if (!issue) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Linear issue ${args.issueId} not found`,\n },\n ],\n };\n }\n\n const updates: any = {};\n\n // Handle status update\n if (args.status) {\n const team = await client.getTeam();\n const states = await client.getWorkflowStates(team.id);\n\n const statusMap: Record<string, string> = {\n todo: 'unstarted',\n 'in-progress': 'started',\n done: 'completed',\n canceled: 'cancelled',\n };\n\n const targetType = statusMap[args.status] || args.status;\n const targetState = states.find((s: any) => s.type === targetType);\n\n if (!targetState) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Invalid status: ${args.status}`,\n },\n ],\n };\n }\n\n updates.stateId = targetState.id;\n }\n\n if (args.title) updates.title = args.title;\n if (args.description) updates.description = args.description;\n if (args.priority) updates.priority = args.priority;\n\n const updatedIssue = await client.updateIssue(issue.id, updates);\n\n // Auto-sync to local tasks after update\n this.linearSync.updateConfig({\n ...DEFAULT_SYNC_CONFIG,\n enabled: true,\n direction: 'from_linear',\n });\n const syncResult = await this.linearSync.sync();\n\n let response = `\u2705 Updated ${updatedIssue.identifier}: ${updatedIssue.title}\\n`;\n if (args.status) {\n response += `Status: ${updatedIssue.state.name}\\n`;\n }\n response += `URL: ${updatedIssue.url}\\n`;\n response += `\\n\uD83D\uDD04 Local sync: ${syncResult.synced.fromLinear} new, ${syncResult.synced.updated} updated`;\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to update Linear task: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleLinearGetTasks(args: any) {\n try {\n const { LinearClient } = await import('../linear/client.js');\n\n const tokens = this.linearAuthManager.loadTokens();\n\n if (!tokens) {\n return {\n content: [\n {\n type: 'text',\n text: '\u274C Linear not authenticated. Run: stackmemory linear setup',\n },\n ],\n };\n }\n\n const client = new LinearClient({\n apiKey: tokens.accessToken,\n useBearer: true,\n onUnauthorized: async () => {\n const refreshed = await this.linearAuthManager.refreshAccessToken();\n return refreshed.accessToken;\n },\n });\n\n let stateType: any = undefined;\n if (args.status && args.status !== 'all') {\n const statusMap: Record<string, string> = {\n todo: 'unstarted',\n 'in-progress': 'started',\n done: 'completed',\n };\n stateType = statusMap[args.status] || args.status;\n }\n\n const issues = await client.getIssues({\n stateType,\n limit: args.limit || 20,\n });\n\n if (!issues || issues.length === 0) {\n return {\n content: [\n {\n type: 'text',\n text: 'No Linear tasks found',\n },\n ],\n };\n }\n\n let response = `\uD83D\uDCCB **Linear Tasks** (${issues.length} items)\\n\\n`;\n issues.forEach((issue: any) => {\n const priority = issue.priority ? `P${issue.priority}` : '-';\n response += `- **${issue.identifier}**: ${issue.title}\\n`;\n response += ` Status: ${issue.state.name} | Priority: ${priority}\\n`;\n if (issue.assignee) {\n response += ` Assignee: ${issue.assignee.name}\\n`;\n }\n response += ` ${issue.url}\\n\\n`;\n });\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to get Linear tasks: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleLinearStatus(_args: any) {\n try {\n const { LinearClient } = await import('../linear/client.js');\n\n const tokens = this.linearAuthManager.loadTokens();\n\n if (!tokens) {\n return {\n content: [\n {\n type: 'text',\n text: '\u274C Linear integration not configured\\nRun: stackmemory linear setup',\n },\n ],\n };\n }\n\n try {\n const client = new LinearClient({\n apiKey: tokens.accessToken,\n useBearer: true,\n onUnauthorized: async () => {\n const refreshed = await this.linearAuthManager.refreshAccessToken();\n return refreshed.accessToken;\n },\n });\n\n const viewer = await client.getViewer();\n const team = await client.getTeam();\n\n return {\n content: [\n {\n type: 'text',\n text: `\u2705 **Linear Integration Status**\\n\\nConnected as: ${viewer.name} (${viewer.email})\\nTeam: ${team.name} (${team.key})\\nTokens: Valid`,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u26A0\uFE0F Linear configured but connection failed: ${error.message}`,\n },\n ],\n };\n }\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Linear status check failed: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleGetTraces(args: any) {\n const { type, minScore, limit = 20 } = args;\n\n // Flush pending traces first\n this.traceDetector.flush();\n\n let traces = this.traceDetector.getTraces();\n\n // Apply filters\n if (type) {\n traces = traces.filter((t) => t.type === type);\n }\n\n if (minScore !== undefined) {\n traces = traces.filter((t) => t.score >= minScore);\n }\n\n // Sort by score and limit\n traces = traces.sort((a, b) => b.score - a.score).slice(0, limit);\n\n // Format traces for display\n const formattedTraces = traces.map((trace) => ({\n id: trace.id,\n type: trace.type,\n score: trace.score.toFixed(2),\n summary: trace.summary,\n toolCount: trace.tools.length,\n duration: `${((trace.metadata.endTime - trace.metadata.startTime) / 1000).toFixed(1)}s`,\n filesModified: trace.metadata.filesModified.length,\n hasErrors: trace.metadata.errorsEncountered.length > 0,\n compressed: !!trace.compressed,\n }));\n\n return {\n content: [\n {\n type: 'text',\n text: `Found ${formattedTraces.length} traces:\\n\\n${formattedTraces\n .map(\n (t) =>\n `[${t.type}] Score: ${t.score} | Tools: ${t.toolCount} | Duration: ${t.duration}\\n ${t.summary}`\n )\n .join('\\n\\n')}`,\n },\n ],\n };\n }\n\n private async handleGetTraceStatistics(args: any) {\n this.traceDetector.flush();\n const stats = this.traceDetector.getStatistics();\n\n const typeBreakdown = Object.entries(stats.tracesByType)\n .map(([type, count]) => ` ${type}: ${count}`)\n .join('\\n');\n\n return {\n content: [\n {\n type: 'text',\n text: `**Trace Statistics**\\n\\nTotal Traces: ${stats.totalTraces}\nAverage Score: ${stats.averageScore.toFixed(2)}\nAverage Length: ${stats.averageLength.toFixed(1)} tools\nHigh Importance (>0.7): ${stats.highImportanceCount}\nCompressed: ${stats.compressedCount}\n\n**Trace Types:**\n${typeBreakdown}`,\n },\n ],\n };\n }\n\n private async handleFlushTraces(args: any) {\n this.traceDetector.flush();\n\n return {\n content: [\n {\n type: 'text',\n text: 'Pending traces have been flushed and finalized.',\n },\n ],\n };\n }\n\n private async handleCompressOldTraces(args: any) {\n const { ageHours = 24 } = args;\n\n const compressedCount = this.traceDetector.compressOldTraces(ageHours);\n\n return {\n content: [\n {\n type: 'text',\n text: `Compressed ${compressedCount} traces older than ${ageHours} hours.`,\n },\n ],\n };\n }\n\n private async handleSmartContext(args: any) {\n const { query, tokenBudget = 4000, forceRefresh = false } = args;\n\n try {\n const result = await this.contextRetrieval.retrieveContext(query, {\n tokenBudget,\n forceRefresh,\n });\n\n // Log the retrieval\n const currentFrameId = this.frameManager.getCurrentFrameId();\n if (currentFrameId) {\n this.frameManager.addEvent('observation', {\n action: 'smart_context',\n query,\n framesRetrieved: result.frames.length,\n tokenUsage: result.tokenUsage,\n confidence: result.analysis.confidenceScore,\n });\n }\n\n // Build response with metadata\n let response = result.context;\n response += `\\n\\n---\\n\uD83D\uDCCA **Retrieval Stats**\\n`;\n response += `- Frames included: ${result.frames.length}\\n`;\n response += `- Tokens used: ${result.tokenUsage.used}/${result.tokenUsage.budget}\\n`;\n response += `- Confidence: ${(result.analysis.confidenceScore * 100).toFixed(0)}%\\n`;\n response += `- Time: ${result.metadata.retrievalTimeMs}ms`;\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Context retrieval failed: ${error.message}`,\n },\n ],\n };\n }\n }\n\n private async handleGetSummary(args: any) {\n const { forceRefresh = false } = args;\n\n try {\n const summary = this.contextRetrieval.getSummary(forceRefresh);\n\n // Format the summary for display\n let response = '\uD83D\uDCCB **Compressed Memory Summary**\\n\\n';\n\n // Recent session\n response += '## Recent Session\\n';\n response += `- Frames: ${summary.recentSession.frames.length}\\n`;\n response += `- Time range: ${new Date(summary.recentSession.timeRange.start).toLocaleString()} - ${new Date(summary.recentSession.timeRange.end).toLocaleString()}\\n`;\n\n if (summary.recentSession.dominantOperations.length > 0) {\n response += `- Dominant ops: ${summary.recentSession.dominantOperations\n .slice(0, 5)\n .map((o) => `${o.operation}(${o.count})`)\n .join(', ')}\\n`;\n }\n\n if (summary.recentSession.filesTouched.length > 0) {\n response += `- Files touched: ${summary.recentSession.filesTouched\n .slice(0, 5)\n .map((f) => f.path)\n .join(', ')}\\n`;\n }\n\n if (summary.recentSession.errorsEncountered.length > 0) {\n response += `- Errors: ${summary.recentSession.errorsEncountered.length}\\n`;\n }\n\n // Historical patterns\n response += '\\n## Historical Patterns\\n';\n response += `- Topic counts: ${Object.keys(summary.historicalPatterns.topicFrameCounts).length} topics\\n`;\n\n if (summary.historicalPatterns.keyDecisions.length > 0) {\n response += `\\n### Key Decisions (${summary.historicalPatterns.keyDecisions.length})\\n`;\n summary.historicalPatterns.keyDecisions.slice(0, 5).forEach((d) => {\n response += `- ${d.text.substring(0, 80)}${d.text.length > 80 ? '...' : ''}\\n`;\n });\n }\n\n if (summary.historicalPatterns.recurringIssues.length > 0) {\n response += `\\n### Recurring Issues (${summary.historicalPatterns.recurringIssues.length})\\n`;\n summary.historicalPatterns.recurringIssues.slice(0, 3).forEach((i) => {\n response += `- ${i.issueType} (${i.occurrenceCount} times)\\n`;\n });\n }\n\n // Queryable indices\n response += '\\n## Available Indices\\n';\n response += `- By time: ${Object.keys(summary.queryableIndices.byTimeframe).length} periods\\n`;\n response += `- By file: ${Object.keys(summary.queryableIndices.byFile).length} files\\n`;\n response += `- By topic: ${Object.keys(summary.queryableIndices.byTopic).length} topics\\n`;\n response += `- By error: ${Object.keys(summary.queryableIndices.byErrorType).length} error types\\n`;\n\n // Stats\n response += `\\n## Stats\\n`;\n response += `- Total frames: ${summary.stats.totalFrames}\\n`;\n response += `- Total anchors: ${summary.stats.totalAnchors}\\n`;\n response += `- Total events: ${summary.stats.totalEvents}\\n`;\n response += `- Generated: ${new Date(summary.generatedAt).toLocaleString()}`;\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Failed to get summary: ${error.message}`,\n },\n ],\n };\n }\n }\n\n // ============================================\n // Discovery Tools Handlers\n // ============================================\n\n private async handleSmDiscover(args: any) {\n return this.discoveryHandlers.handleDiscover(args);\n }\n\n private async handleSmRelatedFiles(args: any) {\n return this.discoveryHandlers.handleRelatedFiles(args);\n }\n\n private async handleSmSessionSummary(args: any) {\n return this.discoveryHandlers.handleSessionSummary(args);\n }\n\n private async handleSmSearch(args: any) {\n try {\n const { query, scope = 'all', limit = 20 } = args;\n\n if (!query) {\n throw new Error('Query is required');\n }\n\n const results: any[] = [];\n\n // Search frames\n if (scope === 'all' || scope === 'frames') {\n const frames = this.db\n .prepare(\n `\n SELECT frame_id, name, type, created_at, inputs, outputs\n FROM frames\n WHERE project_id = ? AND (name LIKE ? OR inputs LIKE ? OR outputs LIKE ?)\n ORDER BY created_at DESC\n LIMIT ?\n `\n )\n .all(\n this.projectId,\n `%${query}%`,\n `%${query}%`,\n `%${query}%`,\n limit\n ) as any[];\n\n frames.forEach((f) => {\n results.push({\n type: 'frame',\n id: f.frame_id,\n name: f.name,\n frameType: f.type,\n created: new Date(f.created_at * 1000).toISOString(),\n });\n });\n }\n\n // Search events\n if (scope === 'all' || scope === 'events') {\n const events = this.db\n .prepare(\n `\n SELECT e.event_id, e.type, e.data, e.timestamp, f.name as frame_name\n FROM events e\n JOIN frames f ON e.frame_id = f.frame_id\n WHERE f.project_id = ? AND e.data LIKE ?\n ORDER BY e.timestamp DESC\n LIMIT ?\n `\n )\n .all(this.projectId, `%${query}%`, limit) as any[];\n\n events.forEach((e) => {\n results.push({\n type: 'event',\n id: e.event_id,\n eventType: e.type,\n frame: e.frame_name,\n timestamp: new Date(e.timestamp * 1000).toISOString(),\n });\n });\n }\n\n // Search decisions/anchors\n if (scope === 'all' || scope === 'decisions') {\n const anchors = this.db\n .prepare(\n `\n SELECT a.anchor_id, a.type, a.text, a.priority, a.created_at, f.name as frame_name\n FROM anchors a\n JOIN frames f ON a.frame_id = f.frame_id\n WHERE f.project_id = ? AND a.text LIKE ?\n ORDER BY a.created_at DESC\n LIMIT ?\n `\n )\n .all(this.projectId, `%${query}%`, limit) as any[];\n\n anchors.forEach((a) => {\n results.push({\n type: 'decision',\n id: a.anchor_id,\n decisionType: a.type,\n text: a.text,\n priority: a.priority,\n frame: a.frame_name,\n });\n });\n }\n\n // Search tasks\n if (scope === 'all' || scope === 'tasks') {\n try {\n const tasks = this.db\n .prepare(\n `\n SELECT id, title, description, status, priority\n FROM task_cache\n WHERE title LIKE ? OR description LIKE ?\n ORDER BY created_at DESC\n LIMIT ?\n `\n )\n .all(`%${query}%`, `%${query}%`, limit) as any[];\n\n tasks.forEach((t) => {\n results.push({\n type: 'task',\n id: t.id,\n title: t.title,\n status: t.status,\n priority: t.priority,\n });\n });\n } catch {\n // Task table may not exist\n }\n }\n\n // Format results\n let response = `# Search Results for \"${query}\"\\n\\n`;\n response += `Found ${results.length} results\\n\\n`;\n\n const grouped = results.reduce(\n (acc, r) => {\n if (!acc[r.type]) acc[r.type] = [];\n acc[r.type].push(r);\n return acc;\n },\n {} as Record<string, any[]>\n );\n\n for (const [type, items] of Object.entries(grouped)) {\n response += `## ${type.charAt(0).toUpperCase() + type.slice(1)}s (${items.length})\\n`;\n for (const item of items.slice(0, 10)) {\n if (type === 'frame') {\n response += `- [${item.frameType}] ${item.name}\\n`;\n } else if (type === 'decision') {\n response += `- [${item.decisionType}] ${item.text.slice(0, 60)}...\\n`;\n } else if (type === 'task') {\n response += `- [${item.status}] ${item.title}\\n`;\n } else {\n response += `- ${JSON.stringify(item).slice(0, 80)}...\\n`;\n }\n }\n response += '\\n';\n }\n\n return {\n content: [\n {\n type: 'text',\n text: response,\n },\n ],\n metadata: { results, query, scope },\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `\u274C Search failed: ${error.message}`,\n },\n ],\n };\n }\n }\n\n async start() {\n const transport = new StdioServerTransport();\n await this.server.connect(transport);\n console.error('StackMemory MCP Server started');\n }\n}\n\n// Export the class\nexport default LocalStackMemoryMCP;\n\n// Export function to run the server\nexport async function runMCPServer(): Promise<void> {\n const server = new LocalStackMemoryMCP();\n await server.start();\n}\n\n// Start the server\nif (import.meta.url === `file://${process.argv[1]}`) {\n const server = new LocalStackMemoryMCP();\n server.start().catch(console.error);\n}\n"],
|
|
5
5
|
"mappings": ";;;;;AAMA,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC,SAAS,SAAS;AAClB,OAAO,cAAc;AACrB;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,cAAc,YAAY,iBAAiB;AACpD,SAAS,MAAM,eAAe;AAC9B,SAAS,gBAAgB;AACzB,SAAS,oBAA+B;AACxC;AAAA,EACE;AAAA,OAGK;AACP,SAAS,yBAA2C;AACpD,SAAS,kBAAkB,2BAA2B;AACtD,SAAS,cAAc;AACvB,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;AAE9B,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAClC,SAAS,MAAM,cAAc;AAE7B,SAAS,OAAO,KAAa,cAA+B;AAC1D,QAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,MAAI,UAAU,QAAW;AACvB,QAAI,iBAAiB,OAAW,QAAO;AACvC,UAAM,IAAI,MAAM,wBAAwB,GAAG,cAAc;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,SAAS,eAAe,KAAiC;AACvD,SAAO,QAAQ,IAAI,GAAG;AACxB;AAMA,MAAM,oBAAoB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAA6B,oBAAI,IAAI;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,cAAc;AAEZ,SAAK,cAAc,KAAK,gBAAgB;AACxC,SAAK,YAAY,KAAK,aAAa;AAGnC,UAAM,QAAQ,KAAK,KAAK,aAAa,cAAc;AACnD,QAAI,CAAC,WAAW,KAAK,GAAG;AACtB,gBAAU,OAAO,EAAE,WAAW,KAAK,CAAC;AAAA,IACtC;AAGA,UAAM,SAAS,KAAK,OAAO,YAAY;AACvC,SAAK,KAAK,IAAI,SAAS,MAAM;AAC7B,SAAK,OAAO;AAGZ,SAAK,eAAe,IAAI,aAAa,KAAK,IAAI,KAAK,SAAS;AAG5D,SAAK,YAAY,IAAI,kBAAkB,KAAK,aAAa,KAAK,EAAE;AAGhE,SAAK,oBAAoB,IAAI,kBAAkB,KAAK,WAAW;AAC/D,SAAK,aAAa,IAAI;AAAA,MACpB,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,IACF;AAGA,SAAK,SAAS,IAAI;AAAA,MAChB;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,cAAc;AAAA,UACZ,OAAO,CAAC;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAGA,SAAK,aAAa,IAAI,sBAAsB;AAAA,MAC1C,UAAU,QAAQ,IAAI,kBAAkB,MAAM;AAAA,MAC9C,iBAAiB,EAAE,OAAO,MAAM,QAAQ,IAAI;AAAA,IAC9C,CAAC;AAGD,SAAK,gBAAgB,IAAI,cAAc,CAAC,GAAG,QAAW,KAAK,EAAE;AAG7D,SAAK,mBAAmB,IAAI;AAAA,MAC1B,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAGA,SAAK,oBAAoB,IAAI,kBAAkB;AAAA,MAC7C,cAAc,KAAK;AAAA,MACnB,kBAAkB,KAAK;AAAA,MACvB,IAAI,KAAK;AAAA,MACT,aAAa,KAAK;AAAA,IACpB,CAAC;AAED,SAAK,cAAc;AACnB,SAAK,mBAAmB;AAGxB,SAAK,WAAW,WAAW,KAAK,MAAM,EAAE,MAAM,CAAC,UAAU;AACvD,aAAO,MAAM,oCAAoC,KAAK;AAAA,IACxD,CAAC;AAED,WAAO,KAAK,sCAAsC;AAAA,MAChD,aAAa,KAAK;AAAA,MAClB,WAAW,KAAK;AAAA,IAClB,CAAC;AAAA,EACH;AAAA,EAEQ,kBAA0B;AAChC,QAAI,MAAM,QAAQ,IAAI;AACtB,WAAO,QAAQ,KAAK;AAClB,UAAI,WAAW,KAAK,KAAK,MAAM,CAAC,GAAG;AACjC,eAAO;AAAA,MACT;AACA,YAAM,QAAQ,GAAG;AAAA,IACnB;AACA,WAAO,QAAQ,IAAI;AAAA,EACrB;AAAA,EAEQ,SAAS;AAGf,SAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAmBZ;AAAA,EACH;AAAA,EAEQ,qBAAqB;AAE3B,UAAM,cAAc,KAAK,eAAe;AACxC,SAAK;AAAA,MACH;AAAA,MACA,YAAY,YAAY,IAAI;AAAA,QAAW,YAAY,IAAI;AAAA,MACvD;AAAA,IACF;AAGA,QAAI;AACF,YAAM,gBAAgB,SAAS,yBAAyB;AAAA,QACtD,KAAK,KAAK;AAAA,MACZ,CAAC,EAAE,SAAS;AACZ,WAAK,WAAW,eAAe;AAAA,EAAoB,aAAa,IAAI,GAAG;AAAA,IACzE,QAAQ;AAAA,IAER;AAGA,UAAM,aAAa,KAAK,KAAK,aAAa,WAAW;AACrD,QAAI,WAAW,UAAU,GAAG;AAC1B,YAAM,SAAS,aAAa,YAAY,OAAO;AAC/C,YAAM,UAAU,OAAO,UAAU,GAAG,GAAG;AACvC,WAAK,WAAW,UAAU;AAAA,EAAoB,OAAO,OAAO,GAAG;AAAA,IACjE;AAGA,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEQ,eAAuB;AAG7B,QAAI;AACJ,QAAI;AACF,mBAAa,SAAS,sCAAsC;AAAA,QAC1D,KAAK,KAAK;AAAA,QACV,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC,EACE,SAAS,EACT,KAAK;AAAA,IACV,QAAQ;AACN,mBAAa,KAAK;AAAA,IACpB;AAGA,UAAM,UAAU,WACb,QAAQ,UAAU,EAAE,EACpB,QAAQ,kBAAkB,GAAG,EAC7B,YAAY;AAEf,WAAO,QAAQ,UAAU,QAAQ,SAAS,EAAE,KAAK;AAAA,EACnD;AAAA,EAEQ,iBAAiB;AACvB,UAAM,kBAAkB,KAAK,KAAK,aAAa,cAAc;AAC7D,QAAI,WAAW,eAAe,GAAG;AAC/B,YAAM,MAAM,KAAK,MAAM,aAAa,iBAAiB,OAAO,CAAC;AAC7D,aAAO;AAAA,QACL,MAAM,IAAI,QAAQ;AAAA,QAClB,MAAM,KAAK;AAAA,MACb;AAAA,IACF;AACA,WAAO;AAAA,MACL,MAAM,KAAK,YAAY,MAAM,GAAG,EAAE,IAAI,KAAK;AAAA,MAC3C,MAAM,KAAK;AAAA,IACb;AAAA,EACF;AAAA,EAEQ,WAAW,MAAc,SAAiB,aAAqB,KAAK;AAC1E,UAAM,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC;AAEhC,SAAK,GACF;AAAA,MACC;AAAA;AAAA;AAAA;AAAA,IAIF,EACC,IAAI,IAAI,MAAM,SAAS,UAAU;AAEpC,SAAK,SAAS,IAAI,IAAI,EAAE,MAAM,SAAS,WAAW,CAAC;AACnD,WAAO;AAAA,EACT;AAAA,EAEQ,qBAAqB;AAC3B,UAAM,SAAS,KAAK,GACjB;AAAA,MACC;AAAA;AAAA;AAAA;AAAA;AAAA,IAKF,EACC,IAAI;AAEP,WAAO,QAAQ,CAAC,QAAQ;AACtB,WAAK,SAAS,IAAI,IAAI,IAAI,GAAG;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAgB;AAEtB,SAAK,OAAO;AAAA,MACV,EAAE,OAAO;AAAA,QACP,QAAQ,EAAE,QAAQ,YAAY;AAAA,MAChC,CAAC;AAAA,MACD,YAAY;AACV,eAAO;AAAA,UACL,OAAO;AAAA,YACL;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,SAAS;AAAA,oBACP,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,MAAM;AAAA,oBACJ,MAAM;AAAA,oBACN,MAAM,CAAC,YAAY,cAAc,UAAU;AAAA,kBAC7C;AAAA,gBACF;AAAA,gBACA,UAAU,CAAC,WAAW,MAAM;AAAA,cAC9B;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,MAAM,EAAE,MAAM,UAAU,aAAa,kBAAkB;AAAA,kBACvD,MAAM;AAAA,oBACJ,MAAM;AAAA,oBACN,MAAM;AAAA,sBACJ;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,oBACF;AAAA,oBACA,aAAa;AAAA,kBACf;AAAA,kBACA,aAAa;AAAA,oBACX,MAAM;AAAA,oBACN,OAAO,EAAE,MAAM,SAAS;AAAA,oBACxB,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,gBACA,UAAU,CAAC,QAAQ,MAAM;AAAA,cAC3B;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,QAAQ;AAAA,oBACN,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,SAAS;AAAA,oBACP,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aACE;AAAA,cACF,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,MAAM;AAAA,oBACJ,MAAM;AAAA,oBACN,MAAM;AAAA,sBACJ;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,oBACF;AAAA,oBACA,aAAa;AAAA,kBACf;AAAA,kBACA,MAAM,EAAE,MAAM,UAAU,aAAa,iBAAiB;AAAA,kBACtD,UAAU;AAAA,oBACR,MAAM;AAAA,oBACN,aAAa;AAAA,oBACb,SAAS;AAAA,oBACT,SAAS;AAAA,kBACX;AAAA,gBACF;AAAA,gBACA,UAAU,CAAC,QAAQ,MAAM;AAAA,cAC3B;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,WAAW;AAAA,oBACT,MAAM;AAAA,oBACN,aAAa;AAAA,oBACb,SAAS;AAAA,kBACX;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,OAAO,EAAE,MAAM,UAAU,aAAa,aAAa;AAAA,kBACnD,aAAa;AAAA,oBACX,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,UAAU;AAAA,oBACR,MAAM;AAAA,oBACN,MAAM,CAAC,OAAO,UAAU,QAAQ,QAAQ;AAAA,oBACxC,aAAa;AAAA,kBACf;AAAA,kBACA,iBAAiB;AAAA,oBACf,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,WAAW;AAAA,oBACT,MAAM;AAAA,oBACN,OAAO,EAAE,MAAM,SAAS;AAAA,oBACxB,aAAa;AAAA,kBACf;AAAA,kBACA,MAAM;AAAA,oBACJ,MAAM;AAAA,oBACN,OAAO,EAAE,MAAM,SAAS;AAAA,oBACxB,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,gBACA,UAAU,CAAC,OAAO;AAAA,cACpB;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,QAAQ,EAAE,MAAM,UAAU,aAAa,oBAAoB;AAAA,kBAC3D,QAAQ;AAAA,oBACN,MAAM;AAAA,oBACN,MAAM;AAAA,sBACJ;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,oBACF;AAAA,oBACA,aAAa;AAAA,kBACf;AAAA,kBACA,QAAQ;AAAA,oBACN,MAAM;AAAA,oBACN,aACE;AAAA,kBACJ;AAAA,gBACF;AAAA,gBACA,UAAU,CAAC,UAAU,QAAQ;AAAA,cAC/B;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,SAAS;AAAA,oBACP,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,QAAQ;AAAA,oBACN,MAAM;AAAA,oBACN,MAAM;AAAA,sBACJ;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,oBACF;AAAA,oBACA,aAAa;AAAA,kBACf;AAAA,kBACA,UAAU;AAAA,oBACR,MAAM;AAAA,oBACN,MAAM,CAAC,OAAO,UAAU,QAAQ,QAAQ;AAAA,oBACxC,aAAa;AAAA,kBACf;AAAA,kBACA,QAAQ;AAAA,oBACN,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY,CAAC;AAAA,cACf;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,QAAQ;AAAA,oBACN,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,aAAa;AAAA,oBACX,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,gBACA,UAAU,CAAC,UAAU,aAAa;AAAA,cACpC;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,WAAW;AAAA,oBACT,MAAM;AAAA,oBACN,MAAM,CAAC,iBAAiB,aAAa,aAAa;AAAA,oBAClD,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,SAAS;AAAA,oBACP,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,QAAQ;AAAA,oBACN,MAAM;AAAA,oBACN,MAAM,CAAC,QAAQ,eAAe,QAAQ,UAAU;AAAA,oBAChD,aAAa;AAAA,kBACf;AAAA,kBACA,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,aAAa;AAAA,oBACX,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,UAAU;AAAA,oBACR,MAAM;AAAA,oBACN,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,oBACjB,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,gBACA,UAAU,CAAC,SAAS;AAAA,cACtB;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,QAAQ;AAAA,oBACN,MAAM;AAAA,oBACN,MAAM,CAAC,QAAQ,eAAe,QAAQ,KAAK;AAAA,oBAC3C,aAAa;AAAA,kBACf;AAAA,kBACA,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY,CAAC;AAAA,cACf;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,MAAM;AAAA,oBACJ,MAAM;AAAA,oBACN,MAAM;AAAA,sBACJ;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA,oBACF;AAAA,oBACA,aAAa;AAAA,kBACf;AAAA,kBACA,UAAU;AAAA,oBACR,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY,CAAC;AAAA,cACf;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY,CAAC;AAAA,cACf;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,UAAU;AAAA,oBACR,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aACE;AAAA,cACF,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aACE;AAAA,kBACJ;AAAA,kBACA,aAAa;AAAA,oBACX,MAAM;AAAA,oBACN,aACE;AAAA,kBACJ;AAAA,kBACA,cAAc;AAAA,oBACZ,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,gBACA,UAAU,CAAC,OAAO;AAAA,cACpB;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aACE;AAAA,cACF,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,cAAc;AAAA,oBACZ,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA;AAAA,YAEA;AAAA,cACE,MAAM;AAAA,cACN,aACE;AAAA,cACF,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,MAAM,CAAC,WAAW,UAAU,MAAM;AAAA,oBAClC,aAAa;AAAA,kBACf;AAAA,kBACA,UAAU;AAAA,oBACR,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aAAa;AAAA,cACb,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,MAAM;AAAA,oBACJ,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,SAAS;AAAA,oBACP,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,UAAU;AAAA,oBACR,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aACE;AAAA,cACF,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,cAAc;AAAA,oBACZ,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,kBAAkB;AAAA,oBAChB,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,aACE;AAAA,cACF,aAAa;AAAA,gBACX,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,kBACA,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,MAAM,CAAC,OAAO,UAAU,UAAU,aAAa,OAAO;AAAA,oBACtD,aAAa;AAAA,kBACf;AAAA,kBACA,OAAO;AAAA,oBACL,MAAM;AAAA,oBACN,aAAa;AAAA,kBACf;AAAA,gBACF;AAAA,gBACA,UAAU,CAAC,OAAO;AAAA,cACpB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,SAAK,OAAO;AAAA,MACV,EAAE,OAAO;AAAA,QACP,QAAQ,EAAE,QAAQ,YAAY;AAAA,QAC9B,QAAQ,EAAE,OAAO;AAAA,UACf,MAAM,EAAE,OAAO;AAAA,UACf,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,QACjC,CAAC;AAAA,MACH,CAAC;AAAA,MACD,OAAO,YAAY;AACjB,cAAM,EAAE,MAAM,WAAW,KAAK,IAAI,QAAQ;AAC1C,cAAM,SAAS,OAAO;AACtB,cAAM,YAAY,KAAK,IAAI;AAG3B,cAAM,iBAAiB,KAAK,aAAa,kBAAkB;AAC3D,YAAI,gBAAgB;AAClB,eAAK,aAAa,SAAS,aAAa;AAAA,YACtC,WAAW;AAAA,YACX,WAAW;AAAA,YACX,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAGA,cAAM,WAAqB;AAAA,UACzB,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,WAAW;AAAA,UACX,WAAW;AAAA,QACb;AAEA,YAAI;AACJ,YAAI;AAEJ,YAAI;AACF,kBAAQ,MAAM;AAAA,YACZ,KAAK;AACH,uBAAS,MAAM,KAAK,iBAAiB,IAAI;AACzC;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,kBAAkB,IAAI;AAC1C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,iBAAiB,IAAI;AACzC;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,iBAAiB,IAAI;AACzC;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,gBAAgB,IAAI;AACxC;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,kBAAkB,IAAI;AAC1C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,iBAAiB,IAAI;AACzC;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,uBAAuB,IAAI;AAC/C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,qBAAqB,IAAI;AAC7C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,qBAAqB,IAAI;AAC7C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,wBAAwB,IAAI;AAChD;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,iBAAiB,IAAI;AACzC;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,uBAAuB,IAAI;AAC/C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,qBAAqB,IAAI;AAC7C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,mBAAmB,IAAI;AAC3C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,gBAAgB,IAAI;AACxC;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,yBAAyB,IAAI;AACjD;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,kBAAkB,IAAI;AAC1C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,wBAAwB,IAAI;AAChD;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,mBAAmB,IAAI;AAC3C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,iBAAiB,IAAI;AACzC;AAAA;AAAA,YAGF,KAAK;AACH,uBAAS,MAAM,KAAK,iBAAiB,IAAI;AACzC;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,qBAAqB,IAAI;AAC7C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,uBAAuB,IAAI;AAC/C;AAAA,YAEF,KAAK;AACH,uBAAS,MAAM,KAAK,eAAe,IAAI;AACvC;AAAA,YAEF;AACE,oBAAM,IAAI,MAAM,iBAAiB,IAAI,EAAE;AAAA,UAC3C;AAAA,QACF,SAAS,KAAc;AACrB,kBAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAC1D,mBAAS,QAAQ,MAAM;AACvB,gBAAM;AAAA,QACR,UAAE;AACA,gBAAM,UAAU,KAAK,IAAI;AAIzB,cAAI,kBAAkB,SAAS,eAAe;AAC5C,gBAAI;AACF,mBAAK,aAAa,SAAS,eAAe;AAAA,gBACxC,WAAW;AAAA,gBACX,SAAS,CAAC;AAAA,gBACV,QAAQ,QAAQ,EAAE,OAAO,MAAM,QAAQ,IAAI;AAAA,gBAC3C,WAAW;AAAA,cACb,CAAC;AAAA,YACH,QAAQ;AAAA,YAER;AAAA,UACF;AAGA,mBAAS,SAAS,QAAQ,SAAY;AACtC,mBAAS,WAAW,UAAU;AAG9B,cAAI,KAAK,aAAa,KAAK,MAAM;AAC/B,qBAAS,gBAAgB,CAAC,KAAK,aAAa,KAAK,IAAI,EAAE;AAAA,cACrD;AAAA,YACF;AAAA,UACF,WAAY,QAAgB,OAAO;AACjC,kBAAM,QAAS,OAAe;AAC9B,qBAAS,gBAAgB,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAAA,UAChE;AAGA,eAAK,cAAc,YAAY,QAAQ;AAAA,QACzC;AAEA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,MAAW;AACxC,UAAM,EAAE,QAAQ,IAAI,QAAQ,GAAG,IAAI;AAGnC,UAAM,WAAW,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC,EAC/C,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU,EAC1C,MAAM,GAAG,KAAK;AAGjB,aAAS,QAAQ,CAAC,QAAQ;AACxB,WAAK,GACF;AAAA,QACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMF,EACC,IAAI,IAAI,EAAE;AAAA,IACf,CAAC;AAGD,UAAM,WAAW,SACd;AAAA,MACC,CAAC,QACC,IAAI,IAAI,KAAK,YAAY,CAAC,kBAAkB,IAAI,WAAW,QAAQ,CAAC,CAAC;AAAA,EAAM,IAAI,OAAO;AAAA,IAC1F,EACC,KAAK,aAAa;AAGrB,SAAK,aAAa,OAAO,QAAQ;AAEjC,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MACE,YACA;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,kBAAkB,MAAW;AACzC,UAAM,EAAE,SAAS,OAAO,WAAW,IAAI;AAEvC,UAAM,KAAK,KAAK,WAAW,MAAM,SAAS,GAAG;AAE7C,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,gBAAW,IAAI,KAAK,OAAO;AAAA,MAAS,EAAE;AAAA,QAC9C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,MAAe;AAC5C,UAAM,EAAE,MAAM,MAAM,YAAY,IAAI;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,SAA8B,CAAC;AACrC,QAAI,aAAa;AACf,aAAO,cAAc;AAAA,IACvB;AAEA,UAAM,UAAU,KAAK,aAAa,YAAY;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGD,SAAK,aAAa,SAAS,gBAAgB;AAAA,MACzC,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGD,SAAK,WAAW,gBAAgB,iBAAiB,IAAI,KAAK,IAAI,KAAK,GAAG;AAEtE,UAAM,aAAa,KAAK,aAAa,cAAc;AAEnD,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,qBAAc,IAAI,KAAK,IAAI;AAAA,YAAe,OAAO;AAAA,eAAkB,UAAU;AAAA,QACrF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,MAAW;AACxC,UAAM,EAAE,QAAQ,QAAQ,IAAI;AAC5B,UAAM,iBAAiB,KAAK,aAAa,kBAAkB;AAE3D,QAAI,CAAC,gBAAgB;AACnB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,SAAK,aAAa,SAAS,qBAAqB;AAAA,MAC9C,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,aAAa,WAAW,gBAAgB,OAAO;AAEpD,UAAM,gBAAgB,KAAK,aAAa,cAAc;AAEtD,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,wBAAmB,UAAU,WAAW;AAAA,eAAkB,aAAa;AAAA,QAC/E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,MAAe;AAC3C,UAAM,EAAE,MAAM,MAAM,SAAS,IAAI;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,aAAa,UAAU,MAAM,MAAM,QAAQ;AAGjE,SAAK,aAAa,SAAS,YAAY;AAAA,MACrC,aAAa;AAAA,MACb;AAAA,MACA;AAAA,MACA,WAAW;AAAA,IACb,CAAC;AAED,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,mBAAY,IAAI,KAAK,IAAI;AAAA,aAAgB,QAAQ;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,kBAAkB,MAAW;AACzC,UAAM,EAAE,YAAY,GAAG,IAAI;AAE3B,UAAM,WAAW,KAAK,aAAa,mBAAmB,SAAS;AAC/D,UAAM,aAAa,KAAK,aAAa,mBAAmB;AAExD,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,WAAW;AAEf,eAAW,QAAQ,CAAC,OAAO,UAAU;AACnC,YAAM,SAAS,KAAK,OAAO,KAAK;AAChC,YAAM,UAAU,SAAS,KAAK;AAE9B,kBAAY,GAAG,MAAM,GAAG,QAAQ,CAAC,OAAO,MAAM,IAAI,OAAO,MAAM,IAAI;AAAA;AAEnE,UAAI,WAAW,QAAQ,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAC5D,oBAAY,GAAG,MAAM,gBAAS,QAAQ,QAAQ,MAAM;AAAA;AAAA,MACtD;AAEA,UAAI,WAAW,QAAQ,gBAAgB,QAAQ,aAAa,SAAS,GAAG;AACtE,oBAAY,GAAG,MAAM,gBAAS,QAAQ,aAAa,MAAM;AAAA;AAAA,MAC3D;AAEA,kBAAY;AAAA,IACd,CAAC;AAED,gBAAY,0BAA0B,SAAS,MAAM;AAGrD,SAAK,aAAa,SAAS,eAAe;AAAA,MACxC,QAAQ;AAAA,MACR,aAAa,SAAS;AAAA,MACtB,eAAe,SAAS;AAAA,QACtB,CAAC,KAAK,UAAU,MAAM,MAAM,QAAQ;AAAA,QACpC;AAAA,MACF;AAAA,MACA,cAAc,SAAS;AAAA,QACrB,CAAC,KAAK,UAAU,MAAM,MAAM,aAAa;AAAA,QACzC;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa,OAAe,UAAkB;AAEpD,SAAK,GACF;AAAA,MACC;AAAA;AAAA;AAAA;AAAA,IAIF,EACC,IAAI,OAAO,QAAQ;AAAA,EACxB;AAAA,EAEA,MAAc,iBAAiB,MAAe;AAC5C,UAAM,YAAY,cAAc,kBAAkB,MAAM,aAAa;AACrE,UAAM,EAAE,OAAO,aAAa,UAAU,KAAK,IAAI;AAC/C,UAAM,EAAE,iBAAiB,UAAU,IAAI;AACvC,UAAM,iBAAiB,KAAK,aAAa,kBAAkB;AAE3D,QAAI,CAAC,gBAAgB;AACnB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,UAAU,WAAW;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGD,SAAK,aAAa,SAAS,YAAY;AAAA,MACrC,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,UAAU,YAAY;AAAA,IACxB,CAAC;AAED,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,wBAAmB,KAAK;AAAA,MAAS,MAAM;AAAA,SAAY,cAAc;AAAA;AAAA,QACzE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,uBAAuB,MAAW;AAC9C,UAAM,EAAE,QAAQ,QAAQ,OAAO,IAAI;AAEnC,QAAI;AACF,WAAK,UAAU,iBAAiB,QAAQ,QAAsB,MAAM;AAGpE,WAAK,aAAa,SAAS,eAAe;AAAA,QACxC,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,YAAY;AAAA,QACZ;AAAA,MACF,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,uBAAkB,MAAM,OAAO,MAAM,GAAG,SAAS;AAAA,UAAa,MAAM,KAAK,EAAE;AAAA,UACnF;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAgB;AACvB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,iCAA4B,KAAK;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,qBAAqB,MAAW;AAC5C,UAAM,EAAE,SAAS,QAAQ,UAAU,QAAQ,QAAQ,GAAG,IAAI;AAC1D,QAAI,QAAQ,KAAK,UAAU,eAAe,OAAO;AAGjD,QAAI,QAAQ;AACV,cAAQ,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAAA,IACjD;AACA,QAAI,UAAU;AACZ,cAAQ,MAAM,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ;AAAA,IACrD;AACA,QAAI,QAAQ;AACV,YAAM,cAAc,OAAO,YAAY;AACvC,cAAQ,MAAM;AAAA,QACZ,CAAC,MACC,EAAE,MAAM,YAAY,EAAE,SAAS,WAAW,KACzC,EAAE,eAAe,EAAE,YAAY,YAAY,EAAE,SAAS,WAAW;AAAA,MACtE;AAAA,IACF;AAGA,UAAM,gBAAgB,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,EAAE;AAC9D,UAAM,KAAK,CAAC,GAAG,MAAM;AACnB,YAAM,KAAK,cAAc,EAAE,QAAQ,KAAK;AACxC,YAAM,KAAK,cAAc,EAAE,QAAQ,KAAK;AACxC,UAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,aAAO,EAAE,aAAa,EAAE;AAAA,IAC1B,CAAC;AAGD,YAAQ,MAAM,MAAM,GAAG,KAAK;AAE5B,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,SACF,gCAAyB,MAAM,MAC/B;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,WAAW,wBAAiB,MAAM,MAAM;AAAA;AAAA;AAC5C,UAAM,QAAQ,CAAC,SAAS;AACtB,YAAM,eACJ,EAAE,QAAQ,aAAM,MAAM,aAAM,QAAQ,aAAM,KAAK,YAAK,EAAE,KAAK,QAAQ,KACnE;AACF,YAAM,aACJ;AAAA,QACE,SAAS;AAAA,QACT,aAAa;AAAA,QACb,WAAW;AAAA,QACX,SAAS;AAAA,QACT,WAAW;AAAA,MACb,EAAE,KAAK,MAAM,KAAK;AACpB,YAAM,SAAS,KAAK,mBAChB,MAAM,KAAK,gBAAgB,OAC3B;AAGJ,YAAM,cAAc,KAAK,MAAM,MAAM,aAAa;AAClD,YAAM,WAAW,cAAc,YAAY,CAAC,IAAI;AAChD,YAAM,QAAQ,WACV,KAAK,MAAM,QAAQ,UAAU,EAAE,EAAE,KAAK,IACtC,KAAK;AAET,kBAAY,GAAG,UAAU,IAAI,YAAY,MAAM,YAAY,KAAK,EAAE,MAAM,KAAK,GAAG,MAAM;AAAA;AACtF,UAAI,KAAK,aAAa;AACpB,cAAM,OAAO,KAAK,YAAY,MAAM,IAAI,EAAE,CAAC,EAAE,MAAM,GAAG,GAAG;AACzD,oBAAY,MAAM,IAAI,GAAG,KAAK,YAAY,SAAS,MAAM,QAAQ,EAAE;AAAA;AAAA,MACrE;AACA,UAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;AACrC,oBAAY,sBAAU,KAAK,KAAK,KAAK,IAAI,CAAC;AAAA;AAAA,MAC5C;AACA,kBAAY;AAAA,IACd,CAAC;AAED,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,qBAAqB,OAAY;AAC7C,UAAM,UAAU,KAAK,UAAU,WAAW;AAE1C,QAAI,WAAW;AACf,gBAAY,oBAAoB,QAAQ,WAAW;AAAA;AACnD,gBAAY,yBAAyB,QAAQ,kBAAkB,KAAK,QAAQ,CAAC,CAAC;AAAA;AAAA;AAE9E,gBAAY;AACZ,WAAO,QAAQ,QAAQ,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,KAAK,MAAM;AAC7D,kBAAY,KAAK,MAAM,KAAK,KAAK;AAAA;AAAA,IACnC,CAAC;AAED,gBAAY;AACZ,WAAO,QAAQ,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,UAAU,KAAK,MAAM;AACjE,kBAAY,KAAK,QAAQ,KAAK,KAAK;AAAA;AAAA,IACrC,CAAC;AAED,QAAI,QAAQ,gBAAgB,GAAG;AAC7B,kBAAY;AAAA,iBAAU,QAAQ,aAAa;AAAA,IAC7C;AAEA,QAAI,QAAQ,sBAAsB,GAAG;AACnC,kBAAY;AAAA,kCAA8B,QAAQ,sBAAsB,KAAK,QAAQ,CAAC,CAAC;AAAA,IACzF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,wBAAwB,MAAW;AAC/C,UAAM,EAAE,QAAQ,YAAY,IAAI;AAEhC,QAAI;AACF,WAAK,UAAU,cAAc,QAAQ,WAAW;AAGhD,WAAK,aAAa,SAAS,YAAY;AAAA,QACrC,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,eAAe;AAAA,MACjB,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,+BAAwB,MAAM,eAAe,WAAW;AAAA,UAChE;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAgB;AACvB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,oCAA+B,KAAK;AAAA,UAC5C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,iBAAiB,MAAW;AACxC,QAAI;AACF,YAAM,SAAS,KAAK,kBAAkB,WAAW;AAEjD,UAAI,CAAC,QAAQ;AACX,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM,aAAa,EAAE,GAAG,qBAAqB,SAAS,KAAK;AAC3D,UAAI,KAAK,WAAW;AAClB,mBAAW,YAAY,KAAK;AAAA,MAC9B;AAGA,WAAK,WAAW,aAAa,UAAU;AACvC,YAAM,SAAS,MAAM,KAAK,WAAW,KAAK;AAE1C,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,eAAyC,OAAO,OAAO,QAAQ;AAAA,iBAA0B,OAAO,OAAO,UAAU;AAAA,aAAsB,OAAO,OAAO,OAAO;AAAA,UACpK;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAY;AACnB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,8BAAyB,MAAM,OAAO;AAAA,UAC9C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,uBAAuB,MAAW;AAC9C,QAAI;AACF,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,qBAAqB;AAE3D,YAAM,SAAS,KAAK,kBAAkB,WAAW;AAEjD,UAAI,CAAC,QAAQ;AACX,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM,SAAS,IAAI,aAAa;AAAA,QAC9B,QAAQ,OAAO;AAAA,QACf,WAAW;AAAA,QACX,gBAAgB,YAAY;AAC1B,gBAAM,YAAY,MAAM,KAAK,kBAAkB,mBAAmB;AAClE,iBAAO,UAAU;AAAA,QACnB;AAAA,MACF,CAAC;AAGD,UAAI,QAAQ,MAAM,OAAO,SAAS,KAAK,OAAO;AAC9C,UAAI,CAAC,OAAO;AACV,gBAAQ,MAAM,OAAO,sBAAsB,KAAK,OAAO;AAAA,MACzD;AAEA,UAAI,CAAC,OAAO;AACV,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM,uBAAkB,KAAK,OAAO;AAAA,YACtC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM,UAAe,CAAC;AAGtB,UAAI,KAAK,QAAQ;AACf,cAAM,OAAO,MAAM,OAAO,QAAQ;AAClC,cAAM,SAAS,MAAM,OAAO,kBAAkB,KAAK,EAAE;AAErD,cAAM,YAAoC;AAAA,UACxC,MAAM;AAAA,UACN,eAAe;AAAA,UACf,MAAM;AAAA,UACN,UAAU;AAAA,QACZ;AAEA,cAAM,aAAa,UAAU,KAAK,MAAM,KAAK,KAAK;AAClD,cAAM,cAAc,OAAO,KAAK,CAAC,MAAW,EAAE,SAAS,UAAU;AAEjE,YAAI,CAAC,aAAa;AAChB,iBAAO;AAAA,YACL,SAAS;AAAA,cACP;AAAA,gBACE,MAAM;AAAA,gBACN,MAAM,0BAAqB,KAAK,MAAM;AAAA,cACxC;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAEA,gBAAQ,UAAU,YAAY;AAAA,MAChC;AAEA,UAAI,KAAK,MAAO,SAAQ,QAAQ,KAAK;AACrC,UAAI,KAAK,YAAa,SAAQ,cAAc,KAAK;AACjD,UAAI,KAAK,SAAU,SAAQ,WAAW,KAAK;AAE3C,YAAM,eAAe,MAAM,OAAO,YAAY,MAAM,IAAI,OAAO;AAG/D,WAAK,WAAW,aAAa;AAAA,QAC3B,GAAG;AAAA,QACH,SAAS;AAAA,QACT,WAAW;AAAA,MACb,CAAC;AACD,YAAM,aAAa,MAAM,KAAK,WAAW,KAAK;AAE9C,UAAI,WAAW,kBAAa,aAAa,UAAU,KAAK,aAAa,KAAK;AAAA;AAC1E,UAAI,KAAK,QAAQ;AACf,oBAAY,WAAW,aAAa,MAAM,IAAI;AAAA;AAAA,MAChD;AACA,kBAAY,QAAQ,aAAa,GAAG;AAAA;AACpC,kBAAY;AAAA,wBAAoB,WAAW,OAAO,UAAU,SAAS,WAAW,OAAO,OAAO;AAE9F,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAY;AACnB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,wCAAmC,MAAM,OAAO;AAAA,UACxD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,qBAAqB,MAAW;AAC5C,QAAI;AACF,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,qBAAqB;AAE3D,YAAM,SAAS,KAAK,kBAAkB,WAAW;AAEjD,UAAI,CAAC,QAAQ;AACX,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM,SAAS,IAAI,aAAa;AAAA,QAC9B,QAAQ,OAAO;AAAA,QACf,WAAW;AAAA,QACX,gBAAgB,YAAY;AAC1B,gBAAM,YAAY,MAAM,KAAK,kBAAkB,mBAAmB;AAClE,iBAAO,UAAU;AAAA,QACnB;AAAA,MACF,CAAC;AAED,UAAI,YAAiB;AACrB,UAAI,KAAK,UAAU,KAAK,WAAW,OAAO;AACxC,cAAM,YAAoC;AAAA,UACxC,MAAM;AAAA,UACN,eAAe;AAAA,UACf,MAAM;AAAA,QACR;AACA,oBAAY,UAAU,KAAK,MAAM,KAAK,KAAK;AAAA,MAC7C;AAEA,YAAM,SAAS,MAAM,OAAO,UAAU;AAAA,QACpC;AAAA,QACA,OAAO,KAAK,SAAS;AAAA,MACvB,CAAC;AAED,UAAI,CAAC,UAAU,OAAO,WAAW,GAAG;AAClC,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI,WAAW,+BAAwB,OAAO,MAAM;AAAA;AAAA;AACpD,aAAO,QAAQ,CAAC,UAAe;AAC7B,cAAM,WAAW,MAAM,WAAW,IAAI,MAAM,QAAQ,KAAK;AACzD,oBAAY,OAAO,MAAM,UAAU,OAAO,MAAM,KAAK;AAAA;AACrD,oBAAY,aAAa,MAAM,MAAM,IAAI,gBAAgB,QAAQ;AAAA;AACjE,YAAI,MAAM,UAAU;AAClB,sBAAY,eAAe,MAAM,SAAS,IAAI;AAAA;AAAA,QAChD;AACA,oBAAY,KAAK,MAAM,GAAG;AAAA;AAAA;AAAA,MAC5B,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAY;AACnB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,sCAAiC,MAAM,OAAO;AAAA,UACtD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,mBAAmB,OAAY;AAC3C,QAAI;AACF,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,qBAAqB;AAE3D,YAAM,SAAS,KAAK,kBAAkB,WAAW;AAEjD,UAAI,CAAC,QAAQ;AACX,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,IAAI,aAAa;AAAA,UAC9B,QAAQ,OAAO;AAAA,UACf,WAAW;AAAA,UACX,gBAAgB,YAAY;AAC1B,kBAAM,YAAY,MAAM,KAAK,kBAAkB,mBAAmB;AAClE,mBAAO,UAAU;AAAA,UACnB;AAAA,QACF,CAAC;AAED,cAAM,SAAS,MAAM,OAAO,UAAU;AACtC,cAAM,OAAO,MAAM,OAAO,QAAQ;AAElC,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM;AAAA;AAAA,gBAAoD,OAAO,IAAI,KAAK,OAAO,KAAK;AAAA,QAAY,KAAK,IAAI,KAAK,KAAK,GAAG;AAAA;AAAA,YAC1H;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,OAAY;AACnB,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM,yDAA+C,MAAM,OAAO;AAAA,YACpE;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAY;AACnB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,sCAAiC,MAAM,OAAO;AAAA,UACtD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,MAAW;AACvC,UAAM,EAAE,MAAM,UAAU,QAAQ,GAAG,IAAI;AAGvC,SAAK,cAAc,MAAM;AAEzB,QAAI,SAAS,KAAK,cAAc,UAAU;AAG1C,QAAI,MAAM;AACR,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,IAC/C;AAEA,QAAI,aAAa,QAAW;AAC1B,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ;AAAA,IACnD;AAGA,aAAS,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;AAGhE,UAAM,kBAAkB,OAAO,IAAI,CAAC,WAAW;AAAA,MAC7C,IAAI,MAAM;AAAA,MACV,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM,MAAM,QAAQ,CAAC;AAAA,MAC5B,SAAS,MAAM;AAAA,MACf,WAAW,MAAM,MAAM;AAAA,MACvB,UAAU,KAAK,MAAM,SAAS,UAAU,MAAM,SAAS,aAAa,KAAM,QAAQ,CAAC,CAAC;AAAA,MACpF,eAAe,MAAM,SAAS,cAAc;AAAA,MAC5C,WAAW,MAAM,SAAS,kBAAkB,SAAS;AAAA,MACrD,YAAY,CAAC,CAAC,MAAM;AAAA,IACtB,EAAE;AAEF,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,SAAS,gBAAgB,MAAM;AAAA;AAAA,EAAe,gBACjD;AAAA,YACC,CAAC,MACC,IAAI,EAAE,IAAI,YAAY,EAAE,KAAK,aAAa,EAAE,SAAS,gBAAgB,EAAE,QAAQ;AAAA,IAAO,EAAE,OAAO;AAAA,UACnG,EACC,KAAK,MAAM,CAAC;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,yBAAyB,MAAW;AAChD,SAAK,cAAc,MAAM;AACzB,UAAM,QAAQ,KAAK,cAAc,cAAc;AAE/C,UAAM,gBAAgB,OAAO,QAAQ,MAAM,YAAY,EACpD,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,KAAK,IAAI,KAAK,KAAK,EAAE,EAC5C,KAAK,IAAI;AAEZ,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA;AAAA,gBAAyC,MAAM,WAAW;AAAA,iBACzD,MAAM,aAAa,QAAQ,CAAC,CAAC;AAAA,kBAC5B,MAAM,cAAc,QAAQ,CAAC,CAAC;AAAA,0BACtB,MAAM,mBAAmB;AAAA,cACrC,MAAM,eAAe;AAAA;AAAA;AAAA,EAGjC,aAAa;AAAA,QACP;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,kBAAkB,MAAW;AACzC,SAAK,cAAc,MAAM;AAEzB,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,wBAAwB,MAAW;AAC/C,UAAM,EAAE,WAAW,GAAG,IAAI;AAE1B,UAAM,kBAAkB,KAAK,cAAc,kBAAkB,QAAQ;AAErE,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,cAAc,eAAe,sBAAsB,QAAQ;AAAA,QACnE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,mBAAmB,MAAW;AAC1C,UAAM,EAAE,OAAO,cAAc,KAAM,eAAe,MAAM,IAAI;AAE5D,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,iBAAiB,gBAAgB,OAAO;AAAA,QAChE;AAAA,QACA;AAAA,MACF,CAAC;AAGD,YAAM,iBAAiB,KAAK,aAAa,kBAAkB;AAC3D,UAAI,gBAAgB;AAClB,aAAK,aAAa,SAAS,eAAe;AAAA,UACxC,QAAQ;AAAA,UACR;AAAA,UACA,iBAAiB,OAAO,OAAO;AAAA,UAC/B,YAAY,OAAO;AAAA,UACnB,YAAY,OAAO,SAAS;AAAA,QAC9B,CAAC;AAAA,MACH;AAGA,UAAI,WAAW,OAAO;AACtB,kBAAY;AAAA;AAAA;AAAA;AAAA;AACZ,kBAAY,sBAAsB,OAAO,OAAO,MAAM;AAAA;AACtD,kBAAY,kBAAkB,OAAO,WAAW,IAAI,IAAI,OAAO,WAAW,MAAM;AAAA;AAChF,kBAAY,kBAAkB,OAAO,SAAS,kBAAkB,KAAK,QAAQ,CAAC,CAAC;AAAA;AAC/E,kBAAY,WAAW,OAAO,SAAS,eAAe;AAEtD,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAY;AACnB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,oCAA+B,MAAM,OAAO;AAAA,UACpD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,MAAW;AACxC,UAAM,EAAE,eAAe,MAAM,IAAI;AAEjC,QAAI;AACF,YAAM,UAAU,KAAK,iBAAiB,WAAW,YAAY;AAG7D,UAAI,WAAW;AAGf,kBAAY;AACZ,kBAAY,aAAa,QAAQ,cAAc,OAAO,MAAM;AAAA;AAC5D,kBAAY,iBAAiB,IAAI,KAAK,QAAQ,cAAc,UAAU,KAAK,EAAE,eAAe,CAAC,MAAM,IAAI,KAAK,QAAQ,cAAc,UAAU,GAAG,EAAE,eAAe,CAAC;AAAA;AAEjK,UAAI,QAAQ,cAAc,mBAAmB,SAAS,GAAG;AACvD,oBAAY,mBAAmB,QAAQ,cAAc,mBAClD,MAAM,GAAG,CAAC,EACV,IAAI,CAAC,MAAM,GAAG,EAAE,SAAS,IAAI,EAAE,KAAK,GAAG,EACvC,KAAK,IAAI,CAAC;AAAA;AAAA,MACf;AAEA,UAAI,QAAQ,cAAc,aAAa,SAAS,GAAG;AACjD,oBAAY,oBAAoB,QAAQ,cAAc,aACnD,MAAM,GAAG,CAAC,EACV,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,IAAI,CAAC;AAAA;AAAA,MACf;AAEA,UAAI,QAAQ,cAAc,kBAAkB,SAAS,GAAG;AACtD,oBAAY,aAAa,QAAQ,cAAc,kBAAkB,MAAM;AAAA;AAAA,MACzE;AAGA,kBAAY;AACZ,kBAAY,mBAAmB,OAAO,KAAK,QAAQ,mBAAmB,gBAAgB,EAAE,MAAM;AAAA;AAE9F,UAAI,QAAQ,mBAAmB,aAAa,SAAS,GAAG;AACtD,oBAAY;AAAA,qBAAwB,QAAQ,mBAAmB,aAAa,MAAM;AAAA;AAClF,gBAAQ,mBAAmB,aAAa,MAAM,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM;AACjE,sBAAY,KAAK,EAAE,KAAK,UAAU,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,SAAS,KAAK,QAAQ,EAAE;AAAA;AAAA,QAC5E,CAAC;AAAA,MACH;AAEA,UAAI,QAAQ,mBAAmB,gBAAgB,SAAS,GAAG;AACzD,oBAAY;AAAA,wBAA2B,QAAQ,mBAAmB,gBAAgB,MAAM;AAAA;AACxF,gBAAQ,mBAAmB,gBAAgB,MAAM,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM;AACpE,sBAAY,KAAK,EAAE,SAAS,KAAK,EAAE,eAAe;AAAA;AAAA,QACpD,CAAC;AAAA,MACH;AAGA,kBAAY;AACZ,kBAAY,cAAc,OAAO,KAAK,QAAQ,iBAAiB,WAAW,EAAE,MAAM;AAAA;AAClF,kBAAY,cAAc,OAAO,KAAK,QAAQ,iBAAiB,MAAM,EAAE,MAAM;AAAA;AAC7E,kBAAY,eAAe,OAAO,KAAK,QAAQ,iBAAiB,OAAO,EAAE,MAAM;AAAA;AAC/E,kBAAY,eAAe,OAAO,KAAK,QAAQ,iBAAiB,WAAW,EAAE,MAAM;AAAA;AAGnF,kBAAY;AAAA;AAAA;AACZ,kBAAY,mBAAmB,QAAQ,MAAM,WAAW;AAAA;AACxD,kBAAY,oBAAoB,QAAQ,MAAM,YAAY;AAAA;AAC1D,kBAAY,mBAAmB,QAAQ,MAAM,WAAW;AAAA;AACxD,kBAAY,gBAAgB,IAAI,KAAK,QAAQ,WAAW,EAAE,eAAe,CAAC;AAE1E,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAY;AACnB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,iCAA4B,MAAM,OAAO;AAAA,UACjD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBAAiB,MAAW;AACxC,WAAO,KAAK,kBAAkB,eAAe,IAAI;AAAA,EACnD;AAAA,EAEA,MAAc,qBAAqB,MAAW;AAC5C,WAAO,KAAK,kBAAkB,mBAAmB,IAAI;AAAA,EACvD;AAAA,EAEA,MAAc,uBAAuB,MAAW;AAC9C,WAAO,KAAK,kBAAkB,qBAAqB,IAAI;AAAA,EACzD;AAAA,EAEA,MAAc,eAAe,MAAW;AACtC,QAAI;AACF,YAAM,EAAE,OAAO,QAAQ,OAAO,QAAQ,GAAG,IAAI;AAE7C,UAAI,CAAC,OAAO;AACV,cAAM,IAAI,MAAM,mBAAmB;AAAA,MACrC;AAEA,YAAM,UAAiB,CAAC;AAGxB,UAAI,UAAU,SAAS,UAAU,UAAU;AACzC,cAAM,SAAS,KAAK,GACjB;AAAA,UACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOF,EACC;AAAA,UACC,KAAK;AAAA,UACL,IAAI,KAAK;AAAA,UACT,IAAI,KAAK;AAAA,UACT,IAAI,KAAK;AAAA,UACT;AAAA,QACF;AAEF,eAAO,QAAQ,CAAC,MAAM;AACpB,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,IAAI,EAAE;AAAA,YACN,MAAM,EAAE;AAAA,YACR,WAAW,EAAE;AAAA,YACb,SAAS,IAAI,KAAK,EAAE,aAAa,GAAI,EAAE,YAAY;AAAA,UACrD,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAGA,UAAI,UAAU,SAAS,UAAU,UAAU;AACzC,cAAM,SAAS,KAAK,GACjB;AAAA,UACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQF,EACC,IAAI,KAAK,WAAW,IAAI,KAAK,KAAK,KAAK;AAE1C,eAAO,QAAQ,CAAC,MAAM;AACpB,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,IAAI,EAAE;AAAA,YACN,WAAW,EAAE;AAAA,YACb,OAAO,EAAE;AAAA,YACT,WAAW,IAAI,KAAK,EAAE,YAAY,GAAI,EAAE,YAAY;AAAA,UACtD,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAGA,UAAI,UAAU,SAAS,UAAU,aAAa;AAC5C,cAAM,UAAU,KAAK,GAClB;AAAA,UACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQF,EACC,IAAI,KAAK,WAAW,IAAI,KAAK,KAAK,KAAK;AAE1C,gBAAQ,QAAQ,CAAC,MAAM;AACrB,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,IAAI,EAAE;AAAA,YACN,cAAc,EAAE;AAAA,YAChB,MAAM,EAAE;AAAA,YACR,UAAU,EAAE;AAAA,YACZ,OAAO,EAAE;AAAA,UACX,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAGA,UAAI,UAAU,SAAS,UAAU,SAAS;AACxC,YAAI;AACF,gBAAM,QAAQ,KAAK,GAChB;AAAA,YACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAOF,EACC,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK;AAExC,gBAAM,QAAQ,CAAC,MAAM;AACnB,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,IAAI,EAAE;AAAA,cACN,OAAO,EAAE;AAAA,cACT,QAAQ,EAAE;AAAA,cACV,UAAU,EAAE;AAAA,YACd,CAAC;AAAA,UACH,CAAC;AAAA,QACH,QAAQ;AAAA,QAER;AAAA,MACF;AAGA,UAAI,WAAW,yBAAyB,KAAK;AAAA;AAAA;AAC7C,kBAAY,SAAS,QAAQ,MAAM;AAAA;AAAA;AAEnC,YAAM,UAAU,QAAQ;AAAA,QACtB,CAAC,KAAK,MAAM;AACV,cAAI,CAAC,IAAI,EAAE,IAAI,EAAG,KAAI,EAAE,IAAI,IAAI,CAAC;AACjC,cAAI,EAAE,IAAI,EAAE,KAAK,CAAC;AAClB,iBAAO;AAAA,QACT;AAAA,QACA,CAAC;AAAA,MACH;AAEA,iBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AACnD,oBAAY,MAAM,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,MAAM,MAAM,MAAM;AAAA;AAChF,mBAAW,QAAQ,MAAM,MAAM,GAAG,EAAE,GAAG;AACrC,cAAI,SAAS,SAAS;AACpB,wBAAY,MAAM,KAAK,SAAS,KAAK,KAAK,IAAI;AAAA;AAAA,UAChD,WAAW,SAAS,YAAY;AAC9B,wBAAY,MAAM,KAAK,YAAY,KAAK,KAAK,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA;AAAA,UAChE,WAAW,SAAS,QAAQ;AAC1B,wBAAY,MAAM,KAAK,MAAM,KAAK,KAAK,KAAK;AAAA;AAAA,UAC9C,OAAO;AACL,wBAAY,KAAK,KAAK,UAAU,IAAI,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA;AAAA,UACpD;AAAA,QACF;AACA,oBAAY;AAAA,MACd;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,QACA,UAAU,EAAE,SAAS,OAAO,MAAM;AAAA,MACpC;AAAA,IACF,SAAS,OAAY;AACnB,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,yBAAoB,MAAM,OAAO;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ;AACZ,UAAM,YAAY,IAAI,qBAAqB;AAC3C,UAAM,KAAK,OAAO,QAAQ,SAAS;AACnC,YAAQ,MAAM,gCAAgC;AAAA,EAChD;AACF;AAGA,IAAO,iBAAQ;AAGf,eAAsB,eAA8B;AAClD,QAAM,SAAS,IAAI,oBAAoB;AACvC,QAAM,OAAO,MAAM;AACrB;AAGA,IAAI,YAAY,QAAQ,UAAU,QAAQ,KAAK,CAAC,CAAC,IAAI;AACnD,QAAM,SAAS,IAAI,oBAAoB;AACvC,SAAO,MAAM,EAAE,MAAM,QAAQ,KAAK;AACpC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -7,7 +7,7 @@ import * as fs from "fs/promises";
|
|
|
7
7
|
import * as path from "path";
|
|
8
8
|
import { execSync } from "child_process";
|
|
9
9
|
import { logger } from "../../../core/monitoring/logger.js";
|
|
10
|
-
import { FrameManager } from "../../../core/context/
|
|
10
|
+
import { FrameManager } from "../../../core/context/index.js";
|
|
11
11
|
import { SessionManager } from "../../../core/session/session-manager.js";
|
|
12
12
|
import { SQLiteAdapter } from "../../../core/database/sqlite-adapter.js";
|
|
13
13
|
import { ContextBudgetManager } from "../context/context-budget-manager.js";
|