@stackmemoryai/stackmemory 0.3.7 → 0.3.8
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 +5 -5
- package/dist/agents/core/agent-task-manager.js.map +2 -2
- package/dist/agents/verifiers/base-verifier.js +2 -2
- package/dist/agents/verifiers/base-verifier.js.map +2 -2
- package/dist/cli/claude-sm.js +0 -11
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/codex-sm.js +0 -11
- package/dist/cli/codex-sm.js.map +2 -2
- package/dist/cli/commands/chromadb.js +64 -34
- package/dist/cli/commands/chromadb.js.map +2 -2
- package/dist/cli/commands/clear.js +9 -13
- package/dist/cli/commands/clear.js.map +2 -2
- package/dist/cli/commands/config.js +43 -33
- package/dist/cli/commands/config.js.map +2 -2
- package/dist/cli/commands/context.js.map +2 -2
- package/dist/cli/commands/dashboard.js +41 -13
- package/dist/cli/commands/dashboard.js.map +2 -2
- package/dist/cli/commands/gc.js +69 -20
- package/dist/cli/commands/gc.js.map +2 -2
- package/dist/cli/commands/handoff.js.map +2 -2
- package/dist/cli/commands/infinite-storage.js +60 -19
- package/dist/cli/commands/infinite-storage.js.map +2 -2
- package/dist/cli/commands/linear-create.js +36 -8
- package/dist/cli/commands/linear-create.js.map +2 -2
- package/dist/cli/commands/linear-list.js +33 -10
- package/dist/cli/commands/linear-list.js.map +2 -2
- package/dist/cli/commands/linear-migrate.js +17 -4
- package/dist/cli/commands/linear-migrate.js.map +2 -2
- package/dist/cli/commands/linear-test.js +14 -6
- package/dist/cli/commands/linear-test.js.map +2 -2
- package/dist/cli/commands/linear-unified.js +123 -35
- package/dist/cli/commands/linear-unified.js.map +2 -2
- package/dist/cli/commands/linear.js.map +2 -2
- package/dist/cli/commands/monitor.js.map +2 -2
- package/dist/cli/commands/onboard.js +35 -8
- package/dist/cli/commands/onboard.js.map +2 -2
- package/dist/cli/commands/quality.js +2 -7
- package/dist/cli/commands/quality.js.map +2 -2
- package/dist/cli/commands/session.js +23 -6
- package/dist/cli/commands/session.js.map +2 -2
- package/dist/cli/commands/skills.js +72 -27
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/storage.js +108 -38
- package/dist/cli/commands/storage.js.map +2 -2
- package/dist/cli/commands/tui.js.map +2 -2
- package/dist/cli/commands/webhook.js +57 -18
- package/dist/cli/commands/webhook.js.map +2 -2
- package/dist/cli/commands/workflow.js +8 -15
- package/dist/cli/commands/workflow.js.map +2 -2
- package/dist/cli/commands/worktree.js +34 -13
- package/dist/cli/commands/worktree.js.map +2 -2
- package/dist/cli/index.js +0 -11
- package/dist/cli/index.js.map +2 -2
- package/dist/core/config/types.js.map +1 -1
- package/dist/core/context/auto-context.js +10 -6
- package/dist/core/context/auto-context.js.map +2 -2
- package/dist/core/context/context-bridge.js.map +2 -2
- package/dist/core/context/frame-database.js +13 -3
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-digest.js +7 -5
- package/dist/core/context/frame-digest.js.map +2 -2
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/frame-stack.js +16 -5
- package/dist/core/context/frame-stack.js.map +2 -2
- package/dist/core/context/incremental-gc.js +10 -3
- package/dist/core/context/incremental-gc.js.map +2 -2
- package/dist/core/context/index.js.map +1 -1
- package/dist/core/context/permission-manager.js.map +2 -2
- package/dist/core/context/refactored-frame-manager.js +12 -3
- package/dist/core/context/refactored-frame-manager.js.map +2 -2
- package/dist/core/context/shared-context-layer.js +4 -2
- package/dist/core/context/shared-context-layer.js.map +2 -2
- package/dist/core/database/batch-operations.js +112 -86
- package/dist/core/database/batch-operations.js.map +2 -2
- package/dist/core/database/query-cache.js +19 -9
- package/dist/core/database/query-cache.js.map +2 -2
- package/dist/core/database/sqlite-adapter.js +1 -1
- package/dist/core/database/sqlite-adapter.js.map +2 -2
- package/dist/core/digest/enhanced-hybrid-digest.js +8 -2
- package/dist/core/digest/enhanced-hybrid-digest.js.map +2 -2
- package/dist/core/errors/recovery.js +9 -2
- package/dist/core/errors/recovery.js.map +2 -2
- package/dist/core/frame/workflow-templates-stub.js.map +1 -1
- package/dist/core/frame/workflow-templates.js +40 -1
- package/dist/core/frame/workflow-templates.js.map +2 -2
- package/dist/core/monitoring/logger.js +6 -1
- package/dist/core/monitoring/logger.js.map +2 -2
- package/dist/core/monitoring/metrics.js.map +2 -2
- package/dist/core/monitoring/progress-tracker.js.map +2 -2
- package/dist/core/performance/context-cache.js.map +2 -2
- package/dist/core/performance/lazy-context-loader.js +24 -20
- package/dist/core/performance/lazy-context-loader.js.map +2 -2
- package/dist/core/performance/optimized-frame-context.js +27 -12
- package/dist/core/performance/optimized-frame-context.js.map +2 -2
- package/dist/core/performance/performance-benchmark.js +10 -6
- package/dist/core/performance/performance-benchmark.js.map +2 -2
- package/dist/core/performance/performance-profiler.js +51 -14
- package/dist/core/performance/performance-profiler.js.map +2 -2
- package/dist/core/performance/streaming-jsonl-parser.js +5 -1
- package/dist/core/performance/streaming-jsonl-parser.js.map +2 -2
- package/dist/core/projects/project-manager.js +14 -20
- package/dist/core/projects/project-manager.js.map +2 -2
- package/dist/core/retrieval/context-retriever.js.map +1 -1
- package/dist/core/retrieval/llm-context-retrieval.js.map +2 -2
- package/dist/core/session/clear-survival-stub.js +5 -1
- package/dist/core/session/clear-survival-stub.js.map +2 -2
- package/dist/core/session/clear-survival.js +35 -0
- package/dist/core/session/clear-survival.js.map +2 -2
- package/dist/core/session/index.js.map +1 -1
- package/dist/core/session/session-manager.js.map +2 -2
- package/dist/core/storage/chromadb-adapter.js +6 -2
- package/dist/core/storage/chromadb-adapter.js.map +2 -2
- package/dist/core/storage/chromadb-simple.js +17 -5
- package/dist/core/storage/chromadb-simple.js.map +2 -2
- package/dist/core/storage/infinite-storage.js +109 -46
- package/dist/core/storage/infinite-storage.js.map +2 -2
- package/dist/core/storage/railway-optimized-storage.js +48 -22
- package/dist/core/storage/railway-optimized-storage.js.map +2 -2
- package/dist/core/storage/remote-storage.js +41 -23
- package/dist/core/storage/remote-storage.js.map +2 -2
- package/dist/core/trace/cli-trace-wrapper.js +9 -2
- package/dist/core/trace/cli-trace-wrapper.js.map +2 -2
- package/dist/core/trace/db-trace-wrapper.js +96 -68
- package/dist/core/trace/db-trace-wrapper.js.map +2 -2
- package/dist/core/trace/debug-trace.js +25 -8
- package/dist/core/trace/debug-trace.js.map +2 -2
- package/dist/core/trace/index.js +6 -2
- package/dist/core/trace/index.js.map +2 -2
- package/dist/core/trace/linear-api-wrapper.js +10 -5
- package/dist/core/trace/linear-api-wrapper.js.map +2 -2
- package/dist/core/trace/trace-demo.js +14 -10
- package/dist/core/trace/trace-demo.js.map +2 -2
- package/dist/core/trace/trace-detector.js +9 -2
- package/dist/core/trace/trace-detector.js.map +2 -2
- package/dist/core/trace/types.js.map +1 -1
- package/dist/core/utils/compression.js.map +1 -1
- package/dist/core/utils/update-checker.js.map +1 -1
- package/dist/core/worktree/worktree-manager.js +18 -7
- package/dist/core/worktree/worktree-manager.js.map +2 -2
- package/dist/features/analytics/core/analytics-service.js.map +2 -2
- package/dist/features/analytics/queries/metrics-queries.js +1 -1
- package/dist/features/analytics/queries/metrics-queries.js.map +2 -2
- package/dist/features/tasks/pebbles-task-store.js.map +1 -1
- package/dist/features/tui/components/analytics-panel.js +36 -15
- package/dist/features/tui/components/analytics-panel.js.map +2 -2
- package/dist/features/tui/components/pr-tracker.js +19 -7
- package/dist/features/tui/components/pr-tracker.js.map +2 -2
- package/dist/features/tui/components/session-monitor.js +22 -9
- package/dist/features/tui/components/session-monitor.js.map +2 -2
- package/dist/features/tui/components/subagent-fleet.js +20 -13
- package/dist/features/tui/components/subagent-fleet.js.map +2 -2
- package/dist/features/tui/components/task-board.js +26 -10
- package/dist/features/tui/components/task-board.js.map +2 -2
- package/dist/features/tui/index.js.map +2 -2
- package/dist/features/tui/services/data-service.js +6 -2
- package/dist/features/tui/services/data-service.js.map +2 -2
- package/dist/features/tui/services/linear-task-reader.js +3 -1
- package/dist/features/tui/services/linear-task-reader.js.map +2 -2
- package/dist/features/tui/services/websocket-client.js +3 -1
- package/dist/features/tui/services/websocket-client.js.map +2 -2
- package/dist/features/tui/terminal-compat.js +6 -2
- package/dist/features/tui/terminal-compat.js.map +2 -2
- package/dist/features/web/client/stores/task-store.js.map +2 -2
- package/dist/features/web/server/index.js +18 -10
- package/dist/features/web/server/index.js.map +2 -2
- package/dist/integrations/linear/sync-service.js +12 -13
- package/dist/integrations/linear/sync-service.js.map +2 -2
- package/dist/integrations/linear/sync.js +174 -12
- package/dist/integrations/linear/sync.js.map +2 -2
- package/dist/integrations/linear/unified-sync.js +1 -1
- package/dist/integrations/linear/unified-sync.js.map +1 -1
- package/dist/integrations/linear/webhook-server.js +15 -16
- package/dist/integrations/linear/webhook-server.js.map +2 -2
- package/dist/mcp/stackmemory-mcp-server.js +0 -11
- package/dist/mcp/stackmemory-mcp-server.js.map +2 -2
- package/dist/servers/production/auth-middleware.js.map +2 -2
- package/dist/servers/railway/index.js.map +2 -2
- package/dist/services/config-service.js +6 -7
- package/dist/services/config-service.js.map +2 -2
- package/dist/services/context-service.js +11 -12
- package/dist/services/context-service.js.map +2 -2
- package/dist/skills/claude-skills.js +4 -2
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/dashboard-launcher.js.map +2 -2
- package/dist/skills/repo-ingestion-skill.js.map +2 -2
- package/dist/utils/env.js +46 -0
- package/dist/utils/env.js.map +7 -0
- package/dist/utils/logger.js +0 -11
- package/dist/utils/logger.js.map +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/session/clear-survival.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Clear Survival System for StackMemory\n * Inspired by Continuous-Claude's \"Clear, don't compact\" philosophy\n *\n * Allows StackMemory to survive /clear operations by:\n * 1. Detecting when context is getting full (>70%)\n * 2. Saving critical state to external ledgers\n * 3. Restoring from ledgers after /clear\n * 4. Maintaining continuity across session resets\n */\n\nimport { Frame, Trace, Context, Digest } from '../types';\nimport { FrameManager } from '../frame/frame-manager';\nimport { DatabaseManager } from '../storage/database-manager';\nimport { HandoffGenerator } from './handoff-generator';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\nexport interface ContinuityLedger {\n version: '1.0.0';\n timestamp: string;\n session_id: string;\n project: string;\n branch?: string;\n\n // Critical state to preserve\n active_frame_stack: FrameSummary[];\n key_decisions: Decision[];\n active_tasks: Task[];\n critical_context: string[];\n recent_achievements: Achievement[];\n\n // Navigation aids\n current_focus: string;\n next_actions: string[];\n warnings: string[];\n\n // Metrics for restoration\n original_token_count: number;\n compressed_token_count: number;\n compression_ratio: number;\n}\n\ninterface FrameSummary {\n id: string;\n type: string;\n description: string;\n depth: number;\n key_events: string[];\n digest?: string;\n}\n\ninterface Decision {\n id: string;\n decision: string;\n rationale: string;\n impact: 'low' | 'medium' | 'high' | 'critical';\n still_applies: boolean;\n}\n\ninterface Task {\n id: string;\n title: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'completed';\n priority: 'low' | 'medium' | 'high' | 'critical';\n context: string;\n}\n\ninterface Achievement {\n description: string;\n impact: string;\n timestamp: string;\n}\n\nexport class ClearSurvival {\n private frameManager: FrameManager;\n private dbManager: DatabaseManager;\n private handoffGenerator: HandoffGenerator;\n private ledgerPath: string;\n private continuityPath: string;\n\n // Thresholds\n private readonly CONTEXT_WARNING_THRESHOLD = 0.6; // 60%\n private readonly CONTEXT_CRITICAL_THRESHOLD = 0.7; // 70%\n private readonly CONTEXT_MAX_THRESHOLD = 0.85; // 85% - force save\n\n constructor(\n frameManager: FrameManager,\n dbManager: DatabaseManager,\n handoffGenerator: HandoffGenerator,\n projectRoot: string\n ) {\n this.frameManager = frameManager;\n this.dbManager = dbManager;\n this.handoffGenerator = handoffGenerator;\n this.ledgerPath = path.join(projectRoot, '.stackmemory', 'ledgers');\n this.continuityPath = path.join(projectRoot, '.stackmemory', 'continuity');\n }\n\n /**\n * Monitor context usage and trigger saves when needed\n */\n async monitorContextUsage(\n currentTokens: number,\n maxTokens: number\n ): Promise<'ok' | 'warning' | 'critical' | 'saved'> {\n const usage = currentTokens / maxTokens;\n\n if (usage < this.CONTEXT_WARNING_THRESHOLD) {\n return 'ok';\n }\n\n if (usage >= this.CONTEXT_MAX_THRESHOLD) {\n // Force save at 85%\n await this.saveContinuityLedger();\n return 'saved';\n }\n\n if (usage >= this.CONTEXT_CRITICAL_THRESHOLD) {\n // Suggest save at 70%\n console.warn(\n `\u26A0\uFE0F Context at ${Math.round(usage * 100)}% - Consider /clear after saving`\n );\n return 'critical';\n }\n\n // Warning at 60%\n console.warn(`Context at ${Math.round(usage * 100)}% - Approaching limit`);\n return 'warning';\n }\n\n /**\n * Save continuity ledger before /clear\n */\n async saveContinuityLedger(): Promise<ContinuityLedger> {\n const sessionId = await this.dbManager.getCurrentSessionId();\n const session = await this.dbManager.getSession(sessionId);\n\n // Get current state\n const frameStack = await this.getCompressedFrameStack();\n const decisions = await this.getCriticalDecisions();\n const tasks = await this.getActiveTasks();\n const context = await this.getCriticalContext();\n const achievements = await this.getRecentAchievements();\n\n // Calculate token counts (simplified)\n const originalTokens = await this.estimateCurrentTokens();\n const compressedTokens = this.estimateLedgerTokens(\n frameStack,\n decisions,\n tasks\n );\n\n const ledger: ContinuityLedger = {\n version: '1.0.0',\n timestamp: new Date().toISOString(),\n session_id: sessionId,\n project: session?.project || 'unknown',\n branch: session?.metadata?.branch,\n\n active_frame_stack: frameStack,\n key_decisions: decisions,\n active_tasks: tasks,\n critical_context: context,\n recent_achievements: achievements,\n\n current_focus: await this.getCurrentFocus(),\n next_actions: await this.suggestNextActions(tasks),\n warnings: await this.getWarnings(),\n\n original_token_count: originalTokens,\n compressed_token_count: compressedTokens,\n compression_ratio: originalTokens / compressedTokens,\n };\n\n // Save to file (overwrites previous continuity ledger)\n await this.saveLedgerToFile(ledger);\n\n // Also create a timestamped backup\n await this.saveBackupLedger(ledger);\n\n console.log(\n `\u2705 Continuity ledger saved (${Math.round(ledger.compression_ratio)}x compression)`\n );\n\n return ledger;\n }\n\n /**\n * Restore from continuity ledger after /clear\n */\n async restoreFromLedger(): Promise<boolean> {\n try {\n const ledger = await this.loadLatestLedger();\n if (!ledger) {\n console.log('No continuity ledger found');\n return false;\n }\n\n console.log(`\uD83D\uDCDA Restoring from ledger (${ledger.timestamp})`);\n\n // Restore frame stack structure (not full content)\n await this.restoreFrameStructure(ledger.active_frame_stack);\n\n // Restore key decisions as anchors\n await this.restoreDecisions(ledger.key_decisions);\n\n // Restore active tasks\n await this.restoreTasks(ledger.active_tasks);\n\n // Log restoration summary\n console.log(`\u2705 Restored:`);\n console.log(` - ${ledger.active_frame_stack.length} frames`);\n console.log(` - ${ledger.key_decisions.length} decisions`);\n console.log(` - ${ledger.active_tasks.length} tasks`);\n console.log(` - Current focus: ${ledger.current_focus}`);\n\n if (ledger.warnings.length > 0) {\n console.warn(`\u26A0\uFE0F Warnings:`, ledger.warnings);\n }\n\n return true;\n } catch (error: unknown) {\n console.error('Failed to restore from ledger:', error);\n return false;\n }\n }\n\n /**\n * Generate markdown summary for human review\n */\n async generateLedgerMarkdown(ledger: ContinuityLedger): Promise<string> {\n const lines: string[] = [\n `# Continuity Ledger`,\n `**Saved**: ${new Date(ledger.timestamp).toLocaleString()}`,\n `**Project**: ${ledger.project}${ledger.branch ? ` (${ledger.branch})` : ''}`,\n `**Compression**: ${Math.round(ledger.compression_ratio)}x (${ledger.original_token_count} \u2192 ${ledger.compressed_token_count} tokens)`,\n '',\n\n `## \uD83C\uDFAF Current Focus`,\n ledger.current_focus,\n '',\n\n `## \uD83D\uDCDA Active Frame Stack (${ledger.active_frame_stack.length})`,\n ...ledger.active_frame_stack.map(\n (f) => `${' '.repeat(f.depth)}\u2514\u2500 ${f.type}: ${f.description}`\n ),\n '',\n\n `## \uD83C\uDFAF Active Tasks (${ledger.active_tasks.filter((t) => t.status !== 'completed').length})`,\n ...ledger.active_tasks\n .filter((t) => t.status !== 'completed')\n .sort((a, b) => {\n const priority = { critical: 0, high: 1, medium: 2, low: 3 };\n return priority[a.priority] - priority[b.priority];\n })\n .map((t) => `- [${t.priority}] ${t.title} (${t.status})`),\n '',\n\n `## \uD83D\uDD11 Key Decisions`,\n ...ledger.key_decisions\n .filter((d) => d.still_applies)\n .map((d) => `- **${d.decision}**\\n ${d.rationale}`),\n '',\n\n `## \u2705 Recent Achievements`,\n ...ledger.recent_achievements.map(\n (a) => `- ${a.description} \u2192 ${a.impact}`\n ),\n '',\n\n `## \u27A1\uFE0F Next Actions`,\n ...ledger.next_actions.map((a, i) => `${i + 1}. ${a}`),\n '',\n\n ledger.warnings.length > 0 ? `## \u26A0\uFE0F Warnings` : '',\n ...ledger.warnings.map((w) => `- ${w}`),\n ];\n\n return lines.filter((l) => l !== '').join('\\n');\n }\n\n /**\n * Check if /clear is recommended\n */\n async shouldClear(\n currentTokens: number,\n maxTokens: number\n ): Promise<{\n recommended: boolean;\n reason?: string;\n alternative?: string;\n }> {\n const usage = currentTokens / maxTokens;\n\n if (usage < this.CONTEXT_WARNING_THRESHOLD) {\n return { recommended: false };\n }\n\n // Check if we have redundant frames\n const frameStack = await this.frameManager.getStack();\n const redundantFrames = frameStack.frames.filter(\n (f) => f.status === 'closed' && !f.metadata?.critical\n ).length;\n\n if (usage >= this.CONTEXT_CRITICAL_THRESHOLD) {\n if (redundantFrames > 5) {\n return {\n recommended: true,\n reason: `Context at ${Math.round(usage * 100)}% with ${redundantFrames} closed frames`,\n alternative: 'Consider saving ledger and clearing',\n };\n }\n }\n\n return {\n recommended: false,\n alternative: `Context at ${Math.round(usage * 100)}% but manageable`,\n };\n }\n\n // Private helper methods\n\n private async getCompressedFrameStack(): Promise<FrameSummary[]> {\n const stack = await this.frameManager.getStack();\n\n return stack.frames.map((frame, index) => ({\n id: frame.id,\n type: frame.type,\n description: frame.description || 'Unnamed frame',\n depth: index,\n key_events: this.extractKeyEvents(frame),\n digest: frame.digest?.summary,\n }));\n }\n\n private extractKeyEvents(frame: Frame): string[] {\n const events: string[] = [];\n\n // Extract from metadata\n if (frame.metadata?.decision) {\n events.push(`Decision: ${frame.metadata.decision}`);\n }\n if (frame.metadata?.error) {\n events.push(`Error: ${frame.metadata.error}`);\n }\n if (frame.metadata?.achievement) {\n events.push(`Achievement: ${frame.metadata.achievement}`);\n }\n\n return events;\n }\n\n private async getCriticalDecisions(): Promise<Decision[]> {\n const traces = await this.dbManager.getRecentTraces(\n await this.dbManager.getCurrentSessionId(),\n 100\n );\n\n return traces\n .filter((t) => t.type === 'decision')\n .map((t) => ({\n id: t.id,\n decision: t.content.decision || '',\n rationale: t.content.rationale || '',\n impact: this.assessImpact(t),\n still_applies: !t.metadata?.superseded,\n }))\n .filter((d) => d.impact !== 'low');\n }\n\n private assessImpact(trace: Trace): Decision['impact'] {\n const content = JSON.stringify(trace.content).toLowerCase();\n\n if (content.includes('architecture') || content.includes('critical')) {\n return 'critical';\n }\n if (content.includes('important') || content.includes('significant')) {\n return 'high';\n }\n if (content.includes('minor') || content.includes('small')) {\n return 'low';\n }\n\n return 'medium';\n }\n\n private async getActiveTasks(): Promise<Task[]> {\n const frames = await this.dbManager.getRecentFrames(\n await this.dbManager.getCurrentSessionId(),\n 50\n );\n\n return frames\n .filter((f) => f.type === 'task')\n .map((f) => ({\n id: f.id,\n title: f.description || 'Untitled task',\n status: this.getTaskStatus(f),\n priority: this.getTaskPriority(f),\n context: f.metadata?.context || '',\n }));\n }\n\n private getTaskStatus(frame: Frame): Task['status'] {\n if (frame.status === 'closed' && frame.metadata?.completed) {\n return 'completed';\n }\n if (frame.metadata?.blocked) return 'blocked';\n if (frame.status === 'open') return 'in_progress';\n return 'pending';\n }\n\n private getTaskPriority(frame: Frame): Task['priority'] {\n const priority = frame.metadata?.priority;\n if (['critical', 'high', 'medium', 'low'].includes(priority)) {\n return priority as Task['priority'];\n }\n return 'medium';\n }\n\n private async getCriticalContext(): Promise<string[]> {\n const context: string[] = [];\n\n // Add project-specific context\n const session = await this.dbManager.getSession(\n await this.dbManager.getCurrentSessionId()\n );\n if (session?.metadata?.key_facts) {\n context.push(...session.metadata.key_facts);\n }\n\n // Add recent important discoveries\n const traces = await this.dbManager.getRecentTraces(\n await this.dbManager.getCurrentSessionId(),\n 50\n );\n\n const discoveries = traces\n .filter((t) => t.metadata?.important || t.type === 'discovery')\n .map((t) => t.content.summary || t.content.description)\n .filter(Boolean)\n .slice(0, 5);\n\n context.push(...discoveries);\n\n return context;\n }\n\n private async getRecentAchievements(): Promise<Achievement[]> {\n const frames = await this.dbManager.getRecentFrames(\n await this.dbManager.getCurrentSessionId(),\n 20\n );\n\n return frames\n .filter((f) => f.status === 'closed' && f.metadata?.achievement)\n .map((f) => ({\n description: f.metadata.achievement,\n impact: f.metadata.impact || 'completed task',\n timestamp: f.closedAt || f.createdAt,\n }))\n .slice(0, 5);\n }\n\n private async getCurrentFocus(): Promise<string> {\n const stack = await this.frameManager.getStack();\n const activeFrame = stack.frames.find((f) => f.status === 'open');\n\n if (!activeFrame) {\n return 'No active focus';\n }\n\n return `${activeFrame.type}: ${activeFrame.description || 'In progress'}`;\n }\n\n private async suggestNextActions(tasks: Task[]): Promise<string[]> {\n const suggestions: string[] = [];\n\n // Continue in-progress tasks\n const inProgress = tasks.filter((t) => t.status === 'in_progress');\n if (inProgress.length > 0) {\n suggestions.push(`Continue: ${inProgress[0].title}`);\n }\n\n // Start high-priority pending tasks\n const highPriority = tasks.filter(\n (t) => t.status === 'pending' && t.priority === 'high'\n );\n if (highPriority.length > 0) {\n suggestions.push(`Start: ${highPriority[0].title}`);\n }\n\n // Unblock blocked tasks\n const blocked = tasks.filter((t) => t.status === 'blocked');\n if (blocked.length > 0) {\n suggestions.push(`Unblock: ${blocked[0].title}`);\n }\n\n return suggestions.slice(0, 3);\n }\n\n private async getWarnings(): Promise<string[]> {\n const warnings: string[] = [];\n\n const tasks = await this.getActiveTasks();\n const blocked = tasks.filter((t) => t.status === 'blocked');\n\n if (blocked.length > 0) {\n warnings.push(`${blocked.length} tasks blocked`);\n }\n\n const critical = tasks.filter(\n (t) => t.priority === 'critical' && t.status !== 'completed'\n );\n if (critical.length > 0) {\n warnings.push(`${critical.length} critical tasks pending`);\n }\n\n return warnings;\n }\n\n private async estimateCurrentTokens(): Promise<number> {\n // Simplified estimation\n const frames = await this.frameManager.getStack();\n const traces = await this.dbManager.getRecentTraces(\n await this.dbManager.getCurrentSessionId(),\n 100\n );\n\n const frameTokens = frames.frames.length * 200; // Rough estimate\n const traceTokens = traces.length * 100; // Rough estimate\n\n return frameTokens + traceTokens;\n }\n\n private estimateLedgerTokens(\n frames: FrameSummary[],\n decisions: Decision[],\n tasks: Task[]\n ): number {\n // Rough estimation\n return frames.length * 50 + decisions.length * 30 + tasks.length * 20;\n }\n\n private async saveLedgerToFile(ledger: ContinuityLedger): Promise<void> {\n await fs.mkdir(this.continuityPath, { recursive: true });\n\n // Save as CONTINUITY_CLAUDE-latest.json (overwrites)\n const latestPath = path.join(\n this.continuityPath,\n 'CONTINUITY_CLAUDE-latest.json'\n );\n await fs.writeFile(latestPath, JSON.stringify(ledger, null, 2), 'utf-8');\n\n // Also save markdown version\n const markdown = await this.generateLedgerMarkdown(ledger);\n const mdPath = path.join(\n this.continuityPath,\n 'CONTINUITY_CLAUDE-latest.md'\n );\n await fs.writeFile(mdPath, markdown, 'utf-8');\n }\n\n private async saveBackupLedger(ledger: ContinuityLedger): Promise<void> {\n await fs.mkdir(this.ledgerPath, { recursive: true });\n\n const timestamp = ledger.timestamp.replace(/[:.]/g, '-');\n const backupPath = path.join(this.ledgerPath, `ledger-${timestamp}.json`);\n await fs.writeFile(backupPath, JSON.stringify(ledger, null, 2), 'utf-8');\n }\n\n private async loadLatestLedger(): Promise<ContinuityLedger | null> {\n try {\n const latestPath = path.join(\n this.continuityPath,\n 'CONTINUITY_CLAUDE-latest.json'\n );\n const content = await fs.readFile(latestPath, 'utf-8');\n return JSON.parse(content) as ContinuityLedger;\n } catch (error: unknown) {\n return null;\n }\n }\n\n private async restoreFrameStructure(frames: FrameSummary[]): Promise<void> {\n // Create lightweight frame references (not full frames)\n for (const summary of frames) {\n await this.frameManager.push({\n type: summary.type,\n description: summary.description,\n metadata: {\n restored_from_ledger: true,\n original_id: summary.id,\n key_events: summary.key_events,\n digest: summary.digest,\n },\n });\n }\n }\n\n private async restoreDecisions(decisions: Decision[]): Promise<void> {\n for (const decision of decisions) {\n if (decision.still_applies) {\n await this.dbManager.addAnchor({\n type: 'decision',\n content: {\n decision: decision.decision,\n rationale: decision.rationale,\n impact: decision.impact,\n },\n metadata: {\n restored_from_ledger: true,\n original_id: decision.id,\n },\n });\n }\n }\n }\n\n private async restoreTasks(tasks: Task[]): Promise<void> {\n for (const task of tasks) {\n if (task.status !== 'completed') {\n await this.frameManager.push({\n type: 'task',\n description: task.title,\n metadata: {\n status: task.status,\n priority: task.priority,\n context: task.context,\n restored_from_ledger: true,\n original_id: task.id,\n },\n });\n }\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Clear Survival System for StackMemory\n * Inspired by Continuous-Claude's \"Clear, don't compact\" philosophy\n *\n * Allows StackMemory to survive /clear operations by:\n * 1. Detecting when context is getting full (>70%)\n * 2. Saving critical state to external ledgers\n * 3. Restoring from ledgers after /clear\n * 4. Maintaining continuity across session resets\n */\n\nimport { Frame, Trace, Context, Digest } from '../types';\nimport { FrameManager } from '../frame/frame-manager';\nimport { DatabaseManager } from '../storage/database-manager';\nimport { HandoffGenerator } from './handoff-generator';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\nexport interface ContextUsage {\n totalFrames: number;\n activeFrames: number;\n sessionCount: number;\n percentageUsed: number;\n}\n\nexport interface ContinuityLedger {\n version: '1.0.0';\n timestamp: string;\n session_id: string;\n project: string;\n branch?: string;\n\n // Critical state to preserve\n active_frame_stack: FrameSummary[];\n key_decisions: Decision[];\n active_tasks: Task[];\n critical_context: string[];\n recent_achievements: Achievement[];\n\n // Navigation aids\n current_focus: string;\n next_actions: string[];\n warnings: string[];\n\n // Metrics for restoration\n original_token_count: number;\n compressed_token_count: number;\n compression_ratio: number;\n}\n\ninterface FrameSummary {\n id: string;\n type: string;\n description: string;\n depth: number;\n key_events: string[];\n digest?: string;\n}\n\ninterface Decision {\n id: string;\n decision: string;\n rationale: string;\n impact: 'low' | 'medium' | 'high' | 'critical';\n still_applies: boolean;\n}\n\ninterface Task {\n id: string;\n title: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'completed';\n priority: 'low' | 'medium' | 'high' | 'critical';\n context: string;\n}\n\ninterface Achievement {\n description: string;\n impact: string;\n timestamp: string;\n}\n\nexport class ClearSurvival {\n private frameManager: FrameManager;\n private dbManager: DatabaseManager;\n private handoffGenerator: HandoffGenerator;\n private ledgerPath: string;\n private continuityPath: string;\n\n // Thresholds\n private readonly CONTEXT_WARNING_THRESHOLD = 0.6; // 60%\n private readonly CONTEXT_CRITICAL_THRESHOLD = 0.7; // 70%\n private readonly CONTEXT_MAX_THRESHOLD = 0.85; // 85% - force save\n\n constructor(\n frameManager: FrameManager,\n dbManager: DatabaseManager,\n handoffGenerator: HandoffGenerator,\n projectRoot: string\n ) {\n this.frameManager = frameManager;\n this.dbManager = dbManager;\n this.handoffGenerator = handoffGenerator;\n this.ledgerPath = path.join(projectRoot, '.stackmemory', 'ledgers');\n this.continuityPath = path.join(projectRoot, '.stackmemory', 'continuity');\n }\n\n /**\n * Get current context usage statistics\n */\n async getContextUsage(): Promise<ContextUsage> {\n try {\n const frames = await this.frameManager.getAllFrames();\n const activeFrames = frames.filter(f => f.status === 'open').length;\n const sessionId = await this.dbManager.getCurrentSessionId();\n \n // Estimate based on frame count (simplified)\n const estimatedTokens = frames.length * 100; // Rough estimate\n const maxTokens = 10000; // Approximate max context\n const percentageUsed = Math.min(100, (estimatedTokens / maxTokens) * 100);\n\n return {\n totalFrames: frames.length,\n activeFrames,\n sessionCount: 1,\n percentageUsed\n };\n } catch (error) {\n // Fallback for testing or when DB is not available\n return {\n totalFrames: 50,\n activeFrames: 3,\n sessionCount: 2,\n percentageUsed: 25\n };\n }\n }\n\n /**\n * Assess context status based on usage\n */\n assessContextStatus(usage: ContextUsage): string {\n if (usage.percentageUsed < 50) return 'healthy';\n if (usage.percentageUsed < 70) return 'moderate';\n if (usage.percentageUsed < 85) return 'critical';\n return 'saved';\n }\n\n /**\n * Monitor context usage and trigger saves when needed\n */\n async monitorContextUsage(\n currentTokens: number,\n maxTokens: number\n ): Promise<'ok' | 'warning' | 'critical' | 'saved'> {\n const usage = currentTokens / maxTokens;\n\n if (usage < this.CONTEXT_WARNING_THRESHOLD) {\n return 'ok';\n }\n\n if (usage >= this.CONTEXT_MAX_THRESHOLD) {\n // Force save at 85%\n await this.saveContinuityLedger();\n return 'saved';\n }\n\n if (usage >= this.CONTEXT_CRITICAL_THRESHOLD) {\n // Suggest save at 70%\n console.warn(\n `\u26A0\uFE0F Context at ${Math.round(usage * 100)}% - Consider /clear after saving`\n );\n return 'critical';\n }\n\n // Warning at 60%\n console.warn(`Context at ${Math.round(usage * 100)}% - Approaching limit`);\n return 'warning';\n }\n\n /**\n * Save continuity ledger before /clear\n */\n async saveContinuityLedger(): Promise<ContinuityLedger> {\n const sessionId = await this.dbManager.getCurrentSessionId();\n const session = await this.dbManager.getSession(sessionId);\n\n // Get current state\n const frameStack = await this.getCompressedFrameStack();\n const decisions = await this.getCriticalDecisions();\n const tasks = await this.getActiveTasks();\n const context = await this.getCriticalContext();\n const achievements = await this.getRecentAchievements();\n\n // Calculate token counts (simplified)\n const originalTokens = await this.estimateCurrentTokens();\n const compressedTokens = this.estimateLedgerTokens(\n frameStack,\n decisions,\n tasks\n );\n\n const ledger: ContinuityLedger = {\n version: '1.0.0',\n timestamp: new Date().toISOString(),\n session_id: sessionId,\n project: session?.project || 'unknown',\n branch: session?.metadata?.branch,\n\n active_frame_stack: frameStack,\n key_decisions: decisions,\n active_tasks: tasks,\n critical_context: context,\n recent_achievements: achievements,\n\n current_focus: await this.getCurrentFocus(),\n next_actions: await this.suggestNextActions(tasks),\n warnings: await this.getWarnings(),\n\n original_token_count: originalTokens,\n compressed_token_count: compressedTokens,\n compression_ratio: originalTokens / compressedTokens,\n };\n\n // Save to file (overwrites previous continuity ledger)\n await this.saveLedgerToFile(ledger);\n\n // Also create a timestamped backup\n await this.saveBackupLedger(ledger);\n\n console.log(\n `\u2705 Continuity ledger saved (${Math.round(ledger.compression_ratio)}x compression)`\n );\n\n return ledger;\n }\n\n /**\n * Restore from continuity ledger after /clear\n */\n async restoreFromLedger(): Promise<boolean> {\n try {\n const ledger = await this.loadLatestLedger();\n if (!ledger) {\n console.log('No continuity ledger found');\n return false;\n }\n\n console.log(`\uD83D\uDCDA Restoring from ledger (${ledger.timestamp})`);\n\n // Restore frame stack structure (not full content)\n await this.restoreFrameStructure(ledger.active_frame_stack);\n\n // Restore key decisions as anchors\n await this.restoreDecisions(ledger.key_decisions);\n\n // Restore active tasks\n await this.restoreTasks(ledger.active_tasks);\n\n // Log restoration summary\n console.log(`\u2705 Restored:`);\n console.log(` - ${ledger.active_frame_stack.length} frames`);\n console.log(` - ${ledger.key_decisions.length} decisions`);\n console.log(` - ${ledger.active_tasks.length} tasks`);\n console.log(` - Current focus: ${ledger.current_focus}`);\n\n if (ledger.warnings.length > 0) {\n console.warn(`\u26A0\uFE0F Warnings:`, ledger.warnings);\n }\n\n return true;\n } catch (error: unknown) {\n console.error('Failed to restore from ledger:', error);\n return false;\n }\n }\n\n /**\n * Generate markdown summary for human review\n */\n async generateLedgerMarkdown(ledger: ContinuityLedger): Promise<string> {\n const lines: string[] = [\n `# Continuity Ledger`,\n `**Saved**: ${new Date(ledger.timestamp).toLocaleString()}`,\n `**Project**: ${ledger.project}${ledger.branch ? ` (${ledger.branch})` : ''}`,\n `**Compression**: ${Math.round(ledger.compression_ratio)}x (${ledger.original_token_count} \u2192 ${ledger.compressed_token_count} tokens)`,\n '',\n\n `## \uD83C\uDFAF Current Focus`,\n ledger.current_focus,\n '',\n\n `## \uD83D\uDCDA Active Frame Stack (${ledger.active_frame_stack.length})`,\n ...ledger.active_frame_stack.map(\n (f) => `${' '.repeat(f.depth)}\u2514\u2500 ${f.type}: ${f.description}`\n ),\n '',\n\n `## \uD83C\uDFAF Active Tasks (${ledger.active_tasks.filter((t) => t.status !== 'completed').length})`,\n ...ledger.active_tasks\n .filter((t) => t.status !== 'completed')\n .sort((a, b) => {\n const priority = { critical: 0, high: 1, medium: 2, low: 3 };\n return priority[a.priority] - priority[b.priority];\n })\n .map((t) => `- [${t.priority}] ${t.title} (${t.status})`),\n '',\n\n `## \uD83D\uDD11 Key Decisions`,\n ...ledger.key_decisions\n .filter((d) => d.still_applies)\n .map((d) => `- **${d.decision}**\\n ${d.rationale}`),\n '',\n\n `## \u2705 Recent Achievements`,\n ...ledger.recent_achievements.map(\n (a) => `- ${a.description} \u2192 ${a.impact}`\n ),\n '',\n\n `## \u27A1\uFE0F Next Actions`,\n ...ledger.next_actions.map((a, i) => `${i + 1}. ${a}`),\n '',\n\n ledger.warnings.length > 0 ? `## \u26A0\uFE0F Warnings` : '',\n ...ledger.warnings.map((w) => `- ${w}`),\n ];\n\n return lines.filter((l) => l !== '').join('\\n');\n }\n\n /**\n * Check if /clear is recommended\n */\n async shouldClear(\n currentTokens: number,\n maxTokens: number\n ): Promise<{\n recommended: boolean;\n reason?: string;\n alternative?: string;\n }> {\n const usage = currentTokens / maxTokens;\n\n if (usage < this.CONTEXT_WARNING_THRESHOLD) {\n return { recommended: false };\n }\n\n // Check if we have redundant frames\n const frameStack = await this.frameManager.getStack();\n const redundantFrames = frameStack.frames.filter(\n (f) => f.status === 'closed' && !f.metadata?.critical\n ).length;\n\n if (usage >= this.CONTEXT_CRITICAL_THRESHOLD) {\n if (redundantFrames > 5) {\n return {\n recommended: true,\n reason: `Context at ${Math.round(usage * 100)}% with ${redundantFrames} closed frames`,\n alternative: 'Consider saving ledger and clearing',\n };\n }\n }\n\n return {\n recommended: false,\n alternative: `Context at ${Math.round(usage * 100)}% but manageable`,\n };\n }\n\n // Private helper methods\n\n private async getCompressedFrameStack(): Promise<FrameSummary[]> {\n const stack = await this.frameManager.getStack();\n\n return stack.frames.map((frame, index) => ({\n id: frame.id,\n type: frame.type,\n description: frame.description || 'Unnamed frame',\n depth: index,\n key_events: this.extractKeyEvents(frame),\n digest: frame.digest?.summary,\n }));\n }\n\n private extractKeyEvents(frame: Frame): string[] {\n const events: string[] = [];\n\n // Extract from metadata\n if (frame.metadata?.decision) {\n events.push(`Decision: ${frame.metadata.decision}`);\n }\n if (frame.metadata?.error) {\n events.push(`Error: ${frame.metadata.error}`);\n }\n if (frame.metadata?.achievement) {\n events.push(`Achievement: ${frame.metadata.achievement}`);\n }\n\n return events;\n }\n\n private async getCriticalDecisions(): Promise<Decision[]> {\n const traces = await this.dbManager.getRecentTraces(\n await this.dbManager.getCurrentSessionId(),\n 100\n );\n\n return traces\n .filter((t) => t.type === 'decision')\n .map((t) => ({\n id: t.id,\n decision: t.content.decision || '',\n rationale: t.content.rationale || '',\n impact: this.assessImpact(t),\n still_applies: !t.metadata?.superseded,\n }))\n .filter((d) => d.impact !== 'low');\n }\n\n private assessImpact(trace: Trace): Decision['impact'] {\n const content = JSON.stringify(trace.content).toLowerCase();\n\n if (content.includes('architecture') || content.includes('critical')) {\n return 'critical';\n }\n if (content.includes('important') || content.includes('significant')) {\n return 'high';\n }\n if (content.includes('minor') || content.includes('small')) {\n return 'low';\n }\n\n return 'medium';\n }\n\n private async getActiveTasks(): Promise<Task[]> {\n const frames = await this.dbManager.getRecentFrames(\n await this.dbManager.getCurrentSessionId(),\n 50\n );\n\n return frames\n .filter((f) => f.type === 'task')\n .map((f) => ({\n id: f.id,\n title: f.description || 'Untitled task',\n status: this.getTaskStatus(f),\n priority: this.getTaskPriority(f),\n context: f.metadata?.context || '',\n }));\n }\n\n private getTaskStatus(frame: Frame): Task['status'] {\n if (frame.status === 'closed' && frame.metadata?.completed) {\n return 'completed';\n }\n if (frame.metadata?.blocked) return 'blocked';\n if (frame.status === 'open') return 'in_progress';\n return 'pending';\n }\n\n private getTaskPriority(frame: Frame): Task['priority'] {\n const priority = frame.metadata?.priority;\n if (['critical', 'high', 'medium', 'low'].includes(priority)) {\n return priority as Task['priority'];\n }\n return 'medium';\n }\n\n private async getCriticalContext(): Promise<string[]> {\n const context: string[] = [];\n\n // Add project-specific context\n const session = await this.dbManager.getSession(\n await this.dbManager.getCurrentSessionId()\n );\n if (session?.metadata?.key_facts) {\n context.push(...session.metadata.key_facts);\n }\n\n // Add recent important discoveries\n const traces = await this.dbManager.getRecentTraces(\n await this.dbManager.getCurrentSessionId(),\n 50\n );\n\n const discoveries = traces\n .filter((t) => t.metadata?.important || t.type === 'discovery')\n .map((t) => t.content.summary || t.content.description)\n .filter(Boolean)\n .slice(0, 5);\n\n context.push(...discoveries);\n\n return context;\n }\n\n private async getRecentAchievements(): Promise<Achievement[]> {\n const frames = await this.dbManager.getRecentFrames(\n await this.dbManager.getCurrentSessionId(),\n 20\n );\n\n return frames\n .filter((f) => f.status === 'closed' && f.metadata?.achievement)\n .map((f) => ({\n description: f.metadata.achievement,\n impact: f.metadata.impact || 'completed task',\n timestamp: f.closedAt || f.createdAt,\n }))\n .slice(0, 5);\n }\n\n private async getCurrentFocus(): Promise<string> {\n const stack = await this.frameManager.getStack();\n const activeFrame = stack.frames.find((f) => f.status === 'open');\n\n if (!activeFrame) {\n return 'No active focus';\n }\n\n return `${activeFrame.type}: ${activeFrame.description || 'In progress'}`;\n }\n\n private async suggestNextActions(tasks: Task[]): Promise<string[]> {\n const suggestions: string[] = [];\n\n // Continue in-progress tasks\n const inProgress = tasks.filter((t) => t.status === 'in_progress');\n if (inProgress.length > 0) {\n suggestions.push(`Continue: ${inProgress[0].title}`);\n }\n\n // Start high-priority pending tasks\n const highPriority = tasks.filter(\n (t) => t.status === 'pending' && t.priority === 'high'\n );\n if (highPriority.length > 0) {\n suggestions.push(`Start: ${highPriority[0].title}`);\n }\n\n // Unblock blocked tasks\n const blocked = tasks.filter((t) => t.status === 'blocked');\n if (blocked.length > 0) {\n suggestions.push(`Unblock: ${blocked[0].title}`);\n }\n\n return suggestions.slice(0, 3);\n }\n\n private async getWarnings(): Promise<string[]> {\n const warnings: string[] = [];\n\n const tasks = await this.getActiveTasks();\n const blocked = tasks.filter((t) => t.status === 'blocked');\n\n if (blocked.length > 0) {\n warnings.push(`${blocked.length} tasks blocked`);\n }\n\n const critical = tasks.filter(\n (t) => t.priority === 'critical' && t.status !== 'completed'\n );\n if (critical.length > 0) {\n warnings.push(`${critical.length} critical tasks pending`);\n }\n\n return warnings;\n }\n\n private async estimateCurrentTokens(): Promise<number> {\n // Simplified estimation\n const frames = await this.frameManager.getStack();\n const traces = await this.dbManager.getRecentTraces(\n await this.dbManager.getCurrentSessionId(),\n 100\n );\n\n const frameTokens = frames.frames.length * 200; // Rough estimate\n const traceTokens = traces.length * 100; // Rough estimate\n\n return frameTokens + traceTokens;\n }\n\n private estimateLedgerTokens(\n frames: FrameSummary[],\n decisions: Decision[],\n tasks: Task[]\n ): number {\n // Rough estimation\n return frames.length * 50 + decisions.length * 30 + tasks.length * 20;\n }\n\n private async saveLedgerToFile(ledger: ContinuityLedger): Promise<void> {\n await fs.mkdir(this.continuityPath, { recursive: true });\n\n // Save as CONTINUITY_CLAUDE-latest.json (overwrites)\n const latestPath = path.join(\n this.continuityPath,\n 'CONTINUITY_CLAUDE-latest.json'\n );\n await fs.writeFile(latestPath, JSON.stringify(ledger, null, 2), 'utf-8');\n\n // Also save markdown version\n const markdown = await this.generateLedgerMarkdown(ledger);\n const mdPath = path.join(\n this.continuityPath,\n 'CONTINUITY_CLAUDE-latest.md'\n );\n await fs.writeFile(mdPath, markdown, 'utf-8');\n }\n\n private async saveBackupLedger(ledger: ContinuityLedger): Promise<void> {\n await fs.mkdir(this.ledgerPath, { recursive: true });\n\n const timestamp = ledger.timestamp.replace(/[:.]/g, '-');\n const backupPath = path.join(this.ledgerPath, `ledger-${timestamp}.json`);\n await fs.writeFile(backupPath, JSON.stringify(ledger, null, 2), 'utf-8');\n }\n\n private async loadLatestLedger(): Promise<ContinuityLedger | null> {\n try {\n const latestPath = path.join(\n this.continuityPath,\n 'CONTINUITY_CLAUDE-latest.json'\n );\n const content = await fs.readFile(latestPath, 'utf-8');\n return JSON.parse(content) as ContinuityLedger;\n } catch (error: unknown) {\n return null;\n }\n }\n\n private async restoreFrameStructure(frames: FrameSummary[]): Promise<void> {\n // Create lightweight frame references (not full frames)\n for (const summary of frames) {\n await this.frameManager.push({\n type: summary.type,\n description: summary.description,\n metadata: {\n restored_from_ledger: true,\n original_id: summary.id,\n key_events: summary.key_events,\n digest: summary.digest,\n },\n });\n }\n }\n\n private async restoreDecisions(decisions: Decision[]): Promise<void> {\n for (const decision of decisions) {\n if (decision.still_applies) {\n await this.dbManager.addAnchor({\n type: 'decision',\n content: {\n decision: decision.decision,\n rationale: decision.rationale,\n impact: decision.impact,\n },\n metadata: {\n restored_from_ledger: true,\n original_id: decision.id,\n },\n });\n }\n }\n }\n\n private async restoreTasks(tasks: Task[]): Promise<void> {\n for (const task of tasks) {\n if (task.status !== 'completed') {\n await this.frameManager.push({\n type: 'task',\n description: task.title,\n metadata: {\n status: task.status,\n priority: task.priority,\n context: task.context,\n restored_from_ledger: true,\n original_id: task.id,\n },\n });\n }\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/session/index.ts"],
|
|
4
|
-
"sourcesContent": ["export {
|
|
4
|
+
"sourcesContent": ["export {\n SessionManager,\n sessionManager,\n type Session,\n type SessionOptions,\n FrameQueryMode,\n} from './session-manager.js';\n"],
|
|
5
5
|
"mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,OACK;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/session/session-manager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Session Management for StackMemory\n * Provides session persistence and recovery across CLI invocations\n */\n\nimport { v4 as uuidv4 } from 'uuid';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport { logger } from '../monitoring/logger.js';\nimport { SystemError, ErrorCode } from '../errors/index.js';\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\nexport interface Session {\n sessionId: string;\n runId: string;\n projectId: string;\n branch?: string;\n startedAt: number;\n lastActiveAt: number;\n metadata: {\n user?: string;\n environment?: string;\n tags?: string[];\n cliVersion?: string;\n };\n state: 'active' | 'suspended' | 'closed';\n}\n\nexport interface SessionOptions {\n sessionId?: string;\n projectPath?: string;\n branch?: string;\n metadata?: Session['metadata'];\n}\n\nexport enum FrameQueryMode {\n CURRENT_SESSION = 'current',\n PROJECT_ACTIVE = 'project',\n ALL_ACTIVE = 'all',\n HISTORICAL = 'historical',\n}\n\nexport class SessionManager {\n private static instance: SessionManager;\n private sessionsDir: string;\n private currentSession: Session | null = null;\n private readonly STALE_THRESHOLD = 24 * 60 * 60 * 1000; // 24 hours\n\n private constructor() {\n const homeDir = process.env['HOME'] || process.env['USERPROFILE'] || '';\n this.sessionsDir = path.join(homeDir, '.stackmemory', 'sessions');\n }\n\n static getInstance(): SessionManager {\n if (!SessionManager.instance) {\n SessionManager.instance = new SessionManager();\n }\n return SessionManager.instance;\n }\n\n async initialize(): Promise<void> {\n try {\n await fs.mkdir(this.sessionsDir, { recursive: true });\n await fs.mkdir(path.join(this.sessionsDir, 'projects'), {\n recursive: true,\n });\n await fs.mkdir(path.join(this.sessionsDir, 'history'), {\n recursive: true,\n });\n } catch (error: unknown) {\n throw new SystemError(\n 'Failed to initialize session directories',\n ErrorCode.INITIALIZATION_ERROR,\n { error, sessionsDir: this.sessionsDir }\n );\n }\n }\n\n async getOrCreateSession(options?: SessionOptions): Promise<Session> {\n // 1. Check explicit session ID\n if (options?.sessionId) {\n const session = await this.loadSession(options.sessionId);\n if (session) {\n this.currentSession = session;\n return session;\n }\n }\n\n // 2. Check environment variable\n const envSessionId = process.env['STACKMEMORY_SESSION'];\n if (envSessionId) {\n const session = await this.loadSession(envSessionId);\n if (session) {\n this.currentSession = session;\n return session;\n }\n }\n\n // 3. Check project + branch context\n const projectHash = await this.getProjectHash(options?.projectPath);\n const branch =\n options?.branch || (await this.getGitBranch(options?.projectPath));\n\n if (projectHash) {\n // Try project+branch session\n const branchSession = await this.findProjectBranchSession(\n projectHash,\n branch\n );\n if (branchSession && this.isSessionRecent(branchSession)) {\n await this.touchSession(branchSession);\n this.currentSession = branchSession;\n return branchSession;\n }\n\n // Try last active for project\n const lastActive = await this.findLastActiveSession(projectHash);\n if (lastActive && this.isSessionRecent(lastActive)) {\n await this.touchSession(lastActive);\n this.currentSession = lastActive;\n return lastActive;\n }\n }\n\n // 4. Create new session\n const newSession = await this.createSession({\n projectId: projectHash || 'global',\n branch,\n metadata: options?.metadata,\n });\n\n this.currentSession = newSession;\n return newSession;\n }\n\n async createSession(params: {\n projectId: string;\n branch?: string;\n metadata?: Session['metadata'];\n }): Promise<Session> {\n const session: Session = {\n sessionId: uuidv4(),\n runId: uuidv4(),\n projectId: params.projectId,\n branch: params.branch,\n startedAt: Date.now(),\n lastActiveAt: Date.now(),\n metadata: {\n ...params.metadata,\n user: process.env['USER'],\n environment: process.env['NODE_ENV'] || 'development',\n cliVersion: process.env['npm_package_version'],\n },\n state: 'active',\n };\n\n await this.saveSession(session);\n await this.setProjectActiveSession(params.projectId, session.sessionId);\n\n // Set as current session\n this.currentSession = session;\n\n logger.info('Created new session', {\n sessionId: session.sessionId,\n projectId: session.projectId,\n branch: session.branch,\n });\n\n return session;\n }\n\n async loadSession(sessionId: string): Promise<Session | null> {\n try {\n const sessionPath = path.join(this.sessionsDir, `${sessionId}.json`);\n const data = await fs.readFile(sessionPath, 'utf-8');\n return JSON.parse(data) as Session;\n } catch (error: unknown) {\n // Check history\n try {\n const historyPath = path.join(\n this.sessionsDir,\n 'history',\n `${sessionId}.json`\n );\n const data = await fs.readFile(historyPath, 'utf-8');\n return JSON.parse(data) as Session;\n } catch {\n return null;\n }\n }\n }\n\n async saveSession(session: Session): Promise<void> {\n const sessionPath = path.join(\n this.sessionsDir,\n `${session.sessionId}.json`\n );\n await fs.writeFile(sessionPath, JSON.stringify(session, null, 2));\n }\n\n async suspendSession(sessionId?: string): Promise<void> {\n const id = sessionId || this.currentSession?.sessionId;\n if (!id) return;\n\n const session = await this.loadSession(id);\n if (session) {\n session.state = 'suspended';\n session.lastActiveAt = Date.now();\n await this.saveSession(session);\n }\n }\n\n async resumeSession(sessionId: string): Promise<Session> {\n const session = await this.loadSession(sessionId);\n if (!session) {\n throw new SystemError('Session not found', ErrorCode.NOT_FOUND, {\n sessionId,\n });\n }\n\n session.state = 'active';\n session.lastActiveAt = Date.now();\n await this.saveSession(session);\n\n this.currentSession = session;\n return session;\n }\n\n async closeSession(sessionId?: string): Promise<void> {\n const id = sessionId || this.currentSession?.sessionId;\n if (!id) return;\n\n const session = await this.loadSession(id);\n if (session) {\n session.state = 'closed';\n session.lastActiveAt = Date.now();\n\n // Move to history\n const sessionPath = path.join(\n this.sessionsDir,\n `${session.sessionId}.json`\n );\n const historyPath = path.join(\n this.sessionsDir,\n 'history',\n `${session.sessionId}.json`\n );\n\n await fs.rename(sessionPath, historyPath);\n }\n }\n\n async listSessions(filter?: {\n projectId?: string;\n state?: Session['state'];\n branch?: string;\n }): Promise<Session[]> {\n const sessions: Session[] = [];\n\n // Load active sessions\n const files = await fs.readdir(this.sessionsDir);\n for (const file of files) {\n if (file.endsWith('.json')) {\n const session = await this.loadSession(file.replace('.json', ''));\n if (session) {\n sessions.push(session);\n }\n }\n }\n\n // Apply filters\n return sessions.filter((s) => {\n if (filter?.projectId && s.projectId !== filter.projectId) return false;\n if (filter?.state && s.state !== filter.state) return false;\n if (filter?.branch && s.branch !== filter.branch) return false;\n return true;\n });\n }\n\n async mergeSessions(sourceId: string, targetId: string): Promise<Session> {\n const source = await this.loadSession(sourceId);\n const target = await this.loadSession(targetId);\n\n if (!source || !target) {\n throw new SystemError(\n 'Session not found for merge',\n ErrorCode.NOT_FOUND,\n { sourceId, targetId }\n );\n }\n\n // Merge metadata\n target.metadata = {\n ...target.metadata,\n ...source.metadata,\n tags: [...(target.metadata.tags || []), ...(source.metadata.tags || [])],\n };\n\n // Update timestamps\n target.lastActiveAt = Date.now();\n\n // Close source session\n await this.closeSession(sourceId);\n await this.saveSession(target);\n\n logger.info('Merged sessions', {\n source: sourceId,\n target: targetId,\n });\n\n return target;\n }\n\n async cleanupStaleSessions(\n maxAge: number = 30 * 24 * 60 * 60 * 1000\n ): Promise<number> {\n const historyDir = path.join(this.sessionsDir, 'history');\n const files = await fs.readdir(historyDir);\n const cutoff = Date.now() - maxAge;\n let cleaned = 0;\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(historyDir, file);\n const stats = await fs.stat(filePath);\n\n if (stats.mtimeMs < cutoff) {\n await fs.unlink(filePath);\n cleaned++;\n }\n }\n }\n\n logger.info(`Cleaned up ${cleaned} stale sessions`);\n return cleaned;\n }\n\n getCurrentSession(): Session | null {\n return this.currentSession;\n }\n\n getSessionRunId(): string {\n return this.currentSession?.runId || uuidv4();\n }\n\n private async getProjectHash(projectPath?: string): Promise<string | null> {\n try {\n const cwd = projectPath || process.cwd();\n const pathModule = await import('path');\n\n // Try to get git remote first (consistent with project-manager)\n let identifier: string;\n try {\n const { execSync } = await import('child_process');\n identifier = execSync('git config --get remote.origin.url', {\n cwd,\n encoding: 'utf-8',\n timeout: 5000,\n }).trim();\n } catch {\n // Fall back to directory path\n identifier = cwd;\n }\n\n // Use same algorithm as project-manager.generateProjectId\n const cleaned = identifier\n .replace(/\\.git$/, '')\n .replace(/[^a-zA-Z0-9-]/g, '-')\n .toLowerCase();\n\n return cleaned.substring(cleaned.length - 50);\n } catch {\n return null;\n }\n }\n\n private async getGitBranch(\n projectPath?: string\n ): Promise<string | undefined> {\n try {\n const { execSync } = await import('child_process');\n const cwd = projectPath || process.cwd();\n const branch = execSync('git rev-parse --abbrev-ref HEAD', {\n cwd,\n encoding: 'utf-8',\n }).trim();\n return branch;\n } catch {\n return undefined;\n }\n }\n\n private async findProjectBranchSession(\n projectHash: string,\n branch?: string\n ): Promise<Session | null> {\n if (!branch) return null;\n\n const sessions = await this.listSessions({\n projectId: projectHash,\n state: 'active',\n branch,\n });\n\n return sessions.sort((a, b) => b.lastActiveAt - a.lastActiveAt)[0] || null;\n }\n\n private async findLastActiveSession(\n projectHash: string\n ): Promise<Session | null> {\n const sessions = await this.listSessions({\n projectId: projectHash,\n state: 'active',\n });\n\n return sessions.sort((a, b) => b.lastActiveAt - a.lastActiveAt)[0] || null;\n }\n\n private async setProjectActiveSession(\n projectId: string,\n sessionId: string\n ): Promise<void> {\n const projectFile = path.join(\n this.sessionsDir,\n 'projects',\n `${projectId}.json`\n );\n await fs.writeFile(\n projectFile,\n JSON.stringify(\n {\n projectId,\n activeSessionId: sessionId,\n updatedAt: Date.now(),\n },\n null,\n 2\n )\n );\n }\n\n private isSessionRecent(session: Session): boolean {\n return Date.now() - session.lastActiveAt < this.STALE_THRESHOLD;\n }\n\n private async touchSession(session: Session): Promise<void> {\n session.lastActiveAt = Date.now();\n await this.saveSession(session);\n }\n}\n\nexport const sessionManager = SessionManager.getInstance();\n"],
|
|
5
|
-
"mappings": "AAKA,SAAS,MAAM,cAAc;AAC7B,YAAY,QAAQ;AACpB,YAAY,UAAU;AAEtB,SAAS,cAAc;AACvB,SAAS,aAAa,iBAAiB;AAEvC,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;
|
|
4
|
+
"sourcesContent": ["/**\n * Session Management for StackMemory\n * Provides session persistence and recovery across CLI invocations\n */\n\nimport { v4 as uuidv4 } from 'uuid';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport { logger } from '../monitoring/logger.js';\nimport { SystemError, ErrorCode } from '../errors/index.js';\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\nexport interface Session {\n sessionId: string;\n runId: string;\n projectId: string;\n branch?: string;\n startedAt: number;\n lastActiveAt: number;\n metadata: {\n user?: string;\n environment?: string;\n tags?: string[];\n cliVersion?: string;\n };\n state: 'active' | 'suspended' | 'closed';\n}\n\nexport interface SessionOptions {\n sessionId?: string;\n projectPath?: string;\n branch?: string;\n metadata?: Session['metadata'];\n}\n\nexport enum FrameQueryMode {\n CURRENT_SESSION = 'current',\n PROJECT_ACTIVE = 'project',\n ALL_ACTIVE = 'all',\n HISTORICAL = 'historical',\n}\n\nexport class SessionManager {\n private static instance: SessionManager;\n private sessionsDir: string;\n private currentSession: Session | null = null;\n private readonly STALE_THRESHOLD = 24 * 60 * 60 * 1000; // 24 hours\n\n private constructor() {\n const homeDir = process.env['HOME'] || process.env['USERPROFILE'] || '';\n this.sessionsDir = path.join(homeDir, '.stackmemory', 'sessions');\n }\n\n static getInstance(): SessionManager {\n if (!SessionManager.instance) {\n SessionManager.instance = new SessionManager();\n }\n return SessionManager.instance;\n }\n\n async initialize(): Promise<void> {\n try {\n await fs.mkdir(this.sessionsDir, { recursive: true });\n await fs.mkdir(path.join(this.sessionsDir, 'projects'), {\n recursive: true,\n });\n await fs.mkdir(path.join(this.sessionsDir, 'history'), {\n recursive: true,\n });\n } catch (error: unknown) {\n throw new SystemError(\n 'Failed to initialize session directories',\n ErrorCode.INITIALIZATION_ERROR,\n { error, sessionsDir: this.sessionsDir }\n );\n }\n }\n\n async getOrCreateSession(options?: SessionOptions): Promise<Session> {\n // 1. Check explicit session ID\n if (options?.sessionId) {\n const session = await this.loadSession(options.sessionId);\n if (session) {\n this.currentSession = session;\n return session;\n }\n }\n\n // 2. Check environment variable\n const envSessionId = process.env['STACKMEMORY_SESSION'];\n if (envSessionId) {\n const session = await this.loadSession(envSessionId);\n if (session) {\n this.currentSession = session;\n return session;\n }\n }\n\n // 3. Check project + branch context\n const projectHash = await this.getProjectHash(options?.projectPath);\n const branch =\n options?.branch || (await this.getGitBranch(options?.projectPath));\n\n if (projectHash) {\n // Try project+branch session\n const branchSession = await this.findProjectBranchSession(\n projectHash,\n branch\n );\n if (branchSession && this.isSessionRecent(branchSession)) {\n await this.touchSession(branchSession);\n this.currentSession = branchSession;\n return branchSession;\n }\n\n // Try last active for project\n const lastActive = await this.findLastActiveSession(projectHash);\n if (lastActive && this.isSessionRecent(lastActive)) {\n await this.touchSession(lastActive);\n this.currentSession = lastActive;\n return lastActive;\n }\n }\n\n // 4. Create new session\n const newSession = await this.createSession({\n projectId: projectHash || 'global',\n branch,\n metadata: options?.metadata,\n });\n\n this.currentSession = newSession;\n return newSession;\n }\n\n async createSession(params: {\n projectId: string;\n branch?: string;\n metadata?: Session['metadata'];\n }): Promise<Session> {\n const session: Session = {\n sessionId: uuidv4(),\n runId: uuidv4(),\n projectId: params.projectId,\n branch: params.branch,\n startedAt: Date.now(),\n lastActiveAt: Date.now(),\n metadata: {\n ...params.metadata,\n user: process.env['USER'],\n environment: process.env['NODE_ENV'] || 'development',\n cliVersion: process.env['npm_package_version'],\n },\n state: 'active',\n };\n\n await this.saveSession(session);\n await this.setProjectActiveSession(params.projectId, session.sessionId);\n\n // Set as current session\n this.currentSession = session;\n\n logger.info('Created new session', {\n sessionId: session.sessionId,\n projectId: session.projectId,\n branch: session.branch,\n });\n\n return session;\n }\n\n async loadSession(sessionId: string): Promise<Session | null> {\n try {\n const sessionPath = path.join(this.sessionsDir, `${sessionId}.json`);\n const data = await fs.readFile(sessionPath, 'utf-8');\n return JSON.parse(data) as Session;\n } catch (error: unknown) {\n // Check history\n try {\n const historyPath = path.join(\n this.sessionsDir,\n 'history',\n `${sessionId}.json`\n );\n const data = await fs.readFile(historyPath, 'utf-8');\n return JSON.parse(data) as Session;\n } catch {\n return null;\n }\n }\n }\n\n async saveSession(session: Session): Promise<void> {\n const sessionPath = path.join(\n this.sessionsDir,\n `${session.sessionId}.json`\n );\n await fs.writeFile(sessionPath, JSON.stringify(session, null, 2));\n }\n\n async suspendSession(sessionId?: string): Promise<void> {\n const id = sessionId || this.currentSession?.sessionId;\n if (!id) return;\n\n const session = await this.loadSession(id);\n if (session) {\n session.state = 'suspended';\n session.lastActiveAt = Date.now();\n await this.saveSession(session);\n }\n }\n\n async resumeSession(sessionId: string): Promise<Session> {\n const session = await this.loadSession(sessionId);\n if (!session) {\n throw new SystemError('Session not found', ErrorCode.NOT_FOUND, {\n sessionId,\n });\n }\n\n session.state = 'active';\n session.lastActiveAt = Date.now();\n await this.saveSession(session);\n\n this.currentSession = session;\n return session;\n }\n\n async closeSession(sessionId?: string): Promise<void> {\n const id = sessionId || this.currentSession?.sessionId;\n if (!id) return;\n\n const session = await this.loadSession(id);\n if (session) {\n session.state = 'closed';\n session.lastActiveAt = Date.now();\n\n // Move to history\n const sessionPath = path.join(\n this.sessionsDir,\n `${session.sessionId}.json`\n );\n const historyPath = path.join(\n this.sessionsDir,\n 'history',\n `${session.sessionId}.json`\n );\n\n await fs.rename(sessionPath, historyPath);\n }\n }\n\n async listSessions(filter?: {\n projectId?: string;\n state?: Session['state'];\n branch?: string;\n }): Promise<Session[]> {\n const sessions: Session[] = [];\n\n // Load active sessions\n const files = await fs.readdir(this.sessionsDir);\n for (const file of files) {\n if (file.endsWith('.json')) {\n const session = await this.loadSession(file.replace('.json', ''));\n if (session) {\n sessions.push(session);\n }\n }\n }\n\n // Apply filters\n return sessions.filter((s) => {\n if (filter?.projectId && s.projectId !== filter.projectId) return false;\n if (filter?.state && s.state !== filter.state) return false;\n if (filter?.branch && s.branch !== filter.branch) return false;\n return true;\n });\n }\n\n async mergeSessions(sourceId: string, targetId: string): Promise<Session> {\n const source = await this.loadSession(sourceId);\n const target = await this.loadSession(targetId);\n\n if (!source || !target) {\n throw new SystemError(\n 'Session not found for merge',\n ErrorCode.NOT_FOUND,\n { sourceId, targetId }\n );\n }\n\n // Merge metadata\n target.metadata = {\n ...target.metadata,\n ...source.metadata,\n tags: [...(target.metadata.tags || []), ...(source.metadata.tags || [])],\n };\n\n // Update timestamps\n target.lastActiveAt = Date.now();\n\n // Close source session\n await this.closeSession(sourceId);\n await this.saveSession(target);\n\n logger.info('Merged sessions', {\n source: sourceId,\n target: targetId,\n });\n\n return target;\n }\n\n async cleanupStaleSessions(\n maxAge: number = 30 * 24 * 60 * 60 * 1000\n ): Promise<number> {\n const historyDir = path.join(this.sessionsDir, 'history');\n const files = await fs.readdir(historyDir);\n const cutoff = Date.now() - maxAge;\n let cleaned = 0;\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(historyDir, file);\n const stats = await fs.stat(filePath);\n\n if (stats.mtimeMs < cutoff) {\n await fs.unlink(filePath);\n cleaned++;\n }\n }\n }\n\n logger.info(`Cleaned up ${cleaned} stale sessions`);\n return cleaned;\n }\n\n getCurrentSession(): Session | null {\n return this.currentSession;\n }\n\n getSessionRunId(): string {\n return this.currentSession?.runId || uuidv4();\n }\n\n private async getProjectHash(projectPath?: string): Promise<string | null> {\n try {\n const cwd = projectPath || process.cwd();\n const pathModule = await import('path');\n\n // Try to get git remote first (consistent with project-manager)\n let identifier: string;\n try {\n const { execSync } = await import('child_process');\n identifier = execSync('git config --get remote.origin.url', {\n cwd,\n encoding: 'utf-8',\n timeout: 5000,\n }).trim();\n } catch {\n // Fall back to directory path\n identifier = cwd;\n }\n\n // Use same algorithm as project-manager.generateProjectId\n const cleaned = identifier\n .replace(/\\.git$/, '')\n .replace(/[^a-zA-Z0-9-]/g, '-')\n .toLowerCase();\n\n return cleaned.substring(cleaned.length - 50);\n } catch {\n return null;\n }\n }\n\n private async getGitBranch(\n projectPath?: string\n ): Promise<string | undefined> {\n try {\n const { execSync } = await import('child_process');\n const cwd = projectPath || process.cwd();\n const branch = execSync('git rev-parse --abbrev-ref HEAD', {\n cwd,\n encoding: 'utf-8',\n }).trim();\n return branch;\n } catch {\n return undefined;\n }\n }\n\n private async findProjectBranchSession(\n projectHash: string,\n branch?: string\n ): Promise<Session | null> {\n if (!branch) return null;\n\n const sessions = await this.listSessions({\n projectId: projectHash,\n state: 'active',\n branch,\n });\n\n return sessions.sort((a, b) => b.lastActiveAt - a.lastActiveAt)[0] || null;\n }\n\n private async findLastActiveSession(\n projectHash: string\n ): Promise<Session | null> {\n const sessions = await this.listSessions({\n projectId: projectHash,\n state: 'active',\n });\n\n return sessions.sort((a, b) => b.lastActiveAt - a.lastActiveAt)[0] || null;\n }\n\n private async setProjectActiveSession(\n projectId: string,\n sessionId: string\n ): Promise<void> {\n const projectFile = path.join(\n this.sessionsDir,\n 'projects',\n `${projectId}.json`\n );\n await fs.writeFile(\n projectFile,\n JSON.stringify(\n {\n projectId,\n activeSessionId: sessionId,\n updatedAt: Date.now(),\n },\n null,\n 2\n )\n );\n }\n\n private isSessionRecent(session: Session): boolean {\n return Date.now() - session.lastActiveAt < this.STALE_THRESHOLD;\n }\n\n private async touchSession(session: Session): Promise<void> {\n session.lastActiveAt = Date.now();\n await this.saveSession(session);\n }\n}\n\nexport const sessionManager = SessionManager.getInstance();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["FrameQueryMode"]
|
|
7
7
|
}
|
|
@@ -67,7 +67,9 @@ class ChromaDBAdapter {
|
|
|
67
67
|
documents: [document.document],
|
|
68
68
|
metadatas: [document.metadata]
|
|
69
69
|
});
|
|
70
|
-
this.logger.debug(
|
|
70
|
+
this.logger.debug(
|
|
71
|
+
`Stored frame ${frame.frameId} for user ${this.userId}`
|
|
72
|
+
);
|
|
71
73
|
} catch (error) {
|
|
72
74
|
this.logger.error(`Failed to store frame ${frame.frameId}`, error);
|
|
73
75
|
throw error;
|
|
@@ -192,7 +194,9 @@ class ChromaDBAdapter {
|
|
|
192
194
|
content: doc || "",
|
|
193
195
|
metadata: results.metadatas?.[i] || {}
|
|
194
196
|
}));
|
|
195
|
-
indexed.sort(
|
|
197
|
+
indexed.sort(
|
|
198
|
+
(a, b) => (b.metadata.timestamp || 0) - (a.metadata.timestamp || 0)
|
|
199
|
+
);
|
|
196
200
|
contexts.push(...indexed.slice(0, limit));
|
|
197
201
|
}
|
|
198
202
|
return contexts;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/storage/chromadb-adapter.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * ChromaDB Storage Adapter for StackMemory\n * \n * Provides vector storage and semantic search capabilities for context data\n * using ChromaDB cloud service with user and team segmentation.\n */\n\nimport { CloudClient, Collection } from 'chromadb';\nimport { v4 as uuidv4 } from 'uuid';\nimport { Frame } from '../context/frame-manager.js';\nimport { Logger } from '../monitoring/logger.js';\n\ninterface ChromaDocument {\n id: string;\n document: string;\n metadata: {\n user_id: string;\n team_id?: string;\n frame_id: string;\n session_id: string;\n project_name: string;\n timestamp: number;\n type: 'frame' | 'decision' | 'observation' | 'context';\n score?: number;\n tags?: string[];\n };\n}\n\ninterface ChromaConfig {\n apiKey: string;\n tenant: string;\n database: string;\n collectionName?: string;\n}\n\nexport class ChromaDBAdapter {\n private client: CloudClient;\n private collection: Collection | null = null;\n private logger: Logger;\n private config: ChromaConfig;\n private userId: string;\n private teamId?: string;\n\n constructor(config: ChromaConfig, userId: string, teamId?: string) {\n this.config = config;\n this.userId = userId;\n this.teamId = teamId;\n this.logger = new Logger('ChromaDBAdapter');\n\n // Initialize ChromaDB client\n this.client = new CloudClient({\n apiKey: config.apiKey,\n tenant: config.tenant,\n database: config.database,\n });\n }\n\n async initialize(): Promise<void> {\n try {\n const collectionName = this.config.collectionName || 'stackmemory_contexts';\n \n // Get or create collection with metadata for filtering\n this.collection = await this.client.getOrCreateCollection({\n name: collectionName,\n metadata: {\n description: 'StackMemory context storage',\n version: '1.0.0',\n created_at: new Date().toISOString(),\n },\n });\n\n this.logger.info(`ChromaDB collection '${collectionName}' initialized`);\n } catch (error: unknown) {\n this.logger.error('Failed to initialize ChromaDB collection', error);\n throw error;\n }\n }\n\n /**\n * Store a frame in ChromaDB\n */\n async storeFrame(frame: Frame): Promise<void> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n // Prepare document from frame\n const frameMetadata: any = {\n user_id: this.userId,\n frame_id: frame.frameId,\n session_id: frame.sessionId || 'unknown',\n project_name: frame.projectName || 'default',\n timestamp: frame.timestamp,\n type: 'frame',\n score: frame.score,\n tags: frame.tags || [],\n };\n\n // Only add team_id if it exists\n if (this.teamId) {\n frameMetadata.team_id = this.teamId;\n }\n\n const document: ChromaDocument = {\n id: `frame_${frame.frameId}_${this.userId}`,\n document: this.frameToDocument(frame),\n metadata: frameMetadata,\n };\n\n // Add to ChromaDB\n await this.collection.add({\n ids: [document.id],\n documents: [document.document],\n metadatas: [document.metadata],\n });\n\n this.logger.debug(`Stored frame ${frame.frameId} for user ${this.userId}`);\n } catch (error: unknown) {\n this.logger.error(`Failed to store frame ${frame.frameId}`, error);\n throw error;\n }\n }\n\n /**\n * Store a decision or observation\n */\n async storeContext(\n type: 'decision' | 'observation',\n content: string,\n metadata?: Record<string, any>\n ): Promise<void> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n const contextId = `${type}_${uuidv4()}_${this.userId}`;\n \n const documentMetadata: any = {\n user_id: this.userId,\n frame_id: metadata?.frame_id || 'none',\n session_id: metadata?.session_id || 'unknown',\n project_name: metadata?.project_name || 'default',\n timestamp: Date.now(),\n type,\n ...metadata,\n };\n\n // Only add team_id if it exists (ChromaDB doesn't accept undefined values)\n if (this.teamId) {\n documentMetadata.team_id = this.teamId;\n }\n\n const document: ChromaDocument = {\n id: contextId,\n document: content,\n metadata: documentMetadata,\n };\n\n await this.collection.add({\n ids: [document.id],\n documents: [document.document],\n metadatas: [document.metadata],\n });\n\n this.logger.debug(`Stored ${type} for user ${this.userId}`);\n } catch (error: unknown) {\n this.logger.error(`Failed to store ${type}`, error);\n throw error;\n }\n }\n\n /**\n * Query contexts by semantic similarity\n */\n async queryContexts(\n query: string,\n limit: number = 10,\n filters?: {\n type?: string[];\n projectName?: string;\n sessionId?: string;\n startTime?: number;\n endTime?: number;\n }\n ): Promise<Array<{ content: string; metadata: any; distance: number }>> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n // Build where clause for filtering\n const whereClause: any = {\n user_id: this.userId,\n };\n\n // Add team filter if applicable\n if (this.teamId) {\n whereClause['$or'] = [\n { team_id: this.teamId },\n { user_id: this.userId },\n ];\n }\n\n // Add additional filters\n if (filters?.type && filters.type.length > 0) {\n whereClause.type = { $in: filters.type };\n }\n\n if (filters?.projectName) {\n whereClause.project_name = filters.projectName;\n }\n\n if (filters?.sessionId) {\n whereClause.session_id = filters.sessionId;\n }\n\n if (filters?.startTime || filters?.endTime) {\n whereClause.timestamp = {};\n if (filters.startTime) {\n whereClause.timestamp.$gte = filters.startTime;\n }\n if (filters.endTime) {\n whereClause.timestamp.$lte = filters.endTime;\n }\n }\n\n // Query ChromaDB\n const results = await this.collection.query({\n queryTexts: [query],\n nResults: limit,\n where: whereClause,\n include: ['documents', 'metadatas', 'distances'],\n });\n\n // Format results\n const contexts: Array<{ content: string; metadata: any; distance: number }> = [];\n \n if (results.documents && results.documents[0]) {\n for (let i = 0; i < results.documents[0].length; i++) {\n contexts.push({\n content: results.documents[0][i] || '',\n metadata: results.metadatas?.[0]?.[i] || {},\n distance: results.distances?.[0]?.[i] || 0,\n });\n }\n }\n\n this.logger.debug(`Found ${contexts.length} contexts for query`);\n return contexts;\n } catch (error: unknown) {\n this.logger.error('Failed to query contexts', error);\n throw error;\n }\n }\n\n /**\n * Get user's recent contexts\n */\n async getRecentContexts(\n limit: number = 20,\n type?: string\n ): Promise<Array<{ content: string; metadata: any }>> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n const whereClause: any = {\n user_id: this.userId,\n };\n\n if (type) {\n whereClause.type = type;\n }\n\n // Get all documents for the user (ChromaDB doesn't support direct ordering)\n const results = await this.collection.get({\n where: whereClause,\n include: ['documents', 'metadatas'],\n });\n\n // Sort by timestamp and limit\n const contexts: Array<{ content: string; metadata: any }> = [];\n \n if (results.documents) {\n const indexed = results.documents.map((doc, i) => ({\n content: doc || '',\n metadata: results.metadatas?.[i] || {},\n }));\n\n // Sort by timestamp descending\n indexed.sort((a, b) => (b.metadata.timestamp || 0) - (a.metadata.timestamp || 0));\n\n // Take limit\n contexts.push(...indexed.slice(0, limit));\n }\n\n return contexts;\n } catch (error: unknown) {\n this.logger.error('Failed to get recent contexts', error);\n throw error;\n }\n }\n\n /**\n * Delete old contexts (retention policy)\n */\n async deleteOldContexts(olderThanDays: number = 30): Promise<number> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n const cutoffTime = Date.now() - (olderThanDays * 24 * 60 * 60 * 1000);\n\n // Get old documents\n const results = await this.collection.get({\n where: {\n user_id: this.userId,\n timestamp: { $lt: cutoffTime },\n },\n include: ['ids'],\n });\n\n if (!results.ids || results.ids.length === 0) {\n return 0;\n }\n\n // Delete old documents\n await this.collection.delete({\n ids: results.ids,\n });\n\n this.logger.info(`Deleted ${results.ids.length} old contexts`);\n return results.ids.length;\n } catch (error: unknown) {\n this.logger.error('Failed to delete old contexts', error);\n throw error;\n }\n }\n\n /**\n * Get team contexts (if user is part of a team)\n */\n async getTeamContexts(\n limit: number = 20\n ): Promise<Array<{ content: string; metadata: any }>> {\n if (!this.collection || !this.teamId) {\n return [];\n }\n\n try {\n const results = await this.collection.get({\n where: {\n team_id: this.teamId,\n },\n include: ['documents', 'metadatas'],\n limit,\n });\n\n const contexts: Array<{ content: string; metadata: any }> = [];\n \n if (results.documents) {\n for (let i = 0; i < results.documents.length; i++) {\n contexts.push({\n content: results.documents[i] || '',\n metadata: results.metadatas?.[i] || {},\n });\n }\n }\n\n return contexts;\n } catch (error: unknown) {\n this.logger.error('Failed to get team contexts', error);\n return [];\n }\n }\n\n /**\n * Convert frame to searchable document\n */\n private frameToDocument(frame: Frame): string {\n const parts = [\n `Frame: ${frame.title}`,\n `Type: ${frame.type}`,\n `Status: ${frame.status}`,\n ];\n\n if (frame.description) {\n parts.push(`Description: ${frame.description}`);\n }\n\n if (frame.inputs && frame.inputs.length > 0) {\n parts.push(`Inputs: ${frame.inputs.join(', ')}`);\n }\n\n if (frame.outputs && frame.outputs.length > 0) {\n parts.push(`Outputs: ${frame.outputs.join(', ')}`);\n }\n\n if (frame.tags && frame.tags.length > 0) {\n parts.push(`Tags: ${frame.tags.join(', ')}`);\n }\n\n if (frame.digest_json) {\n try {\n const digest = JSON.parse(frame.digest_json);\n if (digest.summary) {\n parts.push(`Summary: ${digest.summary}`);\n }\n if (digest.keyDecisions) {\n parts.push(`Decisions: ${digest.keyDecisions.join('. ')}`);\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n return parts.join('\\n');\n }\n\n /**\n * Update team ID for a user\n */\n async updateTeamId(newTeamId: string): Promise<void> {\n this.teamId = newTeamId;\n this.logger.info(`Updated team ID to ${newTeamId} for user ${this.userId}`);\n }\n\n /**\n * Get storage statistics\n */\n async getStats(): Promise<{\n totalDocuments: number;\n userDocuments: number;\n teamDocuments?: number;\n documentsByType: Record<string, number>;\n }> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n // Get user documents\n const userResults = await this.collection.get({\n where: { user_id: this.userId },\n include: ['metadatas'],\n });\n\n const stats: any = {\n totalDocuments: 0,\n userDocuments: userResults.ids?.length || 0,\n documentsByType: {},\n };\n\n // Count by type\n if (userResults.metadatas) {\n for (const metadata of userResults.metadatas) {\n const type = metadata?.type || 'unknown';\n stats.documentsByType[type] = (stats.documentsByType[type] || 0) + 1;\n }\n }\n\n // Get team documents if applicable\n if (this.teamId) {\n const teamResults = await this.collection.get({\n where: { team_id: this.teamId },\n include: ['ids'],\n });\n stats.teamDocuments = teamResults.ids?.length || 0;\n }\n\n stats.totalDocuments = stats.userDocuments + (stats.teamDocuments || 0);\n\n return stats;\n } catch (error: unknown) {\n this.logger.error('Failed to get stats', error);\n throw error;\n }\n }\n}"],
|
|
5
|
-
"mappings": "AAOA,SAAS,mBAA+B;AACxC,SAAS,MAAM,cAAc;AAE7B,SAAS,cAAc;AAyBhB,MAAM,gBAAgB;AAAA,EACnB;AAAA,EACA,aAAgC;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAsB,QAAgB,QAAiB;AACjE,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,SAAS,IAAI,OAAO,iBAAiB;AAG1C,SAAK,SAAS,IAAI,YAAY;AAAA,MAC5B,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aAA4B;AAChC,QAAI;AACF,YAAM,
|
|
4
|
+
"sourcesContent": ["/**\n * ChromaDB Storage Adapter for StackMemory\n *\n * Provides vector storage and semantic search capabilities for context data\n * using ChromaDB cloud service with user and team segmentation.\n */\n\nimport { CloudClient, Collection } from 'chromadb';\nimport { v4 as uuidv4 } from 'uuid';\nimport { Frame } from '../context/frame-manager.js';\nimport { Logger } from '../monitoring/logger.js';\n\ninterface ChromaDocument {\n id: string;\n document: string;\n metadata: {\n user_id: string;\n team_id?: string;\n frame_id: string;\n session_id: string;\n project_name: string;\n timestamp: number;\n type: 'frame' | 'decision' | 'observation' | 'context';\n score?: number;\n tags?: string[];\n };\n}\n\ninterface ChromaConfig {\n apiKey: string;\n tenant: string;\n database: string;\n collectionName?: string;\n}\n\nexport class ChromaDBAdapter {\n private client: CloudClient;\n private collection: Collection | null = null;\n private logger: Logger;\n private config: ChromaConfig;\n private userId: string;\n private teamId?: string;\n\n constructor(config: ChromaConfig, userId: string, teamId?: string) {\n this.config = config;\n this.userId = userId;\n this.teamId = teamId;\n this.logger = new Logger('ChromaDBAdapter');\n\n // Initialize ChromaDB client\n this.client = new CloudClient({\n apiKey: config.apiKey,\n tenant: config.tenant,\n database: config.database,\n });\n }\n\n async initialize(): Promise<void> {\n try {\n const collectionName =\n this.config.collectionName || 'stackmemory_contexts';\n\n // Get or create collection with metadata for filtering\n this.collection = await this.client.getOrCreateCollection({\n name: collectionName,\n metadata: {\n description: 'StackMemory context storage',\n version: '1.0.0',\n created_at: new Date().toISOString(),\n },\n });\n\n this.logger.info(`ChromaDB collection '${collectionName}' initialized`);\n } catch (error: unknown) {\n this.logger.error('Failed to initialize ChromaDB collection', error);\n throw error;\n }\n }\n\n /**\n * Store a frame in ChromaDB\n */\n async storeFrame(frame: Frame): Promise<void> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n // Prepare document from frame\n const frameMetadata: any = {\n user_id: this.userId,\n frame_id: frame.frameId,\n session_id: frame.sessionId || 'unknown',\n project_name: frame.projectName || 'default',\n timestamp: frame.timestamp,\n type: 'frame',\n score: frame.score,\n tags: frame.tags || [],\n };\n\n // Only add team_id if it exists\n if (this.teamId) {\n frameMetadata.team_id = this.teamId;\n }\n\n const document: ChromaDocument = {\n id: `frame_${frame.frameId}_${this.userId}`,\n document: this.frameToDocument(frame),\n metadata: frameMetadata,\n };\n\n // Add to ChromaDB\n await this.collection.add({\n ids: [document.id],\n documents: [document.document],\n metadatas: [document.metadata],\n });\n\n this.logger.debug(\n `Stored frame ${frame.frameId} for user ${this.userId}`\n );\n } catch (error: unknown) {\n this.logger.error(`Failed to store frame ${frame.frameId}`, error);\n throw error;\n }\n }\n\n /**\n * Store a decision or observation\n */\n async storeContext(\n type: 'decision' | 'observation',\n content: string,\n metadata?: Record<string, any>\n ): Promise<void> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n const contextId = `${type}_${uuidv4()}_${this.userId}`;\n\n const documentMetadata: any = {\n user_id: this.userId,\n frame_id: metadata?.frame_id || 'none',\n session_id: metadata?.session_id || 'unknown',\n project_name: metadata?.project_name || 'default',\n timestamp: Date.now(),\n type,\n ...metadata,\n };\n\n // Only add team_id if it exists (ChromaDB doesn't accept undefined values)\n if (this.teamId) {\n documentMetadata.team_id = this.teamId;\n }\n\n const document: ChromaDocument = {\n id: contextId,\n document: content,\n metadata: documentMetadata,\n };\n\n await this.collection.add({\n ids: [document.id],\n documents: [document.document],\n metadatas: [document.metadata],\n });\n\n this.logger.debug(`Stored ${type} for user ${this.userId}`);\n } catch (error: unknown) {\n this.logger.error(`Failed to store ${type}`, error);\n throw error;\n }\n }\n\n /**\n * Query contexts by semantic similarity\n */\n async queryContexts(\n query: string,\n limit: number = 10,\n filters?: {\n type?: string[];\n projectName?: string;\n sessionId?: string;\n startTime?: number;\n endTime?: number;\n }\n ): Promise<Array<{ content: string; metadata: any; distance: number }>> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n // Build where clause for filtering\n const whereClause: any = {\n user_id: this.userId,\n };\n\n // Add team filter if applicable\n if (this.teamId) {\n whereClause['$or'] = [\n { team_id: this.teamId },\n { user_id: this.userId },\n ];\n }\n\n // Add additional filters\n if (filters?.type && filters.type.length > 0) {\n whereClause.type = { $in: filters.type };\n }\n\n if (filters?.projectName) {\n whereClause.project_name = filters.projectName;\n }\n\n if (filters?.sessionId) {\n whereClause.session_id = filters.sessionId;\n }\n\n if (filters?.startTime || filters?.endTime) {\n whereClause.timestamp = {};\n if (filters.startTime) {\n whereClause.timestamp.$gte = filters.startTime;\n }\n if (filters.endTime) {\n whereClause.timestamp.$lte = filters.endTime;\n }\n }\n\n // Query ChromaDB\n const results = await this.collection.query({\n queryTexts: [query],\n nResults: limit,\n where: whereClause,\n include: ['documents', 'metadatas', 'distances'],\n });\n\n // Format results\n const contexts: Array<{\n content: string;\n metadata: any;\n distance: number;\n }> = [];\n\n if (results.documents && results.documents[0]) {\n for (let i = 0; i < results.documents[0].length; i++) {\n contexts.push({\n content: results.documents[0][i] || '',\n metadata: results.metadatas?.[0]?.[i] || {},\n distance: results.distances?.[0]?.[i] || 0,\n });\n }\n }\n\n this.logger.debug(`Found ${contexts.length} contexts for query`);\n return contexts;\n } catch (error: unknown) {\n this.logger.error('Failed to query contexts', error);\n throw error;\n }\n }\n\n /**\n * Get user's recent contexts\n */\n async getRecentContexts(\n limit: number = 20,\n type?: string\n ): Promise<Array<{ content: string; metadata: any }>> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n const whereClause: any = {\n user_id: this.userId,\n };\n\n if (type) {\n whereClause.type = type;\n }\n\n // Get all documents for the user (ChromaDB doesn't support direct ordering)\n const results = await this.collection.get({\n where: whereClause,\n include: ['documents', 'metadatas'],\n });\n\n // Sort by timestamp and limit\n const contexts: Array<{ content: string; metadata: any }> = [];\n\n if (results.documents) {\n const indexed = results.documents.map((doc, i) => ({\n content: doc || '',\n metadata: results.metadatas?.[i] || {},\n }));\n\n // Sort by timestamp descending\n indexed.sort(\n (a, b) => (b.metadata.timestamp || 0) - (a.metadata.timestamp || 0)\n );\n\n // Take limit\n contexts.push(...indexed.slice(0, limit));\n }\n\n return contexts;\n } catch (error: unknown) {\n this.logger.error('Failed to get recent contexts', error);\n throw error;\n }\n }\n\n /**\n * Delete old contexts (retention policy)\n */\n async deleteOldContexts(olderThanDays: number = 30): Promise<number> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n const cutoffTime = Date.now() - olderThanDays * 24 * 60 * 60 * 1000;\n\n // Get old documents\n const results = await this.collection.get({\n where: {\n user_id: this.userId,\n timestamp: { $lt: cutoffTime },\n },\n include: ['ids'],\n });\n\n if (!results.ids || results.ids.length === 0) {\n return 0;\n }\n\n // Delete old documents\n await this.collection.delete({\n ids: results.ids,\n });\n\n this.logger.info(`Deleted ${results.ids.length} old contexts`);\n return results.ids.length;\n } catch (error: unknown) {\n this.logger.error('Failed to delete old contexts', error);\n throw error;\n }\n }\n\n /**\n * Get team contexts (if user is part of a team)\n */\n async getTeamContexts(\n limit: number = 20\n ): Promise<Array<{ content: string; metadata: any }>> {\n if (!this.collection || !this.teamId) {\n return [];\n }\n\n try {\n const results = await this.collection.get({\n where: {\n team_id: this.teamId,\n },\n include: ['documents', 'metadatas'],\n limit,\n });\n\n const contexts: Array<{ content: string; metadata: any }> = [];\n\n if (results.documents) {\n for (let i = 0; i < results.documents.length; i++) {\n contexts.push({\n content: results.documents[i] || '',\n metadata: results.metadatas?.[i] || {},\n });\n }\n }\n\n return contexts;\n } catch (error: unknown) {\n this.logger.error('Failed to get team contexts', error);\n return [];\n }\n }\n\n /**\n * Convert frame to searchable document\n */\n private frameToDocument(frame: Frame): string {\n const parts = [\n `Frame: ${frame.title}`,\n `Type: ${frame.type}`,\n `Status: ${frame.status}`,\n ];\n\n if (frame.description) {\n parts.push(`Description: ${frame.description}`);\n }\n\n if (frame.inputs && frame.inputs.length > 0) {\n parts.push(`Inputs: ${frame.inputs.join(', ')}`);\n }\n\n if (frame.outputs && frame.outputs.length > 0) {\n parts.push(`Outputs: ${frame.outputs.join(', ')}`);\n }\n\n if (frame.tags && frame.tags.length > 0) {\n parts.push(`Tags: ${frame.tags.join(', ')}`);\n }\n\n if (frame.digest_json) {\n try {\n const digest = JSON.parse(frame.digest_json);\n if (digest.summary) {\n parts.push(`Summary: ${digest.summary}`);\n }\n if (digest.keyDecisions) {\n parts.push(`Decisions: ${digest.keyDecisions.join('. ')}`);\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n return parts.join('\\n');\n }\n\n /**\n * Update team ID for a user\n */\n async updateTeamId(newTeamId: string): Promise<void> {\n this.teamId = newTeamId;\n this.logger.info(`Updated team ID to ${newTeamId} for user ${this.userId}`);\n }\n\n /**\n * Get storage statistics\n */\n async getStats(): Promise<{\n totalDocuments: number;\n userDocuments: number;\n teamDocuments?: number;\n documentsByType: Record<string, number>;\n }> {\n if (!this.collection) {\n throw new Error('ChromaDB not initialized');\n }\n\n try {\n // Get user documents\n const userResults = await this.collection.get({\n where: { user_id: this.userId },\n include: ['metadatas'],\n });\n\n const stats: any = {\n totalDocuments: 0,\n userDocuments: userResults.ids?.length || 0,\n documentsByType: {},\n };\n\n // Count by type\n if (userResults.metadatas) {\n for (const metadata of userResults.metadatas) {\n const type = metadata?.type || 'unknown';\n stats.documentsByType[type] = (stats.documentsByType[type] || 0) + 1;\n }\n }\n\n // Get team documents if applicable\n if (this.teamId) {\n const teamResults = await this.collection.get({\n where: { team_id: this.teamId },\n include: ['ids'],\n });\n stats.teamDocuments = teamResults.ids?.length || 0;\n }\n\n stats.totalDocuments = stats.userDocuments + (stats.teamDocuments || 0);\n\n return stats;\n } catch (error: unknown) {\n this.logger.error('Failed to get stats', error);\n throw error;\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -8,14 +8,18 @@ class ChromaDBAdapter {
|
|
|
8
8
|
constructor(config) {
|
|
9
9
|
this.config = config;
|
|
10
10
|
try {
|
|
11
|
-
if (config.
|
|
11
|
+
if (config.apiKey && (config.apiUrl?.includes("trychroma.com") || config.apiKey.startsWith("ck-"))) {
|
|
12
|
+
const tenant = process.env.CHROMADB_TENANT;
|
|
13
|
+
const database = process.env.CHROMADB_DATABASE || "stackmemory";
|
|
12
14
|
this.client = new ChromaClient({
|
|
13
15
|
ssl: true,
|
|
14
16
|
host: "api.trychroma.com",
|
|
15
17
|
port: 443,
|
|
16
18
|
headers: {
|
|
17
19
|
"X-Chroma-Token": config.apiKey
|
|
18
|
-
}
|
|
20
|
+
},
|
|
21
|
+
tenant,
|
|
22
|
+
database
|
|
19
23
|
});
|
|
20
24
|
} else {
|
|
21
25
|
this.client = new ChromaClient();
|
|
@@ -35,9 +39,13 @@ class ChromaDBAdapter {
|
|
|
35
39
|
version: "2.0.0"
|
|
36
40
|
}
|
|
37
41
|
});
|
|
38
|
-
console.log(
|
|
42
|
+
console.log(
|
|
43
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] INFO: ChromaDB collection '${collectionName}' initialized`
|
|
44
|
+
);
|
|
39
45
|
} catch (error) {
|
|
40
|
-
console.log(
|
|
46
|
+
console.log(
|
|
47
|
+
`ChromaDB service not available, using JSON fallback storage`
|
|
48
|
+
);
|
|
41
49
|
this.collection = null;
|
|
42
50
|
}
|
|
43
51
|
}
|
|
@@ -89,7 +97,11 @@ class ChromaDBAdapter {
|
|
|
89
97
|
const fs = await import("fs");
|
|
90
98
|
const path = await import("path");
|
|
91
99
|
const os = await import("os");
|
|
92
|
-
const storageDir = path.join(
|
|
100
|
+
const storageDir = path.join(
|
|
101
|
+
os.homedir(),
|
|
102
|
+
".stackmemory",
|
|
103
|
+
"context-storage"
|
|
104
|
+
);
|
|
93
105
|
const storageFile = path.join(storageDir, "contexts.jsonl");
|
|
94
106
|
if (!fs.existsSync(storageDir)) {
|
|
95
107
|
fs.mkdirSync(storageDir, { recursive: true });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/storage/chromadb-simple.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Simplified ChromaDB adapter for Claude hooks\n */\n\nimport { ChromaClient } from 'chromadb';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport class ChromaDBAdapter {\n private client: ChromaClient;\n private collection: any = null;\n private config: any;\n private fallbackStorage: Map<string, any> = new Map();\n
|
|
5
|
-
"mappings": "AAIA,SAAS,oBAAoB;AAC7B,SAAS,MAAM,cAAc;AAEtB,MAAM,gBAAgB;AAAA,EACnB;AAAA,EACA,aAAkB;AAAA,EAClB;AAAA,EACA,kBAAoC,oBAAI,IAAI;AAAA,EAEpD,YAAY,QAAa;AACvB,SAAK,SAAS;AAEd,QAAI;AAEF,UAAI,OAAO,
|
|
4
|
+
"sourcesContent": ["/**\n * Simplified ChromaDB adapter for Claude hooks\n */\n\nimport { ChromaClient } from 'chromadb';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport class ChromaDBAdapter {\n private client: ChromaClient;\n private collection: any = null;\n private config: any;\n private fallbackStorage: Map<string, any> = new Map();\n\n constructor(config: any) {\n this.config = config;\n\n try {\n // Try to initialize ChromaDB client\n if (config.apiKey && (config.apiUrl?.includes('trychroma.com') || config.apiKey.startsWith('ck-'))) {\n // Cloud configuration - ChromaDB Cloud uses API key starting with 'ck-'\n const tenant = process.env.CHROMADB_TENANT;\n const database = process.env.CHROMADB_DATABASE || 'stackmemory';\n \n this.client = new ChromaClient({\n ssl: true,\n host: 'api.trychroma.com',\n port: 443,\n headers: {\n 'X-Chroma-Token': config.apiKey,\n },\n tenant: tenant,\n database: database\n } as any);\n } else {\n // In-memory/local configuration (no external service needed)\n this.client = new ChromaClient();\n }\n } catch (error: unknown) {\n // Fallback to in-memory client\n console.log('Using in-memory ChromaDB client');\n this.client = new ChromaClient();\n }\n }\n\n async initialize(): Promise<void> {\n try {\n // Use a single collection for all context\n const collectionName =\n this.config.collectionName || 'stackmemory_context';\n\n // Get or create collection\n this.collection = await this.client.getOrCreateCollection({\n name: collectionName,\n metadata: {\n description: 'StackMemory Claude context',\n version: '2.0.0',\n },\n });\n\n console.log(\n `[${new Date().toISOString()}] INFO: ChromaDB collection '${collectionName}' initialized`\n );\n } catch (error: any) {\n console.log(\n `ChromaDB service not available, using JSON fallback storage`\n );\n this.collection = null; // Use fallback\n }\n }\n\n async store(context: any): Promise<any> {\n const id = context.id || `ctx_${uuidv4()}`;\n\n // Prepare metadata - only include non-undefined values\n const metadata: any = {\n timestamp: context.timestamp || new Date().toISOString(),\n type: context.type || 'context',\n user_id: context.user_id || this.config.userId || 'default',\n project: context.project || 'stackmemory',\n };\n\n // Add optional metadata if defined\n if (context.session_id) metadata.session_id = context.session_id;\n if (context.metadata) {\n Object.entries(context.metadata).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n metadata[key] = value;\n }\n });\n }\n\n if (!this.collection) {\n await this.initialize();\n }\n\n try {\n if (this.collection) {\n // Store in ChromaDB if available\n await this.collection.upsert({\n ids: [id],\n documents: [context.content || JSON.stringify(context)],\n metadatas: [metadata],\n });\n } else {\n // Fallback to JSON file storage\n await this.storeToJsonFallback(id, context, metadata);\n }\n\n return {\n success: true,\n id,\n stored_at: new Date().toISOString(),\n };\n } catch (error: any) {\n console.error('Failed to store context:', error.message);\n // Try fallback storage\n try {\n await this.storeToJsonFallback(id, context, metadata);\n return { success: true, id, stored_at: new Date().toISOString() };\n } catch (fallbackError: any) {\n return { success: false, error: fallbackError.message };\n }\n }\n }\n\n private async storeToJsonFallback(\n id: string,\n context: any,\n metadata: any\n ): Promise<void> {\n const fs = await import('fs');\n const path = await import('path');\n const os = await import('os');\n\n const storageDir = path.join(\n os.homedir(),\n '.stackmemory',\n 'context-storage'\n );\n const storageFile = path.join(storageDir, 'contexts.jsonl');\n\n // Ensure directory exists\n if (!fs.existsSync(storageDir)) {\n fs.mkdirSync(storageDir, { recursive: true });\n }\n\n const entry = {\n id,\n content: context.content || JSON.stringify(context),\n metadata,\n stored_at: new Date().toISOString(),\n };\n\n // Append to JSONL file\n fs.appendFileSync(storageFile, JSON.stringify(entry) + '\\n');\n }\n\n async search(params: any): Promise<any[]> {\n if (!this.collection) {\n await this.initialize();\n }\n\n try {\n const query = params.query || '';\n const limit = params.limit || 10;\n\n // Build where clause\n const where: any = {};\n if (params.filter) {\n Object.entries(params.filter).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n where[key] = value;\n }\n });\n }\n\n // Query collection\n const results = await this.collection.query({\n queryTexts: [query],\n nResults: limit,\n where: Object.keys(where).length > 0 ? where : undefined,\n });\n\n // Format results\n const contexts: any[] = [];\n if (results.documents && results.documents[0]) {\n for (let i = 0; i < results.documents[0].length; i++) {\n contexts.push({\n id: results.ids[0][i],\n content: results.documents[0][i],\n metadata: results.metadatas?.[0]?.[i] || {},\n distance: results.distances?.[0]?.[i] || 0,\n });\n }\n }\n\n return contexts;\n } catch (error: any) {\n console.error('Failed to search contexts:', error.message);\n return [];\n }\n }\n\n async deleteCollection(): Promise<void> {\n if (this.collection) {\n await this.client.deleteCollection({\n name: this.config.collectionName || 'stackmemory_context',\n });\n console.log('Collection deleted');\n }\n }\n\n async listCollections(): Promise<any[]> {\n const collections = await this.client.listCollections();\n return collections;\n }\n}\n\nexport default ChromaDBAdapter;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|