UNPKG

@stackmemoryai/stackmemory

Version:

Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.

177 lines (176 loc) 5.08 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { EnhancedHybridDigestGenerator } from "./enhanced-hybrid-digest.js"; import { logger } from "../monitoring/logger.js"; class FrameDigestIntegration { frameManager; digestGenerator; frameActivityMap = /* @__PURE__ */ new Map(); constructor(frameManager, db, llmProvider) { this.frameManager = frameManager; this.digestGenerator = new EnhancedHybridDigestGenerator( db, { enableAIGeneration: true, maxTokens: 200 }, llmProvider ); this.setupHooks(); } /** * Setup frame lifecycle hooks */ setupHooks() { const originalAddEvent = this.frameManager.addEvent.bind(this.frameManager); this.frameManager.addEvent = (eventType, payload, frameId) => { const result = originalAddEvent(eventType, payload, frameId); if (eventType === "tool_call") { this.digestGenerator.recordToolCall(); } if (eventType === "user_message") { this.digestGenerator.recordUserInput(); } const targetFrameId = frameId || this.frameManager.getCurrentFrameId(); if (targetFrameId) { this.frameActivityMap.set(targetFrameId, Date.now()); } return result; }; const originalCreateFrame = this.frameManager.createFrame.bind( this.frameManager ); this.frameManager.createFrame = (options) => { const frameId = originalCreateFrame(options); this.digestGenerator.onFrameOpened(frameId); this.frameActivityMap.set(frameId, Date.now()); return frameId; }; const originalCloseFrame = this.frameManager.closeFrame.bind( this.frameManager ); this.frameManager.closeFrame = (frameId, outputs) => { const targetFrameId = frameId || this.frameManager.getCurrentFrameId(); if (targetFrameId) { const digest = this.generateEnhancedDigest(targetFrameId); const enhancedOutputs = { ...outputs, digest: digest.json, digestText: digest.text }; this.digestGenerator.onFrameClosed(targetFrameId); this.frameActivityMap.delete(targetFrameId); originalCloseFrame(frameId, enhancedOutputs); } else { originalCloseFrame(frameId, outputs); } }; } /** * Generate enhanced digest for a frame */ generateEnhancedDigest(frameId) { const frame = this.frameManager.getFrame(frameId); if (!frame) { logger.warn("Frame not found for digest generation", { frameId }); return { text: "", json: {} }; } const events = this.frameManager.getFrameEvents(frameId); const anchors = this.getFrameAnchors(frameId); const digestInput = { frame: this.convertFrame(frame), events: events.map(this.convertEvent), anchors: anchors.map(this.convertAnchor) }; const hybridDigest = this.digestGenerator.generateDigest(digestInput); return { text: hybridDigest.text, json: { deterministic: hybridDigest.deterministic, aiGenerated: hybridDigest.aiGenerated, status: hybridDigest.status, generatedAt: Date.now() } }; } /** * Convert FrameManager frame to DigestInput frame */ convertFrame(frame) { return frame; } /** * Convert FrameManager event to DigestInput event */ convertEvent(event) { return event; } /** * Convert FrameManager anchor to DigestInput anchor */ convertAnchor(anchor) { return anchor; } /** * Calculate importance score based on frame characteristics */ calculateImportanceScore(frame) { let score = 0.5; const typeScores = { task: 0.6, debug: 0.8, review: 0.7, write: 0.5, tool_scope: 0.3, subtask: 0.4 }; score = typeScores[frame.type] || score; score -= frame.depth * 0.05; if (frame.closed_at) { const durationMinutes = (frame.closed_at - frame.created_at) / 60; if (durationMinutes > 10) score += 0.1; if (durationMinutes > 30) score += 0.1; } return Math.max(0, Math.min(1, score)); } /** * Get frame anchors (wrapper for proper typing) */ getFrameAnchors(frameId) { return []; } /** * Handle user interruption */ handleUserInterruption() { this.digestGenerator.handleInterruption(); } /** * Get idle status */ getIdleStatus() { return this.digestGenerator.getIdleStatus(); } /** * Force process digest queue */ async forceProcessQueue() { await this.digestGenerator.forceProcessQueue(); } /** * Cleanup */ shutdown() { this.digestGenerator.shutdown(); } } function enhanceFrameManagerWithDigest(frameManager, db, llmProvider) { return new FrameDigestIntegration(frameManager, db, llmProvider); } export { FrameDigestIntegration, enhanceFrameManagerWithDigest }; //# sourceMappingURL=frame-digest-integration.js.map