@stackmemoryai/stackmemory 0.3.5 → 0.3.7
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/verifiers/base-verifier.js.map +2 -2
- package/dist/agents/verifiers/formatter-verifier.js.map +2 -2
- package/dist/agents/verifiers/llm-judge.js.map +2 -2
- package/dist/cli/claude-sm.js +24 -13
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/codex-sm.js +24 -13
- package/dist/cli/codex-sm.js.map +2 -2
- package/dist/cli/commands/agent.js.map +2 -2
- package/dist/cli/commands/chromadb.js +217 -32
- package/dist/cli/commands/chromadb.js.map +2 -2
- package/dist/cli/commands/clear.js +12 -1
- package/dist/cli/commands/clear.js.map +2 -2
- package/dist/cli/commands/context.js +13 -2
- package/dist/cli/commands/context.js.map +2 -2
- package/dist/cli/commands/dashboard.js.map +2 -2
- package/dist/cli/commands/gc.js +202 -0
- package/dist/cli/commands/gc.js.map +7 -0
- package/dist/cli/commands/handoff.js +12 -1
- package/dist/cli/commands/handoff.js.map +2 -2
- package/dist/cli/commands/infinite-storage.js +251 -0
- package/dist/cli/commands/infinite-storage.js.map +7 -0
- package/dist/cli/commands/linear-create.js +13 -2
- package/dist/cli/commands/linear-create.js.map +2 -2
- package/dist/cli/commands/linear-list.js +12 -1
- package/dist/cli/commands/linear-list.js.map +2 -2
- package/dist/cli/commands/linear-migrate.js +12 -1
- package/dist/cli/commands/linear-migrate.js.map +2 -2
- package/dist/cli/commands/linear-test.js +12 -1
- package/dist/cli/commands/linear-test.js.map +2 -2
- package/dist/cli/commands/linear-unified.js +262 -0
- package/dist/cli/commands/linear-unified.js.map +7 -0
- package/dist/cli/commands/linear.js +17 -6
- package/dist/cli/commands/linear.js.map +2 -2
- package/dist/cli/commands/monitor.js.map +2 -2
- package/dist/cli/commands/onboard.js.map +2 -2
- package/dist/cli/commands/quality.js.map +2 -2
- package/dist/cli/commands/search.js.map +2 -2
- package/dist/cli/commands/session.js.map +2 -2
- package/dist/cli/commands/skills.js +12 -1
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/storage.js +18 -7
- package/dist/cli/commands/storage.js.map +2 -2
- package/dist/cli/commands/tasks.js.map +2 -2
- package/dist/cli/commands/tui.js +13 -2
- package/dist/cli/commands/tui.js.map +2 -2
- package/dist/cli/commands/webhook.js +14 -3
- package/dist/cli/commands/webhook.js.map +2 -2
- package/dist/cli/commands/workflow.js +14 -3
- package/dist/cli/commands/workflow.js.map +2 -2
- package/dist/cli/commands/worktree.js.map +2 -2
- package/dist/cli/index.js +20 -5
- package/dist/cli/index.js.map +2 -2
- package/dist/core/config/config-manager.js.map +2 -2
- package/dist/core/context/auto-context.js.map +2 -2
- package/dist/core/context/compaction-handler.js.map +2 -2
- package/dist/core/context/context-bridge.js.map +2 -2
- package/dist/core/context/dual-stack-manager.js.map +2 -2
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-digest.js.map +2 -2
- package/dist/core/context/frame-handoff-manager.js.map +2 -2
- package/dist/core/context/frame-manager.js +12 -1
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/frame-stack.js.map +2 -2
- package/dist/core/context/incremental-gc.js +279 -0
- package/dist/core/context/incremental-gc.js.map +7 -0
- package/dist/core/context/permission-manager.js +12 -1
- package/dist/core/context/permission-manager.js.map +2 -2
- package/dist/core/context/refactored-frame-manager.js.map +2 -2
- package/dist/core/context/shared-context-layer.js +12 -1
- package/dist/core/context/shared-context-layer.js.map +2 -2
- package/dist/core/context/stack-merge-resolver.js.map +2 -2
- package/dist/core/context/validation.js.map +2 -2
- package/dist/core/database/batch-operations.js.map +2 -2
- package/dist/core/database/connection-pool.js.map +2 -2
- package/dist/core/database/migration-manager.js.map +2 -2
- package/dist/core/database/paradedb-adapter.js.map +2 -2
- package/dist/core/database/query-cache.js.map +2 -2
- package/dist/core/database/query-router.js.map +2 -2
- package/dist/core/database/sqlite-adapter.js.map +2 -2
- package/dist/core/digest/enhanced-hybrid-digest.js.map +2 -2
- package/dist/core/errors/recovery.js.map +2 -2
- package/dist/core/merge/resolution-engine.js.map +2 -2
- package/dist/core/monitoring/error-handler.js.map +2 -2
- package/dist/core/monitoring/logger.js +14 -3
- package/dist/core/monitoring/logger.js.map +2 -2
- package/dist/core/monitoring/metrics.js +13 -2
- package/dist/core/monitoring/metrics.js.map +2 -2
- package/dist/core/monitoring/progress-tracker.js +12 -1
- package/dist/core/monitoring/progress-tracker.js.map +2 -2
- package/dist/core/monitoring/session-monitor.js.map +2 -2
- package/dist/core/performance/context-cache.js.map +2 -2
- package/dist/core/performance/lazy-context-loader.js.map +2 -2
- package/dist/core/performance/monitor.js.map +2 -2
- package/dist/core/performance/optimized-frame-context.js.map +2 -2
- package/dist/core/performance/performance-benchmark.js.map +2 -2
- package/dist/core/performance/performance-profiler.js +12 -1
- package/dist/core/performance/performance-profiler.js.map +2 -2
- package/dist/core/performance/streaming-jsonl-parser.js.map +2 -2
- package/dist/core/persistence/postgres-adapter.js.map +2 -2
- package/dist/core/projects/project-manager.js.map +2 -2
- package/dist/core/retrieval/context-retriever.js.map +2 -2
- package/dist/core/retrieval/graph-retrieval.js.map +2 -2
- package/dist/core/retrieval/llm-context-retrieval.js.map +2 -2
- package/dist/core/retrieval/retrieval-benchmarks.js.map +2 -2
- package/dist/core/retrieval/summary-generator.js.map +2 -2
- package/dist/core/session/clear-survival.js.map +2 -2
- package/dist/core/session/handoff-generator.js.map +2 -2
- package/dist/core/session/session-manager.js +16 -5
- package/dist/core/session/session-manager.js.map +2 -2
- package/dist/core/skills/skill-storage.js +13 -2
- package/dist/core/skills/skill-storage.js.map +2 -2
- package/dist/core/storage/chromadb-adapter.js.map +2 -2
- package/dist/core/storage/chromadb-simple.js +160 -0
- package/dist/core/storage/chromadb-simple.js.map +7 -0
- package/dist/core/storage/infinite-storage.js +443 -0
- package/dist/core/storage/infinite-storage.js.map +7 -0
- package/dist/core/storage/railway-optimized-storage.js +19 -8
- package/dist/core/storage/railway-optimized-storage.js.map +2 -2
- package/dist/core/storage/remote-storage.js +12 -1
- package/dist/core/storage/remote-storage.js.map +2 -2
- package/dist/core/trace/cli-trace-wrapper.js +16 -5
- package/dist/core/trace/cli-trace-wrapper.js.map +2 -2
- package/dist/core/trace/db-trace-wrapper.js.map +2 -2
- package/dist/core/trace/debug-trace.js +21 -10
- package/dist/core/trace/debug-trace.js.map +2 -2
- package/dist/core/trace/index.js +46 -35
- package/dist/core/trace/index.js.map +2 -2
- package/dist/core/trace/trace-demo.js +12 -1
- package/dist/core/trace/trace-demo.js.map +2 -2
- package/dist/core/trace/trace-detector.js.map +2 -2
- package/dist/core/trace/trace-store.js.map +2 -2
- package/dist/core/utils/compression.js +79 -0
- package/dist/core/utils/compression.js.map +7 -0
- package/dist/core/utils/update-checker.js.map +2 -2
- package/dist/core/worktree/worktree-manager.js.map +2 -2
- package/dist/features/analytics/api/analytics-api.js.map +2 -2
- package/dist/features/analytics/core/analytics-service.js +12 -1
- package/dist/features/analytics/core/analytics-service.js.map +2 -2
- package/dist/features/analytics/queries/metrics-queries.js.map +2 -2
- package/dist/features/tasks/pebbles-task-store.js.map +2 -2
- package/dist/features/tui/components/analytics-panel.js.map +2 -2
- package/dist/features/tui/components/pr-tracker.js.map +2 -2
- package/dist/features/tui/components/session-monitor.js.map +2 -2
- package/dist/features/tui/components/subagent-fleet.js.map +2 -2
- package/dist/features/tui/components/task-board.js +650 -2
- package/dist/features/tui/components/task-board.js.map +2 -2
- package/dist/features/tui/index.js +16 -5
- package/dist/features/tui/index.js.map +2 -2
- package/dist/features/tui/services/data-service.js +35 -52
- package/dist/features/tui/services/data-service.js.map +2 -2
- package/dist/features/tui/services/linear-task-reader.js +100 -0
- package/dist/features/tui/services/linear-task-reader.js.map +7 -0
- package/dist/features/tui/services/websocket-client.js +13 -2
- package/dist/features/tui/services/websocket-client.js.map +2 -2
- package/dist/features/tui/terminal-compat.js +27 -16
- package/dist/features/tui/terminal-compat.js.map +2 -2
- package/dist/features/web/client/stores/task-store.js +22 -0
- package/dist/features/web/client/stores/task-store.js.map +7 -0
- package/dist/features/web/server/index.js +182 -0
- package/dist/features/web/server/index.js.map +7 -0
- package/dist/integrations/claude-code/enhanced-pre-clear-hooks.js.map +2 -2
- package/dist/integrations/claude-code/lifecycle-hooks.js.map +2 -2
- package/dist/integrations/claude-code/post-task-hooks.js.map +2 -2
- package/dist/integrations/linear/auth.js +17 -6
- package/dist/integrations/linear/auth.js.map +2 -2
- package/dist/integrations/linear/auto-sync.js.map +2 -2
- package/dist/integrations/linear/client.js.map +2 -2
- package/dist/integrations/linear/config.js.map +2 -2
- package/dist/integrations/linear/migration.js.map +2 -2
- package/dist/integrations/linear/oauth-server.js +13 -2
- package/dist/integrations/linear/oauth-server.js.map +2 -2
- package/dist/integrations/linear/rest-client.js.map +2 -2
- package/dist/integrations/linear/sync-enhanced.js +202 -0
- package/dist/integrations/linear/sync-enhanced.js.map +7 -0
- package/dist/integrations/linear/sync-manager.js.map +2 -2
- package/dist/integrations/linear/sync-service.js +12 -1
- package/dist/integrations/linear/sync-service.js.map +2 -2
- package/dist/integrations/linear/sync.js +34 -3
- package/dist/integrations/linear/sync.js.map +2 -2
- package/dist/integrations/linear/unified-sync.js +560 -0
- package/dist/integrations/linear/unified-sync.js.map +7 -0
- package/dist/integrations/linear/webhook-handler.js +12 -1
- package/dist/integrations/linear/webhook-handler.js.map +2 -2
- package/dist/integrations/linear/webhook-server.js +14 -3
- package/dist/integrations/linear/webhook-server.js.map +2 -2
- package/dist/integrations/linear/webhook.js +12 -1
- package/dist/integrations/linear/webhook.js.map +2 -2
- package/dist/integrations/mcp/handlers/context-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/linear-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/skill-handlers.js +13 -2
- package/dist/integrations/mcp/handlers/skill-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/task-handlers.js.map +2 -2
- package/dist/integrations/mcp/handlers/trace-handlers.js.map +2 -2
- package/dist/integrations/mcp/middleware/tool-scoring.js.map +2 -2
- package/dist/integrations/mcp/refactored-server.js +15 -4
- package/dist/integrations/mcp/refactored-server.js.map +2 -2
- package/dist/integrations/mcp/server.js +12 -1
- package/dist/integrations/mcp/server.js.map +2 -2
- package/dist/integrations/mcp/tool-definitions.js.map +2 -2
- package/dist/integrations/pg-aiguide/embedding-provider.js +13 -2
- package/dist/integrations/pg-aiguide/embedding-provider.js.map +2 -2
- package/dist/integrations/pg-aiguide/semantic-search.js.map +2 -2
- package/dist/mcp/stackmemory-mcp-server.js +12 -1
- package/dist/mcp/stackmemory-mcp-server.js.map +2 -2
- package/dist/middleware/exponential-rate-limiter.js.map +2 -2
- package/dist/servers/production/auth-middleware.js +13 -2
- package/dist/servers/production/auth-middleware.js.map +2 -2
- package/dist/servers/railway/index.js +22 -11
- package/dist/servers/railway/index.js.map +2 -2
- package/dist/services/config-service.js.map +2 -2
- package/dist/services/context-service.js.map +2 -2
- package/dist/skills/claude-skills.js +150 -1
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/dashboard-launcher.js +212 -0
- package/dist/skills/dashboard-launcher.js.map +7 -0
- package/dist/skills/repo-ingestion-skill.js +561 -0
- package/dist/skills/repo-ingestion-skill.js.map +7 -0
- package/dist/utils/logger.js +12 -1
- package/dist/utils/logger.js.map +2 -2
- package/package.json +7 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/context/frame-stack.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Frame Stack Management\n * Handles the call stack of active frames\n */\n\nimport { Frame, FrameContext, FrameType } from './frame-types.js';\nimport { FrameDatabase } from './frame-database.js';\nimport { logger } from '../monitoring/logger.js';\nimport { FrameError, ErrorCode } from '../errors/index.js';\n\nexport class FrameStack {\n private activeStack: string[] = [];\n\n constructor(\n private frameDb: FrameDatabase,\n private projectId: string,\n private runId: string\n ) {}\n\n /**\n * Initialize stack by loading active frames\n */\n async initialize(): Promise<void> {\n try {\n const activeFrames = this.frameDb.getFramesByProject(this.projectId, 'active');\n \n // Rebuild stack from database\n this.activeStack = this.buildStackFromFrames(activeFrames);\n \n logger.info('Frame stack initialized', { \n stackDepth: this.activeStack.length,\n projectId: this.projectId,\n });\n } catch (error) {\n logger.error('Failed to initialize frame stack', {\n error: error instanceof Error ? error.message : String(error),\n projectId: this.projectId,\n runId: this.runId,\n });\n throw new FrameError(\n 'Failed to initialize frame stack',\n ErrorCode.FRAME_INIT_FAILED,\n { \n projectId: this.projectId, \n runId: this.runId,\n originalError: error instanceof Error ? error.message : String(error)\n }\n );\n }\n }\n\n /**\n * Push new frame onto stack\n */\n pushFrame(frameId: string): void {\n if (this.activeStack.includes(frameId)) {\n logger.warn('Frame already on stack', { frameId });\n return;\n }\n\n this.activeStack.push(frameId);\n \n logger.debug('Pushed frame to stack', { \n frameId, \n stackDepth: this.activeStack.length \n });\n }\n\n /**\n * Pop frame from stack\n */\n popFrame(frameId?: string): string | undefined {\n if (this.activeStack.length === 0) {\n return undefined;\n }\n\n let poppedFrameId: string | undefined;\n\n if (frameId) {\n // Pop specific frame (and all frames above it)\n const index = this.activeStack.indexOf(frameId);\n if (index === -1) {\n logger.warn('Frame not found on stack', { frameId });\n return undefined;\n }\n\n // Remove the target frame and all frames above it\n const removed = this.activeStack.splice(index);\n poppedFrameId = removed[0];\n\n if (removed.length > 1) {\n logger.info('Popped multiple frames due to stack unwinding', {\n targetFrame: frameId,\n removedFrames: removed,\n });\n }\n } else {\n // Pop top frame\n poppedFrameId = this.activeStack.pop();\n }\n\n if (poppedFrameId) {\n logger.debug('Popped frame from stack', { \n frameId: poppedFrameId, \n stackDepth: this.activeStack.length \n });\n }\n\n return poppedFrameId;\n }\n\n /**\n * Get current (top) frame ID\n */\n getCurrentFrameId(): string | undefined {\n return this.activeStack[this.activeStack.length - 1];\n }\n\n /**\n * Get stack depth\n */\n getDepth(): number {\n return this.activeStack.length;\n }\n\n /**\n * Get complete stack\n */\n getStack(): string[] {\n return [...this.activeStack];\n }\n\n /**\n * Get stack as frame objects\n */\n getStackFrames(): Frame[] {\n return this.activeStack\n .map(frameId => this.frameDb.getFrame(frameId))\n .filter(Boolean) as Frame[];\n }\n\n /**\n * Get frame context for the hot stack\n */\n getHotStackContext(maxEvents: number = 20): FrameContext[] {\n return this.activeStack\n .map(frameId => this.buildFrameContext(frameId, maxEvents))\n .filter(Boolean) as FrameContext[];\n }\n\n /**\n * Check if frame is on stack\n */\n isFrameActive(frameId: string): boolean {\n return this.activeStack.includes(frameId);\n }\n\n /**\n * Get parent frame ID for current frame\n */\n getParentFrameId(): string | undefined {\n if (this.activeStack.length < 2) {\n return undefined;\n }\n return this.activeStack[this.activeStack.length - 2];\n }\n\n /**\n * Get frame depth on stack (0-based)\n */\n getFrameStackDepth(frameId: string): number {\n return this.activeStack.indexOf(frameId);\n }\n\n /**\n * Clear entire stack\n */\n clear(): void {\n const previousDepth = this.activeStack.length;\n this.activeStack = [];\n \n logger.info('Cleared frame stack', { previousDepth });\n }\n\n /**\n * Validate stack consistency\n */\n validateStack(): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n // Check if all frames in stack exist and are active\n for (const frameId of this.activeStack) {\n const frame = this.frameDb.getFrame(frameId);\n \n if (!frame) {\n errors.push(`Frame not found in database: ${frameId}`);\n continue;\n }\n\n if (frame.state !== 'active') {\n errors.push(`Frame on stack is not active: ${frameId} (state: ${frame.state})`);\n }\n\n if (frame.project_id !== this.projectId) {\n errors.push(`Frame belongs to different project: ${frameId}`);\n }\n }\n\n // Check for parent-child consistency\n for (let i = 1; i < this.activeStack.length; i++) {\n const currentFrameId = this.activeStack[i];\n const expectedParentId = this.activeStack[i - 1];\n const currentFrame = this.frameDb.getFrame(currentFrameId);\n\n if (currentFrame?.parent_frame_id !== expectedParentId) {\n errors.push(`Frame parent mismatch: ${currentFrameId} parent should be ${expectedParentId} but is ${currentFrame?.parent_frame_id}`);\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n }\n\n /**\n * Build frame context for a specific frame\n */\n private buildFrameContext(frameId: string, maxEvents: number): FrameContext | null {\n try {\n const frame = this.frameDb.getFrame(frameId);\n if (!frame) {\n logger.warn('Frame not found for context building', { frameId });\n return null;\n }\n\n const anchors = this.frameDb.getFrameAnchors(frameId);\n const recentEvents = this.frameDb.getFrameEvents(frameId, maxEvents);\n const activeArtifacts = this.extractActiveArtifacts(recentEvents);\n\n return {\n frameId,\n header: {\n goal: frame.name,\n constraints: this.extractConstraints(frame.inputs),\n definitions: frame.inputs.definitions,\n },\n anchors,\n recentEvents,\n activeArtifacts,\n };\n } catch (error) {\n logger.warn('Failed to build frame context', { frameId, error });\n return null;\n }\n }\n\n /**\n * Extract constraints from frame inputs\n */\n private extractConstraints(inputs: Record<string, any>): string[] {\n const constraints: string[] = [];\n \n if (inputs.constraints && Array.isArray(inputs.constraints)) {\n constraints.push(...inputs.constraints);\n }\n \n return constraints;\n }\n\n /**\n * Extract active artifacts from events\n */\n private extractActiveArtifacts(events: any[]): string[] {\n const artifacts: string[] = [];\n \n for (const event of events) {\n if (event.event_type === 'artifact' && event.payload?.path) {\n artifacts.push(event.payload.path);\n }\n }\n \n // Return unique artifacts\n return [...new Set(artifacts)];\n }\n\n /**\n * Build stack order from database frames\n */\n private buildStackFromFrames(frames: Frame[]): string[] {\n if (frames.length === 0) {\n return [];\n }\n\n // Create parent-child map\n const parentMap = new Map<string, string>();\n const frameMap = new Map<string, Frame>();\n \n for (const frame of frames) {\n frameMap.set(frame.frame_id, frame);\n if (frame.parent_frame_id) {\n parentMap.set(frame.frame_id, frame.parent_frame_id);\n }\n }\n\n // Find root frames (no parent or parent not in active set)\n const rootFrames = frames.filter(f => \n !f.parent_frame_id || !frameMap.has(f.parent_frame_id)\n );\n\n if (rootFrames.length === 0) {\n logger.warn('No root frames found in active set');\n return [];\n }\n\n if (rootFrames.length > 1) {\n logger.warn('Multiple root frames found, using most recent', {\n rootFrames: rootFrames.map(f => f.frame_id),\n });\n }\n\n // Build stack from root to leaves\n const stack: string[] = [];\n let currentFrame = rootFrames.sort((a, b) => a.created_at - b.created_at)[0];\n\n while (currentFrame) {\n stack.push(currentFrame.frame_id);\n \n // Find child frame\n const childFrame = frames.find(f => f.parent_frame_id === currentFrame.frame_id);\n if (childFrame) {\n currentFrame = childFrame;\n } else {\n break;\n }\n }\n\n return stack;\n }\n}"],
|
|
5
|
-
"mappings": "AAOA,SAAS,cAAc;AACvB,SAAS,YAAY,iBAAiB;AAE/B,MAAM,WAAW;AAAA,EAGtB,YACU,SACA,WACA,OACR;AAHQ;AACA;AACA;AAAA,EACP;AAAA,EANK,cAAwB,CAAC;AAAA;AAAA;AAAA;AAAA,EAWjC,MAAM,aAA4B;AAChC,QAAI;AACF,YAAM,eAAe,KAAK,QAAQ,mBAAmB,KAAK,WAAW,QAAQ;AAG7E,WAAK,cAAc,KAAK,qBAAqB,YAAY;AAEzD,aAAO,KAAK,2BAA2B;AAAA,QACrC,YAAY,KAAK,YAAY;AAAA,QAC7B,WAAW,KAAK;AAAA,MAClB,CAAC;AAAA,IACH,SAAS,
|
|
4
|
+
"sourcesContent": ["/**\n * Frame Stack Management\n * Handles the call stack of active frames\n */\n\nimport { Frame, FrameContext, FrameType } from './frame-types.js';\nimport { FrameDatabase } from './frame-database.js';\nimport { logger } from '../monitoring/logger.js';\nimport { FrameError, ErrorCode } from '../errors/index.js';\n\nexport class FrameStack {\n private activeStack: string[] = [];\n\n constructor(\n private frameDb: FrameDatabase,\n private projectId: string,\n private runId: string\n ) {}\n\n /**\n * Initialize stack by loading active frames\n */\n async initialize(): Promise<void> {\n try {\n const activeFrames = this.frameDb.getFramesByProject(this.projectId, 'active');\n \n // Rebuild stack from database\n this.activeStack = this.buildStackFromFrames(activeFrames);\n \n logger.info('Frame stack initialized', { \n stackDepth: this.activeStack.length,\n projectId: this.projectId,\n });\n } catch (error: unknown) {\n logger.error('Failed to initialize frame stack', {\n error: error instanceof Error ? error.message : String(error),\n projectId: this.projectId,\n runId: this.runId,\n });\n throw new FrameError(\n 'Failed to initialize frame stack',\n ErrorCode.FRAME_INIT_FAILED,\n { \n projectId: this.projectId, \n runId: this.runId,\n originalError: error instanceof Error ? error.message : String(error)\n }\n );\n }\n }\n\n /**\n * Push new frame onto stack\n */\n pushFrame(frameId: string): void {\n if (this.activeStack.includes(frameId)) {\n logger.warn('Frame already on stack', { frameId });\n return;\n }\n\n this.activeStack.push(frameId);\n \n logger.debug('Pushed frame to stack', { \n frameId, \n stackDepth: this.activeStack.length \n });\n }\n\n /**\n * Pop frame from stack\n */\n popFrame(frameId?: string): string | undefined {\n if (this.activeStack.length === 0) {\n return undefined;\n }\n\n let poppedFrameId: string | undefined;\n\n if (frameId) {\n // Pop specific frame (and all frames above it)\n const index = this.activeStack.indexOf(frameId);\n if (index === -1) {\n logger.warn('Frame not found on stack', { frameId });\n return undefined;\n }\n\n // Remove the target frame and all frames above it\n const removed = this.activeStack.splice(index);\n poppedFrameId = removed[0];\n\n if (removed.length > 1) {\n logger.info('Popped multiple frames due to stack unwinding', {\n targetFrame: frameId,\n removedFrames: removed,\n });\n }\n } else {\n // Pop top frame\n poppedFrameId = this.activeStack.pop();\n }\n\n if (poppedFrameId) {\n logger.debug('Popped frame from stack', { \n frameId: poppedFrameId, \n stackDepth: this.activeStack.length \n });\n }\n\n return poppedFrameId;\n }\n\n /**\n * Get current (top) frame ID\n */\n getCurrentFrameId(): string | undefined {\n return this.activeStack[this.activeStack.length - 1];\n }\n\n /**\n * Get stack depth\n */\n getDepth(): number {\n return this.activeStack.length;\n }\n\n /**\n * Get complete stack\n */\n getStack(): string[] {\n return [...this.activeStack];\n }\n\n /**\n * Get stack as frame objects\n */\n getStackFrames(): Frame[] {\n return this.activeStack\n .map((frameId: any) => this.frameDb.getFrame(frameId))\n .filter(Boolean) as Frame[];\n }\n\n /**\n * Get frame context for the hot stack\n */\n getHotStackContext(maxEvents: number = 20): FrameContext[] {\n return this.activeStack\n .map((frameId: any) => this.buildFrameContext(frameId, maxEvents))\n .filter(Boolean) as FrameContext[];\n }\n\n /**\n * Check if frame is on stack\n */\n isFrameActive(frameId: string): boolean {\n return this.activeStack.includes(frameId);\n }\n\n /**\n * Get parent frame ID for current frame\n */\n getParentFrameId(): string | undefined {\n if (this.activeStack.length < 2) {\n return undefined;\n }\n return this.activeStack[this.activeStack.length - 2];\n }\n\n /**\n * Get frame depth on stack (0-based)\n */\n getFrameStackDepth(frameId: string): number {\n return this.activeStack.indexOf(frameId);\n }\n\n /**\n * Clear entire stack\n */\n clear(): void {\n const previousDepth = this.activeStack.length;\n this.activeStack = [];\n \n logger.info('Cleared frame stack', { previousDepth });\n }\n\n /**\n * Validate stack consistency\n */\n validateStack(): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n // Check if all frames in stack exist and are active\n for (const frameId of this.activeStack) {\n const frame = this.frameDb.getFrame(frameId);\n \n if (!frame) {\n errors.push(`Frame not found in database: ${frameId}`);\n continue;\n }\n\n if (frame.state !== 'active') {\n errors.push(`Frame on stack is not active: ${frameId} (state: ${frame.state})`);\n }\n\n if (frame.project_id !== this.projectId) {\n errors.push(`Frame belongs to different project: ${frameId}`);\n }\n }\n\n // Check for parent-child consistency\n for (let i = 1; i < this.activeStack.length; i++) {\n const currentFrameId = this.activeStack[i];\n const expectedParentId = this.activeStack[i - 1];\n const currentFrame = this.frameDb.getFrame(currentFrameId);\n\n if (currentFrame?.parent_frame_id !== expectedParentId) {\n errors.push(`Frame parent mismatch: ${currentFrameId} parent should be ${expectedParentId} but is ${currentFrame?.parent_frame_id}`);\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n }\n\n /**\n * Build frame context for a specific frame\n */\n private buildFrameContext(frameId: string, maxEvents: number): FrameContext | null {\n try {\n const frame = this.frameDb.getFrame(frameId);\n if (!frame) {\n logger.warn('Frame not found for context building', { frameId });\n return null;\n }\n\n const anchors = this.frameDb.getFrameAnchors(frameId);\n const recentEvents = this.frameDb.getFrameEvents(frameId, maxEvents);\n const activeArtifacts = this.extractActiveArtifacts(recentEvents);\n\n return {\n frameId,\n header: {\n goal: frame.name,\n constraints: this.extractConstraints(frame.inputs),\n definitions: frame.inputs.definitions,\n },\n anchors,\n recentEvents,\n activeArtifacts,\n };\n } catch (error: unknown) {\n logger.warn('Failed to build frame context', { frameId, error });\n return null;\n }\n }\n\n /**\n * Extract constraints from frame inputs\n */\n private extractConstraints(inputs: Record<string, any>): string[] {\n const constraints: string[] = [];\n \n if (inputs.constraints && Array.isArray(inputs.constraints)) {\n constraints.push(...inputs.constraints);\n }\n \n return constraints;\n }\n\n /**\n * Extract active artifacts from events\n */\n private extractActiveArtifacts(events: any[]): string[] {\n const artifacts: string[] = [];\n \n for (const event of events) {\n if (event.event_type === 'artifact' && event.payload?.path) {\n artifacts.push(event.payload.path);\n }\n }\n \n // Return unique artifacts\n return [...new Set(artifacts)];\n }\n\n /**\n * Build stack order from database frames\n */\n private buildStackFromFrames(frames: Frame[]): string[] {\n if (frames.length === 0) {\n return [];\n }\n\n // Create parent-child map\n const parentMap = new Map<string, string>();\n const frameMap = new Map<string, Frame>();\n \n for (const frame of frames) {\n frameMap.set(frame.frame_id, frame);\n if (frame.parent_frame_id) {\n parentMap.set(frame.frame_id, frame.parent_frame_id);\n }\n }\n\n // Find root frames (no parent or parent not in active set)\n const rootFrames = frames.filter((f: any) => \n !f.parent_frame_id || !frameMap.has(f.parent_frame_id)\n );\n\n if (rootFrames.length === 0) {\n logger.warn('No root frames found in active set');\n return [];\n }\n\n if (rootFrames.length > 1) {\n logger.warn('Multiple root frames found, using most recent', {\n rootFrames: rootFrames.map((f: any) => f.frame_id),\n });\n }\n\n // Build stack from root to leaves\n const stack: string[] = [];\n let currentFrame = rootFrames.sort((a, b) => a.created_at - b.created_at)[0];\n\n while (currentFrame) {\n stack.push(currentFrame.frame_id);\n \n // Find child frame\n const childFrame = frames.find((f: any) => f.parent_frame_id === currentFrame.frame_id);\n if (childFrame) {\n currentFrame = childFrame;\n } else {\n break;\n }\n }\n\n return stack;\n }\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { Logger } from "../monitoring/logger.js";
|
|
2
|
+
class IncrementalGarbageCollector {
|
|
3
|
+
logger;
|
|
4
|
+
config;
|
|
5
|
+
stats;
|
|
6
|
+
isRunning = false;
|
|
7
|
+
cycleTimer = null;
|
|
8
|
+
frameManager;
|
|
9
|
+
constructor(frameManager, config = {}) {
|
|
10
|
+
this.frameManager = frameManager;
|
|
11
|
+
this.logger = new Logger("IncrementalGC");
|
|
12
|
+
this.config = {
|
|
13
|
+
framesPerCycle: config.framesPerCycle || 100,
|
|
14
|
+
cycleInterval: config.cycleInterval || 6e4,
|
|
15
|
+
// 60 seconds
|
|
16
|
+
maxAge: config.maxAge || 30 * 24 * 60 * 60 * 1e3,
|
|
17
|
+
// 30 days
|
|
18
|
+
generations: {
|
|
19
|
+
young: config.generations?.young || 24 * 60 * 60 * 1e3,
|
|
20
|
+
// 1 day
|
|
21
|
+
mature: config.generations?.mature || 7 * 24 * 60 * 60 * 1e3,
|
|
22
|
+
// 7 days
|
|
23
|
+
old: config.generations?.old || 30 * 24 * 60 * 60 * 1e3
|
|
24
|
+
// 30 days
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
this.stats = {
|
|
28
|
+
totalFrames: 0,
|
|
29
|
+
collectedFrames: 0,
|
|
30
|
+
lastRunTime: 0,
|
|
31
|
+
cycleCount: 0,
|
|
32
|
+
avgCycleTime: 0,
|
|
33
|
+
protectedFrames: 0
|
|
34
|
+
};
|
|
35
|
+
this.logger.info("Incremental GC initialized", this.config);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Start the garbage collection cycle
|
|
39
|
+
*/
|
|
40
|
+
start() {
|
|
41
|
+
if (this.isRunning) {
|
|
42
|
+
this.logger.warn("GC already running");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.isRunning = true;
|
|
46
|
+
this.logger.info(`Starting incremental GC with ${this.config.cycleInterval}ms intervals`);
|
|
47
|
+
this.cycleTimer = setInterval(() => {
|
|
48
|
+
this.runCycle().catch((error) => {
|
|
49
|
+
this.logger.error("GC cycle failed", error);
|
|
50
|
+
});
|
|
51
|
+
}, this.config.cycleInterval);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Stop the garbage collection cycle
|
|
55
|
+
*/
|
|
56
|
+
stop() {
|
|
57
|
+
if (this.cycleTimer) {
|
|
58
|
+
clearInterval(this.cycleTimer);
|
|
59
|
+
this.cycleTimer = null;
|
|
60
|
+
}
|
|
61
|
+
this.isRunning = false;
|
|
62
|
+
this.logger.info("Incremental GC stopped");
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Run a single GC cycle
|
|
66
|
+
*/
|
|
67
|
+
async runCycle() {
|
|
68
|
+
const startTime = Date.now();
|
|
69
|
+
this.logger.debug("Starting GC cycle", { cycle: this.stats.cycleCount + 1 });
|
|
70
|
+
try {
|
|
71
|
+
const allFrames = await this.frameManager.getAllFrames();
|
|
72
|
+
this.stats.totalFrames = allFrames.length;
|
|
73
|
+
if (allFrames.length === 0) {
|
|
74
|
+
this.logger.debug("No frames to collect");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const categorized = this.categorizeFrames(allFrames);
|
|
78
|
+
const candidates = this.selectCollectionCandidates(categorized);
|
|
79
|
+
const collected = await this.collectFramesIncremental(candidates);
|
|
80
|
+
this.updateStats(startTime, collected.length);
|
|
81
|
+
this.logger.info("GC cycle completed", {
|
|
82
|
+
cycle: this.stats.cycleCount,
|
|
83
|
+
collected: collected.length,
|
|
84
|
+
protected: this.stats.protectedFrames,
|
|
85
|
+
duration: Date.now() - startTime
|
|
86
|
+
});
|
|
87
|
+
} catch (error) {
|
|
88
|
+
this.logger.error("GC cycle error", error);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Categorize frames by generation and protection status
|
|
93
|
+
*/
|
|
94
|
+
categorizeFrames(frames) {
|
|
95
|
+
const now = Date.now();
|
|
96
|
+
const categories = { young: [], mature: [], old: [], protected: [] };
|
|
97
|
+
for (const frame of frames) {
|
|
98
|
+
const age = now - frame.created_at;
|
|
99
|
+
if (this.isProtected(frame)) {
|
|
100
|
+
categories.protected.push(frame);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (age < this.config.generations.young) {
|
|
104
|
+
categories.young.push(frame);
|
|
105
|
+
} else if (age < this.config.generations.mature) {
|
|
106
|
+
categories.mature.push(frame);
|
|
107
|
+
} else {
|
|
108
|
+
categories.old.push(frame);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
this.stats.protectedFrames = categories.protected.length;
|
|
112
|
+
this.logger.debug("Frame categorization", {
|
|
113
|
+
young: categories.young.length,
|
|
114
|
+
mature: categories.mature.length,
|
|
115
|
+
old: categories.old.length,
|
|
116
|
+
protected: categories.protected.length
|
|
117
|
+
});
|
|
118
|
+
return categories;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Check if a frame should be protected from collection
|
|
122
|
+
*/
|
|
123
|
+
isProtected(frame) {
|
|
124
|
+
const currentRunId = this.frameManager.getCurrentRunId?.();
|
|
125
|
+
if (frame.run_id === currentRunId) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
if (frame.state === "active") {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
const recentThreshold = Date.now() - 60 * 60 * 1e3;
|
|
132
|
+
if (frame.created_at > recentThreshold) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
if (frame.outputs && Object.keys(frame.outputs).length > 0) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
if (frame.depth === 0) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Select collection candidates with priority ordering
|
|
145
|
+
*/
|
|
146
|
+
selectCollectionCandidates(categorized) {
|
|
147
|
+
const candidates = [];
|
|
148
|
+
const emptyClosedFrames = categorized.old.filter(
|
|
149
|
+
(f) => f.state === "closed" && (!f.outputs || Object.keys(f.outputs).length === 0)
|
|
150
|
+
);
|
|
151
|
+
const orphaned = [...categorized.mature, ...categorized.old].filter(
|
|
152
|
+
(f) => this.isOrphaned(f)
|
|
153
|
+
);
|
|
154
|
+
const duplicates = this.findDuplicateTraces([...categorized.mature, ...categorized.old]);
|
|
155
|
+
const oldMature = categorized.mature.filter((f) => {
|
|
156
|
+
const age = Date.now() - f.created_at;
|
|
157
|
+
return age > this.config.generations.mature * 0.8;
|
|
158
|
+
});
|
|
159
|
+
candidates.push(...emptyClosedFrames);
|
|
160
|
+
candidates.push(...orphaned);
|
|
161
|
+
candidates.push(...duplicates);
|
|
162
|
+
candidates.push(...oldMature);
|
|
163
|
+
const uniqueCandidates = Array.from(new Set(candidates));
|
|
164
|
+
return uniqueCandidates.slice(0, this.config.framesPerCycle);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Check if frame is orphaned (no dependencies)
|
|
168
|
+
*/
|
|
169
|
+
isOrphaned(frame) {
|
|
170
|
+
return !frame.parent_frame_id && frame.depth > 0 && frame.state === "closed";
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Find duplicate trace signatures
|
|
174
|
+
*/
|
|
175
|
+
findDuplicateTraces(frames) {
|
|
176
|
+
const signatureMap = /* @__PURE__ */ new Map();
|
|
177
|
+
for (const frame of frames) {
|
|
178
|
+
const signature = this.createTraceSignature(frame);
|
|
179
|
+
if (!signatureMap.has(signature)) {
|
|
180
|
+
signatureMap.set(signature, []);
|
|
181
|
+
}
|
|
182
|
+
signatureMap.get(signature).push(frame);
|
|
183
|
+
}
|
|
184
|
+
const duplicates = [];
|
|
185
|
+
for (const [signature, frameList] of signatureMap) {
|
|
186
|
+
if (frameList.length > 1) {
|
|
187
|
+
frameList.sort((a, b) => b.timestamp - a.timestamp);
|
|
188
|
+
duplicates.push(...frameList.slice(1));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return duplicates;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Create a signature for duplicate detection
|
|
195
|
+
*/
|
|
196
|
+
createTraceSignature(frame) {
|
|
197
|
+
const type = frame.type;
|
|
198
|
+
const name = frame.name;
|
|
199
|
+
const outputs = JSON.stringify(frame.outputs || {});
|
|
200
|
+
const digestText = frame.digest_text || "";
|
|
201
|
+
return `${type}:${name}:${outputs}:${digestText}`.toLowerCase();
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Collect frames incrementally to avoid blocking
|
|
205
|
+
*/
|
|
206
|
+
async collectFramesIncremental(candidates) {
|
|
207
|
+
const collected = [];
|
|
208
|
+
const chunkSize = Math.min(10, Math.ceil(candidates.length / 10));
|
|
209
|
+
for (let i = 0; i < candidates.length; i += chunkSize) {
|
|
210
|
+
const chunk = candidates.slice(i, i + chunkSize);
|
|
211
|
+
for (const frame of chunk) {
|
|
212
|
+
try {
|
|
213
|
+
await this.frameManager.deleteFrame(frame.frame_id);
|
|
214
|
+
collected.push(frame);
|
|
215
|
+
this.logger.debug(`Collected frame ${frame.frame_id}`, {
|
|
216
|
+
age: Date.now() - frame.created_at,
|
|
217
|
+
type: frame.type,
|
|
218
|
+
reason: this.getCollectionReason(frame)
|
|
219
|
+
});
|
|
220
|
+
} catch (error) {
|
|
221
|
+
this.logger.warn(`Failed to collect frame ${frame.frame_id}`, error);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
225
|
+
}
|
|
226
|
+
return collected;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get human-readable collection reason
|
|
230
|
+
*/
|
|
231
|
+
getCollectionReason(frame) {
|
|
232
|
+
const age = Date.now() - frame.created_at;
|
|
233
|
+
const ageHours = Math.floor(age / (60 * 60 * 1e3));
|
|
234
|
+
if (frame.state === "closed" && (!frame.outputs || Object.keys(frame.outputs).length === 0)) {
|
|
235
|
+
return "empty-closed";
|
|
236
|
+
}
|
|
237
|
+
if (this.isOrphaned(frame)) return "orphaned";
|
|
238
|
+
if (ageHours > 24 * 30) return `old (${ageHours}h)`;
|
|
239
|
+
return "duplicate";
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Update GC statistics
|
|
243
|
+
*/
|
|
244
|
+
updateStats(startTime, collectedCount) {
|
|
245
|
+
const cycleTime = Date.now() - startTime;
|
|
246
|
+
this.stats.cycleCount++;
|
|
247
|
+
this.stats.collectedFrames += collectedCount;
|
|
248
|
+
this.stats.lastRunTime = startTime;
|
|
249
|
+
this.stats.avgCycleTime = (this.stats.avgCycleTime * (this.stats.cycleCount - 1) + cycleTime) / this.stats.cycleCount;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Get GC statistics
|
|
253
|
+
*/
|
|
254
|
+
getStats() {
|
|
255
|
+
return { ...this.stats };
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Force a manual GC cycle
|
|
259
|
+
*/
|
|
260
|
+
async forceCollection() {
|
|
261
|
+
this.logger.info("Forcing manual GC cycle");
|
|
262
|
+
await this.runCycle();
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Update GC configuration
|
|
266
|
+
*/
|
|
267
|
+
updateConfig(newConfig) {
|
|
268
|
+
this.config = { ...this.config, ...newConfig };
|
|
269
|
+
this.logger.info("GC configuration updated", this.config);
|
|
270
|
+
if (this.isRunning && newConfig.cycleInterval) {
|
|
271
|
+
this.stop();
|
|
272
|
+
this.start();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
export {
|
|
277
|
+
IncrementalGarbageCollector
|
|
278
|
+
};
|
|
279
|
+
//# sourceMappingURL=incremental-gc.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/core/context/incremental-gc.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Incremental Garbage Collection System (STA-288)\n * \n * Implements incremental GC strategy to avoid stop-the-world pauses\n * with generational aging and priority-based collection.\n */\n\nimport { Frame, FrameManager } from './frame-manager.js';\nimport { Logger } from '../monitoring/logger.js';\n\ninterface GCConfig {\n framesPerCycle: number; // Process in chunks (default: 100)\n cycleInterval: number; // Every minute (default: 60s)\n maxAge: number; // Max age before eligible for collection (30 days)\n generations: {\n young: number; // < 1 day\n mature: number; // 1-7 days \n old: number; // 7-30 days\n };\n}\n\ninterface GCStats {\n totalFrames: number;\n collectedFrames: number;\n lastRunTime: number;\n cycleCount: number;\n avgCycleTime: number;\n protectedFrames: number;\n}\n\nexport class IncrementalGarbageCollector {\n private logger: Logger;\n private config: GCConfig;\n private stats: GCStats;\n private isRunning: boolean = false;\n private cycleTimer: NodeJS.Timer | null = null;\n private frameManager: FrameManager;\n\n constructor(frameManager: FrameManager, config: Partial<GCConfig> = {}) {\n this.frameManager = frameManager;\n this.logger = new Logger('IncrementalGC');\n \n this.config = {\n framesPerCycle: config.framesPerCycle || 100,\n cycleInterval: config.cycleInterval || 60000, // 60 seconds\n maxAge: config.maxAge || 30 * 24 * 60 * 60 * 1000, // 30 days\n generations: {\n young: config.generations?.young || 24 * 60 * 60 * 1000, // 1 day\n mature: config.generations?.mature || 7 * 24 * 60 * 60 * 1000, // 7 days\n old: config.generations?.old || 30 * 24 * 60 * 60 * 1000, // 30 days\n }\n };\n\n this.stats = {\n totalFrames: 0,\n collectedFrames: 0,\n lastRunTime: 0,\n cycleCount: 0,\n avgCycleTime: 0,\n protectedFrames: 0\n };\n\n this.logger.info('Incremental GC initialized', this.config);\n }\n\n /**\n * Start the garbage collection cycle\n */\n start(): void {\n if (this.isRunning) {\n this.logger.warn('GC already running');\n return;\n }\n\n this.isRunning = true;\n this.logger.info(`Starting incremental GC with ${this.config.cycleInterval}ms intervals`);\n \n this.cycleTimer = setInterval(() => {\n this.runCycle().catch(error => {\n this.logger.error('GC cycle failed', error);\n });\n }, this.config.cycleInterval);\n }\n\n /**\n * Stop the garbage collection cycle\n */\n stop(): void {\n if (this.cycleTimer) {\n clearInterval(this.cycleTimer);\n this.cycleTimer = null;\n }\n this.isRunning = false;\n this.logger.info('Incremental GC stopped');\n }\n\n /**\n * Run a single GC cycle\n */\n async runCycle(): Promise<void> {\n const startTime = Date.now();\n this.logger.debug('Starting GC cycle', { cycle: this.stats.cycleCount + 1 });\n\n try {\n // Get all frames for analysis\n const allFrames = await this.frameManager.getAllFrames();\n this.stats.totalFrames = allFrames.length;\n\n if (allFrames.length === 0) {\n this.logger.debug('No frames to collect');\n return;\n }\n\n // Categorize frames by generation and protection status\n const categorized = this.categorizeFrames(allFrames);\n \n // Select candidates for collection (prioritized)\n const candidates = this.selectCollectionCandidates(categorized);\n \n // Process in chunks to avoid blocking\n const collected = await this.collectFramesIncremental(candidates);\n \n // Update statistics\n this.updateStats(startTime, collected.length);\n \n this.logger.info('GC cycle completed', {\n cycle: this.stats.cycleCount,\n collected: collected.length,\n protected: this.stats.protectedFrames,\n duration: Date.now() - startTime\n });\n\n } catch (error: unknown) {\n this.logger.error('GC cycle error', error);\n }\n }\n\n /**\n * Categorize frames by generation and protection status\n */\n private categorizeFrames(frames: Frame[]): {\n young: Frame[];\n mature: Frame[];\n old: Frame[];\n protected: Frame[];\n } {\n const now = Date.now();\n const categories = { young: [], mature: [], old: [], protected: [] };\n\n for (const frame of frames) {\n const age = now - frame.created_at;\n \n // Check if frame is protected\n if (this.isProtected(frame)) {\n categories.protected.push(frame);\n continue;\n }\n\n // Categorize by age\n if (age < this.config.generations.young) {\n categories.young.push(frame);\n } else if (age < this.config.generations.mature) {\n categories.mature.push(frame);\n } else {\n categories.old.push(frame);\n }\n }\n\n this.stats.protectedFrames = categories.protected.length;\n \n this.logger.debug('Frame categorization', {\n young: categories.young.length,\n mature: categories.mature.length,\n old: categories.old.length,\n protected: categories.protected.length\n });\n\n return categories;\n }\n\n /**\n * Check if a frame should be protected from collection\n */\n private isProtected(frame: Frame): boolean {\n // Protect current session/run frames\n const currentRunId = this.frameManager.getCurrentRunId?.();\n if (frame.run_id === currentRunId) {\n return true;\n }\n\n // Protect active frames\n if (frame.state === 'active') {\n return true;\n }\n\n // Protect recent frames (< 1 hour old)\n const recentThreshold = Date.now() - (60 * 60 * 1000); // 1 hour\n if (frame.created_at > recentThreshold) {\n return true;\n }\n\n // Protect frames with important outputs\n if (frame.outputs && Object.keys(frame.outputs).length > 0) {\n return true;\n }\n\n // Protect parent frames (have children)\n if (frame.depth === 0) { // Root frames\n return true;\n }\n\n return false;\n }\n\n /**\n * Select collection candidates with priority ordering\n */\n private selectCollectionCandidates(categorized: any): Frame[] {\n const candidates: Frame[] = [];\n \n // Priority 1: Closed frames without outputs\n const emptyClosedFrames = categorized.old.filter((f: Frame) => \n f.state === 'closed' && (!f.outputs || Object.keys(f.outputs).length === 0)\n );\n \n // Priority 2: Orphaned frames (no dependencies) \n const orphaned = [...categorized.mature, ...categorized.old].filter((f: Frame) =>\n this.isOrphaned(f)\n );\n \n // Priority 3: Duplicate traces\n const duplicates = this.findDuplicateTraces([...categorized.mature, ...categorized.old]);\n \n // Priority 4: Old mature frames\n const oldMature = categorized.mature.filter((f: Frame) => {\n const age = Date.now() - f.created_at;\n return age > this.config.generations.mature * 0.8; // 80% of mature threshold\n });\n\n // Combine with priority ordering\n candidates.push(...emptyClosedFrames);\n candidates.push(...orphaned);\n candidates.push(...duplicates);\n candidates.push(...oldMature);\n\n // Remove duplicates and limit to cycle size\n const uniqueCandidates = Array.from(new Set(candidates));\n return uniqueCandidates.slice(0, this.config.framesPerCycle);\n }\n\n /**\n * Check if frame is orphaned (no dependencies)\n */\n private isOrphaned(frame: Frame): boolean {\n // Check if frame has any references from other frames \n // This is a simplified check - in practice, would analyze actual dependencies\n return !frame.parent_frame_id && frame.depth > 0 && frame.state === 'closed';\n }\n\n /**\n * Find duplicate trace signatures\n */\n private findDuplicateTraces(frames: Frame[]): Frame[] {\n const signatureMap = new Map<string, Frame[]>();\n \n for (const frame of frames) {\n // Create a signature from trace content\n const signature = this.createTraceSignature(frame);\n if (!signatureMap.has(signature)) {\n signatureMap.set(signature, []);\n }\n signatureMap.get(signature)!.push(frame);\n }\n\n // Return duplicates (keep newest, mark older for collection)\n const duplicates: Frame[] = [];\n for (const [signature, frameList] of signatureMap) {\n if (frameList.length > 1) {\n // Sort by timestamp, keep newest\n frameList.sort((a, b) => b.timestamp - a.timestamp);\n duplicates.push(...frameList.slice(1)); // Mark older ones for collection\n }\n }\n\n return duplicates;\n }\n\n /**\n * Create a signature for duplicate detection\n */\n private createTraceSignature(frame: Frame): string {\n // Create signature from key frame properties\n const type = frame.type;\n const name = frame.name;\n const outputs = JSON.stringify(frame.outputs || {});\n const digestText = frame.digest_text || '';\n return `${type}:${name}:${outputs}:${digestText}`.toLowerCase();\n }\n\n /**\n * Collect frames incrementally to avoid blocking\n */\n private async collectFramesIncremental(candidates: Frame[]): Promise<Frame[]> {\n const collected: Frame[] = [];\n const chunkSize = Math.min(10, Math.ceil(candidates.length / 10)); // Process in small chunks\n\n for (let i = 0; i < candidates.length; i += chunkSize) {\n const chunk = candidates.slice(i, i + chunkSize);\n \n for (const frame of chunk) {\n try {\n await this.frameManager.deleteFrame(frame.frame_id);\n collected.push(frame);\n \n this.logger.debug(`Collected frame ${frame.frame_id}`, {\n age: Date.now() - frame.created_at,\n type: frame.type,\n reason: this.getCollectionReason(frame)\n });\n \n } catch (error: unknown) {\n this.logger.warn(`Failed to collect frame ${frame.frame_id}`, error);\n }\n }\n\n // Yield control to avoid blocking\n await new Promise(resolve => setImmediate(resolve));\n }\n\n return collected;\n }\n\n /**\n * Get human-readable collection reason\n */\n private getCollectionReason(frame: Frame): string {\n const age = Date.now() - frame.created_at;\n const ageHours = Math.floor(age / (60 * 60 * 1000));\n \n if (frame.state === 'closed' && (!frame.outputs || Object.keys(frame.outputs).length === 0)) {\n return 'empty-closed';\n }\n if (this.isOrphaned(frame)) return 'orphaned'; \n if (ageHours > 24 * 30) return `old (${ageHours}h)`;\n return 'duplicate';\n }\n\n /**\n * Update GC statistics\n */\n private updateStats(startTime: number, collectedCount: number): void {\n const cycleTime = Date.now() - startTime;\n \n this.stats.cycleCount++;\n this.stats.collectedFrames += collectedCount;\n this.stats.lastRunTime = startTime;\n this.stats.avgCycleTime = \n (this.stats.avgCycleTime * (this.stats.cycleCount - 1) + cycleTime) / this.stats.cycleCount;\n }\n\n /**\n * Get GC statistics\n */\n getStats(): GCStats {\n return { ...this.stats };\n }\n\n /**\n * Force a manual GC cycle\n */\n async forceCollection(): Promise<void> {\n this.logger.info('Forcing manual GC cycle');\n await this.runCycle();\n }\n\n /**\n * Update GC configuration\n */\n updateConfig(newConfig: Partial<GCConfig>): void {\n this.config = { ...this.config, ...newConfig };\n this.logger.info('GC configuration updated', this.config);\n \n // Restart with new interval if running\n if (this.isRunning && newConfig.cycleInterval) {\n this.stop();\n this.start();\n }\n }\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { ValidationError, ErrorCode } from "../errors/index.js";
|
|
2
2
|
import { logger } from "../monitoring/logger.js";
|
|
3
|
+
function getEnv(key, defaultValue) {
|
|
4
|
+
const value = process.env[key];
|
|
5
|
+
if (value === void 0) {
|
|
6
|
+
if (defaultValue !== void 0) return defaultValue;
|
|
7
|
+
throw new Error(`Environment variable ${key} is required`);
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
function getOptionalEnv(key) {
|
|
12
|
+
return process.env[key];
|
|
13
|
+
}
|
|
3
14
|
class PermissionManager {
|
|
4
15
|
userPermissions = /* @__PURE__ */ new Map();
|
|
5
16
|
adminUsers = /* @__PURE__ */ new Set();
|
|
@@ -132,7 +143,7 @@ class PermissionManager {
|
|
|
132
143
|
* Initialize default permissions
|
|
133
144
|
*/
|
|
134
145
|
initializeDefaultPermissions() {
|
|
135
|
-
const defaultAdmin = process.env
|
|
146
|
+
const defaultAdmin = process.env["STACKMEMORY_DEFAULT_ADMIN"];
|
|
136
147
|
if (defaultAdmin) {
|
|
137
148
|
this.grantAdminAccess(defaultAdmin);
|
|
138
149
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/context/permission-manager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Permission Management for Collaboration Layer\n */\n\nimport { ValidationError, ErrorCode } from '../errors/index.js';\nimport type { StackPermissions, StackContext } from './dual-stack-manager.js';\nimport { logger } from '../monitoring/logger.js';\n\nexport type Operation = 'read' | 'write' | 'handoff' | 'merge' | 'administer';\n\nexport interface PermissionContext {\n userId: string;\n operation: Operation;\n resourceType: 'stack' | 'frame' | 'handoff' | 'merge';\n resourceId: string;\n stackContext?: StackContext;\n}\n\nexport class PermissionManager {\n private userPermissions = new Map<string, Map<string, StackPermissions>>();\n private adminUsers = new Set<string>();\n\n constructor() {\n this.initializeDefaultPermissions();\n }\n\n /**\n * Check if user has permission for specific operation\n */\n async checkPermission(context: PermissionContext): Promise<boolean> {\n try {\n // Super admin always has access\n if (this.adminUsers.has(context.userId)) {\n return true;\n }\n\n // Get stack permissions for user\n const stackPermissions = this.getStackPermissions(\n context.userId,\n context.stackContext?.stackId || context.resourceId\n );\n\n if (!stackPermissions) {\n logger.warn('No permissions found for user', {\n userId: context.userId,\n stackId: context.stackContext?.stackId,\n operation: context.operation,\n });\n return false;\n }\n\n // Check operation-specific permissions\n switch (context.operation) {\n case 'read':\n return stackPermissions.canRead;\n\n case 'write':\n return stackPermissions.canWrite;\n\n case 'handoff':\n return stackPermissions.canHandoff;\n\n case 'merge':\n return stackPermissions.canMerge;\n\n case 'administer':\n return stackPermissions.canAdminister;\n\n default:\n logger.error('Unknown operation type', {\n operation: context.operation,\n });\n return false;\n }\n } catch (error) {\n logger.error('Permission check failed', error);\n return false;\n }\n }\n\n /**\n * Enforce permission check - throws if access denied\n */\n async enforcePermission(context: PermissionContext): Promise<void> {\n const hasPermission = await this.checkPermission(context);\n\n if (!hasPermission) {\n throw new ValidationError(\n `Access denied: User ${context.userId} lacks ${context.operation} permission for ${context.resourceType} ${context.resourceId}`,\n ErrorCode.PERMISSION_VIOLATION,\n {\n userId: context.userId,\n operation: context.operation,\n resourceType: context.resourceType,\n resourceId: context.resourceId,\n }\n );\n }\n\n logger.debug('Permission granted', {\n userId: context.userId,\n operation: context.operation,\n resourceType: context.resourceType,\n resourceId: context.resourceId,\n });\n }\n\n /**\n * Set permissions for user on specific stack\n */\n setStackPermissions(\n userId: string,\n stackId: string,\n permissions: StackPermissions\n ): void {\n if (!this.userPermissions.has(userId)) {\n this.userPermissions.set(userId, new Map());\n }\n\n this.userPermissions.get(userId)!.set(stackId, permissions);\n\n logger.info('Updated stack permissions', {\n userId,\n stackId,\n permissions,\n });\n }\n\n /**\n * Get permissions for user on specific stack\n */\n getStackPermissions(\n userId: string,\n stackId: string\n ): StackPermissions | null {\n const userPerms = this.userPermissions.get(userId);\n if (!userPerms) return null;\n\n return userPerms.get(stackId) || null;\n }\n\n /**\n * Grant admin privileges to user\n */\n grantAdminAccess(userId: string): void {\n this.adminUsers.add(userId);\n logger.info('Granted admin access', { userId });\n }\n\n /**\n * Revoke admin privileges from user\n */\n revokeAdminAccess(userId: string): void {\n this.adminUsers.delete(userId);\n logger.info('Revoked admin access', { userId });\n }\n\n /**\n * Check if user is admin\n */\n isAdmin(userId: string): boolean {\n return this.adminUsers.has(userId);\n }\n\n /**\n * Get all permissions for user\n */\n getUserPermissions(userId: string): Map<string, StackPermissions> {\n return this.userPermissions.get(userId) || new Map();\n }\n\n /**\n * Remove all permissions for user\n */\n removeUserPermissions(userId: string): void {\n this.userPermissions.delete(userId);\n this.adminUsers.delete(userId);\n logger.info('Removed all permissions for user', { userId });\n }\n\n /**\n * Initialize default permissions\n */\n private initializeDefaultPermissions(): void {\n // Set up default admin user if needed\n const defaultAdmin = process.env
|
|
5
|
-
"mappings": "AAIA,SAAS,iBAAiB,iBAAiB;AAE3C,SAAS,cAAc;
|
|
4
|
+
"sourcesContent": ["/**\n * Permission Management for Collaboration Layer\n */\n\nimport { ValidationError, ErrorCode } from '../errors/index.js';\nimport type { StackPermissions, StackContext } from './dual-stack-manager.js';\nimport { logger } from '../monitoring/logger.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 type Operation = 'read' | 'write' | 'handoff' | 'merge' | 'administer';\n\nexport interface PermissionContext {\n userId: string;\n operation: Operation;\n resourceType: 'stack' | 'frame' | 'handoff' | 'merge';\n resourceId: string;\n stackContext?: StackContext;\n}\n\nexport class PermissionManager {\n private userPermissions = new Map<string, Map<string, StackPermissions>>();\n private adminUsers = new Set<string>();\n\n constructor() {\n this.initializeDefaultPermissions();\n }\n\n /**\n * Check if user has permission for specific operation\n */\n async checkPermission(context: PermissionContext): Promise<boolean> {\n try {\n // Super admin always has access\n if (this.adminUsers.has(context.userId)) {\n return true;\n }\n\n // Get stack permissions for user\n const stackPermissions = this.getStackPermissions(\n context.userId,\n context.stackContext?.stackId || context.resourceId\n );\n\n if (!stackPermissions) {\n logger.warn('No permissions found for user', {\n userId: context.userId,\n stackId: context.stackContext?.stackId,\n operation: context.operation,\n });\n return false;\n }\n\n // Check operation-specific permissions\n switch (context.operation) {\n case 'read':\n return stackPermissions.canRead;\n\n case 'write':\n return stackPermissions.canWrite;\n\n case 'handoff':\n return stackPermissions.canHandoff;\n\n case 'merge':\n return stackPermissions.canMerge;\n\n case 'administer':\n return stackPermissions.canAdminister;\n\n default:\n logger.error('Unknown operation type', {\n operation: context.operation,\n });\n return false;\n }\n } catch (error: unknown) {\n logger.error('Permission check failed', error);\n return false;\n }\n }\n\n /**\n * Enforce permission check - throws if access denied\n */\n async enforcePermission(context: PermissionContext): Promise<void> {\n const hasPermission = await this.checkPermission(context);\n\n if (!hasPermission) {\n throw new ValidationError(\n `Access denied: User ${context.userId} lacks ${context.operation} permission for ${context.resourceType} ${context.resourceId}`,\n ErrorCode.PERMISSION_VIOLATION,\n {\n userId: context.userId,\n operation: context.operation,\n resourceType: context.resourceType,\n resourceId: context.resourceId,\n }\n );\n }\n\n logger.debug('Permission granted', {\n userId: context.userId,\n operation: context.operation,\n resourceType: context.resourceType,\n resourceId: context.resourceId,\n });\n }\n\n /**\n * Set permissions for user on specific stack\n */\n setStackPermissions(\n userId: string,\n stackId: string,\n permissions: StackPermissions\n ): void {\n if (!this.userPermissions.has(userId)) {\n this.userPermissions.set(userId, new Map());\n }\n\n this.userPermissions.get(userId)!.set(stackId, permissions);\n\n logger.info('Updated stack permissions', {\n userId,\n stackId,\n permissions,\n });\n }\n\n /**\n * Get permissions for user on specific stack\n */\n getStackPermissions(\n userId: string,\n stackId: string\n ): StackPermissions | null {\n const userPerms = this.userPermissions.get(userId);\n if (!userPerms) return null;\n\n return userPerms.get(stackId) || null;\n }\n\n /**\n * Grant admin privileges to user\n */\n grantAdminAccess(userId: string): void {\n this.adminUsers.add(userId);\n logger.info('Granted admin access', { userId });\n }\n\n /**\n * Revoke admin privileges from user\n */\n revokeAdminAccess(userId: string): void {\n this.adminUsers.delete(userId);\n logger.info('Revoked admin access', { userId });\n }\n\n /**\n * Check if user is admin\n */\n isAdmin(userId: string): boolean {\n return this.adminUsers.has(userId);\n }\n\n /**\n * Get all permissions for user\n */\n getUserPermissions(userId: string): Map<string, StackPermissions> {\n return this.userPermissions.get(userId) || new Map();\n }\n\n /**\n * Remove all permissions for user\n */\n removeUserPermissions(userId: string): void {\n this.userPermissions.delete(userId);\n this.adminUsers.delete(userId);\n logger.info('Removed all permissions for user', { userId });\n }\n\n /**\n * Initialize default permissions\n */\n private initializeDefaultPermissions(): void {\n // Set up default admin user if needed\n const defaultAdmin = process.env['STACKMEMORY_DEFAULT_ADMIN'];\n if (defaultAdmin) {\n this.grantAdminAccess(defaultAdmin);\n }\n }\n\n /**\n * Create permission context helper\n */\n createContext(\n userId: string,\n operation: Operation,\n resourceType: PermissionContext['resourceType'],\n resourceId: string,\n stackContext?: StackContext\n ): PermissionContext {\n return {\n userId,\n operation,\n resourceType,\n resourceId,\n stackContext,\n };\n }\n\n /**\n * Bulk permission update for multiple stacks\n */\n setBulkStackPermissions(\n userId: string,\n stackPermissions: Record<string, StackPermissions>\n ): void {\n if (!this.userPermissions.has(userId)) {\n this.userPermissions.set(userId, new Map());\n }\n\n const userPerms = this.userPermissions.get(userId)!;\n\n Object.entries(stackPermissions).forEach(([stackId, permissions]) => {\n userPerms.set(stackId, permissions);\n });\n\n logger.info('Updated bulk stack permissions', {\n userId,\n stackCount: Object.keys(stackPermissions).length,\n });\n }\n\n /**\n * Get permission summary for debugging\n */\n getPermissionSummary(userId: string): {\n isAdmin: boolean;\n stackPermissions: Record<string, StackPermissions>;\n } {\n return {\n isAdmin: this.isAdmin(userId),\n stackPermissions: Object.fromEntries(this.getUserPermissions(userId)),\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "AAIA,SAAS,iBAAiB,iBAAiB;AAE3C,SAAS,cAAc;AAEvB,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;AAaO,MAAM,kBAAkB;AAAA,EACrB,kBAAkB,oBAAI,IAA2C;AAAA,EACjE,aAAa,oBAAI,IAAY;AAAA,EAErC,cAAc;AACZ,SAAK,6BAA6B;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAgB,SAA8C;AAClE,QAAI;AAEF,UAAI,KAAK,WAAW,IAAI,QAAQ,MAAM,GAAG;AACvC,eAAO;AAAA,MACT;AAGA,YAAM,mBAAmB,KAAK;AAAA,QAC5B,QAAQ;AAAA,QACR,QAAQ,cAAc,WAAW,QAAQ;AAAA,MAC3C;AAEA,UAAI,CAAC,kBAAkB;AACrB,eAAO,KAAK,iCAAiC;AAAA,UAC3C,QAAQ,QAAQ;AAAA,UAChB,SAAS,QAAQ,cAAc;AAAA,UAC/B,WAAW,QAAQ;AAAA,QACrB,CAAC;AACD,eAAO;AAAA,MACT;AAGA,cAAQ,QAAQ,WAAW;AAAA,QACzB,KAAK;AACH,iBAAO,iBAAiB;AAAA,QAE1B,KAAK;AACH,iBAAO,iBAAiB;AAAA,QAE1B,KAAK;AACH,iBAAO,iBAAiB;AAAA,QAE1B,KAAK;AACH,iBAAO,iBAAiB;AAAA,QAE1B,KAAK;AACH,iBAAO,iBAAiB;AAAA,QAE1B;AACE,iBAAO,MAAM,0BAA0B;AAAA,YACrC,WAAW,QAAQ;AAAA,UACrB,CAAC;AACD,iBAAO;AAAA,MACX;AAAA,IACF,SAAS,OAAgB;AACvB,aAAO,MAAM,2BAA2B,KAAK;AAC7C,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,SAA2C;AACjE,UAAM,gBAAgB,MAAM,KAAK,gBAAgB,OAAO;AAExD,QAAI,CAAC,eAAe;AAClB,YAAM,IAAI;AAAA,QACR,uBAAuB,QAAQ,MAAM,UAAU,QAAQ,SAAS,mBAAmB,QAAQ,YAAY,IAAI,QAAQ,UAAU;AAAA,QAC7H,UAAU;AAAA,QACV;AAAA,UACE,QAAQ,QAAQ;AAAA,UAChB,WAAW,QAAQ;AAAA,UACnB,cAAc,QAAQ;AAAA,UACtB,YAAY,QAAQ;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAEA,WAAO,MAAM,sBAAsB;AAAA,MACjC,QAAQ,QAAQ;AAAA,MAChB,WAAW,QAAQ;AAAA,MACnB,cAAc,QAAQ;AAAA,MACtB,YAAY,QAAQ;AAAA,IACtB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,oBACE,QACA,SACA,aACM;AACN,QAAI,CAAC,KAAK,gBAAgB,IAAI,MAAM,GAAG;AACrC,WAAK,gBAAgB,IAAI,QAAQ,oBAAI,IAAI,CAAC;AAAA,IAC5C;AAEA,SAAK,gBAAgB,IAAI,MAAM,EAAG,IAAI,SAAS,WAAW;AAE1D,WAAO,KAAK,6BAA6B;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,oBACE,QACA,SACyB;AACzB,UAAM,YAAY,KAAK,gBAAgB,IAAI,MAAM;AACjD,QAAI,CAAC,UAAW,QAAO;AAEvB,WAAO,UAAU,IAAI,OAAO,KAAK;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,QAAsB;AACrC,SAAK,WAAW,IAAI,MAAM;AAC1B,WAAO,KAAK,wBAAwB,EAAE,OAAO,CAAC;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,QAAsB;AACtC,SAAK,WAAW,OAAO,MAAM;AAC7B,WAAO,KAAK,wBAAwB,EAAE,OAAO,CAAC;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,QAAyB;AAC/B,WAAO,KAAK,WAAW,IAAI,MAAM;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,QAA+C;AAChE,WAAO,KAAK,gBAAgB,IAAI,MAAM,KAAK,oBAAI,IAAI;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,QAAsB;AAC1C,SAAK,gBAAgB,OAAO,MAAM;AAClC,SAAK,WAAW,OAAO,MAAM;AAC7B,WAAO,KAAK,oCAAoC,EAAE,OAAO,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKQ,+BAAqC;AAE3C,UAAM,eAAe,QAAQ,IAAI,2BAA2B;AAC5D,QAAI,cAAc;AAChB,WAAK,iBAAiB,YAAY;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cACE,QACA,WACA,cACA,YACA,cACmB;AACnB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,wBACE,QACA,kBACM;AACN,QAAI,CAAC,KAAK,gBAAgB,IAAI,MAAM,GAAG;AACrC,WAAK,gBAAgB,IAAI,QAAQ,oBAAI,IAAI,CAAC;AAAA,IAC5C;AAEA,UAAM,YAAY,KAAK,gBAAgB,IAAI,MAAM;AAEjD,WAAO,QAAQ,gBAAgB,EAAE,QAAQ,CAAC,CAAC,SAAS,WAAW,MAAM;AACnE,gBAAU,IAAI,SAAS,WAAW;AAAA,IACpC,CAAC;AAED,WAAO,KAAK,kCAAkC;AAAA,MAC5C;AAAA,MACA,YAAY,OAAO,KAAK,gBAAgB,EAAE;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,QAGnB;AACA,WAAO;AAAA,MACL,SAAS,KAAK,QAAQ,MAAM;AAAA,MAC5B,kBAAkB,OAAO,YAAY,KAAK,mBAAmB,MAAM,CAAC;AAAA,IACtE;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/context/refactored-frame-manager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Refactored Frame Manager - Modular Implementation\n * Main orchestrator that uses focused modules for frame management\n */\n\nimport Database from 'better-sqlite3';\nimport { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../monitoring/logger.js';\nimport { trace } from '../trace/index.js';\nimport {\n FrameError,\n SystemError,\n ErrorCode,\n wrapError,\n createErrorHandler,\n} from '../errors/index.js';\nimport { retry, withTimeout } from '../errors/recovery.js';\nimport { sessionManager, FrameQueryMode } from '../session/index.js';\n\n// Import refactored modules\nimport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';\nimport { FrameDatabase } from './frame-database.js';\nimport { FrameStack } from './frame-stack.js';\nimport { FrameDigestGenerator } from './frame-digest.js';\n\nexport class RefactoredFrameManager {\n private frameDb: FrameDatabase;\n private frameStack: FrameStack;\n private digestGenerator: FrameDigestGenerator;\n \n private currentRunId: string;\n private sessionId: string;\n private projectId: string;\n private queryMode: FrameQueryMode = FrameQueryMode.PROJECT_ACTIVE;\n private config: FrameManagerConfig;\n\n constructor(db: Database.Database, projectId: string, config?: Partial<FrameManagerConfig>) {\n this.projectId = projectId;\n this.config = {\n projectId,\n runId: config?.runId || uuidv4(),\n sessionId: config?.sessionId || uuidv4(),\n maxStackDepth: config?.maxStackDepth || 50,\n };\n\n this.currentRunId = this.config.runId!;\n this.sessionId = this.config.sessionId!;\n\n // Initialize modules\n this.frameDb = new FrameDatabase(db);\n this.frameStack = new FrameStack(this.frameDb, projectId, this.currentRunId);\n this.digestGenerator = new FrameDigestGenerator(this.frameDb);\n\n // Initialize database schema\n this.frameDb.initSchema();\n\n logger.info('RefactoredFrameManager initialized', {\n projectId: this.projectId,\n runId: this.currentRunId,\n sessionId: this.sessionId,\n });\n }\n\n /**\n * Initialize the frame manager\n */\n async initialize(): Promise<void> {\n try {\n await this.frameStack.initialize();\n \n logger.info('Frame manager initialization completed', {\n stackDepth: this.frameStack.getDepth(),\n });\n } catch (error) {\n throw new SystemError(\n 'Failed to initialize frame manager',\n ErrorCode.SYSTEM_INIT_FAILED,\n { projectId: this.projectId },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Create a new frame\n */\n createFrame(options: FrameCreationOptions): string;\n createFrame(\n type: FrameType,\n name: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string;\n createFrame(\n typeOrOptions: FrameType | FrameCreationOptions,\n name?: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string {\n return trace.traceSync('function', 'FrameManager.createFrame', { typeOrOptions, name }, () =>\n this._createFrame(typeOrOptions, name, inputs, parentFrameId)\n );\n }\n\n private _createFrame(\n typeOrOptions: FrameType | FrameCreationOptions,\n name?: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string {\n let frameOptions: FrameCreationOptions;\n\n // Handle both function signatures\n if (typeof typeOrOptions === 'string') {\n frameOptions = {\n type: typeOrOptions,\n name: name!,\n inputs: inputs || {},\n parentFrameId,\n };\n } else {\n frameOptions = typeOrOptions;\n }\n\n // Validate inputs\n if (!frameOptions.name || frameOptions.name.trim().length === 0) {\n throw new FrameError(\n 'Frame name is required',\n ErrorCode.FRAME_INVALID_INPUT,\n { frameOptions }\n );\n }\n\n // Check stack depth limit\n if (this.frameStack.getDepth() >= this.config.maxStackDepth!) {\n throw new FrameError(\n `Maximum stack depth reached: ${this.config.maxStackDepth}`,\n ErrorCode.FRAME_STACK_OVERFLOW,\n { currentDepth: this.frameStack.getDepth() }\n );\n }\n\n // Determine parent frame\n const resolvedParentId = frameOptions.parentFrameId || this.frameStack.getCurrentFrameId();\n const depth = resolvedParentId \n ? this.frameStack.getFrameStackDepth(resolvedParentId) + 1 \n : 0;\n\n // Create frame data\n const frameId = uuidv4();\n const frame: Omit<Frame, 'created_at' | 'closed_at'> = {\n frame_id: frameId,\n run_id: this.currentRunId,\n project_id: this.projectId,\n parent_frame_id: resolvedParentId,\n depth,\n type: frameOptions.type,\n name: frameOptions.name,\n state: 'active',\n inputs: frameOptions.inputs || {},\n outputs: {},\n digest_json: {},\n };\n\n // Insert into database\n const createdFrame = this.frameDb.insertFrame(frame);\n\n // Add to stack\n this.frameStack.pushFrame(frameId);\n\n logger.info('Created frame', {\n frameId,\n name: frameOptions.name,\n type: frameOptions.type,\n parentFrameId: resolvedParentId,\n stackDepth: this.frameStack.getDepth(),\n });\n\n return frameId;\n }\n\n /**\n * Close a frame and generate digest\n */\n closeFrame(frameId?: string, outputs?: Record<string, any>): void {\n trace.traceSync('function', 'FrameManager.closeFrame', { frameId, outputs }, () =>\n this._closeFrame(frameId, outputs)\n );\n }\n\n private _closeFrame(frameId?: string, outputs?: Record<string, any>): void {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame to close',\n ErrorCode.FRAME_INVALID_STATE,\n {\n operation: 'closeFrame',\n stackDepth: this.frameStack.getDepth(),\n }\n );\n }\n\n // Get frame details\n const frame = this.frameDb.getFrame(targetFrameId);\n if (!frame) {\n throw new FrameError(\n `Frame not found: ${targetFrameId}`,\n ErrorCode.FRAME_NOT_FOUND,\n {\n frameId: targetFrameId,\n operation: 'closeFrame',\n runId: this.currentRunId,\n }\n );\n }\n\n if (frame.state === 'closed') {\n logger.warn('Attempted to close already closed frame', {\n frameId: targetFrameId,\n });\n return;\n }\n\n // Generate digest before closing\n const digest = this.digestGenerator.generateDigest(targetFrameId);\n const finalOutputs = { ...outputs, ...digest.structured };\n\n // Update frame to closed state\n this.frameDb.updateFrame(targetFrameId, {\n state: 'closed',\n outputs: finalOutputs,\n digest_text: digest.text,\n digest_json: digest.structured,\n closed_at: Math.floor(Date.now() / 1000),\n });\n\n // Remove from stack (this will also remove any child frames)\n this.frameStack.popFrame(targetFrameId);\n\n // Close all child frames recursively\n this.closeChildFrames(targetFrameId);\n\n logger.info('Closed frame', {\n frameId: targetFrameId,\n name: frame.name,\n duration: Math.floor(Date.now() / 1000) - frame.created_at,\n digestLength: digest.text.length,\n stackDepth: this.frameStack.getDepth(),\n });\n }\n\n /**\n * Add an event to the current frame\n */\n addEvent(\n eventType: Event['event_type'],\n payload: Record<string, any>,\n frameId?: string\n ): string {\n return trace.traceSync('function', 'FrameManager.addEvent', { eventType, frameId }, () =>\n this._addEvent(eventType, payload, frameId)\n );\n }\n\n private _addEvent(\n eventType: Event['event_type'],\n payload: Record<string, any>,\n frameId?: string\n ): string {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame for event',\n ErrorCode.FRAME_INVALID_STATE,\n {\n eventType,\n operation: 'addEvent',\n }\n );\n }\n\n const eventId = uuidv4();\n const sequence = this.frameDb.getNextEventSequence(targetFrameId);\n\n const event: Omit<Event, 'ts'> = {\n event_id: eventId,\n frame_id: targetFrameId,\n run_id: this.currentRunId,\n seq: sequence,\n event_type: eventType,\n payload,\n };\n\n const createdEvent = this.frameDb.insertEvent(event);\n\n logger.debug('Added event', {\n eventId,\n frameId: targetFrameId,\n eventType,\n sequence,\n });\n\n return eventId;\n }\n\n /**\n * Add an anchor (important fact) to current frame\n */\n addAnchor(\n type: Anchor['type'],\n text: string,\n priority: number = 5,\n metadata: Record<string, any> = {},\n frameId?: string\n ): string {\n return trace.traceSync('function', 'FrameManager.addAnchor', { type, frameId }, () =>\n this._addAnchor(type, text, priority, metadata, frameId)\n );\n }\n\n private _addAnchor(\n type: Anchor['type'],\n text: string,\n priority: number,\n metadata: Record<string, any>,\n frameId?: string\n ): string {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame for anchor',\n ErrorCode.FRAME_INVALID_STATE,\n {\n anchorType: type,\n operation: 'addAnchor',\n }\n );\n }\n\n const anchorId = uuidv4();\n const anchor: Omit<Anchor, 'created_at'> = {\n anchor_id: anchorId,\n frame_id: targetFrameId,\n type,\n text,\n priority,\n metadata,\n };\n\n const createdAnchor = this.frameDb.insertAnchor(anchor);\n\n logger.debug('Added anchor', {\n anchorId,\n frameId: targetFrameId,\n type,\n priority,\n });\n\n return anchorId;\n }\n\n /**\n * Get hot stack context\n */\n getHotStackContext(maxEvents: number = 20): FrameContext[] {\n return this.frameStack.getHotStackContext(maxEvents);\n }\n\n /**\n * Get active frame path (root to current)\n */\n getActiveFramePath(): Frame[] {\n return this.frameStack.getStackFrames();\n }\n\n /**\n * Get current frame ID\n */\n getCurrentFrameId(): string | undefined {\n return this.frameStack.getCurrentFrameId();\n }\n\n /**\n * Get stack depth\n */\n getStackDepth(): number {\n return this.frameStack.getDepth();\n }\n\n /**\n * Get frame by ID\n */\n getFrame(frameId: string): Frame | undefined {\n return this.frameDb.getFrame(frameId);\n }\n\n /**\n * Get frame events\n */\n getFrameEvents(frameId: string, limit?: number): Event[] {\n return this.frameDb.getFrameEvents(frameId, limit);\n }\n\n /**\n * Get frame anchors\n */\n getFrameAnchors(frameId: string): Anchor[] {\n return this.frameDb.getFrameAnchors(frameId);\n }\n\n /**\n * Generate digest for a frame\n */\n generateDigest(frameId: string): DigestResult {\n return this.digestGenerator.generateDigest(frameId);\n }\n\n /**\n * Validate stack consistency\n */\n validateStack(): { isValid: boolean; errors: string[] } {\n return this.frameStack.validateStack();\n }\n\n /**\n * Get database statistics\n */\n getStatistics(): Record<string, number> {\n return this.frameDb.getStatistics();\n }\n\n /**\n * Close all child frames recursively\n */\n private closeChildFrames(parentFrameId: string): void {\n try {\n const activeFrames = this.frameDb.getFramesByProject(this.projectId, 'active');\n const childFrames = activeFrames.filter(f => f.parent_frame_id === parentFrameId);\n\n for (const childFrame of childFrames) {\n if (this.frameStack.isFrameActive(childFrame.frame_id)) {\n this.closeFrame(childFrame.frame_id);\n }\n }\n } catch (error) {\n logger.warn('Failed to close child frames', { parentFrameId, error });\n }\n }\n\n /**\n * Extract active artifacts from frame events\n */\n getActiveArtifacts(frameId: string): string[] {\n const events = this.frameDb.getFrameEvents(frameId);\n const artifacts: string[] = [];\n\n for (const event of events) {\n if (event.event_type === 'artifact' && event.payload.path) {\n artifacts.push(event.payload.path);\n }\n }\n\n return [...new Set(artifacts)];\n }\n\n /**\n * Extract constraints from frame inputs\n */\n extractConstraints(inputs: Record<string, any>): string[] {\n const constraints: string[] = [];\n \n if (inputs.constraints && Array.isArray(inputs.constraints)) {\n constraints.push(...inputs.constraints);\n }\n \n if (inputs.requirements && Array.isArray(inputs.requirements)) {\n constraints.push(...inputs.requirements);\n }\n \n if (inputs.limitations && Array.isArray(inputs.limitations)) {\n constraints.push(...inputs.limitations);\n }\n\n return constraints;\n }\n}\n\n// Re-export types for compatibility\nexport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';"],
|
|
5
|
-
"mappings": "AAMA,SAAS,MAAM,cAAc;AAC7B,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAEP,SAAyB,sBAAsB;AAc/C,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,4BAA4B;AAE9B,MAAM,uBAAuB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAA4B,eAAe;AAAA,EAC3C;AAAA,EAER,YAAY,IAAuB,WAAmB,QAAsC;AAC1F,SAAK,YAAY;AACjB,SAAK,SAAS;AAAA,MACZ;AAAA,MACA,OAAO,QAAQ,SAAS,OAAO;AAAA,MAC/B,WAAW,QAAQ,aAAa,OAAO;AAAA,MACvC,eAAe,QAAQ,iBAAiB;AAAA,IAC1C;AAEA,SAAK,eAAe,KAAK,OAAO;AAChC,SAAK,YAAY,KAAK,OAAO;AAG7B,SAAK,UAAU,IAAI,cAAc,EAAE;AACnC,SAAK,aAAa,IAAI,WAAW,KAAK,SAAS,WAAW,KAAK,YAAY;AAC3E,SAAK,kBAAkB,IAAI,qBAAqB,KAAK,OAAO;AAG5D,SAAK,QAAQ,WAAW;AAExB,WAAO,KAAK,sCAAsC;AAAA,MAChD,WAAW,KAAK;AAAA,MAChB,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK;AAAA,IAClB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4B;AAChC,QAAI;AACF,YAAM,KAAK,WAAW,WAAW;AAEjC,aAAO,KAAK,0CAA0C;AAAA,QACpD,YAAY,KAAK,WAAW,SAAS;AAAA,MACvC,CAAC;AAAA,IACH,SAAS,
|
|
4
|
+
"sourcesContent": ["/**\n * Refactored Frame Manager - Modular Implementation\n * Main orchestrator that uses focused modules for frame management\n */\n\nimport Database from 'better-sqlite3';\nimport { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../monitoring/logger.js';\nimport { trace } from '../trace/index.js';\nimport {\n FrameError,\n SystemError,\n ErrorCode,\n wrapError,\n createErrorHandler,\n} from '../errors/index.js';\nimport { retry, withTimeout } from '../errors/recovery.js';\nimport { sessionManager, FrameQueryMode } from '../session/index.js';\n\n// Import refactored modules\nimport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';\nimport { FrameDatabase } from './frame-database.js';\nimport { FrameStack } from './frame-stack.js';\nimport { FrameDigestGenerator } from './frame-digest.js';\n\nexport class RefactoredFrameManager {\n private frameDb: FrameDatabase;\n private frameStack: FrameStack;\n private digestGenerator: FrameDigestGenerator;\n \n private currentRunId: string;\n private sessionId: string;\n private projectId: string;\n private queryMode: FrameQueryMode = FrameQueryMode.PROJECT_ACTIVE;\n private config: FrameManagerConfig;\n\n constructor(db: Database.Database, projectId: string, config?: Partial<FrameManagerConfig>) {\n this.projectId = projectId;\n this.config = {\n projectId,\n runId: config?.runId || uuidv4(),\n sessionId: config?.sessionId || uuidv4(),\n maxStackDepth: config?.maxStackDepth || 50,\n };\n\n this.currentRunId = this.config.runId!;\n this.sessionId = this.config.sessionId!;\n\n // Initialize modules\n this.frameDb = new FrameDatabase(db);\n this.frameStack = new FrameStack(this.frameDb, projectId, this.currentRunId);\n this.digestGenerator = new FrameDigestGenerator(this.frameDb);\n\n // Initialize database schema\n this.frameDb.initSchema();\n\n logger.info('RefactoredFrameManager initialized', {\n projectId: this.projectId,\n runId: this.currentRunId,\n sessionId: this.sessionId,\n });\n }\n\n /**\n * Initialize the frame manager\n */\n async initialize(): Promise<void> {\n try {\n await this.frameStack.initialize();\n \n logger.info('Frame manager initialization completed', {\n stackDepth: this.frameStack.getDepth(),\n });\n } catch (error: unknown) {\n throw new SystemError(\n 'Failed to initialize frame manager',\n ErrorCode.SYSTEM_INIT_FAILED,\n { projectId: this.projectId },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Create a new frame\n */\n createFrame(options: FrameCreationOptions): string;\n createFrame(\n type: FrameType,\n name: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string;\n createFrame(\n typeOrOptions: FrameType | FrameCreationOptions,\n name?: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string {\n return trace.traceSync('function', 'FrameManager.createFrame', { typeOrOptions, name }, () =>\n this._createFrame(typeOrOptions, name, inputs, parentFrameId)\n );\n }\n\n private _createFrame(\n typeOrOptions: FrameType | FrameCreationOptions,\n name?: string,\n inputs?: Record<string, any>,\n parentFrameId?: string\n ): string {\n let frameOptions: FrameCreationOptions;\n\n // Handle both function signatures\n if (typeof typeOrOptions === 'string') {\n frameOptions = {\n type: typeOrOptions,\n name: name!,\n inputs: inputs || {},\n parentFrameId,\n };\n } else {\n frameOptions = typeOrOptions;\n }\n\n // Validate inputs\n if (!frameOptions.name || frameOptions.name.trim().length === 0) {\n throw new FrameError(\n 'Frame name is required',\n ErrorCode.FRAME_INVALID_INPUT,\n { frameOptions }\n );\n }\n\n // Check stack depth limit\n if (this.frameStack.getDepth() >= this.config.maxStackDepth!) {\n throw new FrameError(\n `Maximum stack depth reached: ${this.config.maxStackDepth}`,\n ErrorCode.FRAME_STACK_OVERFLOW,\n { currentDepth: this.frameStack.getDepth() }\n );\n }\n\n // Determine parent frame\n const resolvedParentId = frameOptions.parentFrameId || this.frameStack.getCurrentFrameId();\n const depth = resolvedParentId \n ? this.frameStack.getFrameStackDepth(resolvedParentId) + 1 \n : 0;\n\n // Create frame data\n const frameId = uuidv4();\n const frame: Omit<Frame, 'created_at' | 'closed_at'> = {\n frame_id: frameId,\n run_id: this.currentRunId,\n project_id: this.projectId,\n parent_frame_id: resolvedParentId,\n depth,\n type: frameOptions.type,\n name: frameOptions.name,\n state: 'active',\n inputs: frameOptions.inputs || {},\n outputs: {},\n digest_json: {},\n };\n\n // Insert into database\n const createdFrame = this.frameDb.insertFrame(frame);\n\n // Add to stack\n this.frameStack.pushFrame(frameId);\n\n logger.info('Created frame', {\n frameId,\n name: frameOptions.name,\n type: frameOptions.type,\n parentFrameId: resolvedParentId,\n stackDepth: this.frameStack.getDepth(),\n });\n\n return frameId;\n }\n\n /**\n * Close a frame and generate digest\n */\n closeFrame(frameId?: string, outputs?: Record<string, any>): void {\n trace.traceSync('function', 'FrameManager.closeFrame', { frameId, outputs }, () =>\n this._closeFrame(frameId, outputs)\n );\n }\n\n private _closeFrame(frameId?: string, outputs?: Record<string, any>): void {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame to close',\n ErrorCode.FRAME_INVALID_STATE,\n {\n operation: 'closeFrame',\n stackDepth: this.frameStack.getDepth(),\n }\n );\n }\n\n // Get frame details\n const frame = this.frameDb.getFrame(targetFrameId);\n if (!frame) {\n throw new FrameError(\n `Frame not found: ${targetFrameId}`,\n ErrorCode.FRAME_NOT_FOUND,\n {\n frameId: targetFrameId,\n operation: 'closeFrame',\n runId: this.currentRunId,\n }\n );\n }\n\n if (frame.state === 'closed') {\n logger.warn('Attempted to close already closed frame', {\n frameId: targetFrameId,\n });\n return;\n }\n\n // Generate digest before closing\n const digest = this.digestGenerator.generateDigest(targetFrameId);\n const finalOutputs = { ...outputs, ...digest.structured };\n\n // Update frame to closed state\n this.frameDb.updateFrame(targetFrameId, {\n state: 'closed',\n outputs: finalOutputs,\n digest_text: digest.text,\n digest_json: digest.structured,\n closed_at: Math.floor(Date.now() / 1000),\n });\n\n // Remove from stack (this will also remove any child frames)\n this.frameStack.popFrame(targetFrameId);\n\n // Close all child frames recursively\n this.closeChildFrames(targetFrameId);\n\n logger.info('Closed frame', {\n frameId: targetFrameId,\n name: frame.name,\n duration: Math.floor(Date.now() / 1000) - frame.created_at,\n digestLength: digest.text.length,\n stackDepth: this.frameStack.getDepth(),\n });\n }\n\n /**\n * Add an event to the current frame\n */\n addEvent(\n eventType: Event['event_type'],\n payload: Record<string, any>,\n frameId?: string\n ): string {\n return trace.traceSync('function', 'FrameManager.addEvent', { eventType, frameId }, () =>\n this._addEvent(eventType, payload, frameId)\n );\n }\n\n private _addEvent(\n eventType: Event['event_type'],\n payload: Record<string, any>,\n frameId?: string\n ): string {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame for event',\n ErrorCode.FRAME_INVALID_STATE,\n {\n eventType,\n operation: 'addEvent',\n }\n );\n }\n\n const eventId = uuidv4();\n const sequence = this.frameDb.getNextEventSequence(targetFrameId);\n\n const event: Omit<Event, 'ts'> = {\n event_id: eventId,\n frame_id: targetFrameId,\n run_id: this.currentRunId,\n seq: sequence,\n event_type: eventType,\n payload,\n };\n\n const createdEvent = this.frameDb.insertEvent(event);\n\n logger.debug('Added event', {\n eventId,\n frameId: targetFrameId,\n eventType,\n sequence,\n });\n\n return eventId;\n }\n\n /**\n * Add an anchor (important fact) to current frame\n */\n addAnchor(\n type: Anchor['type'],\n text: string,\n priority: number = 5,\n metadata: Record<string, any> = {},\n frameId?: string\n ): string {\n return trace.traceSync('function', 'FrameManager.addAnchor', { type, frameId }, () =>\n this._addAnchor(type, text, priority, metadata, frameId)\n );\n }\n\n private _addAnchor(\n type: Anchor['type'],\n text: string,\n priority: number,\n metadata: Record<string, any>,\n frameId?: string\n ): string {\n const targetFrameId = frameId || this.frameStack.getCurrentFrameId();\n if (!targetFrameId) {\n throw new FrameError(\n 'No active frame for anchor',\n ErrorCode.FRAME_INVALID_STATE,\n {\n anchorType: type,\n operation: 'addAnchor',\n }\n );\n }\n\n const anchorId = uuidv4();\n const anchor: Omit<Anchor, 'created_at'> = {\n anchor_id: anchorId,\n frame_id: targetFrameId,\n type,\n text,\n priority,\n metadata,\n };\n\n const createdAnchor = this.frameDb.insertAnchor(anchor);\n\n logger.debug('Added anchor', {\n anchorId,\n frameId: targetFrameId,\n type,\n priority,\n });\n\n return anchorId;\n }\n\n /**\n * Get hot stack context\n */\n getHotStackContext(maxEvents: number = 20): FrameContext[] {\n return this.frameStack.getHotStackContext(maxEvents);\n }\n\n /**\n * Get active frame path (root to current)\n */\n getActiveFramePath(): Frame[] {\n return this.frameStack.getStackFrames();\n }\n\n /**\n * Get current frame ID\n */\n getCurrentFrameId(): string | undefined {\n return this.frameStack.getCurrentFrameId();\n }\n\n /**\n * Get stack depth\n */\n getStackDepth(): number {\n return this.frameStack.getDepth();\n }\n\n /**\n * Get frame by ID\n */\n getFrame(frameId: string): Frame | undefined {\n return this.frameDb.getFrame(frameId);\n }\n\n /**\n * Get frame events\n */\n getFrameEvents(frameId: string, limit?: number): Event[] {\n return this.frameDb.getFrameEvents(frameId, limit);\n }\n\n /**\n * Get frame anchors\n */\n getFrameAnchors(frameId: string): Anchor[] {\n return this.frameDb.getFrameAnchors(frameId);\n }\n\n /**\n * Generate digest for a frame\n */\n generateDigest(frameId: string): DigestResult {\n return this.digestGenerator.generateDigest(frameId);\n }\n\n /**\n * Validate stack consistency\n */\n validateStack(): { isValid: boolean; errors: string[] } {\n return this.frameStack.validateStack();\n }\n\n /**\n * Get database statistics\n */\n getStatistics(): Record<string, number> {\n return this.frameDb.getStatistics();\n }\n\n /**\n * Close all child frames recursively\n */\n private closeChildFrames(parentFrameId: string): void {\n try {\n const activeFrames = this.frameDb.getFramesByProject(this.projectId, 'active');\n const childFrames = activeFrames.filter((f: any) => f.parent_frame_id === parentFrameId);\n\n for (const childFrame of childFrames) {\n if (this.frameStack.isFrameActive(childFrame.frame_id)) {\n this.closeFrame(childFrame.frame_id);\n }\n }\n } catch (error: unknown) {\n logger.warn('Failed to close child frames', { parentFrameId, error });\n }\n }\n\n /**\n * Extract active artifacts from frame events\n */\n getActiveArtifacts(frameId: string): string[] {\n const events = this.frameDb.getFrameEvents(frameId);\n const artifacts: string[] = [];\n\n for (const event of events) {\n if (event.event_type === 'artifact' && event.payload.path) {\n artifacts.push(event.payload.path);\n }\n }\n\n return [...new Set(artifacts)];\n }\n\n /**\n * Extract constraints from frame inputs\n */\n extractConstraints(inputs: Record<string, any>): string[] {\n const constraints: string[] = [];\n \n if (inputs.constraints && Array.isArray(inputs.constraints)) {\n constraints.push(...inputs.constraints);\n }\n \n if (inputs.requirements && Array.isArray(inputs.requirements)) {\n constraints.push(...inputs.requirements);\n }\n \n if (inputs.limitations && Array.isArray(inputs.limitations)) {\n constraints.push(...inputs.limitations);\n }\n\n return constraints;\n }\n}\n\n// Re-export types for compatibility\nexport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Frame", "FrameContext", "Anchor", "Event", "FrameType", "FrameState", "FrameCreationOptions", "FrameManagerConfig", "DigestResult"]
|
|
7
7
|
}
|
|
@@ -2,6 +2,17 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
2
2
|
import * as fs from "fs/promises";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import { sessionManager } from "../session/session-manager.js";
|
|
5
|
+
function getEnv(key, defaultValue) {
|
|
6
|
+
const value = process.env[key];
|
|
7
|
+
if (value === void 0) {
|
|
8
|
+
if (defaultValue !== void 0) return defaultValue;
|
|
9
|
+
throw new Error(`Environment variable ${key} is required`);
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
function getOptionalEnv(key) {
|
|
14
|
+
return process.env[key];
|
|
15
|
+
}
|
|
5
16
|
class SharedContextLayer {
|
|
6
17
|
static instance;
|
|
7
18
|
contextDir;
|
|
@@ -11,7 +22,7 @@ class SharedContextLayer {
|
|
|
11
22
|
// 5 minutes
|
|
12
23
|
lastCacheClean = Date.now();
|
|
13
24
|
constructor() {
|
|
14
|
-
const homeDir = process.env
|
|
25
|
+
const homeDir = process.env["HOME"] || process.env["USERPROFILE"] || "";
|
|
15
26
|
this.contextDir = path.join(homeDir, ".stackmemory", "shared-context");
|
|
16
27
|
}
|
|
17
28
|
static getInstance() {
|