@stackmemoryai/stackmemory 0.3.6 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/core/agent-task-manager.js +5 -5
- package/dist/agents/core/agent-task-manager.js.map +2 -2
- package/dist/agents/verifiers/base-verifier.js +2 -2
- package/dist/agents/verifiers/base-verifier.js.map +2 -2
- package/dist/agents/verifiers/formatter-verifier.js.map +2 -2
- package/dist/agents/verifiers/llm-judge.js.map +2 -2
- package/dist/cli/claude-sm.js +13 -13
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/codex-sm.js +13 -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 +261 -46
- package/dist/cli/commands/chromadb.js.map +2 -2
- package/dist/cli/commands/clear.js +10 -3
- package/dist/cli/commands/clear.js.map +2 -2
- package/dist/cli/commands/config.js +43 -33
- package/dist/cli/commands/config.js.map +2 -2
- package/dist/cli/commands/context.js +13 -2
- package/dist/cli/commands/context.js.map +2 -2
- package/dist/cli/commands/dashboard.js +41 -13
- package/dist/cli/commands/dashboard.js.map +2 -2
- package/dist/cli/commands/gc.js +251 -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 +92 -40
- package/dist/cli/commands/infinite-storage.js.map +2 -2
- package/dist/cli/commands/linear-create.js +49 -10
- package/dist/cli/commands/linear-create.js.map +2 -2
- package/dist/cli/commands/linear-list.js +45 -11
- package/dist/cli/commands/linear-list.js.map +2 -2
- package/dist/cli/commands/linear-migrate.js +29 -5
- package/dist/cli/commands/linear-migrate.js.map +2 -2
- package/dist/cli/commands/linear-test.js +26 -7
- package/dist/cli/commands/linear-test.js.map +2 -2
- package/dist/cli/commands/linear-unified.js +350 -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 +35 -8
- package/dist/cli/commands/onboard.js.map +2 -2
- package/dist/cli/commands/quality.js +2 -7
- package/dist/cli/commands/quality.js.map +2 -2
- package/dist/cli/commands/search.js.map +2 -2
- package/dist/cli/commands/session.js +23 -6
- package/dist/cli/commands/session.js.map +2 -2
- package/dist/cli/commands/skills.js +84 -28
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/storage.js +119 -38
- 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 +71 -21
- package/dist/cli/commands/webhook.js.map +2 -2
- package/dist/cli/commands/workflow.js +11 -7
- package/dist/cli/commands/workflow.js.map +2 -2
- package/dist/cli/commands/worktree.js +34 -13
- package/dist/cli/commands/worktree.js.map +2 -2
- package/dist/cli/index.js +7 -5
- package/dist/cli/index.js.map +2 -2
- package/dist/core/config/config-manager.js.map +2 -2
- package/dist/core/config/types.js.map +1 -1
- package/dist/core/context/auto-context.js +10 -6
- package/dist/core/context/auto-context.js.map +2 -2
- package/dist/core/context/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 +13 -3
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-digest.js +7 -5
- package/dist/core/context/frame-digest.js.map +2 -2
- package/dist/core/context/frame-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 +16 -5
- package/dist/core/context/frame-stack.js.map +2 -2
- package/dist/core/context/incremental-gc.js +286 -0
- package/dist/core/context/incremental-gc.js.map +7 -0
- package/dist/core/context/index.js.map +1 -1
- 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 +12 -3
- package/dist/core/context/refactored-frame-manager.js.map +2 -2
- package/dist/core/context/shared-context-layer.js +16 -3
- 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 +112 -86
- 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 +19 -9
- 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 +1 -1
- package/dist/core/database/sqlite-adapter.js.map +2 -2
- package/dist/core/digest/enhanced-hybrid-digest.js +8 -2
- package/dist/core/digest/enhanced-hybrid-digest.js.map +2 -2
- package/dist/core/errors/recovery.js +9 -2
- package/dist/core/errors/recovery.js.map +2 -2
- package/dist/core/frame/workflow-templates-stub.js.map +1 -1
- package/dist/core/frame/workflow-templates.js +40 -1
- package/dist/core/frame/workflow-templates.js.map +2 -2
- package/dist/core/merge/resolution-engine.js.map +2 -2
- package/dist/core/monitoring/error-handler.js.map +2 -2
- package/dist/core/monitoring/logger.js +19 -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 +24 -20
- 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 +27 -12
- package/dist/core/performance/optimized-frame-context.js.map +2 -2
- package/dist/core/performance/performance-benchmark.js +10 -6
- package/dist/core/performance/performance-benchmark.js.map +2 -2
- package/dist/core/performance/performance-profiler.js +63 -15
- package/dist/core/performance/performance-profiler.js.map +2 -2
- package/dist/core/performance/streaming-jsonl-parser.js +5 -1
- package/dist/core/performance/streaming-jsonl-parser.js.map +2 -2
- package/dist/core/persistence/postgres-adapter.js.map +2 -2
- package/dist/core/projects/project-manager.js +14 -20
- package/dist/core/projects/project-manager.js.map +2 -2
- package/dist/core/retrieval/context-retriever.js.map +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-stub.js +5 -1
- package/dist/core/session/clear-survival-stub.js.map +2 -2
- package/dist/core/session/clear-survival.js +35 -0
- package/dist/core/session/clear-survival.js.map +2 -2
- package/dist/core/session/handoff-generator.js.map +2 -2
- package/dist/core/session/index.js.map +1 -1
- 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 +6 -2
- package/dist/core/storage/chromadb-adapter.js.map +2 -2
- package/dist/core/storage/chromadb-simple.js +17 -5
- package/dist/core/storage/chromadb-simple.js.map +2 -2
- package/dist/core/storage/infinite-storage.js +109 -46
- package/dist/core/storage/infinite-storage.js.map +2 -2
- package/dist/core/storage/railway-optimized-storage.js +67 -30
- package/dist/core/storage/railway-optimized-storage.js.map +2 -2
- package/dist/core/storage/remote-storage.js +53 -24
- package/dist/core/storage/remote-storage.js.map +2 -2
- package/dist/core/trace/cli-trace-wrapper.js +25 -7
- package/dist/core/trace/cli-trace-wrapper.js.map +2 -2
- package/dist/core/trace/db-trace-wrapper.js +96 -68
- package/dist/core/trace/db-trace-wrapper.js.map +2 -2
- package/dist/core/trace/debug-trace.js +44 -16
- package/dist/core/trace/debug-trace.js.map +2 -2
- package/dist/core/trace/index.js +50 -35
- package/dist/core/trace/index.js.map +2 -2
- package/dist/core/trace/linear-api-wrapper.js +10 -5
- package/dist/core/trace/linear-api-wrapper.js.map +2 -2
- package/dist/core/trace/trace-demo.js +26 -11
- package/dist/core/trace/trace-demo.js.map +2 -2
- package/dist/core/trace/trace-detector.js +9 -2
- package/dist/core/trace/trace-detector.js.map +2 -2
- package/dist/core/trace/trace-store.js.map +2 -2
- package/dist/core/trace/types.js.map +1 -1
- package/dist/core/utils/compression.js.map +1 -1
- package/dist/core/utils/update-checker.js.map +2 -2
- package/dist/core/worktree/worktree-manager.js +18 -7
- 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 +1 -1
- 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 +36 -15
- package/dist/features/tui/components/analytics-panel.js.map +2 -2
- package/dist/features/tui/components/pr-tracker.js +19 -7
- package/dist/features/tui/components/pr-tracker.js.map +2 -2
- package/dist/features/tui/components/session-monitor.js +22 -9
- package/dist/features/tui/components/session-monitor.js.map +2 -2
- package/dist/features/tui/components/subagent-fleet.js +20 -13
- package/dist/features/tui/components/subagent-fleet.js.map +2 -2
- package/dist/features/tui/components/task-board.js +666 -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 +30 -15
- package/dist/features/tui/services/data-service.js.map +2 -2
- package/dist/features/tui/services/linear-task-reader.js +3 -1
- package/dist/features/tui/services/linear-task-reader.js.map +2 -2
- package/dist/features/tui/services/websocket-client.js +16 -3
- package/dist/features/tui/services/websocket-client.js.map +2 -2
- package/dist/features/tui/terminal-compat.js +33 -18
- package/dist/features/tui/terminal-compat.js.map +2 -2
- package/dist/features/web/client/stores/task-store.js.map +2 -2
- package/dist/features/web/server/index.js +31 -12
- package/dist/features/web/server/index.js.map +2 -2
- 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 +24 -14
- package/dist/integrations/linear/sync-service.js.map +2 -2
- package/dist/integrations/linear/sync.js +196 -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 +29 -19
- 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 +1 -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 +6 -7
- package/dist/services/config-service.js.map +2 -2
- package/dist/services/context-service.js +11 -12
- package/dist/services/context-service.js.map +2 -2
- package/dist/skills/claude-skills.js +108 -3
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/dashboard-launcher.js.map +2 -2
- package/dist/skills/repo-ingestion-skill.js +561 -0
- package/dist/skills/repo-ingestion-skill.js.map +7 -0
- package/dist/utils/env.js +46 -0
- package/dist/utils/env.js.map +7 -0
- package/dist/utils/logger.js +1 -1
- package/dist/utils/logger.js.map +2 -2
- package/package.json +5 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/performance/context-cache.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * High-Performance Context Cache\n * LRU cache with TTL for frequently accessed context data\n */\n\nimport { EventEmitter } from 'events';\nimport { logger } from '../monitoring/logger.js';\n\nexport interface CacheEntry<T> {\n value: T;\n size: number;\n hits: number;\n createdAt: number;\n lastAccessed: number;\n ttl?: number;\n}\n\nexport interface CacheStats {\n hits: number;\n misses: number;\n evictions: number;\n size: number;\n itemCount: number;\n hitRate: number;\n avgAccessTime: number;\n}\n\nexport interface CacheOptions {\n maxSize?: number; // Max memory in bytes\n maxItems?: number; // Max number of items\n defaultTTL?: number; // Default TTL in ms\n enableStats?: boolean;\n onEvict?: (key: string, entry: CacheEntry<any>) => void;\n}\n\nexport class ContextCache<T = any> extends EventEmitter {\n private cache = new Map<string, CacheEntry<T>>();\n private accessOrder: string[] = [];\n private options: Required<CacheOptions>;\n private stats: CacheStats;\n private currentSize = 0;\n\n constructor(options: CacheOptions = {}) {\n super();\n this.options = {\n maxSize: options.maxSize || 100 * 1024 * 1024, // 100MB default\n maxItems: options.maxItems || 10000,\n defaultTTL: options.defaultTTL || 3600000, // 1 hour default\n enableStats: options.enableStats ?? true,\n onEvict: options.onEvict || (() => {}),\n };\n\n this.stats = {\n hits: 0,\n misses: 0,\n evictions: 0,\n size: 0,\n itemCount: 0,\n hitRate: 0,\n avgAccessTime: 0,\n };\n }\n\n /**\n * Get item from cache\n */\n get(key: string): T | undefined {\n const startTime = Date.now();\n const entry = this.cache.get(key);\n\n if (!entry) {\n this.stats.misses++;\n this.updateHitRate();\n return undefined;\n }\n\n // Check TTL\n if (entry.ttl && Date.now() - entry.createdAt > entry.ttl) {\n this.delete(key);\n this.stats.misses++;\n this.updateHitRate();\n return undefined;\n }\n\n // Update access tracking\n entry.hits++;\n entry.lastAccessed = Date.now();\n this.updateAccessOrder(key);\n\n this.stats.hits++;\n this.updateHitRate();\n this.updateAvgAccessTime(Date.now() - startTime);\n\n return entry.value;\n }\n\n /**\n * Set item in cache\n */\n set(key: string
|
|
5
|
-
"mappings": "AAKA,SAAS,oBAAoB;AAC7B,SAAS,cAAc;AA6BhB,MAAM,qBAA8B,aAAa;AAAA,EAC9C,QAAQ,oBAAI,IAA2B;AAAA,EACvC,cAAwB,CAAC;AAAA,EACzB;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EAEtB,YAAY,UAAwB,CAAC,GAAG;AACtC,UAAM;AACN,SAAK,UAAU;AAAA,MACb,SAAS,QAAQ,WAAW,MAAM,OAAO;AAAA;AAAA,MACzC,UAAU,QAAQ,YAAY;AAAA,MAC9B,YAAY,QAAQ,cAAc;AAAA;AAAA,MAClC,aAAa,QAAQ,eAAe;AAAA,MACpC,SAAS,QAAQ,YAAY,MAAM;AAAA,MAAC;AAAA,IACtC;AAEA,SAAK,QAAQ;AAAA,MACX,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,MACT,eAAe;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,KAA4B;AAC9B,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAEhC,QAAI,CAAC,OAAO;AACV,WAAK,MAAM;AACX,WAAK,cAAc;AACnB,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,OAAO,KAAK,IAAI,IAAI,MAAM,YAAY,MAAM,KAAK;AACzD,WAAK,OAAO,GAAG;AACf,WAAK,MAAM;AACX,WAAK,cAAc;AACnB,aAAO;AAAA,IACT;AAGA,UAAM;AACN,UAAM,eAAe,KAAK,IAAI;AAC9B,SAAK,kBAAkB,GAAG;AAE1B,SAAK,MAAM;AACX,SAAK,cAAc;AACnB,SAAK,oBAAoB,KAAK,IAAI,IAAI,SAAS;AAE/C,WAAO,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,
|
|
4
|
+
"sourcesContent": ["/**\n * High-Performance Context Cache\n * LRU cache with TTL for frequently accessed context data\n */\n\nimport { EventEmitter } from 'events';\nimport { logger } from '../monitoring/logger.js';\n\nexport interface CacheEntry<T> {\n value: T;\n size: number;\n hits: number;\n createdAt: number;\n lastAccessed: number;\n ttl?: number;\n}\n\nexport interface CacheStats {\n hits: number;\n misses: number;\n evictions: number;\n size: number;\n itemCount: number;\n hitRate: number;\n avgAccessTime: number;\n}\n\nexport interface CacheOptions {\n maxSize?: number; // Max memory in bytes\n maxItems?: number; // Max number of items\n defaultTTL?: number; // Default TTL in ms\n enableStats?: boolean;\n onEvict?: (key: string, entry: CacheEntry<any>) => void;\n}\n\nexport class ContextCache<T = any> extends EventEmitter {\n private cache = new Map<string, CacheEntry<T>>();\n private accessOrder: string[] = [];\n private options: Required<CacheOptions>;\n private stats: CacheStats;\n private currentSize = 0;\n\n constructor(options: CacheOptions = {}) {\n super();\n this.options = {\n maxSize: options.maxSize || 100 * 1024 * 1024, // 100MB default\n maxItems: options.maxItems || 10000,\n defaultTTL: options.defaultTTL || 3600000, // 1 hour default\n enableStats: options.enableStats ?? true,\n onEvict: options.onEvict || (() => {}),\n };\n\n this.stats = {\n hits: 0,\n misses: 0,\n evictions: 0,\n size: 0,\n itemCount: 0,\n hitRate: 0,\n avgAccessTime: 0,\n };\n }\n\n /**\n * Get item from cache\n */\n get(key: string): T | undefined {\n const startTime = Date.now();\n const entry = this.cache.get(key);\n\n if (!entry) {\n this.stats.misses++;\n this.updateHitRate();\n return undefined;\n }\n\n // Check TTL\n if (entry.ttl && Date.now() - entry.createdAt > entry.ttl) {\n this.delete(key);\n this.stats.misses++;\n this.updateHitRate();\n return undefined;\n }\n\n // Update access tracking\n entry.hits++;\n entry.lastAccessed = Date.now();\n this.updateAccessOrder(key);\n\n this.stats.hits++;\n this.updateHitRate();\n this.updateAvgAccessTime(Date.now() - startTime);\n\n return entry.value;\n }\n\n /**\n * Set item in cache\n */\n set(\n key: string,\n value: T,\n options: { ttl?: number; size?: number } = {}\n ): void {\n const size = options.size || this.estimateSize(value);\n const ttl = options.ttl ?? this.options.defaultTTL;\n\n // Check if we need to evict\n if (\n this.cache.size >= this.options.maxItems ||\n this.currentSize + size > this.options.maxSize\n ) {\n this.evict(size);\n }\n\n // Remove old entry if exists\n if (this.cache.has(key)) {\n this.delete(key);\n }\n\n const entry: CacheEntry<T> = {\n value,\n size,\n hits: 0,\n createdAt: Date.now(),\n lastAccessed: Date.now(),\n ttl,\n };\n\n this.cache.set(key, entry);\n this.accessOrder.push(key);\n this.currentSize += size;\n this.stats.size = this.currentSize;\n this.stats.itemCount = this.cache.size;\n\n this.emit('set', key, value);\n }\n\n /**\n * Delete item from cache\n */\n delete(key: string): boolean {\n const entry = this.cache.get(key);\n if (!entry) return false;\n\n this.cache.delete(key);\n this.currentSize -= entry.size;\n this.accessOrder = this.accessOrder.filter((k: any) => k !== key);\n\n this.stats.size = this.currentSize;\n this.stats.itemCount = this.cache.size;\n\n this.emit('delete', key);\n return true;\n }\n\n /**\n * Clear entire cache\n */\n clear(): void {\n const oldSize = this.cache.size;\n this.cache.clear();\n this.accessOrder = [];\n this.currentSize = 0;\n\n this.stats.size = 0;\n this.stats.itemCount = 0;\n this.stats.evictions += oldSize;\n\n this.emit('clear');\n }\n\n /**\n * Check if key exists and is valid\n */\n has(key: string): boolean {\n const entry = this.cache.get(key);\n if (!entry) return false;\n\n // Check TTL\n if (entry.ttl && Date.now() - entry.createdAt > entry.ttl) {\n this.delete(key);\n return false;\n }\n\n return true;\n }\n\n /**\n * Get cache statistics\n */\n getStats(): CacheStats {\n return { ...this.stats };\n }\n\n /**\n * Get cache size info\n */\n getSize(): { bytes: number; items: number; utilization: number } {\n return {\n bytes: this.currentSize,\n items: this.cache.size,\n utilization: this.currentSize / this.options.maxSize,\n };\n }\n\n /**\n * Preload multiple items\n */\n preload(\n entries: Array<{ key: string; value: T; ttl?: number; size?: number }>\n ): void {\n const startTime = Date.now();\n\n for (const entry of entries) {\n this.set(entry.key, entry.value, {\n ttl: entry.ttl,\n size: entry.size,\n });\n }\n\n logger.debug('Cache preload complete', {\n items: entries.length,\n duration: Date.now() - startTime,\n cacheSize: this.currentSize,\n });\n }\n\n /**\n * Get multiple items efficiently\n */\n getMany(keys: string[]): Map<string, T> {\n const results = new Map<string, T>();\n\n for (const key of keys) {\n const value = this.get(key);\n if (value !== undefined) {\n results.set(key, value);\n }\n }\n\n return results;\n }\n\n /**\n * Warm cache with computed values\n */\n async warmUp(\n keys: string[],\n compute: (key: string) => Promise<T>,\n options: { ttl?: number; parallel?: boolean } = {}\n ): Promise<void> {\n const { parallel = true } = options;\n\n if (parallel) {\n const promises = keys.map(async (key) => {\n if (!this.has(key)) {\n const value = await compute(key);\n this.set(key, value, { ttl: options.ttl });\n }\n });\n await Promise.all(promises);\n } else {\n for (const key of keys) {\n if (!this.has(key)) {\n const value = await compute(key);\n this.set(key, value, { ttl: options.ttl });\n }\n }\n }\n }\n\n /**\n * Get or compute value\n */\n async getOrCompute(\n key: string,\n compute: () => Promise<T>,\n options: { ttl?: number; size?: number } = {}\n ): Promise<T> {\n const cached = this.get(key);\n if (cached !== undefined) {\n return cached;\n }\n\n const value = await compute();\n this.set(key, value, options);\n return value;\n }\n\n // Private methods\n\n private evict(requiredSize: number): void {\n const startEvictions = this.stats.evictions;\n\n // LRU eviction\n while (\n (this.cache.size >= this.options.maxItems ||\n this.currentSize + requiredSize > this.options.maxSize) &&\n this.accessOrder.length > 0\n ) {\n const keyToEvict = this.accessOrder.shift()!;\n const entry = this.cache.get(keyToEvict);\n\n if (entry) {\n this.cache.delete(keyToEvict);\n this.currentSize -= entry.size;\n this.stats.evictions++;\n this.options.onEvict(keyToEvict, entry);\n this.emit('evict', keyToEvict, entry);\n }\n }\n\n if (this.stats.evictions > startEvictions) {\n logger.debug('Cache eviction', {\n evicted: this.stats.evictions - startEvictions,\n currentSize: this.currentSize,\n requiredSize,\n });\n }\n }\n\n private updateAccessOrder(key: string): void {\n const index = this.accessOrder.indexOf(key);\n if (index > -1) {\n this.accessOrder.splice(index, 1);\n }\n this.accessOrder.push(key);\n }\n\n private estimateSize(value: T): number {\n // Simple size estimation - can be overridden for specific types\n if (typeof value === 'string') {\n return value.length * 2; // UTF-16\n }\n if (typeof value === 'object' && value !== null) {\n return JSON.stringify(value).length * 2;\n }\n return 8; // Default for primitives\n }\n\n private updateHitRate(): void {\n const total = this.stats.hits + this.stats.misses;\n this.stats.hitRate = total > 0 ? this.stats.hits / total : 0;\n }\n\n private updateAvgAccessTime(time: number): void {\n const alpha = 0.1; // Exponential moving average factor\n this.stats.avgAccessTime =\n this.stats.avgAccessTime * (1 - alpha) + time * alpha;\n }\n\n /**\n * Cleanup expired entries periodically\n */\n startCleanup(intervalMs: number = 60000): NodeJS.Timeout {\n return setInterval(() => {\n let cleaned = 0;\n for (const [key, entry] of this.cache.entries()) {\n if (entry.ttl && Date.now() - entry.createdAt > entry.ttl) {\n this.delete(key);\n cleaned++;\n }\n }\n if (cleaned > 0) {\n logger.debug('Cache cleanup', { cleaned, remaining: this.cache.size });\n }\n }, intervalMs);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -48,13 +48,16 @@ class LazyContextLoader {
|
|
|
48
48
|
*/
|
|
49
49
|
lazyFrame(frameId) {
|
|
50
50
|
if (!this.frameLoaders.has(frameId)) {
|
|
51
|
-
this.frameLoaders.set(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
this.frameLoaders.set(
|
|
52
|
+
frameId,
|
|
53
|
+
new LazyProxy(async () => {
|
|
54
|
+
const frame = this.loadFrame(frameId);
|
|
55
|
+
if (!frame) {
|
|
56
|
+
throw new Error(`Frame not found: ${frameId}`);
|
|
57
|
+
}
|
|
58
|
+
return frame;
|
|
59
|
+
})
|
|
60
|
+
);
|
|
58
61
|
}
|
|
59
62
|
return this.frameLoaders.get(frameId);
|
|
60
63
|
}
|
|
@@ -63,9 +66,12 @@ class LazyContextLoader {
|
|
|
63
66
|
*/
|
|
64
67
|
lazyAnchors(frameId) {
|
|
65
68
|
if (!this.anchorLoaders.has(frameId)) {
|
|
66
|
-
this.anchorLoaders.set(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
this.anchorLoaders.set(
|
|
70
|
+
frameId,
|
|
71
|
+
new LazyProxy(async () => {
|
|
72
|
+
return this.loadAnchors(frameId);
|
|
73
|
+
})
|
|
74
|
+
);
|
|
69
75
|
}
|
|
70
76
|
return this.anchorLoaders.get(frameId);
|
|
71
77
|
}
|
|
@@ -75,9 +81,12 @@ class LazyContextLoader {
|
|
|
75
81
|
lazyEvents(frameId, limit = 100) {
|
|
76
82
|
const key = `${frameId}:${limit}`;
|
|
77
83
|
if (!this.eventLoaders.has(key)) {
|
|
78
|
-
this.eventLoaders.set(
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
this.eventLoaders.set(
|
|
85
|
+
key,
|
|
86
|
+
new LazyProxy(async () => {
|
|
87
|
+
return this.loadEvents(frameId, limit);
|
|
88
|
+
})
|
|
89
|
+
);
|
|
81
90
|
}
|
|
82
91
|
return this.eventLoaders.get(key);
|
|
83
92
|
}
|
|
@@ -85,10 +94,7 @@ class LazyContextLoader {
|
|
|
85
94
|
* Progressive context loading with chunking
|
|
86
95
|
*/
|
|
87
96
|
async *loadContextProgressive(frameIds, options = {}) {
|
|
88
|
-
const {
|
|
89
|
-
chunkSize = 10,
|
|
90
|
-
priority = "recency"
|
|
91
|
-
} = options;
|
|
97
|
+
const { chunkSize = 10, priority = "recency" } = options;
|
|
92
98
|
const sortedIds = this.sortByPriority(frameIds, priority);
|
|
93
99
|
const totalChunks = Math.ceil(sortedIds.length / chunkSize);
|
|
94
100
|
for (let i = 0; i < sortedIds.length; i += chunkSize) {
|
|
@@ -220,9 +226,7 @@ class LazyContextLoader {
|
|
|
220
226
|
// Private methods
|
|
221
227
|
loadFrame(frameId) {
|
|
222
228
|
try {
|
|
223
|
-
const row = this.db.prepare(
|
|
224
|
-
"SELECT * FROM frames WHERE id = ?"
|
|
225
|
-
).get(frameId);
|
|
229
|
+
const row = this.db.prepare("SELECT * FROM frames WHERE id = ?").get(frameId);
|
|
226
230
|
if (!row) return null;
|
|
227
231
|
return {
|
|
228
232
|
...row,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/performance/lazy-context-loader.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Lazy Context Loader\n * Deferred loading and progressive enhancement for context data\n */\n\nimport Database from 'better-sqlite3';\nimport { Frame, Anchor, Event } from '../context/frame-manager.js';\nimport { logger } from '../monitoring/logger.js';\n\nexport interface LazyLoadOptions {\n preloadDepth?: number; // How many levels to preload\n chunkSize?: number; // Items per chunk\n priority?: 'recency' | 'relevance' | 'frequency';\n}\n\nexport interface ContextChunk {\n frames: Frame[];\n anchors: Anchor[];\n events: Event[];\n metadata: {\n chunkId: number;\n totalChunks: number;\n hasMore: boolean;\n nextCursor?: string;\n };\n}\n\n/**\n * Lazy proxy for deferred data loading\n */\nexport class LazyProxy<T> {\n private _value?: T;\n private _promise?: Promise<T>;\n private _loader: () => Promise<T>;\n private _loaded = false;\n\n constructor(loader: () => Promise<T>) {\n this._loader = loader;\n }\n\n async get(): Promise<T> {\n if (this._loaded && this._value !== undefined) {\n return this._value;\n }\n\n if (!this._promise) {\n this._promise = this._loader().then(value => {\n this._value = value;\n this._loaded = true;\n return value;\n });\n }\n\n return this._promise;\n }\n\n isLoaded(): boolean {\n return this._loaded;\n }\n\n peek(): T | undefined {\n return this._value;\n }\n\n reset(): void {\n this._value = undefined;\n this._promise = undefined;\n this._loaded = false;\n }\n}\n\nexport class LazyContextLoader {\n private db: Database.Database;\n private projectId: string;\n \n // Lazy loading registries\n private frameLoaders = new Map<string, LazyProxy<Frame>>();\n private anchorLoaders = new Map<string, LazyProxy<Anchor[]>>();\n private eventLoaders = new Map<string, LazyProxy<Event[]>>();\n \n constructor(db: Database.Database, projectId: string) {\n this.db = db;\n this.projectId = projectId;\n }\n\n /**\n * Create a lazy frame reference\n */\n lazyFrame(frameId: string): LazyProxy<Frame> {\n if (!this.frameLoaders.has(frameId)) {\n this.frameLoaders.set(frameId, new LazyProxy(async () => {\n const frame = this.loadFrame(frameId);\n if (!frame) {\n throw new Error(`Frame not found: ${frameId}`);\n }\n return frame;\n }));\n }\n return this.frameLoaders.get(frameId)!;\n }\n\n /**\n * Create lazy anchor references\n */\n lazyAnchors(frameId: string): LazyProxy<Anchor[]> {\n if (!this.anchorLoaders.has(frameId)) {\n this.anchorLoaders.set(frameId, new LazyProxy(async () => {\n return this.loadAnchors(frameId);\n }));\n }\n return this.anchorLoaders.get(frameId)!;\n }\n\n /**\n * Create lazy event references\n */\n lazyEvents(frameId: string, limit = 100): LazyProxy<Event[]> {\n const key = `${frameId}:${limit}`;\n if (!this.eventLoaders.has(key)) {\n this.eventLoaders.set(key, new LazyProxy(async () => {\n return this.loadEvents(frameId, limit);\n }));\n }\n return this.eventLoaders.get(key)!;\n }\n\n /**\n * Progressive context loading with chunking\n */\n async* loadContextProgressive(\n frameIds: string[],\n options: LazyLoadOptions = {}\n ): AsyncGenerator<ContextChunk, void, unknown> {\n const {\n chunkSize = 10,\n priority = 'recency',\n } = options;\n\n // Sort frame IDs by priority\n const sortedIds = this.sortByPriority(frameIds, priority);\n const totalChunks = Math.ceil(sortedIds.length / chunkSize);\n\n for (let i = 0; i < sortedIds.length; i += chunkSize) {\n const chunkIds = sortedIds.slice(i, i + chunkSize);\n const chunkNumber = Math.floor(i / chunkSize) + 1;\n\n const frames: Frame[] = [];\n const anchors: Anchor[] = [];\n const events: Event[] = [];\n\n // Load chunk data\n for (const frameId of chunkIds) {\n const frame = await this.lazyFrame(frameId).get();\n frames.push(frame);\n\n // Load associated data\n const frameAnchors = await this.lazyAnchors(frameId).get();\n anchors.push(...frameAnchors);\n\n const frameEvents = await this.lazyEvents(frameId).get();\n events.push(...frameEvents);\n }\n\n yield {\n frames,\n anchors,\n events,\n metadata: {\n chunkId: chunkNumber,\n totalChunks,\n hasMore: i + chunkSize < sortedIds.length,\n nextCursor: i + chunkSize < sortedIds.length \n ? sortedIds[i + chunkSize] \n : undefined,\n },\n };\n }\n }\n\n /**\n * Preload context data for better performance\n */\n async preloadContext(\n frameIds: string[],\n options: { parallel?: boolean; depth?: number } = {}\n ): Promise<void> {\n const { parallel = true, depth = 1 } = options;\n const startTime = Date.now();\n\n if (parallel) {\n const promises: Promise<any>[] = [];\n \n for (const frameId of frameIds) {\n promises.push(this.lazyFrame(frameId).get());\n \n if (depth > 0) {\n promises.push(this.lazyAnchors(frameId).get());\n }\n \n if (depth > 1) {\n promises.push(this.lazyEvents(frameId).get());\n }\n }\n \n await Promise.all(promises);\n } else {\n for (const frameId of frameIds) {\n await this.lazyFrame(frameId).get();\n \n if (depth > 0) {\n await this.lazyAnchors(frameId).get();\n }\n \n if (depth > 1) {\n await this.lazyEvents(frameId).get();\n }\n }\n }\n\n logger.debug('Context preload complete', {\n frames: frameIds.length,\n depth,\n duration: Date.now() - startTime,\n });\n }\n\n /**\n * Load only frame headers (lightweight)\n */\n async loadFrameHeaders(frameIds: string[]): Promise<Map<string, any>> {\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `\n SELECT id, type, name, state, score, created_at, updated_at\n FROM frames \n WHERE id IN (${placeholders})\n `;\n\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n const headers = new Map<string, any>();\n\n for (const row of rows) {\n headers.set(row.id, {\n id: row.id,\n type: row.type,\n name: row.name,\n state: row.state,\n score: row.score,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n });\n }\n\n return headers;\n }\n\n /**\n * Stream context data for memory efficiency\n */\n async* streamContext(\n query: string,\n params: any[] = []\n ): AsyncGenerator<Frame | Anchor | Event, void, unknown> {\n const stmt = this.db.prepare(query);\n const iterator = stmt.iterate(...params);\n\n for (const row of iterator) {\n yield row as any;\n }\n }\n\n /**\n * Clear lazy loading cache\n */\n clearCache(): void {\n this.frameLoaders.clear();\n this.anchorLoaders.clear();\n this.eventLoaders.clear();\n }\n\n /**\n * Get cache statistics\n */\n getCacheStats(): {\n frames: number;\n anchors: number;\n events: number;\n loaded: number;\n } {\n let loaded = 0;\n \n for (const loader of this.frameLoaders.values()) {\n if (loader.isLoaded()) loaded++;\n }\n \n for (const loader of this.anchorLoaders.values()) {\n if (loader.isLoaded()) loaded++;\n }\n \n for (const loader of this.eventLoaders.values()) {\n if (loader.isLoaded()) loaded++;\n }\n\n return {\n frames: this.frameLoaders.size,\n anchors: this.anchorLoaders.size,\n events: this.eventLoaders.size,\n loaded,\n };\n }\n\n // Private methods\n\n private loadFrame(frameId: string): Frame | null {\n try {\n const row = this.db.prepare(\n 'SELECT * FROM frames WHERE id = ?'\n ).get(frameId) as any;\n\n if (!row) return null;\n\n return {\n ...row,\n metadata: JSON.parse(row.metadata || '{}'),\n };\n } catch (error) {\n // Return mock frame if table doesn't exist (for benchmarking)\n if (frameId.startsWith('frame-')) {\n return {\n id: frameId,\n type: 'mock',\n name: `Mock ${frameId}`,\n state: 'open',\n score: 0.5,\n created_at: Date.now(),\n updated_at: Date.now(),\n metadata: {},\n } as any;\n }\n return null;\n }\n }\n\n private loadAnchors(frameId: string): Anchor[] {\n try {\n const rows = this.db.prepare(\n 'SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at DESC'\n ).all(frameId) as any[];\n\n return rows.map(row => ({\n ...row,\n metadata: JSON.parse(row.metadata || '{}'),\n }));\n } catch {\n return []; // Return empty array if table doesn't exist\n }\n }\n\n private loadEvents(frameId: string, limit: number): Event[] {\n try {\n const rows = this.db.prepare(\n 'SELECT * FROM events WHERE frame_id = ? ORDER BY timestamp DESC LIMIT ?'\n ).all(frameId, limit) as any[];\n\n return rows.map(row => ({\n ...row,\n data: JSON.parse(row.data || '{}'),\n metadata: JSON.parse(row.metadata || '{}'),\n }));\n } catch {\n return []; // Return empty array if table doesn't exist\n }\n }\n\n private sortByPriority(\n frameIds: string[],\n priority: 'recency' | 'relevance' | 'frequency'\n ): string[] {\n try {\n switch (priority) {\n case 'recency': {\n // Get timestamps and sort\n const query = `\n SELECT id, updated_at FROM frames \n WHERE id IN (${frameIds.map(() => '?').join(',')})\n ORDER BY updated_at DESC\n `;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n return rows.map(r => r.id);\n }\n \n case 'relevance': {\n // Get scores and sort\n const query = `\n SELECT id, score FROM frames \n WHERE id IN (${frameIds.map(() => '?').join(',')})\n ORDER BY score DESC\n `;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n return rows.map(r => r.id);\n }\n \n case 'frequency': {\n // Get event counts and sort\n const query = `\n SELECT f.id, COUNT(e.id) as event_count\n FROM frames f\n LEFT JOIN events e ON f.id = e.frame_id\n WHERE f.id IN (${frameIds.map(() => '?').join(',')})\n GROUP BY f.id\n ORDER BY event_count DESC\n `;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n return rows.map(r => r.id);\n }\n \n default:\n return frameIds;\n }\n } catch {\n // Return original order if tables don't exist\n return frameIds;\n }\n }\n}"],
|
|
5
|
-
"mappings": "AAOA,SAAS,cAAc;AAuBhB,MAAM,UAAa;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EAElB,YAAY,QAA0B;AACpC,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,MAAkB;AACtB,QAAI,KAAK,WAAW,KAAK,WAAW,QAAW;AAC7C,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,WAAW,KAAK,QAAQ,EAAE,KAAK,
|
|
4
|
+
"sourcesContent": ["/**\n * Lazy Context Loader\n * Deferred loading and progressive enhancement for context data\n */\n\nimport Database from 'better-sqlite3';\nimport { Frame, Anchor, Event } from '../context/frame-manager.js';\nimport { logger } from '../monitoring/logger.js';\n\nexport interface LazyLoadOptions {\n preloadDepth?: number; // How many levels to preload\n chunkSize?: number; // Items per chunk\n priority?: 'recency' | 'relevance' | 'frequency';\n}\n\nexport interface ContextChunk {\n frames: Frame[];\n anchors: Anchor[];\n events: Event[];\n metadata: {\n chunkId: number;\n totalChunks: number;\n hasMore: boolean;\n nextCursor?: string;\n };\n}\n\n/**\n * Lazy proxy for deferred data loading\n */\nexport class LazyProxy<T> {\n private _value?: T;\n private _promise?: Promise<T>;\n private _loader: () => Promise<T>;\n private _loaded = false;\n\n constructor(loader: () => Promise<T>) {\n this._loader = loader;\n }\n\n async get(): Promise<T> {\n if (this._loaded && this._value !== undefined) {\n return this._value;\n }\n\n if (!this._promise) {\n this._promise = this._loader().then((value) => {\n this._value = value;\n this._loaded = true;\n return value;\n });\n }\n\n return this._promise;\n }\n\n isLoaded(): boolean {\n return this._loaded;\n }\n\n peek(): T | undefined {\n return this._value;\n }\n\n reset(): void {\n this._value = undefined;\n this._promise = undefined;\n this._loaded = false;\n }\n}\n\nexport class LazyContextLoader {\n private db: Database.Database;\n private projectId: string;\n\n // Lazy loading registries\n private frameLoaders = new Map<string, LazyProxy<Frame>>();\n private anchorLoaders = new Map<string, LazyProxy<Anchor[]>>();\n private eventLoaders = new Map<string, LazyProxy<Event[]>>();\n\n constructor(db: Database.Database, projectId: string) {\n this.db = db;\n this.projectId = projectId;\n }\n\n /**\n * Create a lazy frame reference\n */\n lazyFrame(frameId: string): LazyProxy<Frame> {\n if (!this.frameLoaders.has(frameId)) {\n this.frameLoaders.set(\n frameId,\n new LazyProxy(async () => {\n const frame = this.loadFrame(frameId);\n if (!frame) {\n throw new Error(`Frame not found: ${frameId}`);\n }\n return frame;\n })\n );\n }\n return this.frameLoaders.get(frameId)!;\n }\n\n /**\n * Create lazy anchor references\n */\n lazyAnchors(frameId: string): LazyProxy<Anchor[]> {\n if (!this.anchorLoaders.has(frameId)) {\n this.anchorLoaders.set(\n frameId,\n new LazyProxy(async () => {\n return this.loadAnchors(frameId);\n })\n );\n }\n return this.anchorLoaders.get(frameId)!;\n }\n\n /**\n * Create lazy event references\n */\n lazyEvents(frameId: string, limit = 100): LazyProxy<Event[]> {\n const key = `${frameId}:${limit}`;\n if (!this.eventLoaders.has(key)) {\n this.eventLoaders.set(\n key,\n new LazyProxy(async () => {\n return this.loadEvents(frameId, limit);\n })\n );\n }\n return this.eventLoaders.get(key)!;\n }\n\n /**\n * Progressive context loading with chunking\n */\n async *loadContextProgressive(\n frameIds: string[],\n options: LazyLoadOptions = {}\n ): AsyncGenerator<ContextChunk, void, unknown> {\n const { chunkSize = 10, priority = 'recency' } = options;\n\n // Sort frame IDs by priority\n const sortedIds = this.sortByPriority(frameIds, priority);\n const totalChunks = Math.ceil(sortedIds.length / chunkSize);\n\n for (let i = 0; i < sortedIds.length; i += chunkSize) {\n const chunkIds = sortedIds.slice(i, i + chunkSize);\n const chunkNumber = Math.floor(i / chunkSize) + 1;\n\n const frames: Frame[] = [];\n const anchors: Anchor[] = [];\n const events: Event[] = [];\n\n // Load chunk data\n for (const frameId of chunkIds) {\n const frame = await this.lazyFrame(frameId).get();\n frames.push(frame);\n\n // Load associated data\n const frameAnchors = await this.lazyAnchors(frameId).get();\n anchors.push(...frameAnchors);\n\n const frameEvents = await this.lazyEvents(frameId).get();\n events.push(...frameEvents);\n }\n\n yield {\n frames,\n anchors,\n events,\n metadata: {\n chunkId: chunkNumber,\n totalChunks,\n hasMore: i + chunkSize < sortedIds.length,\n nextCursor:\n i + chunkSize < sortedIds.length\n ? sortedIds[i + chunkSize]\n : undefined,\n },\n };\n }\n }\n\n /**\n * Preload context data for better performance\n */\n async preloadContext(\n frameIds: string[],\n options: { parallel?: boolean; depth?: number } = {}\n ): Promise<void> {\n const { parallel = true, depth = 1 } = options;\n const startTime = Date.now();\n\n if (parallel) {\n const promises: Promise<any>[] = [];\n\n for (const frameId of frameIds) {\n promises.push(this.lazyFrame(frameId).get());\n\n if (depth > 0) {\n promises.push(this.lazyAnchors(frameId).get());\n }\n\n if (depth > 1) {\n promises.push(this.lazyEvents(frameId).get());\n }\n }\n\n await Promise.all(promises);\n } else {\n for (const frameId of frameIds) {\n await this.lazyFrame(frameId).get();\n\n if (depth > 0) {\n await this.lazyAnchors(frameId).get();\n }\n\n if (depth > 1) {\n await this.lazyEvents(frameId).get();\n }\n }\n }\n\n logger.debug('Context preload complete', {\n frames: frameIds.length,\n depth,\n duration: Date.now() - startTime,\n });\n }\n\n /**\n * Load only frame headers (lightweight)\n */\n async loadFrameHeaders(frameIds: string[]): Promise<Map<string, any>> {\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `\n SELECT id, type, name, state, score, created_at, updated_at\n FROM frames \n WHERE id IN (${placeholders})\n `;\n\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n const headers = new Map<string, any>();\n\n for (const row of rows) {\n headers.set(row.id, {\n id: row.id,\n type: row.type,\n name: row.name,\n state: row.state,\n score: row.score,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n });\n }\n\n return headers;\n }\n\n /**\n * Stream context data for memory efficiency\n */\n async *streamContext(\n query: string,\n params: any[] = []\n ): AsyncGenerator<Frame | Anchor | Event, void, unknown> {\n const stmt = this.db.prepare(query);\n const iterator = stmt.iterate(...params);\n\n for (const row of iterator) {\n yield row as any;\n }\n }\n\n /**\n * Clear lazy loading cache\n */\n clearCache(): void {\n this.frameLoaders.clear();\n this.anchorLoaders.clear();\n this.eventLoaders.clear();\n }\n\n /**\n * Get cache statistics\n */\n getCacheStats(): {\n frames: number;\n anchors: number;\n events: number;\n loaded: number;\n } {\n let loaded = 0;\n\n for (const loader of this.frameLoaders.values()) {\n if (loader.isLoaded()) loaded++;\n }\n\n for (const loader of this.anchorLoaders.values()) {\n if (loader.isLoaded()) loaded++;\n }\n\n for (const loader of this.eventLoaders.values()) {\n if (loader.isLoaded()) loaded++;\n }\n\n return {\n frames: this.frameLoaders.size,\n anchors: this.anchorLoaders.size,\n events: this.eventLoaders.size,\n loaded,\n };\n }\n\n // Private methods\n\n private loadFrame(frameId: string): Frame | null {\n try {\n const row = this.db\n .prepare('SELECT * FROM frames WHERE id = ?')\n .get(frameId) as any;\n\n if (!row) return null;\n\n return {\n ...row,\n metadata: JSON.parse(row.metadata || '{}'),\n };\n } catch (error: unknown) {\n // Return mock frame if table doesn't exist (for benchmarking)\n if (frameId.startsWith('frame-')) {\n return {\n id: frameId,\n type: 'mock',\n name: `Mock ${frameId}`,\n state: 'open',\n score: 0.5,\n created_at: Date.now(),\n updated_at: Date.now(),\n metadata: {},\n } as any;\n }\n return null;\n }\n }\n\n private loadAnchors(frameId: string): Anchor[] {\n try {\n const rows = this.db\n .prepare(\n 'SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at DESC'\n )\n .all(frameId) as any[];\n\n return rows.map((row: any) => ({\n ...row,\n metadata: JSON.parse(row.metadata || '{}'),\n }));\n } catch {\n return []; // Return empty array if table doesn't exist\n }\n }\n\n private loadEvents(frameId: string, limit: number): Event[] {\n try {\n const rows = this.db\n .prepare(\n 'SELECT * FROM events WHERE frame_id = ? ORDER BY timestamp DESC LIMIT ?'\n )\n .all(frameId, limit) as any[];\n\n return rows.map((row: any) => ({\n ...row,\n data: JSON.parse(row.data || '{}'),\n metadata: JSON.parse(row.metadata || '{}'),\n }));\n } catch {\n return []; // Return empty array if table doesn't exist\n }\n }\n\n private sortByPriority(\n frameIds: string[],\n priority: 'recency' | 'relevance' | 'frequency'\n ): string[] {\n try {\n switch (priority) {\n case 'recency': {\n // Get timestamps and sort\n const query = `\n SELECT id, updated_at FROM frames \n WHERE id IN (${frameIds.map(() => '?').join(',')})\n ORDER BY updated_at DESC\n `;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n return rows.map((r: any) => r.id);\n }\n\n case 'relevance': {\n // Get scores and sort\n const query = `\n SELECT id, score FROM frames \n WHERE id IN (${frameIds.map(() => '?').join(',')})\n ORDER BY score DESC\n `;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n return rows.map((r: any) => r.id);\n }\n\n case 'frequency': {\n // Get event counts and sort\n const query = `\n SELECT f.id, COUNT(e.id) as event_count\n FROM frames f\n LEFT JOIN events e ON f.id = e.frame_id\n WHERE f.id IN (${frameIds.map(() => '?').join(',')})\n GROUP BY f.id\n ORDER BY event_count DESC\n `;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n return rows.map((r: any) => r.id);\n }\n\n default:\n return frameIds;\n }\n } catch {\n // Return original order if tables don't exist\n return frameIds;\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/performance/monitor.ts"],
|
|
4
|
-
"sourcesContent": ["import { performance } from 'perf_hooks';\nimport { EventEmitter } from 'events';\n\ninterface PerformanceMetrics {\n operation: string;\n startTime: number;\n endTime?: number;\n duration?: number;\n memoryBefore: NodeJS.MemoryUsage;\n memoryAfter?: NodeJS.MemoryUsage;\n memoryDelta?: number;\n metadata?: Record<string, any>;\n}\n\ninterface PerformanceThreshold {\n operation: string;\n maxDuration?: number;\n maxMemory?: number;\n action?: 'warn' | 'error' | 'optimize';\n}\n\nexport class PerformanceMonitor extends EventEmitter {\n private metrics: Map<string, PerformanceMetrics[]> = new Map();\n private activeOperations: Map<string, PerformanceMetrics> = new Map();\n private thresholds: Map<string, PerformanceThreshold> = new Map();\n private isMonitoring: boolean = false;\n private gcInterval?: NodeJS.Timeout;\n\n constructor() {\n super();\n this.setupDefaultThresholds();\n }\n\n private setupDefaultThresholds() {\n this.addThreshold({\n operation: 'digest.process',\n maxDuration: 500,\n maxMemory: 50 * 1024 * 1024,\n action: 'warn',\n });\n\n this.addThreshold({\n operation: 'cache.lookup',\n maxDuration: 10,\n action: 'optimize',\n });\n\n this.addThreshold({\n operation: 'context.save',\n maxDuration: 1000,\n maxMemory: 100 * 1024 * 1024,\n action: 'error',\n });\n }\n\n startMonitoring() {\n if (this.isMonitoring) return;\n\n this.isMonitoring = true;\n\n this.gcInterval = setInterval(() => {\n if (global.gc) {\n const beforeGC = process.memoryUsage();\n global.gc();\n const afterGC = process.memoryUsage();\n\n const freed = beforeGC.heapUsed - afterGC.heapUsed;\n if (freed > 10 * 1024 * 1024) {\n this.emit('gc', {\n freed,\n beforeGC,\n afterGC,\n });\n }\n }\n }, 30000);\n\n this.emit('monitoring.started');\n }\n\n stopMonitoring() {\n if (!this.isMonitoring) return;\n\n this.isMonitoring = false;\n\n if (this.gcInterval) {\n clearInterval(this.gcInterval);\n this.gcInterval = undefined;\n }\n\n this.emit('monitoring.stopped');\n }\n\n startOperation(\n operationId: string,\n operation: string,\n metadata?: Record<string, any>\n ): void {\n const metric: PerformanceMetrics = {\n operation,\n startTime: performance.now(),\n memoryBefore: process.memoryUsage(),\n metadata,\n };\n\n this.activeOperations.set(operationId, metric);\n this.emit('operation.started', { operationId, operation, metadata });\n }\n\n endOperation(\n operationId: string,\n additionalMetadata?: Record<string, any>\n ): PerformanceMetrics | undefined {\n const metric = this.activeOperations.get(operationId);\n if (!metric) {\n console.warn(`Operation ${operationId} not found`);\n return undefined;\n }\n\n metric.endTime = performance.now();\n metric.duration = metric.endTime - metric.startTime;\n metric.memoryAfter = process.memoryUsage();\n metric.memoryDelta =\n metric.memoryAfter.heapUsed - metric.memoryBefore.heapUsed;\n\n if (additionalMetadata) {\n metric.metadata = { ...metric.metadata, ...additionalMetadata };\n }\n\n this.activeOperations.delete(operationId);\n\n if (!this.metrics.has(metric.operation)) {\n this.metrics.set(metric.operation, []);\n }\n this.metrics.get(metric.operation)!.push(metric);\n\n this.checkThresholds(metric);\n this.emit('operation.completed', { operationId, metric });\n\n return metric;\n }\n\n async measureAsync<T>(\n operation: string,\n fn: () => Promise<T>,\n metadata?: Record<string, any>\n ): Promise<T> {\n const operationId = `${operation}-${Date.now()}-${Math.random()}`;\n this.startOperation(operationId, operation, metadata);\n\n try {\n const result = await fn();\n this.endOperation(operationId, { success: true });\n return result;\n } catch (error) {\n this.endOperation(operationId, {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n measure<T>(\n operation: string,\n fn: () => T,\n metadata?: Record<string, any>\n ): T {\n const operationId = `${operation}-${Date.now()}-${Math.random()}`;\n this.startOperation(operationId, operation, metadata);\n\n try {\n const result = fn();\n this.endOperation(operationId, { success: true });\n return result;\n } catch (error) {\n this.endOperation(operationId, {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n private checkThresholds(metric: PerformanceMetrics) {\n const threshold = this.thresholds.get(metric.operation);\n if (!threshold) return;\n\n const violations: string[] = [];\n\n if (\n threshold.maxDuration &&\n metric.duration &&\n metric.duration > threshold.maxDuration\n ) {\n violations.push(\n `Duration ${metric.duration.toFixed(2)}ms exceeds ${threshold.maxDuration}ms`\n );\n }\n\n if (\n threshold.maxMemory &&\n metric.memoryDelta &&\n metric.memoryDelta > threshold.maxMemory\n ) {\n const memoryMB = (metric.memoryDelta / 1024 / 1024).toFixed(2);\n const thresholdMB = (threshold.maxMemory / 1024 / 1024).toFixed(2);\n violations.push(`Memory ${memoryMB}MB exceeds ${thresholdMB}MB`);\n }\n\n if (violations.length > 0) {\n const message = `Performance threshold violation for ${metric.operation}: ${violations.join(', ')}`;\n\n switch (threshold.action) {\n case 'error':\n this.emit('threshold.error', { metric, violations, message });\n break;\n case 'warn':\n this.emit('threshold.warning', { metric, violations, message });\n break;\n case 'optimize':\n this.emit('threshold.optimize', { metric, violations, message });\n break;\n }\n }\n }\n\n addThreshold(threshold: PerformanceThreshold) {\n this.thresholds.set(threshold.operation, threshold);\n }\n\n getMetrics(operation?: string): PerformanceMetrics[] {\n if (operation) {\n return this.metrics.get(operation) || [];\n }\n\n const allMetrics: PerformanceMetrics[] = [];\n for (const metrics of this.metrics.values()) {\n allMetrics.push(...metrics);\n }\n return allMetrics;\n }\n\n getStatistics(operation: string):\n | {\n count: number;\n avgDuration: number;\n minDuration: number;\n maxDuration: number;\n avgMemory: number;\n successRate: number;\n }\n | undefined {\n const metrics = this.metrics.get(operation);\n if (!metrics || metrics.length === 0) return undefined;\n\n const durations = metrics\n .filter((m) => m.duration !== undefined)\n .map((m) => m.duration!);\n\n const memoryDeltas = metrics\n .filter((m) => m.memoryDelta !== undefined)\n .map((m) => m.memoryDelta!);\n\n const successCount = metrics.filter(\n (m) => m.metadata?.success === true\n ).length;\n\n return {\n count: metrics.length,\n avgDuration:\n durations.length > 0\n ? durations.reduce((a, b) => a + b, 0) / durations.length\n : 0,\n minDuration: durations.length > 0 ? Math.min(...durations) : 0,\n maxDuration: durations.length > 0 ? Math.max(...durations) : 0,\n avgMemory:\n memoryDeltas.length > 0\n ? memoryDeltas.reduce((a, b) => a + b, 0) / memoryDeltas.length\n : 0,\n successRate:\n metrics.length > 0 ? (successCount / metrics.length) * 100 : 0,\n };\n }\n\n clearMetrics(operation?: string) {\n if (operation) {\n this.metrics.delete(operation);\n } else {\n this.metrics.clear();\n }\n }\n\n getActiveOperations(): string[] {\n return Array.from(this.activeOperations.keys());\n }\n\n generateReport(): string {\n const report: string[] = [];\n report.push('Performance Report');\n report.push('='.repeat(60));\n\n for (const [operation] of this.metrics) {\n const stats = this.getStatistics(operation);\n if (!stats) continue;\n\n report.push(`\\nOperation: ${operation}`);\n report.push(` Count: ${stats.count}`);\n report.push(` Avg Duration: ${stats.avgDuration.toFixed(2)}ms`);\n report.push(\n ` Min/Max: ${stats.minDuration.toFixed(2)}ms / ${stats.maxDuration.toFixed(2)}ms`\n );\n report.push(\n ` Avg Memory: ${(stats.avgMemory / 1024 / 1024).toFixed(2)}MB`\n );\n report.push(` Success Rate: ${stats.successRate.toFixed(1)}%`);\n }\n\n return report.join('\\n');\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAoBtB,MAAM,2BAA2B,aAAa;AAAA,EAC3C,UAA6C,oBAAI,IAAI;AAAA,EACrD,mBAAoD,oBAAI,IAAI;AAAA,EAC5D,aAAgD,oBAAI,IAAI;AAAA,EACxD,eAAwB;AAAA,EACxB;AAAA,EAER,cAAc;AACZ,UAAM;AACN,SAAK,uBAAuB;AAAA,EAC9B;AAAA,EAEQ,yBAAyB;AAC/B,SAAK,aAAa;AAAA,MAChB,WAAW;AAAA,MACX,aAAa;AAAA,MACb,WAAW,KAAK,OAAO;AAAA,MACvB,QAAQ;AAAA,IACV,CAAC;AAED,SAAK,aAAa;AAAA,MAChB,WAAW;AAAA,MACX,aAAa;AAAA,MACb,QAAQ;AAAA,IACV,CAAC;AAED,SAAK,aAAa;AAAA,MAChB,WAAW;AAAA,MACX,aAAa;AAAA,MACb,WAAW,MAAM,OAAO;AAAA,MACxB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEA,kBAAkB;AAChB,QAAI,KAAK,aAAc;AAEvB,SAAK,eAAe;AAEpB,SAAK,aAAa,YAAY,MAAM;AAClC,UAAI,OAAO,IAAI;AACb,cAAM,WAAW,QAAQ,YAAY;AACrC,eAAO,GAAG;AACV,cAAM,UAAU,QAAQ,YAAY;AAEpC,cAAM,QAAQ,SAAS,WAAW,QAAQ;AAC1C,YAAI,QAAQ,KAAK,OAAO,MAAM;AAC5B,eAAK,KAAK,MAAM;AAAA,YACd;AAAA,YACA;AAAA,YACA;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,GAAG,GAAK;AAER,SAAK,KAAK,oBAAoB;AAAA,EAChC;AAAA,EAEA,iBAAiB;AACf,QAAI,CAAC,KAAK,aAAc;AAExB,SAAK,eAAe;AAEpB,QAAI,KAAK,YAAY;AACnB,oBAAc,KAAK,UAAU;AAC7B,WAAK,aAAa;AAAA,IACpB;AAEA,SAAK,KAAK,oBAAoB;AAAA,EAChC;AAAA,EAEA,eACE,aACA,WACA,UACM;AACN,UAAM,SAA6B;AAAA,MACjC;AAAA,MACA,WAAW,YAAY,IAAI;AAAA,MAC3B,cAAc,QAAQ,YAAY;AAAA,MAClC;AAAA,IACF;AAEA,SAAK,iBAAiB,IAAI,aAAa,MAAM;AAC7C,SAAK,KAAK,qBAAqB,EAAE,aAAa,WAAW,SAAS,CAAC;AAAA,EACrE;AAAA,EAEA,aACE,aACA,oBACgC;AAChC,UAAM,SAAS,KAAK,iBAAiB,IAAI,WAAW;AACpD,QAAI,CAAC,QAAQ;AACX,cAAQ,KAAK,aAAa,WAAW,YAAY;AACjD,aAAO;AAAA,IACT;AAEA,WAAO,UAAU,YAAY,IAAI;AACjC,WAAO,WAAW,OAAO,UAAU,OAAO;AAC1C,WAAO,cAAc,QAAQ,YAAY;AACzC,WAAO,cACL,OAAO,YAAY,WAAW,OAAO,aAAa;AAEpD,QAAI,oBAAoB;AACtB,aAAO,WAAW,EAAE,GAAG,OAAO,UAAU,GAAG,mBAAmB;AAAA,IAChE;AAEA,SAAK,iBAAiB,OAAO,WAAW;AAExC,QAAI,CAAC,KAAK,QAAQ,IAAI,OAAO,SAAS,GAAG;AACvC,WAAK,QAAQ,IAAI,OAAO,WAAW,CAAC,CAAC;AAAA,IACvC;AACA,SAAK,QAAQ,IAAI,OAAO,SAAS,EAAG,KAAK,MAAM;AAE/C,SAAK,gBAAgB,MAAM;AAC3B,SAAK,KAAK,uBAAuB,EAAE,aAAa,OAAO,CAAC;AAExD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aACJ,WACA,IACA,UACY;AACZ,UAAM,cAAc,GAAG,SAAS,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC;AAC/D,SAAK,eAAe,aAAa,WAAW,QAAQ;AAEpD,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,aAAa,aAAa,EAAE,SAAS,KAAK,CAAC;AAChD,aAAO;AAAA,IACT,SAAS,
|
|
4
|
+
"sourcesContent": ["import { performance } from 'perf_hooks';\nimport { EventEmitter } from 'events';\n\ninterface PerformanceMetrics {\n operation: string;\n startTime: number;\n endTime?: number;\n duration?: number;\n memoryBefore: NodeJS.MemoryUsage;\n memoryAfter?: NodeJS.MemoryUsage;\n memoryDelta?: number;\n metadata?: Record<string, any>;\n}\n\ninterface PerformanceThreshold {\n operation: string;\n maxDuration?: number;\n maxMemory?: number;\n action?: 'warn' | 'error' | 'optimize';\n}\n\nexport class PerformanceMonitor extends EventEmitter {\n private metrics: Map<string, PerformanceMetrics[]> = new Map();\n private activeOperations: Map<string, PerformanceMetrics> = new Map();\n private thresholds: Map<string, PerformanceThreshold> = new Map();\n private isMonitoring: boolean = false;\n private gcInterval?: NodeJS.Timeout;\n\n constructor() {\n super();\n this.setupDefaultThresholds();\n }\n\n private setupDefaultThresholds() {\n this.addThreshold({\n operation: 'digest.process',\n maxDuration: 500,\n maxMemory: 50 * 1024 * 1024,\n action: 'warn',\n });\n\n this.addThreshold({\n operation: 'cache.lookup',\n maxDuration: 10,\n action: 'optimize',\n });\n\n this.addThreshold({\n operation: 'context.save',\n maxDuration: 1000,\n maxMemory: 100 * 1024 * 1024,\n action: 'error',\n });\n }\n\n startMonitoring() {\n if (this.isMonitoring) return;\n\n this.isMonitoring = true;\n\n this.gcInterval = setInterval(() => {\n if (global.gc) {\n const beforeGC = process.memoryUsage();\n global.gc();\n const afterGC = process.memoryUsage();\n\n const freed = beforeGC.heapUsed - afterGC.heapUsed;\n if (freed > 10 * 1024 * 1024) {\n this.emit('gc', {\n freed,\n beforeGC,\n afterGC,\n });\n }\n }\n }, 30000);\n\n this.emit('monitoring.started');\n }\n\n stopMonitoring() {\n if (!this.isMonitoring) return;\n\n this.isMonitoring = false;\n\n if (this.gcInterval) {\n clearInterval(this.gcInterval);\n this.gcInterval = undefined;\n }\n\n this.emit('monitoring.stopped');\n }\n\n startOperation(\n operationId: string,\n operation: string,\n metadata?: Record<string, any>\n ): void {\n const metric: PerformanceMetrics = {\n operation,\n startTime: performance.now(),\n memoryBefore: process.memoryUsage(),\n metadata,\n };\n\n this.activeOperations.set(operationId, metric);\n this.emit('operation.started', { operationId, operation, metadata });\n }\n\n endOperation(\n operationId: string,\n additionalMetadata?: Record<string, any>\n ): PerformanceMetrics | undefined {\n const metric = this.activeOperations.get(operationId);\n if (!metric) {\n console.warn(`Operation ${operationId} not found`);\n return undefined;\n }\n\n metric.endTime = performance.now();\n metric.duration = metric.endTime - metric.startTime;\n metric.memoryAfter = process.memoryUsage();\n metric.memoryDelta =\n metric.memoryAfter.heapUsed - metric.memoryBefore.heapUsed;\n\n if (additionalMetadata) {\n metric.metadata = { ...metric.metadata, ...additionalMetadata };\n }\n\n this.activeOperations.delete(operationId);\n\n if (!this.metrics.has(metric.operation)) {\n this.metrics.set(metric.operation, []);\n }\n this.metrics.get(metric.operation)!.push(metric);\n\n this.checkThresholds(metric);\n this.emit('operation.completed', { operationId, metric });\n\n return metric;\n }\n\n async measureAsync<T>(\n operation: string,\n fn: () => Promise<T>,\n metadata?: Record<string, any>\n ): Promise<T> {\n const operationId = `${operation}-${Date.now()}-${Math.random()}`;\n this.startOperation(operationId, operation, metadata);\n\n try {\n const result = await fn();\n this.endOperation(operationId, { success: true });\n return result;\n } catch (error: unknown) {\n this.endOperation(operationId, {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n measure<T>(\n operation: string,\n fn: () => T,\n metadata?: Record<string, any>\n ): T {\n const operationId = `${operation}-${Date.now()}-${Math.random()}`;\n this.startOperation(operationId, operation, metadata);\n\n try {\n const result = fn();\n this.endOperation(operationId, { success: true });\n return result;\n } catch (error: unknown) {\n this.endOperation(operationId, {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n private checkThresholds(metric: PerformanceMetrics) {\n const threshold = this.thresholds.get(metric.operation);\n if (!threshold) return;\n\n const violations: string[] = [];\n\n if (\n threshold.maxDuration &&\n metric.duration &&\n metric.duration > threshold.maxDuration\n ) {\n violations.push(\n `Duration ${metric.duration.toFixed(2)}ms exceeds ${threshold.maxDuration}ms`\n );\n }\n\n if (\n threshold.maxMemory &&\n metric.memoryDelta &&\n metric.memoryDelta > threshold.maxMemory\n ) {\n const memoryMB = (metric.memoryDelta / 1024 / 1024).toFixed(2);\n const thresholdMB = (threshold.maxMemory / 1024 / 1024).toFixed(2);\n violations.push(`Memory ${memoryMB}MB exceeds ${thresholdMB}MB`);\n }\n\n if (violations.length > 0) {\n const message = `Performance threshold violation for ${metric.operation}: ${violations.join(', ')}`;\n\n switch (threshold.action) {\n case 'error':\n this.emit('threshold.error', { metric, violations, message });\n break;\n case 'warn':\n this.emit('threshold.warning', { metric, violations, message });\n break;\n case 'optimize':\n this.emit('threshold.optimize', { metric, violations, message });\n break;\n }\n }\n }\n\n addThreshold(threshold: PerformanceThreshold) {\n this.thresholds.set(threshold.operation, threshold);\n }\n\n getMetrics(operation?: string): PerformanceMetrics[] {\n if (operation) {\n return this.metrics.get(operation) || [];\n }\n\n const allMetrics: PerformanceMetrics[] = [];\n for (const metrics of this.metrics.values()) {\n allMetrics.push(...metrics);\n }\n return allMetrics;\n }\n\n getStatistics(operation: string):\n | {\n count: number;\n avgDuration: number;\n minDuration: number;\n maxDuration: number;\n avgMemory: number;\n successRate: number;\n }\n | undefined {\n const metrics = this.metrics.get(operation);\n if (!metrics || metrics.length === 0) return undefined;\n\n const durations = metrics\n .filter((m) => m.duration !== undefined)\n .map((m) => m.duration!);\n\n const memoryDeltas = metrics\n .filter((m) => m.memoryDelta !== undefined)\n .map((m) => m.memoryDelta!);\n\n const successCount = metrics.filter(\n (m) => m.metadata?.success === true\n ).length;\n\n return {\n count: metrics.length,\n avgDuration:\n durations.length > 0\n ? durations.reduce((a, b) => a + b, 0) / durations.length\n : 0,\n minDuration: durations.length > 0 ? Math.min(...durations) : 0,\n maxDuration: durations.length > 0 ? Math.max(...durations) : 0,\n avgMemory:\n memoryDeltas.length > 0\n ? memoryDeltas.reduce((a, b) => a + b, 0) / memoryDeltas.length\n : 0,\n successRate:\n metrics.length > 0 ? (successCount / metrics.length) * 100 : 0,\n };\n }\n\n clearMetrics(operation?: string) {\n if (operation) {\n this.metrics.delete(operation);\n } else {\n this.metrics.clear();\n }\n }\n\n getActiveOperations(): string[] {\n return Array.from(this.activeOperations.keys());\n }\n\n generateReport(): string {\n const report: string[] = [];\n report.push('Performance Report');\n report.push('='.repeat(60));\n\n for (const [operation] of this.metrics) {\n const stats = this.getStatistics(operation);\n if (!stats) continue;\n\n report.push(`\\nOperation: ${operation}`);\n report.push(` Count: ${stats.count}`);\n report.push(` Avg Duration: ${stats.avgDuration.toFixed(2)}ms`);\n report.push(\n ` Min/Max: ${stats.minDuration.toFixed(2)}ms / ${stats.maxDuration.toFixed(2)}ms`\n );\n report.push(\n ` Avg Memory: ${(stats.avgMemory / 1024 / 1024).toFixed(2)}MB`\n );\n report.push(` Success Rate: ${stats.successRate.toFixed(1)}%`);\n }\n\n return report.join('\\n');\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -59,10 +59,7 @@ class OptimizedContextAssembler {
|
|
|
59
59
|
async getFrameContext(frameId, options = {}) {
|
|
60
60
|
const startTime = performance.now();
|
|
61
61
|
const stats = { cacheHits: 0, dbQueries: 0, totalRows: 0 };
|
|
62
|
-
const {
|
|
63
|
-
maxEvents = 50,
|
|
64
|
-
enableCaching = true
|
|
65
|
-
} = options;
|
|
62
|
+
const { maxEvents = 50, enableCaching = true } = options;
|
|
66
63
|
const cacheKey = createCacheKey("frame_context", [frameId, maxEvents]);
|
|
67
64
|
if (enableCaching) {
|
|
68
65
|
const cached = this.cache.getFrameContext(cacheKey);
|
|
@@ -78,7 +75,11 @@ class OptimizedContextAssembler {
|
|
|
78
75
|
}
|
|
79
76
|
}
|
|
80
77
|
try {
|
|
81
|
-
const context = await this.assembleFrameContext(
|
|
78
|
+
const context = await this.assembleFrameContext(
|
|
79
|
+
frameId,
|
|
80
|
+
maxEvents,
|
|
81
|
+
stats
|
|
82
|
+
);
|
|
82
83
|
if (!context) return null;
|
|
83
84
|
if (enableCaching) {
|
|
84
85
|
this.cache.cacheFrameContext(cacheKey, context);
|
|
@@ -254,12 +255,20 @@ class OptimizedContextAssembler {
|
|
|
254
255
|
* Assemble single frame context
|
|
255
256
|
*/
|
|
256
257
|
async assembleFrameContext(frameId, maxEvents, stats) {
|
|
257
|
-
const frame = await this.batchGetFrames([frameId], stats).then(
|
|
258
|
+
const frame = await this.batchGetFrames([frameId], stats).then(
|
|
259
|
+
(map) => map.get(frameId)
|
|
260
|
+
);
|
|
258
261
|
if (!frame) return null;
|
|
259
262
|
const [events, anchors, artifacts] = await Promise.all([
|
|
260
|
-
this.batchGetEvents([frameId], maxEvents, stats).then(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
+
this.batchGetEvents([frameId], maxEvents, stats).then(
|
|
264
|
+
(map) => map.get(frameId) || []
|
|
265
|
+
),
|
|
266
|
+
this.batchGetAnchors([frameId], stats).then(
|
|
267
|
+
(map) => map.get(frameId) || []
|
|
268
|
+
),
|
|
269
|
+
this.batchGetArtifacts([frameId], stats).then(
|
|
270
|
+
(map) => map.get(frameId) || []
|
|
271
|
+
)
|
|
263
272
|
]);
|
|
264
273
|
return {
|
|
265
274
|
frameId,
|
|
@@ -300,13 +309,19 @@ class OptimizedContextAssembler {
|
|
|
300
309
|
);
|
|
301
310
|
this.preparedStatements.set(
|
|
302
311
|
"frame_events",
|
|
303
|
-
this.db.prepare(
|
|
312
|
+
this.db.prepare(
|
|
313
|
+
"SELECT * FROM events WHERE frame_id = ? ORDER BY seq DESC LIMIT ?"
|
|
314
|
+
)
|
|
304
315
|
);
|
|
305
316
|
this.preparedStatements.set(
|
|
306
317
|
"frame_anchors",
|
|
307
|
-
this.db.prepare(
|
|
318
|
+
this.db.prepare(
|
|
319
|
+
"SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at ASC"
|
|
320
|
+
)
|
|
321
|
+
);
|
|
322
|
+
logger.info(
|
|
323
|
+
"Prepared statements initialized for optimized context assembly"
|
|
308
324
|
);
|
|
309
|
-
logger.info("Prepared statements initialized for optimized context assembly");
|
|
310
325
|
} catch (error) {
|
|
311
326
|
logger.error("Failed to initialize prepared statements", error);
|
|
312
327
|
throw error;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/performance/optimized-frame-context.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Optimized Frame Context Assembly\n * High-performance context retrieval with caching and batching\n */\n\nimport Database from 'better-sqlite3';\nimport { getQueryCache, createCacheKey } from '../database/query-cache.js';\nimport { logger } from '../monitoring/logger.js';\nimport { Frame, FrameContext, Anchor, Event } from '../context/frame-manager.js';\n\nexport interface ContextAssemblyOptions {\n maxEvents?: number;\n includeClosed?: boolean;\n enableCaching?: boolean;\n batchSize?: number;\n}\n\nexport interface OptimizedFrameContext extends FrameContext {\n performance: {\n assemblyTimeMs: number;\n cacheHits: number;\n dbQueries: number;\n totalRows: number;\n };\n}\n\n/**\n * Optimized context assembly with caching and batching\n */\nexport class OptimizedContextAssembler {\n private db: Database.Database;\n private cache = getQueryCache();\n private preparedStatements = new Map<string, Database.Statement>();\n\n constructor(db: Database.Database) {\n this.db = db;\n this.initializePreparedStatements();\n }\n\n /**\n * Get hot stack context with optimizations\n */\n async getHotStackContext(\n activeStack: string[],\n options: ContextAssemblyOptions = {}\n ): Promise<OptimizedFrameContext[]> {\n const startTime = performance.now();\n const stats = {\n cacheHits: 0,\n dbQueries: 0,\n totalRows: 0,\n };\n\n const {\n maxEvents = 20,\n includeClosed = false,\n enableCaching = true,\n batchSize = 10,\n } = options;\n\n try {\n // Batch process frames for better performance\n const contexts: OptimizedFrameContext[] = [];\n \n for (let i = 0; i < activeStack.length; i += batchSize) {\n const batch = activeStack.slice(i, i + batchSize);\n const batchContexts = await this.processBatch(\n batch,\n maxEvents,\n includeClosed,\n enableCaching,\n stats\n );\n contexts.push(...batchContexts);\n }\n\n const assemblyTimeMs = performance.now() - startTime;\n\n // Add performance stats to each context\n return contexts.map(context => ({\n ...context,\n performance: {\n assemblyTimeMs: assemblyTimeMs / contexts.length,\n ...stats,\n },\n }));\n\n } catch (error) {\n logger.error('Failed to assemble hot stack context', error as Error, {\n activeStack,\n options,\n });\n throw error;\n }\n }\n\n /**\n * Get single frame context with full optimization\n */\n async getFrameContext(\n frameId: string,\n options: ContextAssemblyOptions = {}\n ): Promise<OptimizedFrameContext | null> {\n const startTime = performance.now();\n const stats = { cacheHits: 0, dbQueries: 0, totalRows: 0 };\n\n const {\n maxEvents = 50,\n enableCaching = true,\n } = options;\n\n // Check cache first\n const cacheKey = createCacheKey('frame_context', [frameId, maxEvents]);\n if (enableCaching) {\n const cached = this.cache.getFrameContext(cacheKey);\n if (cached) {\n stats.cacheHits++;\n return {\n ...cached,\n performance: {\n assemblyTimeMs: performance.now() - startTime,\n ...stats,\n },\n };\n }\n }\n\n try {\n const context = await this.assembleFrameContext(frameId, maxEvents, stats);\n \n if (!context) return null;\n\n // Cache the result\n if (enableCaching) {\n this.cache.cacheFrameContext(cacheKey, context);\n }\n\n const result: OptimizedFrameContext = {\n ...context,\n performance: {\n assemblyTimeMs: performance.now() - startTime,\n ...stats,\n },\n };\n\n return result;\n\n } catch (error) {\n logger.error('Failed to get frame context', error as Error, { frameId });\n throw error;\n }\n }\n\n /**\n * Process a batch of frames efficiently\n */\n private async processBatch(\n frameIds: string[],\n maxEvents: number,\n includeClosed: boolean,\n enableCaching: boolean,\n stats: { cacheHits: number; dbQueries: number; totalRows: number }\n ): Promise<OptimizedFrameContext[]> {\n const contexts: OptimizedFrameContext[] = [];\n \n // Get cached contexts first\n const uncachedIds = [];\n for (const frameId of frameIds) {\n const cacheKey = createCacheKey('frame_context', [frameId, maxEvents]);\n if (enableCaching) {\n const cached = this.cache.getFrameContext(cacheKey);\n if (cached) {\n stats.cacheHits++;\n contexts.push(cached);\n continue;\n }\n }\n uncachedIds.push(frameId);\n }\n\n if (uncachedIds.length === 0) {\n return contexts;\n }\n\n // Batch fetch uncached frames\n const frames = await this.batchGetFrames(uncachedIds, stats);\n const allEvents = await this.batchGetEvents(uncachedIds, maxEvents, stats);\n const allAnchors = await this.batchGetAnchors(uncachedIds, stats);\n const allArtifacts = await this.batchGetArtifacts(uncachedIds, stats);\n\n // Assemble contexts from batched data\n for (const frameId of uncachedIds) {\n const frame = frames.get(frameId);\n if (!frame || (!includeClosed && frame.state === 'closed')) {\n continue;\n }\n\n const context: FrameContext = {\n frameId,\n header: {\n goal: frame.name,\n constraints: this.extractConstraints(frame.inputs),\n definitions: frame.inputs.definitions,\n },\n anchors: allAnchors.get(frameId) || [],\n recentEvents: allEvents.get(frameId) || [],\n activeArtifacts: allArtifacts.get(frameId) || [],\n };\n\n // Cache the context\n if (enableCaching) {\n const cacheKey = createCacheKey('frame_context', [frameId, maxEvents]);\n this.cache.cacheFrameContext(cacheKey, context);\n }\n\n contexts.push(context as OptimizedFrameContext);\n }\n\n return contexts;\n }\n\n /**\n * Batch get frames with single query\n */\n private async batchGetFrames(\n frameIds: string[],\n stats: { dbQueries: number; totalRows: number }\n ): Promise<Map<string, Frame>> {\n if (frameIds.length === 0) return new Map();\n\n const stmt = this.preparedStatements.get('batch_frames');\n if (!stmt) throw new Error('Prepared statement not found: batch_frames');\n\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `SELECT * FROM frames WHERE frame_id IN (${placeholders})`;\n \n stats.dbQueries++;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n stats.totalRows += rows.length;\n\n const frameMap = new Map<string, Frame>();\n for (const row of rows) {\n frameMap.set(row.frame_id, {\n ...row,\n inputs: JSON.parse(row.inputs || '{}'),\n outputs: JSON.parse(row.outputs || '{}'),\n digest_json: JSON.parse(row.digest_json || '{}'),\n });\n }\n\n return frameMap;\n }\n\n /**\n * Batch get events for multiple frames\n */\n private async batchGetEvents(\n frameIds: string[],\n maxEvents: number,\n stats: { dbQueries: number; totalRows: number }\n ): Promise<Map<string, Event[]>> {\n if (frameIds.length === 0) return new Map();\n\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `\n SELECT *, ROW_NUMBER() OVER (PARTITION BY frame_id ORDER BY seq DESC) as rn\n FROM events \n WHERE frame_id IN (${placeholders}) \n AND rn <= ${maxEvents}\n ORDER BY frame_id, seq DESC\n `;\n\n stats.dbQueries++;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n stats.totalRows += rows.length;\n\n const eventMap = new Map<string, Event[]>();\n for (const row of rows) {\n if (!eventMap.has(row.frame_id)) {\n eventMap.set(row.frame_id, []);\n }\n eventMap.get(row.frame_id)!.push({\n ...row,\n payload: JSON.parse(row.payload),\n });\n }\n\n return eventMap;\n }\n\n /**\n * Batch get anchors for multiple frames\n */\n private async batchGetAnchors(\n frameIds: string[],\n stats: { dbQueries: number; totalRows: number }\n ): Promise<Map<string, Anchor[]>> {\n if (frameIds.length === 0) return new Map();\n\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `\n SELECT * FROM anchors \n WHERE frame_id IN (${placeholders}) \n ORDER BY frame_id, priority DESC, created_at ASC\n `;\n\n stats.dbQueries++;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n stats.totalRows += rows.length;\n\n const anchorMap = new Map<string, Anchor[]>();\n for (const row of rows) {\n if (!anchorMap.has(row.frame_id)) {\n anchorMap.set(row.frame_id, []);\n }\n anchorMap.get(row.frame_id)!.push({\n ...row,\n metadata: JSON.parse(row.metadata || '{}'),\n });\n }\n\n return anchorMap;\n }\n\n /**\n * Batch get active artifacts for multiple frames\n */\n private async batchGetArtifacts(\n frameIds: string[],\n stats: { dbQueries: number; totalRows: number }\n ): Promise<Map<string, string[]>> {\n if (frameIds.length === 0) return new Map();\n\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `\n SELECT frame_id, payload\n FROM events \n WHERE frame_id IN (${placeholders}) \n AND event_type = 'artifact'\n ORDER BY frame_id, ts DESC\n `;\n\n stats.dbQueries++;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n stats.totalRows += rows.length;\n\n const artifactMap = new Map<string, string[]>();\n for (const row of rows) {\n const payload = JSON.parse(row.payload);\n if (!artifactMap.has(row.frame_id)) {\n artifactMap.set(row.frame_id, []);\n }\n if (payload.path) {\n artifactMap.get(row.frame_id)!.push(payload.path);\n }\n }\n\n return artifactMap;\n }\n\n /**\n * Assemble single frame context\n */\n private async assembleFrameContext(\n frameId: string,\n maxEvents: number,\n stats: { dbQueries: number; totalRows: number }\n ): Promise<FrameContext | null> {\n // Single frame operations - these could be further optimized with prepared statements\n const frame = await this.batchGetFrames([frameId], stats).then(map => map.get(frameId));\n if (!frame) return null;\n\n const [events, anchors, artifacts] = await Promise.all([\n this.batchGetEvents([frameId], maxEvents, stats).then(map => map.get(frameId) || []),\n this.batchGetAnchors([frameId], stats).then(map => map.get(frameId) || []),\n this.batchGetArtifacts([frameId], stats).then(map => map.get(frameId) || []),\n ]);\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: events,\n activeArtifacts: artifacts,\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 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 * Initialize prepared statements for common queries\n */\n private initializePreparedStatements(): void {\n try {\n // Single frame query\n this.preparedStatements.set(\n 'single_frame',\n this.db.prepare('SELECT * FROM frames WHERE frame_id = ?')\n );\n\n // Frame events with limit\n this.preparedStatements.set(\n 'frame_events',\n this.db.prepare('SELECT * FROM events WHERE frame_id = ? ORDER BY seq DESC LIMIT ?')\n );\n\n // Frame anchors\n this.preparedStatements.set(\n 'frame_anchors',\n this.db.prepare('SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at ASC')\n );\n\n logger.info('Prepared statements initialized for optimized context assembly');\n } catch (error) {\n logger.error('Failed to initialize prepared statements', error as Error);\n throw error;\n }\n }\n\n /**\n * Clear cache and reset prepared statements\n */\n cleanup(): void {\n this.cache.clear();\n // Modern better-sqlite3 automatically handles cleanup\n this.preparedStatements.clear();\n }\n}"],
|
|
5
|
-
"mappings": "AAMA,SAAS,eAAe,sBAAsB;AAC9C,SAAS,cAAc;
|
|
4
|
+
"sourcesContent": ["/**\n * Optimized Frame Context Assembly\n * High-performance context retrieval with caching and batching\n */\n\nimport Database from 'better-sqlite3';\nimport { getQueryCache, createCacheKey } from '../database/query-cache.js';\nimport { logger } from '../monitoring/logger.js';\nimport {\n Frame,\n FrameContext,\n Anchor,\n Event,\n} from '../context/frame-manager.js';\n\nexport interface ContextAssemblyOptions {\n maxEvents?: number;\n includeClosed?: boolean;\n enableCaching?: boolean;\n batchSize?: number;\n}\n\nexport interface OptimizedFrameContext extends FrameContext {\n performance: {\n assemblyTimeMs: number;\n cacheHits: number;\n dbQueries: number;\n totalRows: number;\n };\n}\n\n/**\n * Optimized context assembly with caching and batching\n */\nexport class OptimizedContextAssembler {\n private db: Database.Database;\n private cache = getQueryCache();\n private preparedStatements = new Map<string, Database.Statement>();\n\n constructor(db: Database.Database) {\n this.db = db;\n this.initializePreparedStatements();\n }\n\n /**\n * Get hot stack context with optimizations\n */\n async getHotStackContext(\n activeStack: string[],\n options: ContextAssemblyOptions = {}\n ): Promise<OptimizedFrameContext[]> {\n const startTime = performance.now();\n const stats = {\n cacheHits: 0,\n dbQueries: 0,\n totalRows: 0,\n };\n\n const {\n maxEvents = 20,\n includeClosed = false,\n enableCaching = true,\n batchSize = 10,\n } = options;\n\n try {\n // Batch process frames for better performance\n const contexts: OptimizedFrameContext[] = [];\n\n for (let i = 0; i < activeStack.length; i += batchSize) {\n const batch = activeStack.slice(i, i + batchSize);\n const batchContexts = await this.processBatch(\n batch,\n maxEvents,\n includeClosed,\n enableCaching,\n stats\n );\n contexts.push(...batchContexts);\n }\n\n const assemblyTimeMs = performance.now() - startTime;\n\n // Add performance stats to each context\n return contexts.map((context: any) => ({\n ...context,\n performance: {\n assemblyTimeMs: assemblyTimeMs / contexts.length,\n ...stats,\n },\n }));\n } catch (error: unknown) {\n logger.error('Failed to assemble hot stack context', error as Error, {\n activeStack,\n options,\n });\n throw error;\n }\n }\n\n /**\n * Get single frame context with full optimization\n */\n async getFrameContext(\n frameId: string,\n options: ContextAssemblyOptions = {}\n ): Promise<OptimizedFrameContext | null> {\n const startTime = performance.now();\n const stats = { cacheHits: 0, dbQueries: 0, totalRows: 0 };\n\n const { maxEvents = 50, enableCaching = true } = options;\n\n // Check cache first\n const cacheKey = createCacheKey('frame_context', [frameId, maxEvents]);\n if (enableCaching) {\n const cached = this.cache.getFrameContext(cacheKey);\n if (cached) {\n stats.cacheHits++;\n return {\n ...cached,\n performance: {\n assemblyTimeMs: performance.now() - startTime,\n ...stats,\n },\n };\n }\n }\n\n try {\n const context = await this.assembleFrameContext(\n frameId,\n maxEvents,\n stats\n );\n\n if (!context) return null;\n\n // Cache the result\n if (enableCaching) {\n this.cache.cacheFrameContext(cacheKey, context);\n }\n\n const result: OptimizedFrameContext = {\n ...context,\n performance: {\n assemblyTimeMs: performance.now() - startTime,\n ...stats,\n },\n };\n\n return result;\n } catch (error: unknown) {\n logger.error('Failed to get frame context', error as Error, { frameId });\n throw error;\n }\n }\n\n /**\n * Process a batch of frames efficiently\n */\n private async processBatch(\n frameIds: string[],\n maxEvents: number,\n includeClosed: boolean,\n enableCaching: boolean,\n stats: { cacheHits: number; dbQueries: number; totalRows: number }\n ): Promise<OptimizedFrameContext[]> {\n const contexts: OptimizedFrameContext[] = [];\n\n // Get cached contexts first\n const uncachedIds = [];\n for (const frameId of frameIds) {\n const cacheKey = createCacheKey('frame_context', [frameId, maxEvents]);\n if (enableCaching) {\n const cached = this.cache.getFrameContext(cacheKey);\n if (cached) {\n stats.cacheHits++;\n contexts.push(cached);\n continue;\n }\n }\n uncachedIds.push(frameId);\n }\n\n if (uncachedIds.length === 0) {\n return contexts;\n }\n\n // Batch fetch uncached frames\n const frames = await this.batchGetFrames(uncachedIds, stats);\n const allEvents = await this.batchGetEvents(uncachedIds, maxEvents, stats);\n const allAnchors = await this.batchGetAnchors(uncachedIds, stats);\n const allArtifacts = await this.batchGetArtifacts(uncachedIds, stats);\n\n // Assemble contexts from batched data\n for (const frameId of uncachedIds) {\n const frame = frames.get(frameId);\n if (!frame || (!includeClosed && frame.state === 'closed')) {\n continue;\n }\n\n const context: FrameContext = {\n frameId,\n header: {\n goal: frame.name,\n constraints: this.extractConstraints(frame.inputs),\n definitions: frame.inputs.definitions,\n },\n anchors: allAnchors.get(frameId) || [],\n recentEvents: allEvents.get(frameId) || [],\n activeArtifacts: allArtifacts.get(frameId) || [],\n };\n\n // Cache the context\n if (enableCaching) {\n const cacheKey = createCacheKey('frame_context', [frameId, maxEvents]);\n this.cache.cacheFrameContext(cacheKey, context);\n }\n\n contexts.push(context as OptimizedFrameContext);\n }\n\n return contexts;\n }\n\n /**\n * Batch get frames with single query\n */\n private async batchGetFrames(\n frameIds: string[],\n stats: { dbQueries: number; totalRows: number }\n ): Promise<Map<string, Frame>> {\n if (frameIds.length === 0) return new Map();\n\n const stmt = this.preparedStatements.get('batch_frames');\n if (!stmt) throw new Error('Prepared statement not found: batch_frames');\n\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `SELECT * FROM frames WHERE frame_id IN (${placeholders})`;\n\n stats.dbQueries++;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n stats.totalRows += rows.length;\n\n const frameMap = new Map<string, Frame>();\n for (const row of rows) {\n frameMap.set(row.frame_id, {\n ...row,\n inputs: JSON.parse(row.inputs || '{}'),\n outputs: JSON.parse(row.outputs || '{}'),\n digest_json: JSON.parse(row.digest_json || '{}'),\n });\n }\n\n return frameMap;\n }\n\n /**\n * Batch get events for multiple frames\n */\n private async batchGetEvents(\n frameIds: string[],\n maxEvents: number,\n stats: { dbQueries: number; totalRows: number }\n ): Promise<Map<string, Event[]>> {\n if (frameIds.length === 0) return new Map();\n\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `\n SELECT *, ROW_NUMBER() OVER (PARTITION BY frame_id ORDER BY seq DESC) as rn\n FROM events \n WHERE frame_id IN (${placeholders}) \n AND rn <= ${maxEvents}\n ORDER BY frame_id, seq DESC\n `;\n\n stats.dbQueries++;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n stats.totalRows += rows.length;\n\n const eventMap = new Map<string, Event[]>();\n for (const row of rows) {\n if (!eventMap.has(row.frame_id)) {\n eventMap.set(row.frame_id, []);\n }\n eventMap.get(row.frame_id)!.push({\n ...row,\n payload: JSON.parse(row.payload),\n });\n }\n\n return eventMap;\n }\n\n /**\n * Batch get anchors for multiple frames\n */\n private async batchGetAnchors(\n frameIds: string[],\n stats: { dbQueries: number; totalRows: number }\n ): Promise<Map<string, Anchor[]>> {\n if (frameIds.length === 0) return new Map();\n\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `\n SELECT * FROM anchors \n WHERE frame_id IN (${placeholders}) \n ORDER BY frame_id, priority DESC, created_at ASC\n `;\n\n stats.dbQueries++;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n stats.totalRows += rows.length;\n\n const anchorMap = new Map<string, Anchor[]>();\n for (const row of rows) {\n if (!anchorMap.has(row.frame_id)) {\n anchorMap.set(row.frame_id, []);\n }\n anchorMap.get(row.frame_id)!.push({\n ...row,\n metadata: JSON.parse(row.metadata || '{}'),\n });\n }\n\n return anchorMap;\n }\n\n /**\n * Batch get active artifacts for multiple frames\n */\n private async batchGetArtifacts(\n frameIds: string[],\n stats: { dbQueries: number; totalRows: number }\n ): Promise<Map<string, string[]>> {\n if (frameIds.length === 0) return new Map();\n\n const placeholders = frameIds.map(() => '?').join(',');\n const query = `\n SELECT frame_id, payload\n FROM events \n WHERE frame_id IN (${placeholders}) \n AND event_type = 'artifact'\n ORDER BY frame_id, ts DESC\n `;\n\n stats.dbQueries++;\n const rows = this.db.prepare(query).all(...frameIds) as any[];\n stats.totalRows += rows.length;\n\n const artifactMap = new Map<string, string[]>();\n for (const row of rows) {\n const payload = JSON.parse(row.payload);\n if (!artifactMap.has(row.frame_id)) {\n artifactMap.set(row.frame_id, []);\n }\n if (payload.path) {\n artifactMap.get(row.frame_id)!.push(payload.path);\n }\n }\n\n return artifactMap;\n }\n\n /**\n * Assemble single frame context\n */\n private async assembleFrameContext(\n frameId: string,\n maxEvents: number,\n stats: { dbQueries: number; totalRows: number }\n ): Promise<FrameContext | null> {\n // Single frame operations - these could be further optimized with prepared statements\n const frame = await this.batchGetFrames([frameId], stats).then((map) =>\n map.get(frameId)\n );\n if (!frame) return null;\n\n const [events, anchors, artifacts] = await Promise.all([\n this.batchGetEvents([frameId], maxEvents, stats).then(\n (map) => map.get(frameId) || []\n ),\n this.batchGetAnchors([frameId], stats).then(\n (map) => map.get(frameId) || []\n ),\n this.batchGetArtifacts([frameId], stats).then(\n (map) => map.get(frameId) || []\n ),\n ]);\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: events,\n activeArtifacts: artifacts,\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 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 * Initialize prepared statements for common queries\n */\n private initializePreparedStatements(): void {\n try {\n // Single frame query\n this.preparedStatements.set(\n 'single_frame',\n this.db.prepare('SELECT * FROM frames WHERE frame_id = ?')\n );\n\n // Frame events with limit\n this.preparedStatements.set(\n 'frame_events',\n this.db.prepare(\n 'SELECT * FROM events WHERE frame_id = ? ORDER BY seq DESC LIMIT ?'\n )\n );\n\n // Frame anchors\n this.preparedStatements.set(\n 'frame_anchors',\n this.db.prepare(\n 'SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at ASC'\n )\n );\n\n logger.info(\n 'Prepared statements initialized for optimized context assembly'\n );\n } catch (error: unknown) {\n logger.error('Failed to initialize prepared statements', error as Error);\n throw error;\n }\n }\n\n /**\n * Clear cache and reset prepared statements\n */\n cleanup(): void {\n this.cache.clear();\n // Modern better-sqlite3 automatically handles cleanup\n this.preparedStatements.clear();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -129,9 +129,7 @@ class PerformanceBenchmark {
|
|
|
129
129
|
const loader = new LazyContextLoader(db, projectId);
|
|
130
130
|
let frames = [];
|
|
131
131
|
try {
|
|
132
|
-
frames = db.prepare(
|
|
133
|
-
"SELECT id FROM frames ORDER BY updated_at DESC LIMIT ?"
|
|
134
|
-
).all(frameCount);
|
|
132
|
+
frames = db.prepare("SELECT id FROM frames ORDER BY updated_at DESC LIMIT ?").all(frameCount);
|
|
135
133
|
} catch (error) {
|
|
136
134
|
logger.warn("Frames table not found, using mock data for benchmark");
|
|
137
135
|
frames = Array.from({ length: Math.min(frameCount, 10) }, (_, i) => ({
|
|
@@ -227,17 +225,23 @@ class PerformanceBenchmark {
|
|
|
227
225
|
for (const result of suite.results) {
|
|
228
226
|
console.log(`\u{1F4CA} ${result.name}`);
|
|
229
227
|
console.log(` Duration: ${result.duration.toFixed(2)}ms`);
|
|
230
|
-
console.log(
|
|
228
|
+
console.log(
|
|
229
|
+
` Memory: ${(result.memoryUsed / 1024 / 1024).toFixed(2)}MB`
|
|
230
|
+
);
|
|
231
231
|
console.log(` Throughput: ${result.throughput.toFixed(0)} items/sec`);
|
|
232
232
|
if (result.improvement !== void 0) {
|
|
233
233
|
const icon = result.improvement > 0 ? "\u{1F680}" : "\u26A0\uFE0F";
|
|
234
|
-
console.log(
|
|
234
|
+
console.log(
|
|
235
|
+
` ${icon} Improvement: ${result.improvement.toFixed(1)}%`
|
|
236
|
+
);
|
|
235
237
|
}
|
|
236
238
|
console.log("");
|
|
237
239
|
}
|
|
238
240
|
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
239
241
|
console.log(`\u23F1\uFE0F Total Duration: ${suite.totalDuration.toFixed(2)}ms`);
|
|
240
|
-
console.log(
|
|
242
|
+
console.log(
|
|
243
|
+
`\u{1F4C8} Average Improvement: ${suite.averageImprovement.toFixed(1)}%`
|
|
244
|
+
);
|
|
241
245
|
console.log("");
|
|
242
246
|
logger.info("Performance Benchmark Complete", {
|
|
243
247
|
suite: suite.name,
|