@stackmemoryai/stackmemory 0.3.7 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/dist/agents/core/agent-task-manager.js +5 -5
  2. package/dist/agents/core/agent-task-manager.js.map +2 -2
  3. package/dist/agents/verifiers/base-verifier.js +2 -2
  4. package/dist/agents/verifiers/base-verifier.js.map +2 -2
  5. package/dist/cli/claude-sm.js +0 -11
  6. package/dist/cli/claude-sm.js.map +2 -2
  7. package/dist/cli/codex-sm.js +0 -11
  8. package/dist/cli/codex-sm.js.map +2 -2
  9. package/dist/cli/commands/chromadb.js +64 -34
  10. package/dist/cli/commands/chromadb.js.map +2 -2
  11. package/dist/cli/commands/clear.js +9 -13
  12. package/dist/cli/commands/clear.js.map +2 -2
  13. package/dist/cli/commands/config.js +43 -33
  14. package/dist/cli/commands/config.js.map +2 -2
  15. package/dist/cli/commands/context.js.map +2 -2
  16. package/dist/cli/commands/dashboard.js +41 -13
  17. package/dist/cli/commands/dashboard.js.map +2 -2
  18. package/dist/cli/commands/gc.js +69 -20
  19. package/dist/cli/commands/gc.js.map +2 -2
  20. package/dist/cli/commands/handoff.js.map +2 -2
  21. package/dist/cli/commands/infinite-storage.js +60 -19
  22. package/dist/cli/commands/infinite-storage.js.map +2 -2
  23. package/dist/cli/commands/linear-create.js +36 -8
  24. package/dist/cli/commands/linear-create.js.map +2 -2
  25. package/dist/cli/commands/linear-list.js +33 -10
  26. package/dist/cli/commands/linear-list.js.map +2 -2
  27. package/dist/cli/commands/linear-migrate.js +17 -4
  28. package/dist/cli/commands/linear-migrate.js.map +2 -2
  29. package/dist/cli/commands/linear-test.js +14 -6
  30. package/dist/cli/commands/linear-test.js.map +2 -2
  31. package/dist/cli/commands/linear-unified.js +123 -35
  32. package/dist/cli/commands/linear-unified.js.map +2 -2
  33. package/dist/cli/commands/linear.js.map +2 -2
  34. package/dist/cli/commands/monitor.js.map +2 -2
  35. package/dist/cli/commands/onboard.js +35 -8
  36. package/dist/cli/commands/onboard.js.map +2 -2
  37. package/dist/cli/commands/quality.js +2 -7
  38. package/dist/cli/commands/quality.js.map +2 -2
  39. package/dist/cli/commands/session.js +23 -6
  40. package/dist/cli/commands/session.js.map +2 -2
  41. package/dist/cli/commands/skills.js +72 -27
  42. package/dist/cli/commands/skills.js.map +2 -2
  43. package/dist/cli/commands/storage.js +108 -38
  44. package/dist/cli/commands/storage.js.map +2 -2
  45. package/dist/cli/commands/tui.js.map +2 -2
  46. package/dist/cli/commands/webhook.js +57 -18
  47. package/dist/cli/commands/webhook.js.map +2 -2
  48. package/dist/cli/commands/workflow.js +8 -15
  49. package/dist/cli/commands/workflow.js.map +2 -2
  50. package/dist/cli/commands/worktree.js +34 -13
  51. package/dist/cli/commands/worktree.js.map +2 -2
  52. package/dist/cli/index.js +0 -11
  53. package/dist/cli/index.js.map +2 -2
  54. package/dist/core/config/types.js.map +1 -1
  55. package/dist/core/context/auto-context.js +10 -6
  56. package/dist/core/context/auto-context.js.map +2 -2
  57. package/dist/core/context/context-bridge.js.map +2 -2
  58. package/dist/core/context/frame-database.js +13 -3
  59. package/dist/core/context/frame-database.js.map +2 -2
  60. package/dist/core/context/frame-digest.js +7 -5
  61. package/dist/core/context/frame-digest.js.map +2 -2
  62. package/dist/core/context/frame-manager.js.map +2 -2
  63. package/dist/core/context/frame-stack.js +16 -5
  64. package/dist/core/context/frame-stack.js.map +2 -2
  65. package/dist/core/context/incremental-gc.js +10 -3
  66. package/dist/core/context/incremental-gc.js.map +2 -2
  67. package/dist/core/context/index.js.map +1 -1
  68. package/dist/core/context/permission-manager.js.map +2 -2
  69. package/dist/core/context/recursive-context-manager.js +582 -0
  70. package/dist/core/context/recursive-context-manager.js.map +7 -0
  71. package/dist/core/context/refactored-frame-manager.js +12 -3
  72. package/dist/core/context/refactored-frame-manager.js.map +2 -2
  73. package/dist/core/context/shared-context-layer.js +4 -2
  74. package/dist/core/context/shared-context-layer.js.map +2 -2
  75. package/dist/core/database/batch-operations.js +112 -86
  76. package/dist/core/database/batch-operations.js.map +2 -2
  77. package/dist/core/database/query-cache.js +19 -9
  78. package/dist/core/database/query-cache.js.map +2 -2
  79. package/dist/core/database/sqlite-adapter.js +1 -1
  80. package/dist/core/database/sqlite-adapter.js.map +2 -2
  81. package/dist/core/digest/enhanced-hybrid-digest.js +8 -2
  82. package/dist/core/digest/enhanced-hybrid-digest.js.map +2 -2
  83. package/dist/core/errors/recovery.js +9 -2
  84. package/dist/core/errors/recovery.js.map +2 -2
  85. package/dist/core/execution/parallel-executor.js +254 -0
  86. package/dist/core/execution/parallel-executor.js.map +7 -0
  87. package/dist/core/frame/workflow-templates-stub.js.map +1 -1
  88. package/dist/core/frame/workflow-templates.js +40 -1
  89. package/dist/core/frame/workflow-templates.js.map +2 -2
  90. package/dist/core/monitoring/logger.js +6 -1
  91. package/dist/core/monitoring/logger.js.map +2 -2
  92. package/dist/core/monitoring/metrics.js.map +2 -2
  93. package/dist/core/monitoring/progress-tracker.js.map +2 -2
  94. package/dist/core/performance/context-cache.js.map +2 -2
  95. package/dist/core/performance/lazy-context-loader.js +24 -20
  96. package/dist/core/performance/lazy-context-loader.js.map +2 -2
  97. package/dist/core/performance/optimized-frame-context.js +27 -12
  98. package/dist/core/performance/optimized-frame-context.js.map +2 -2
  99. package/dist/core/performance/performance-benchmark.js +10 -6
  100. package/dist/core/performance/performance-benchmark.js.map +2 -2
  101. package/dist/core/performance/performance-profiler.js +51 -14
  102. package/dist/core/performance/performance-profiler.js.map +2 -2
  103. package/dist/core/performance/streaming-jsonl-parser.js +5 -1
  104. package/dist/core/performance/streaming-jsonl-parser.js.map +2 -2
  105. package/dist/core/projects/project-manager.js +14 -20
  106. package/dist/core/projects/project-manager.js.map +2 -2
  107. package/dist/core/retrieval/context-retriever.js.map +1 -1
  108. package/dist/core/retrieval/llm-context-retrieval.js.map +2 -2
  109. package/dist/core/session/clear-survival-stub.js +5 -1
  110. package/dist/core/session/clear-survival-stub.js.map +2 -2
  111. package/dist/core/session/clear-survival.js +35 -0
  112. package/dist/core/session/clear-survival.js.map +2 -2
  113. package/dist/core/session/index.js.map +1 -1
  114. package/dist/core/session/session-manager.js.map +2 -2
  115. package/dist/core/storage/chromadb-adapter.js +6 -2
  116. package/dist/core/storage/chromadb-adapter.js.map +2 -2
  117. package/dist/core/storage/chromadb-simple.js +17 -5
  118. package/dist/core/storage/chromadb-simple.js.map +2 -2
  119. package/dist/core/storage/infinite-storage.js +109 -46
  120. package/dist/core/storage/infinite-storage.js.map +2 -2
  121. package/dist/core/storage/railway-optimized-storage.js +48 -22
  122. package/dist/core/storage/railway-optimized-storage.js.map +2 -2
  123. package/dist/core/storage/remote-storage.js +41 -23
  124. package/dist/core/storage/remote-storage.js.map +2 -2
  125. package/dist/core/trace/cli-trace-wrapper.js +9 -2
  126. package/dist/core/trace/cli-trace-wrapper.js.map +2 -2
  127. package/dist/core/trace/db-trace-wrapper.js +96 -68
  128. package/dist/core/trace/db-trace-wrapper.js.map +2 -2
  129. package/dist/core/trace/debug-trace.js +25 -8
  130. package/dist/core/trace/debug-trace.js.map +2 -2
  131. package/dist/core/trace/index.js +6 -2
  132. package/dist/core/trace/index.js.map +2 -2
  133. package/dist/core/trace/linear-api-wrapper.js +10 -5
  134. package/dist/core/trace/linear-api-wrapper.js.map +2 -2
  135. package/dist/core/trace/trace-demo.js +14 -10
  136. package/dist/core/trace/trace-demo.js.map +2 -2
  137. package/dist/core/trace/trace-detector.js +9 -2
  138. package/dist/core/trace/trace-detector.js.map +2 -2
  139. package/dist/core/trace/types.js.map +1 -1
  140. package/dist/core/utils/compression.js.map +1 -1
  141. package/dist/core/utils/update-checker.js.map +1 -1
  142. package/dist/core/worktree/worktree-manager.js +18 -7
  143. package/dist/core/worktree/worktree-manager.js.map +2 -2
  144. package/dist/features/analytics/core/analytics-service.js.map +2 -2
  145. package/dist/features/analytics/queries/metrics-queries.js +1 -1
  146. package/dist/features/analytics/queries/metrics-queries.js.map +2 -2
  147. package/dist/features/tasks/pebbles-task-store.js.map +1 -1
  148. package/dist/features/tui/components/analytics-panel.js +36 -15
  149. package/dist/features/tui/components/analytics-panel.js.map +2 -2
  150. package/dist/features/tui/components/pr-tracker.js +19 -7
  151. package/dist/features/tui/components/pr-tracker.js.map +2 -2
  152. package/dist/features/tui/components/session-monitor.js +22 -9
  153. package/dist/features/tui/components/session-monitor.js.map +2 -2
  154. package/dist/features/tui/components/subagent-fleet.js +20 -13
  155. package/dist/features/tui/components/subagent-fleet.js.map +2 -2
  156. package/dist/features/tui/components/task-board.js +26 -10
  157. package/dist/features/tui/components/task-board.js.map +2 -2
  158. package/dist/features/tui/index.js.map +2 -2
  159. package/dist/features/tui/services/data-service.js +6 -2
  160. package/dist/features/tui/services/data-service.js.map +2 -2
  161. package/dist/features/tui/services/linear-task-reader.js +3 -1
  162. package/dist/features/tui/services/linear-task-reader.js.map +2 -2
  163. package/dist/features/tui/services/websocket-client.js +3 -1
  164. package/dist/features/tui/services/websocket-client.js.map +2 -2
  165. package/dist/features/tui/terminal-compat.js +6 -2
  166. package/dist/features/tui/terminal-compat.js.map +2 -2
  167. package/dist/features/web/client/stores/task-store.js.map +2 -2
  168. package/dist/features/web/server/index.js +18 -10
  169. package/dist/features/web/server/index.js.map +2 -2
  170. package/dist/integrations/anthropic/client.js +259 -0
  171. package/dist/integrations/anthropic/client.js.map +7 -0
  172. package/dist/integrations/claude-code/subagent-client.js +404 -0
  173. package/dist/integrations/claude-code/subagent-client.js.map +7 -0
  174. package/dist/integrations/linear/sync-service.js +12 -13
  175. package/dist/integrations/linear/sync-service.js.map +2 -2
  176. package/dist/integrations/linear/sync.js +174 -12
  177. package/dist/integrations/linear/sync.js.map +2 -2
  178. package/dist/integrations/linear/unified-sync.js +1 -1
  179. package/dist/integrations/linear/unified-sync.js.map +1 -1
  180. package/dist/integrations/linear/webhook-server.js +15 -16
  181. package/dist/integrations/linear/webhook-server.js.map +2 -2
  182. package/dist/mcp/stackmemory-mcp-server.js +0 -11
  183. package/dist/mcp/stackmemory-mcp-server.js.map +2 -2
  184. package/dist/servers/production/auth-middleware.js.map +2 -2
  185. package/dist/servers/railway/index.js.map +2 -2
  186. package/dist/services/config-service.js +6 -7
  187. package/dist/services/config-service.js.map +2 -2
  188. package/dist/services/context-service.js +11 -12
  189. package/dist/services/context-service.js.map +2 -2
  190. package/dist/skills/claude-skills.js +101 -2
  191. package/dist/skills/claude-skills.js.map +2 -2
  192. package/dist/skills/dashboard-launcher.js.map +2 -2
  193. package/dist/skills/recursive-agent-orchestrator.js +559 -0
  194. package/dist/skills/recursive-agent-orchestrator.js.map +7 -0
  195. package/dist/skills/repo-ingestion-skill.js.map +2 -2
  196. package/dist/skills/security-secrets-scanner.js +265 -0
  197. package/dist/skills/security-secrets-scanner.js.map +7 -0
  198. package/dist/utils/env.js +46 -0
  199. package/dist/utils/env.js.map +7 -0
  200. package/dist/utils/logger.js +0 -11
  201. package/dist/utils/logger.js.map +2 -2
  202. package/package.json +1 -1
@@ -12,7 +12,10 @@ class FrameStack {
12
12
  */
13
13
  async initialize() {
14
14
  try {
15
- const activeFrames = this.frameDb.getFramesByProject(this.projectId, "active");
15
+ const activeFrames = this.frameDb.getFramesByProject(
16
+ this.projectId,
17
+ "active"
18
+ );
16
19
  this.activeStack = this.buildStackFromFrames(activeFrames);
17
20
  logger.info("Frame stack initialized", {
18
21
  stackDepth: this.activeStack.length,
@@ -153,7 +156,9 @@ class FrameStack {
153
156
  continue;
154
157
  }
155
158
  if (frame.state !== "active") {
156
- errors.push(`Frame on stack is not active: ${frameId} (state: ${frame.state})`);
159
+ errors.push(
160
+ `Frame on stack is not active: ${frameId} (state: ${frame.state})`
161
+ );
157
162
  }
158
163
  if (frame.project_id !== this.projectId) {
159
164
  errors.push(`Frame belongs to different project: ${frameId}`);
@@ -164,7 +169,9 @@ class FrameStack {
164
169
  const expectedParentId = this.activeStack[i - 1];
165
170
  const currentFrame = this.frameDb.getFrame(currentFrameId);
166
171
  if (currentFrame?.parent_frame_id !== expectedParentId) {
167
- errors.push(`Frame parent mismatch: ${currentFrameId} parent should be ${expectedParentId} but is ${currentFrame?.parent_frame_id}`);
172
+ errors.push(
173
+ `Frame parent mismatch: ${currentFrameId} parent should be ${expectedParentId} but is ${currentFrame?.parent_frame_id}`
174
+ );
168
175
  }
169
176
  }
170
177
  return {
@@ -251,10 +258,14 @@ class FrameStack {
251
258
  });
252
259
  }
253
260
  const stack = [];
254
- let currentFrame = rootFrames.sort((a, b) => a.created_at - b.created_at)[0];
261
+ let currentFrame = rootFrames.sort(
262
+ (a, b) => a.created_at - b.created_at
263
+ )[0];
255
264
  while (currentFrame) {
256
265
  stack.push(currentFrame.frame_id);
257
- const childFrame = frames.find((f) => f.parent_frame_id === currentFrame.frame_id);
266
+ const childFrame = frames.find(
267
+ (f) => f.parent_frame_id === currentFrame.frame_id
268
+ );
258
269
  if (childFrame) {
259
270
  currentFrame = childFrame;
260
271
  } else {
@@ -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: 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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",
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(\n this.projectId,\n 'active'\n );\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(\n `Frame on stack is not active: ${frameId} (state: ${frame.state})`\n );\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(\n `Frame parent mismatch: ${currentFrameId} parent should be ${expectedParentId} but is ${currentFrame?.parent_frame_id}`\n );\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(\n frameId: string,\n maxEvents: number\n ): 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(\n (f: any) => !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(\n (a, b) => a.created_at - b.created_at\n )[0];\n\n while (currentFrame) {\n stack.push(currentFrame.frame_id);\n\n // Find child frame\n const childFrame = frames.find(\n (f: any) => f.parent_frame_id === currentFrame.frame_id\n );\n if (childFrame) {\n currentFrame = childFrame;\n } else {\n break;\n }\n }\n\n return stack;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -43,7 +43,9 @@ class IncrementalGarbageCollector {
43
43
  return;
44
44
  }
45
45
  this.isRunning = true;
46
- this.logger.info(`Starting incremental GC with ${this.config.cycleInterval}ms intervals`);
46
+ this.logger.info(
47
+ `Starting incremental GC with ${this.config.cycleInterval}ms intervals`
48
+ );
47
49
  this.cycleTimer = setInterval(() => {
48
50
  this.runCycle().catch((error) => {
49
51
  this.logger.error("GC cycle failed", error);
@@ -66,7 +68,9 @@ class IncrementalGarbageCollector {
66
68
  */
67
69
  async runCycle() {
68
70
  const startTime = Date.now();
69
- this.logger.debug("Starting GC cycle", { cycle: this.stats.cycleCount + 1 });
71
+ this.logger.debug("Starting GC cycle", {
72
+ cycle: this.stats.cycleCount + 1
73
+ });
70
74
  try {
71
75
  const allFrames = await this.frameManager.getAllFrames();
72
76
  this.stats.totalFrames = allFrames.length;
@@ -151,7 +155,10 @@ class IncrementalGarbageCollector {
151
155
  const orphaned = [...categorized.mature, ...categorized.old].filter(
152
156
  (f) => this.isOrphaned(f)
153
157
  );
154
- const duplicates = this.findDuplicateTraces([...categorized.mature, ...categorized.old]);
158
+ const duplicates = this.findDuplicateTraces([
159
+ ...categorized.mature,
160
+ ...categorized.old
161
+ ]);
155
162
  const oldMature = categorized.mature.filter((f) => {
156
163
  const age = Date.now() - f.created_at;
157
164
  return age > this.config.generations.mature * 0.8;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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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",
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(\n `Starting incremental GC with ${this.config.cycleInterval}ms intervals`\n );\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', {\n cycle: this.stats.cycleCount + 1,\n });\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 } 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) {\n // 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(\n (f: Frame) =>\n f.state === 'closed' &&\n (!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(\n (f: Frame) => this.isOrphaned(f)\n );\n\n // Priority 3: Duplicate traces\n const duplicates = this.findDuplicateTraces([\n ...categorized.mature,\n ...categorized.old,\n ]);\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 (\n !frame.parent_frame_id && frame.depth > 0 && frame.state === 'closed'\n );\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(\n candidates: Frame[]\n ): 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 } 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 (\n frame.state === 'closed' &&\n (!frame.outputs || Object.keys(frame.outputs).length === 0)\n ) {\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) /\n 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}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/context/index.ts"],
4
- "sourcesContent": ["/**\n * Context Module Exports\n * Maintains compatibility while providing access to refactored components\n */\n\n// Export refactored components as primary\nexport { RefactoredFrameManager as FrameManager } from './refactored-frame-manager.js';\n\n// Export types\nexport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';\n\n// Export focused modules for direct access\nexport { FrameDatabase } from './frame-database.js';\nexport { FrameStack } from './frame-stack.js';\nexport { FrameDigestGenerator } from './frame-digest.js';\n\n// Re-export from old frame-manager for backwards compatibility\n// This allows existing code to continue working without changes\nexport { FrameManager as LegacyFrameManager } from './frame-manager.js';"],
4
+ "sourcesContent": ["/**\n * Context Module Exports\n * Maintains compatibility while providing access to refactored components\n */\n\n// Export refactored components as primary\nexport { RefactoredFrameManager as FrameManager } from './refactored-frame-manager.js';\n\n// Export types\nexport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n FrameType,\n FrameState,\n FrameCreationOptions,\n FrameManagerConfig,\n DigestResult,\n} from './frame-types.js';\n\n// Export focused modules for direct access\nexport { FrameDatabase } from './frame-database.js';\nexport { FrameStack } from './frame-stack.js';\nexport { FrameDigestGenerator } from './frame-digest.js';\n\n// Re-export from old frame-manager for backwards compatibility\n// This allows existing code to continue working without changes\nexport { FrameManager as LegacyFrameManager } from './frame-manager.js';\n"],
5
5
  "mappings": "AAMA,SAAmC,8BAAoB;AAGvD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,4BAA4B;AAIrC,SAAyB,oBAA0B;",
6
6
  "names": []
7
7
  }
@@ -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// 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": "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",
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\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": "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",
6
6
  "names": []
7
7
  }