@stackmemoryai/stackmemory 0.2.9 → 0.3.0
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 +512 -0
- package/dist/agents/core/agent-task-manager.js.map +7 -0
- package/dist/agents/verifiers/base-verifier.js +129 -0
- package/dist/agents/verifiers/base-verifier.js.map +7 -0
- package/dist/agents/verifiers/formatter-verifier.js +126 -0
- package/dist/agents/verifiers/formatter-verifier.js.map +7 -0
- package/dist/agents/verifiers/llm-judge.js +248 -0
- package/dist/agents/verifiers/llm-judge.js.map +7 -0
- package/dist/cli/__tests__/index.test.js +290 -0
- package/dist/cli/__tests__/index.test.js.map +7 -0
- package/dist/cli/auto-detect.js +317 -0
- package/dist/cli/auto-detect.js.map +7 -0
- package/dist/cli/browser-test.js +29 -0
- package/dist/cli/browser-test.js.map +7 -0
- package/dist/cli/claude-sm.js +369 -0
- package/dist/cli/claude-sm.js.map +7 -0
- package/dist/cli/codex-sm.js +283 -0
- package/dist/cli/codex-sm.js.map +7 -0
- package/dist/cli/commands/agent.js +286 -0
- package/dist/cli/commands/agent.js.map +7 -0
- package/dist/cli/commands/config.js +199 -0
- package/dist/cli/commands/config.js.map +7 -0
- package/dist/cli/commands/context.js +327 -0
- package/dist/cli/commands/context.js.map +7 -0
- package/dist/cli/commands/handoff.js +191 -0
- package/dist/cli/commands/handoff.js.map +7 -0
- package/dist/cli/commands/linear-test.js +115 -0
- package/dist/cli/commands/linear-test.js.map +7 -0
- package/dist/cli/commands/linear.js +378 -0
- package/dist/cli/commands/linear.js.map +7 -0
- package/dist/cli/commands/log.js +165 -0
- package/dist/cli/commands/log.js.map +7 -0
- package/dist/cli/commands/onboard.js +349 -0
- package/dist/cli/commands/onboard.js.map +7 -0
- package/dist/cli/commands/projects.js +195 -0
- package/dist/cli/commands/projects.js.map +7 -0
- package/dist/cli/commands/search.js +152 -0
- package/dist/cli/commands/search.js.map +7 -0
- package/dist/cli/commands/session.js +179 -0
- package/dist/cli/commands/session.js.map +7 -0
- package/dist/cli/commands/tasks.js +205 -0
- package/dist/cli/commands/tasks.js.map +7 -0
- package/dist/cli/commands/webhook.js +131 -0
- package/dist/cli/commands/webhook.js.map +7 -0
- package/dist/cli/commands/worktree.js +276 -0
- package/dist/cli/commands/worktree.js.map +7 -0
- package/dist/cli/index.js +953 -0
- package/dist/cli/index.js.map +7 -0
- package/dist/cli/utils/viewer.js +92 -0
- package/dist/cli/utils/viewer.js.map +7 -0
- package/dist/core/config/__tests__/config-manager.test.js +248 -0
- package/dist/core/config/__tests__/config-manager.test.js.map +7 -0
- package/dist/core/config/config-manager.js +368 -0
- package/dist/core/config/config-manager.js.map +7 -0
- package/dist/core/config/types.js +140 -0
- package/dist/core/config/types.js.map +7 -0
- package/dist/core/context/__tests__/frame-manager.test.js +879 -0
- package/dist/core/context/__tests__/frame-manager.test.js.map +7 -0
- package/dist/core/context/auto-context.js +72 -0
- package/dist/core/context/auto-context.js.map +7 -0
- package/dist/core/context/compaction-handler.js +326 -0
- package/dist/core/context/compaction-handler.js.map +7 -0
- package/dist/core/context/frame-database.js +376 -0
- package/dist/core/context/frame-database.js.map +7 -0
- package/dist/core/context/frame-digest.js +239 -0
- package/dist/core/context/frame-digest.js.map +7 -0
- package/dist/core/context/frame-manager.js +682 -0
- package/dist/core/context/frame-manager.js.map +7 -0
- package/dist/core/context/frame-stack.js +270 -0
- package/dist/core/context/frame-stack.js.map +7 -0
- package/dist/core/context/frame-types.js +1 -0
- package/dist/core/context/frame-types.js.map +7 -0
- package/dist/core/context/index.js +33 -0
- package/dist/core/context/index.js.map +7 -0
- package/dist/core/context/model-aware-compaction.js +619 -0
- package/dist/core/context/model-aware-compaction.js.map +7 -0
- package/dist/core/context/refactored-frame-manager.js +393 -0
- package/dist/core/context/refactored-frame-manager.js.map +7 -0
- package/dist/core/database/batch-operations.js +329 -0
- package/dist/core/database/batch-operations.js.map +7 -0
- package/dist/core/database/connection-pool.js +224 -0
- package/dist/core/database/connection-pool.js.map +7 -0
- package/dist/core/database/query-cache.js +284 -0
- package/dist/core/database/query-cache.js.map +7 -0
- package/dist/core/digest/__tests__/enhanced-hybrid-digest.test.js +379 -0
- package/dist/core/digest/__tests__/enhanced-hybrid-digest.test.js.map +7 -0
- package/dist/core/digest/__tests__/frame-digest-integration.test.js +230 -0
- package/dist/core/digest/__tests__/frame-digest-integration.test.js.map +7 -0
- package/dist/core/digest/enhanced-hybrid-digest.js +267 -0
- package/dist/core/digest/enhanced-hybrid-digest.js.map +7 -0
- package/dist/core/digest/frame-digest-integration.js +172 -0
- package/dist/core/digest/frame-digest-integration.js.map +7 -0
- package/dist/core/digest/hybrid-digest-generator.js +549 -0
- package/dist/core/digest/hybrid-digest-generator.js.map +7 -0
- package/dist/core/digest/index.js +5 -0
- package/dist/core/digest/index.js.map +7 -0
- package/dist/core/digest/types.js +21 -0
- package/dist/core/digest/types.js.map +7 -0
- package/dist/core/errors/__tests__/error-handling.test.js +270 -0
- package/dist/core/errors/__tests__/error-handling.test.js.map +7 -0
- package/dist/core/errors/index.js +239 -0
- package/dist/core/errors/index.js.map +7 -0
- package/dist/core/errors/recovery.js +258 -0
- package/dist/core/errors/recovery.js.map +7 -0
- package/dist/core/merge/__tests__/conflict-scenarios.test.js +414 -0
- package/dist/core/merge/__tests__/conflict-scenarios.test.js.map +7 -0
- package/dist/core/merge/conflict-detector.js +424 -0
- package/dist/core/merge/conflict-detector.js.map +7 -0
- package/dist/core/merge/index.js +5 -0
- package/dist/core/merge/index.js.map +7 -0
- package/dist/core/merge/resolution-engine.js +565 -0
- package/dist/core/merge/resolution-engine.js.map +7 -0
- package/dist/core/merge/stack-diff.js +528 -0
- package/dist/core/merge/stack-diff.js.map +7 -0
- package/dist/core/merge/types.js +1 -0
- package/dist/core/merge/types.js.map +7 -0
- package/dist/core/monitoring/error-handler.js +278 -0
- package/dist/core/monitoring/error-handler.js.map +7 -0
- package/dist/core/monitoring/logger.js +115 -0
- package/dist/core/monitoring/logger.js.map +7 -0
- package/dist/core/monitoring/metrics.js +157 -0
- package/dist/core/monitoring/metrics.js.map +7 -0
- package/dist/core/monitoring/progress-tracker.js +174 -0
- package/dist/core/monitoring/progress-tracker.js.map +7 -0
- package/dist/core/performance/context-cache.js +269 -0
- package/dist/core/performance/context-cache.js.map +7 -0
- package/dist/core/performance/index.js +7 -0
- package/dist/core/performance/index.js.map +7 -0
- package/dist/core/performance/lazy-context-loader.js +319 -0
- package/dist/core/performance/lazy-context-loader.js.map +7 -0
- package/dist/core/performance/monitor.js +217 -0
- package/dist/core/performance/monitor.js.map +7 -0
- package/dist/core/performance/optimized-frame-context.js +326 -0
- package/dist/core/performance/optimized-frame-context.js.map +7 -0
- package/dist/core/performance/performance-benchmark.js +269 -0
- package/dist/core/performance/performance-benchmark.js.map +7 -0
- package/dist/core/performance/performance-profiler.js +318 -0
- package/dist/core/performance/performance-profiler.js.map +7 -0
- package/dist/core/performance/streaming-jsonl-parser.js +187 -0
- package/dist/core/performance/streaming-jsonl-parser.js.map +7 -0
- package/dist/core/persistence/postgres-adapter.js +345 -0
- package/dist/core/persistence/postgres-adapter.js.map +7 -0
- package/dist/core/projects/project-manager.js +699 -0
- package/dist/core/projects/project-manager.js.map +7 -0
- package/dist/core/query/__tests__/query-parser.test.js +301 -0
- package/dist/core/query/__tests__/query-parser.test.js.map +7 -0
- package/dist/core/query/__tests__/query-templates.test.js +210 -0
- package/dist/core/query/__tests__/query-templates.test.js.map +7 -0
- package/dist/core/query/query-parser.js +366 -0
- package/dist/core/query/query-parser.js.map +7 -0
- package/dist/core/query/query-templates.js +317 -0
- package/dist/core/query/query-templates.js.map +7 -0
- package/dist/core/retrieval/index.js +4 -0
- package/dist/core/retrieval/index.js.map +7 -0
- package/dist/core/retrieval/llm-context-retrieval.js +577 -0
- package/dist/core/retrieval/llm-context-retrieval.js.map +7 -0
- package/dist/core/retrieval/summary-generator.js +585 -0
- package/dist/core/retrieval/summary-generator.js.map +7 -0
- package/dist/core/retrieval/types.js +17 -0
- package/dist/core/retrieval/types.js.map +7 -0
- package/dist/core/session/index.js +11 -0
- package/dist/core/session/index.js.map +7 -0
- package/dist/core/session/session-manager.js +297 -0
- package/dist/core/session/session-manager.js.map +7 -0
- package/dist/core/trace/cli-trace-wrapper.js +110 -0
- package/dist/core/trace/cli-trace-wrapper.js.map +7 -0
- package/dist/core/trace/db-trace-wrapper.js +215 -0
- package/dist/core/trace/db-trace-wrapper.js.map +7 -0
- package/dist/core/trace/debug-trace.js +385 -0
- package/dist/core/trace/debug-trace.js.map +7 -0
- package/dist/core/trace/index.js +158 -0
- package/dist/core/trace/index.js.map +7 -0
- package/dist/core/trace/linear-api-wrapper.js +169 -0
- package/dist/core/trace/linear-api-wrapper.js.map +7 -0
- package/dist/core/trace/trace-demo.js +135 -0
- package/dist/core/trace/trace-demo.js.map +7 -0
- package/dist/core/trace/trace-detector.demo.js +138 -0
- package/dist/core/trace/trace-detector.demo.js.map +7 -0
- package/dist/core/trace/trace-detector.js +386 -0
- package/dist/core/trace/trace-detector.js.map +7 -0
- package/dist/core/trace/trace-detector.test.js +401 -0
- package/dist/core/trace/trace-detector.test.js.map +7 -0
- package/dist/core/trace/trace-store.js +341 -0
- package/dist/core/trace/trace-store.js.map +7 -0
- package/dist/core/trace/types.js +73 -0
- package/dist/core/trace/types.js.map +7 -0
- package/dist/core/types.js +1 -0
- package/dist/core/types.js.map +7 -0
- package/dist/core/utils/update-checker.js +214 -0
- package/dist/core/utils/update-checker.js.map +7 -0
- package/dist/core/worktree/worktree-manager.js +450 -0
- package/dist/core/worktree/worktree-manager.js.map +7 -0
- package/dist/features/analytics/api/analytics-api.js +283 -0
- package/dist/features/analytics/api/analytics-api.js.map +7 -0
- package/dist/features/analytics/core/analytics-service.js +267 -0
- package/dist/features/analytics/core/analytics-service.js.map +7 -0
- package/dist/features/analytics/index.js +14 -0
- package/dist/features/analytics/index.js.map +7 -0
- package/dist/features/analytics/queries/metrics-queries.js +273 -0
- package/dist/features/analytics/queries/metrics-queries.js.map +7 -0
- package/dist/features/analytics/types/metrics.js +1 -0
- package/dist/features/analytics/types/metrics.js.map +7 -0
- package/dist/features/browser/browser-mcp.js +488 -0
- package/dist/features/browser/browser-mcp.js.map +7 -0
- package/dist/features/tasks/__tests__/pebbles-task-store.test.js +747 -0
- package/dist/features/tasks/__tests__/pebbles-task-store.test.js.map +7 -0
- package/dist/features/tasks/pebbles-task-store.js +647 -0
- package/dist/features/tasks/pebbles-task-store.js.map +7 -0
- package/dist/features/tasks/task-aware-context.js +406 -0
- package/dist/features/tasks/task-aware-context.js.map +7 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +7 -0
- package/dist/integrations/linear/__tests__/auth.test.js +558 -0
- package/dist/integrations/linear/__tests__/auth.test.js.map +7 -0
- package/dist/integrations/linear/__tests__/sync-service.test.js +760 -0
- package/dist/integrations/linear/__tests__/sync-service.test.js.map +7 -0
- package/dist/integrations/linear/auth.js +308 -0
- package/dist/integrations/linear/auth.js.map +7 -0
- package/dist/integrations/linear/auto-sync.js +244 -0
- package/dist/integrations/linear/auto-sync.js.map +7 -0
- package/dist/integrations/linear/client.js +448 -0
- package/dist/integrations/linear/client.js.map +7 -0
- package/dist/integrations/linear/config.js +115 -0
- package/dist/integrations/linear/config.js.map +7 -0
- package/dist/integrations/linear/sync-manager.js +233 -0
- package/dist/integrations/linear/sync-manager.js.map +7 -0
- package/dist/integrations/linear/sync-service.js +214 -0
- package/dist/integrations/linear/sync-service.js.map +7 -0
- package/dist/integrations/linear/sync.js +565 -0
- package/dist/integrations/linear/sync.js.map +7 -0
- package/dist/integrations/linear/types.js +1 -0
- package/dist/integrations/linear/types.js.map +7 -0
- package/dist/integrations/linear/webhook-server.js +204 -0
- package/dist/integrations/linear/webhook-server.js.map +7 -0
- package/dist/integrations/linear/webhook.js +269 -0
- package/dist/integrations/linear/webhook.js.map +7 -0
- package/dist/integrations/mcp/__tests__/server.test.js +798 -0
- package/dist/integrations/mcp/__tests__/server.test.js.map +7 -0
- package/dist/integrations/mcp/handlers/context-handlers.js +253 -0
- package/dist/integrations/mcp/handlers/context-handlers.js.map +7 -0
- package/dist/integrations/mcp/handlers/index.js +134 -0
- package/dist/integrations/mcp/handlers/index.js.map +7 -0
- package/dist/integrations/mcp/handlers/linear-handlers.js +243 -0
- package/dist/integrations/mcp/handlers/linear-handlers.js.map +7 -0
- package/dist/integrations/mcp/handlers/task-handlers.js +235 -0
- package/dist/integrations/mcp/handlers/task-handlers.js.map +7 -0
- package/dist/integrations/mcp/handlers/trace-handlers.js +304 -0
- package/dist/integrations/mcp/handlers/trace-handlers.js.map +7 -0
- package/dist/integrations/mcp/index.js +19 -0
- package/dist/integrations/mcp/index.js.map +7 -0
- package/dist/integrations/mcp/refactored-server.js +331 -0
- package/dist/integrations/mcp/refactored-server.js.map +7 -0
- package/dist/integrations/mcp/server.js +1621 -0
- package/dist/integrations/mcp/server.js.map +7 -0
- package/dist/integrations/mcp/tool-definitions.js +562 -0
- package/dist/integrations/mcp/tool-definitions.js.map +7 -0
- package/dist/integrations/mcp/trace-test.js +44 -0
- package/dist/integrations/mcp/trace-test.js.map +7 -0
- package/dist/integrations/pg-aiguide/embedding-provider.js +174 -0
- package/dist/integrations/pg-aiguide/embedding-provider.js.map +7 -0
- package/dist/integrations/pg-aiguide/semantic-search.js +183 -0
- package/dist/integrations/pg-aiguide/semantic-search.js.map +7 -0
- package/dist/integrations/pg-aiguide/timescale-analytics.js +220 -0
- package/dist/integrations/pg-aiguide/timescale-analytics.js.map +7 -0
- package/dist/mcp/stackmemory-mcp-server.js +550 -0
- package/dist/mcp/stackmemory-mcp-server.js.map +7 -0
- package/dist/middleware/exponential-rate-limiter.js +285 -0
- package/dist/middleware/exponential-rate-limiter.js.map +7 -0
- package/dist/models/user.model.js +351 -0
- package/dist/models/user.model.js.map +7 -0
- package/dist/scripts/benchmark-performance.d.ts +7 -0
- package/dist/scripts/benchmark-performance.d.ts.map +1 -0
- package/dist/scripts/benchmark-performance.js +44 -0
- package/dist/scripts/benchmark-performance.js.map +1 -0
- package/dist/scripts/cleanup-duplicate-tasks.d.ts +12 -0
- package/dist/scripts/cleanup-duplicate-tasks.d.ts.map +1 -0
- package/dist/scripts/cleanup-duplicate-tasks.js +215 -0
- package/dist/scripts/cleanup-duplicate-tasks.js.map +1 -0
- package/dist/servers/production/auth-middleware.js +513 -0
- package/dist/servers/production/auth-middleware.js.map +7 -0
- package/dist/servers/railway/index.js +390 -0
- package/dist/servers/railway/index.js.map +7 -0
- package/dist/services/config-service.js +62 -0
- package/dist/services/config-service.js.map +7 -0
- package/dist/services/context-service.js +191 -0
- package/dist/services/context-service.js.map +7 -0
- package/dist/src/agents/core/agent-task-manager.d.ts +154 -0
- package/dist/src/agents/core/agent-task-manager.d.ts.map +1 -0
- package/dist/src/agents/core/agent-task-manager.js +504 -0
- package/dist/src/agents/core/agent-task-manager.js.map +1 -0
- package/dist/src/agents/verifiers/base-verifier.d.ts +112 -0
- package/dist/src/agents/verifiers/base-verifier.d.ts.map +1 -0
- package/dist/src/agents/verifiers/base-verifier.js +130 -0
- package/dist/src/agents/verifiers/base-verifier.js.map +1 -0
- package/dist/src/agents/verifiers/formatter-verifier.d.ts +14 -0
- package/dist/src/agents/verifiers/formatter-verifier.d.ts.map +1 -0
- package/dist/src/agents/verifiers/formatter-verifier.js +107 -0
- package/dist/src/agents/verifiers/formatter-verifier.js.map +1 -0
- package/dist/src/agents/verifiers/llm-judge.d.ts +46 -0
- package/dist/src/agents/verifiers/llm-judge.d.ts.map +1 -0
- package/dist/src/agents/verifiers/llm-judge.js +248 -0
- package/dist/src/agents/verifiers/llm-judge.js.map +1 -0
- package/dist/src/cli/claude-sm.js +55 -0
- package/dist/src/cli/claude-sm.js.map +1 -1
- package/dist/src/cli/commands/agent.d.ts +9 -0
- package/dist/src/cli/commands/agent.d.ts.map +1 -0
- package/dist/src/cli/commands/agent.js +303 -0
- package/dist/src/cli/commands/agent.js.map +1 -0
- package/dist/src/cli/commands/handoff.d.ts +6 -0
- package/dist/src/cli/commands/handoff.d.ts.map +1 -0
- package/dist/src/cli/commands/handoff.js +212 -0
- package/dist/src/cli/commands/handoff.js.map +1 -0
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +4 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/core/context/frame-database.d.ts +59 -0
- package/dist/src/core/context/frame-database.d.ts.map +1 -0
- package/dist/src/core/context/frame-database.js +333 -0
- package/dist/src/core/context/frame-database.js.map +1 -0
- package/dist/src/core/context/frame-digest.d.ts +59 -0
- package/dist/src/core/context/frame-digest.d.ts.map +1 -0
- package/dist/src/core/context/frame-digest.js +264 -0
- package/dist/src/core/context/frame-digest.js.map +1 -0
- package/dist/src/core/context/frame-manager.d.ts +2 -0
- package/dist/src/core/context/frame-manager.d.ts.map +1 -1
- package/dist/src/core/context/frame-manager.js +7 -0
- package/dist/src/core/context/frame-manager.js.map +1 -1
- package/dist/src/core/context/frame-stack.d.ts +85 -0
- package/dist/src/core/context/frame-stack.d.ts.map +1 -0
- package/dist/src/core/context/frame-stack.js +287 -0
- package/dist/src/core/context/frame-stack.js.map +1 -0
- package/dist/src/core/context/frame-types.d.ts +67 -0
- package/dist/src/core/context/frame-types.d.ts.map +1 -0
- package/dist/src/core/context/frame-types.js +6 -0
- package/dist/src/core/context/frame-types.js.map +1 -0
- package/dist/src/core/context/index.d.ts +11 -0
- package/dist/src/core/context/index.d.ts.map +1 -0
- package/dist/src/core/context/index.js +14 -0
- package/dist/src/core/context/index.js.map +1 -0
- package/dist/src/core/context/refactored-frame-manager.d.ts +99 -0
- package/dist/src/core/context/refactored-frame-manager.d.ts.map +1 -0
- package/dist/src/core/context/refactored-frame-manager.js +340 -0
- package/dist/src/core/context/refactored-frame-manager.js.map +1 -0
- package/dist/src/core/database/batch-operations.d.ts +118 -0
- package/dist/src/core/database/batch-operations.d.ts.map +1 -0
- package/dist/src/core/database/batch-operations.js +339 -0
- package/dist/src/core/database/batch-operations.js.map +1 -0
- package/dist/src/core/database/connection-pool.d.ts +79 -0
- package/dist/src/core/database/connection-pool.d.ts.map +1 -0
- package/dist/src/core/database/connection-pool.js +236 -0
- package/dist/src/core/database/connection-pool.js.map +1 -0
- package/dist/src/core/database/query-cache.d.ts +135 -0
- package/dist/src/core/database/query-cache.d.ts.map +1 -0
- package/dist/src/core/database/query-cache.js +294 -0
- package/dist/src/core/database/query-cache.js.map +1 -0
- package/dist/src/core/digest/enhanced-hybrid-digest.d.ts +125 -0
- package/dist/src/core/digest/enhanced-hybrid-digest.d.ts.map +1 -0
- package/dist/src/core/digest/enhanced-hybrid-digest.js +282 -0
- package/dist/src/core/digest/enhanced-hybrid-digest.js.map +1 -0
- package/dist/src/core/digest/frame-digest-integration.d.ts +67 -0
- package/dist/src/core/digest/frame-digest-integration.d.ts.map +1 -0
- package/dist/src/core/digest/frame-digest-integration.js +198 -0
- package/dist/src/core/digest/frame-digest-integration.js.map +1 -0
- package/dist/src/core/digest/hybrid-digest-generator.d.ts +3 -3
- package/dist/src/core/digest/hybrid-digest-generator.d.ts.map +1 -1
- package/dist/src/core/digest/hybrid-digest-generator.js.map +1 -1
- package/dist/src/core/digest/index.d.ts +3 -1
- package/dist/src/core/digest/index.d.ts.map +1 -1
- package/dist/src/core/digest/index.js +3 -1
- package/dist/src/core/digest/index.js.map +1 -1
- package/dist/src/core/errors/index.d.ts +13 -5
- package/dist/src/core/errors/index.d.ts.map +1 -1
- package/dist/src/core/errors/index.js +13 -5
- package/dist/src/core/errors/index.js.map +1 -1
- package/dist/src/core/merge/conflict-detector.d.ts +122 -0
- package/dist/src/core/merge/conflict-detector.d.ts.map +1 -0
- package/dist/src/core/merge/conflict-detector.js +468 -0
- package/dist/src/core/merge/conflict-detector.js.map +1 -0
- package/dist/src/core/merge/index.d.ts +9 -0
- package/dist/src/core/merge/index.d.ts.map +1 -0
- package/dist/src/core/merge/index.js +9 -0
- package/dist/src/core/merge/index.js.map +1 -0
- package/dist/src/core/merge/resolution-engine.d.ts +120 -0
- package/dist/src/core/merge/resolution-engine.d.ts.map +1 -0
- package/dist/src/core/merge/resolution-engine.js +573 -0
- package/dist/src/core/merge/resolution-engine.js.map +1 -0
- package/dist/src/core/merge/stack-diff.d.ts +97 -0
- package/dist/src/core/merge/stack-diff.d.ts.map +1 -0
- package/dist/src/core/merge/stack-diff.js +516 -0
- package/dist/src/core/merge/stack-diff.js.map +1 -0
- package/dist/src/core/merge/types.d.ts +110 -0
- package/dist/src/core/merge/types.d.ts.map +1 -0
- package/dist/src/core/merge/types.js +6 -0
- package/dist/src/core/merge/types.js.map +1 -0
- package/dist/src/core/performance/context-cache.d.ts +109 -0
- package/dist/src/core/performance/context-cache.d.ts.map +1 -0
- package/dist/src/core/performance/context-cache.js +280 -0
- package/dist/src/core/performance/context-cache.js.map +1 -0
- package/dist/src/core/performance/index.d.ts +3 -0
- package/dist/src/core/performance/index.d.ts.map +1 -0
- package/dist/src/core/performance/index.js +3 -0
- package/dist/src/core/performance/index.js.map +1 -0
- package/dist/src/core/performance/lazy-context-loader.d.ts +93 -0
- package/dist/src/core/performance/lazy-context-loader.d.ts.map +1 -0
- package/dist/src/core/performance/lazy-context-loader.js +332 -0
- package/dist/src/core/performance/lazy-context-loader.js.map +1 -0
- package/dist/src/core/performance/monitor.d.ts +48 -0
- package/dist/src/core/performance/monitor.d.ts.map +1 -0
- package/dist/src/core/performance/monitor.js +226 -0
- package/dist/src/core/performance/monitor.js.map +1 -0
- package/dist/src/core/performance/optimized-frame-context.d.ts +74 -0
- package/dist/src/core/performance/optimized-frame-context.d.ts.map +1 -0
- package/dist/src/core/performance/optimized-frame-context.js +330 -0
- package/dist/src/core/performance/optimized-frame-context.js.map +1 -0
- package/dist/src/core/performance/performance-benchmark.d.ts +50 -0
- package/dist/src/core/performance/performance-benchmark.d.ts.map +1 -0
- package/dist/src/core/performance/performance-benchmark.js +290 -0
- package/dist/src/core/performance/performance-benchmark.js.map +1 -0
- package/dist/src/core/performance/performance-profiler.d.ts +151 -0
- package/dist/src/core/performance/performance-profiler.d.ts.map +1 -0
- package/dist/src/core/performance/performance-profiler.js +346 -0
- package/dist/src/core/performance/performance-profiler.js.map +1 -0
- package/dist/src/core/performance/streaming-jsonl-parser.d.ts +41 -0
- package/dist/src/core/performance/streaming-jsonl-parser.d.ts.map +1 -0
- package/dist/src/core/performance/streaming-jsonl-parser.js +193 -0
- package/dist/src/core/performance/streaming-jsonl-parser.js.map +1 -0
- package/dist/src/core/persistence/postgres-adapter.d.ts.map +1 -1
- package/dist/src/core/persistence/postgres-adapter.js +18 -4
- package/dist/src/core/persistence/postgres-adapter.js.map +1 -1
- package/dist/src/core/query/query-parser.d.ts +5 -0
- package/dist/src/core/query/query-parser.d.ts.map +1 -1
- package/dist/src/core/query/query-parser.js +86 -18
- package/dist/src/core/query/query-parser.js.map +1 -1
- package/dist/src/core/query/query-templates.d.ts +44 -0
- package/dist/src/core/query/query-templates.d.ts.map +1 -0
- package/dist/src/core/query/query-templates.js +326 -0
- package/dist/src/core/query/query-templates.js.map +1 -0
- package/dist/src/core/retrieval/llm-context-retrieval.d.ts +5 -3
- package/dist/src/core/retrieval/llm-context-retrieval.d.ts.map +1 -1
- package/dist/src/core/retrieval/llm-context-retrieval.js +73 -21
- package/dist/src/core/retrieval/llm-context-retrieval.js.map +1 -1
- package/dist/src/core/trace/cli-trace-wrapper.d.ts +23 -0
- package/dist/src/core/trace/cli-trace-wrapper.d.ts.map +1 -0
- package/dist/src/core/trace/cli-trace-wrapper.js +141 -0
- package/dist/src/core/trace/cli-trace-wrapper.js.map +1 -0
- package/dist/src/core/trace/db-trace-wrapper.d.ts +36 -0
- package/dist/src/core/trace/db-trace-wrapper.d.ts.map +1 -0
- package/dist/src/core/trace/db-trace-wrapper.js +252 -0
- package/dist/src/core/trace/db-trace-wrapper.js.map +1 -0
- package/dist/src/core/trace/debug-trace.d.ts +84 -0
- package/dist/src/core/trace/debug-trace.d.ts.map +1 -0
- package/dist/src/core/trace/debug-trace.js +402 -0
- package/dist/src/core/trace/debug-trace.js.map +1 -0
- package/dist/src/core/trace/error-test.d.ts +6 -0
- package/dist/src/core/trace/error-test.d.ts.map +1 -0
- package/dist/src/core/trace/error-test.js +128 -0
- package/dist/src/core/trace/error-test.js.map +1 -0
- package/dist/src/core/trace/index.d.ts +25 -0
- package/dist/src/core/trace/index.d.ts.map +1 -0
- package/dist/src/core/trace/index.js +121 -0
- package/dist/src/core/trace/index.js.map +1 -0
- package/dist/src/core/trace/linear-api-wrapper.d.ts +17 -0
- package/dist/src/core/trace/linear-api-wrapper.d.ts.map +1 -0
- package/dist/src/core/trace/linear-api-wrapper.js +205 -0
- package/dist/src/core/trace/linear-api-wrapper.js.map +1 -0
- package/dist/src/core/trace/performance-test.d.ts +6 -0
- package/dist/src/core/trace/performance-test.d.ts.map +1 -0
- package/dist/src/core/trace/performance-test.js +111 -0
- package/dist/src/core/trace/performance-test.js.map +1 -0
- package/dist/src/core/trace/trace-demo.d.ts +8 -0
- package/dist/src/core/trace/trace-demo.d.ts.map +1 -0
- package/dist/src/core/trace/trace-demo.js +154 -0
- package/dist/src/core/trace/trace-demo.js.map +1 -0
- package/dist/src/core/trace/trace-detector.d.ts +2 -2
- package/dist/src/core/trace/trace-detector.d.ts.map +1 -1
- package/dist/src/core/trace/trace-detector.demo.js +1 -1
- package/dist/src/core/trace/trace-detector.demo.js.map +1 -1
- package/dist/src/core/trace/trace-detector.js +3 -3
- package/dist/src/core/trace/trace-detector.js.map +1 -1
- package/dist/src/features/tasks/pebbles-task-store.d.ts +9 -2
- package/dist/src/features/tasks/pebbles-task-store.d.ts.map +1 -1
- package/dist/src/features/tasks/pebbles-task-store.js +97 -18
- package/dist/src/features/tasks/pebbles-task-store.js.map +1 -1
- package/dist/src/integrations/linear/auth.d.ts.map +1 -1
- package/dist/src/integrations/linear/auth.js.map +1 -1
- package/dist/src/integrations/linear/client.d.ts +15 -1
- package/dist/src/integrations/linear/client.d.ts.map +1 -1
- package/dist/src/integrations/linear/client.js +85 -3
- package/dist/src/integrations/linear/client.js.map +1 -1
- package/dist/src/integrations/linear/sync-manager.d.ts +2 -0
- package/dist/src/integrations/linear/sync-manager.d.ts.map +1 -1
- package/dist/src/integrations/linear/sync-manager.js +16 -4
- package/dist/src/integrations/linear/sync-manager.js.map +1 -1
- package/dist/src/integrations/linear/sync-service.d.ts +23 -2
- package/dist/src/integrations/linear/sync-service.d.ts.map +1 -1
- package/dist/src/integrations/linear/sync-service.js +44 -25
- package/dist/src/integrations/linear/sync-service.js.map +1 -1
- package/dist/src/integrations/linear/sync.d.ts +6 -0
- package/dist/src/integrations/linear/sync.d.ts.map +1 -1
- package/dist/src/integrations/linear/sync.js +27 -2
- package/dist/src/integrations/linear/sync.js.map +1 -1
- package/dist/src/integrations/linear/types.d.ts +16 -1
- package/dist/src/integrations/linear/types.d.ts.map +1 -1
- package/dist/src/integrations/linear/webhook-server.d.ts.map +1 -1
- package/dist/src/integrations/linear/webhook-server.js +10 -8
- package/dist/src/integrations/linear/webhook-server.js.map +1 -1
- package/dist/src/integrations/linear/webhook.d.ts +13 -0
- package/dist/src/integrations/linear/webhook.d.ts.map +1 -1
- package/dist/src/integrations/linear/webhook.js +101 -14
- package/dist/src/integrations/linear/webhook.js.map +1 -1
- package/dist/src/integrations/mcp/handlers/context-handlers.d.ts +39 -0
- package/dist/src/integrations/mcp/handlers/context-handlers.d.ts.map +1 -0
- package/dist/src/integrations/mcp/handlers/context-handlers.js +266 -0
- package/dist/src/integrations/mcp/handlers/context-handlers.js.map +1 -0
- package/dist/src/integrations/mcp/handlers/index.d.ts +37 -0
- package/dist/src/integrations/mcp/handlers/index.d.ts.map +1 -0
- package/dist/src/integrations/mcp/handlers/index.js +134 -0
- package/dist/src/integrations/mcp/handlers/index.js.map +1 -0
- package/dist/src/integrations/mcp/handlers/linear-handlers.d.ts +33 -0
- package/dist/src/integrations/mcp/handlers/linear-handlers.d.ts.map +1 -0
- package/dist/src/integrations/mcp/handlers/linear-handlers.js +251 -0
- package/dist/src/integrations/mcp/handlers/linear-handlers.js.map +1 -0
- package/dist/src/integrations/mcp/handlers/task-handlers.d.ts +42 -0
- package/dist/src/integrations/mcp/handlers/task-handlers.d.ts.map +1 -0
- package/dist/src/integrations/mcp/handlers/task-handlers.js +238 -0
- package/dist/src/integrations/mcp/handlers/task-handlers.js.map +1 -0
- package/dist/src/integrations/mcp/handlers/trace-handlers.d.ts +41 -0
- package/dist/src/integrations/mcp/handlers/trace-handlers.d.ts.map +1 -0
- package/dist/src/integrations/mcp/handlers/trace-handlers.js +298 -0
- package/dist/src/integrations/mcp/handlers/trace-handlers.js.map +1 -0
- package/dist/src/integrations/mcp/index.d.ts +13 -0
- package/dist/src/integrations/mcp/index.d.ts.map +1 -0
- package/dist/src/integrations/mcp/index.js +17 -0
- package/dist/src/integrations/mcp/index.js.map +1 -0
- package/dist/src/integrations/mcp/refactored-server.d.ts +76 -0
- package/dist/src/integrations/mcp/refactored-server.d.ts.map +1 -0
- package/dist/src/integrations/mcp/refactored-server.js +351 -0
- package/dist/src/integrations/mcp/refactored-server.js.map +1 -0
- package/dist/src/integrations/mcp/tool-definitions.d.ts +44 -0
- package/dist/src/integrations/mcp/tool-definitions.d.ts.map +1 -0
- package/dist/src/integrations/mcp/tool-definitions.js +563 -0
- package/dist/src/integrations/mcp/tool-definitions.js.map +1 -0
- package/dist/src/integrations/pg-aiguide/semantic-search.d.ts.map +1 -1
- package/dist/src/integrations/pg-aiguide/semantic-search.js +43 -21
- package/dist/src/integrations/pg-aiguide/semantic-search.js.map +1 -1
- package/dist/src/mcp/stackmemory-mcp-server.d.ts +9 -0
- package/dist/src/mcp/stackmemory-mcp-server.d.ts.map +1 -0
- package/dist/src/mcp/stackmemory-mcp-server.js +519 -0
- package/dist/src/mcp/stackmemory-mcp-server.js.map +1 -0
- package/dist/src/middleware/exponential-rate-limiter.d.ts +78 -0
- package/dist/src/middleware/exponential-rate-limiter.d.ts.map +1 -0
- package/dist/src/middleware/exponential-rate-limiter.js +293 -0
- package/dist/src/middleware/exponential-rate-limiter.js.map +1 -0
- package/dist/src/models/user.model.d.ts +8 -1
- package/dist/src/models/user.model.d.ts.map +1 -1
- package/dist/src/models/user.model.js +62 -14
- package/dist/src/models/user.model.js.map +1 -1
- package/dist/src/servers/production/auth-middleware.d.ts +5 -2
- package/dist/src/servers/production/auth-middleware.d.ts.map +1 -1
- package/dist/src/servers/production/auth-middleware.js +71 -34
- package/dist/src/servers/production/auth-middleware.js.map +1 -1
- package/dist/src/services/context-service.d.ts.map +1 -1
- package/dist/src/services/context-service.js +86 -1
- package/dist/src/services/context-service.js.map +1 -1
- package/dist/src/validation/schemas.d.ts +633 -0
- package/dist/src/validation/schemas.d.ts.map +1 -0
- package/dist/src/validation/schemas.js +347 -0
- package/dist/src/validation/schemas.js.map +1 -0
- package/dist/types/task.js +1 -0
- package/dist/types/task.js.map +7 -0
- package/dist/utils/logger.js +52 -0
- package/dist/utils/logger.js.map +7 -0
- package/dist/validation/schemas.js +218 -0
- package/dist/validation/schemas.js.map +7 -0
- package/package.json +7 -3
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/core/worktree/worktree-manager.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Git Worktree Manager for StackMemory\n * Manages multiple instances across git worktrees with context isolation\n */\n\nimport { execSync } from 'child_process';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join, basename, dirname, resolve } from 'path';\nimport { homedir } from 'os';\nimport Database from 'better-sqlite3';\nimport { logger } from '../monitoring/logger.js';\nimport { ProjectManager } from '../projects/project-manager.js';\nimport {\n DatabaseError,\n SystemError,\n ErrorCode,\n createErrorHandler,\n} from '../errors/index.js';\nimport { retry } from '../errors/recovery.js';\n\nexport interface WorktreeInfo {\n path: string;\n branch: string;\n commit: string;\n isMainWorktree: boolean;\n isBare: boolean;\n isDetached: boolean;\n linkedPath?: string; // Path to main worktree\n contextId: string; // Unique context identifier\n}\n\nexport interface WorktreeConfig {\n enabled: boolean;\n autoDetect: boolean;\n isolateContexts: boolean;\n shareGlobalContext: boolean;\n syncInterval?: number; // Minutes between syncs\n maxWorktrees?: number;\n}\n\nexport interface WorktreeContext {\n worktreeId: string;\n projectId: string;\n branch: string;\n contextPath: string;\n dbPath: string;\n lastSynced: Date;\n metadata: Record<string, any>;\n}\n\nexport class WorktreeManager {\n private static instance: WorktreeManager;\n private config: WorktreeConfig;\n private configPath: string;\n private worktreeCache: Map<string, WorktreeInfo> = new Map();\n private contextMap: Map<string, WorktreeContext> = new Map();\n private db?: Database.Database;\n\n private constructor() {\n this.configPath = join(homedir(), '.stackmemory', 'worktree-config.json');\n this.config = this.loadConfig();\n \n try {\n if (this.config.enabled) {\n this.initialize();\n }\n } catch (error) {\n logger.error(\n 'Failed to initialize WorktreeManager',\n error instanceof Error ? error : new Error(String(error)),\n {\n configPath: this.configPath,\n }\n );\n // Don't throw here - allow the manager to be created without worktree support\n this.config.enabled = false;\n }\n }\n\n static getInstance(): WorktreeManager {\n if (!WorktreeManager.instance) {\n WorktreeManager.instance = new WorktreeManager();\n }\n return WorktreeManager.instance;\n }\n\n /**\n * Initialize worktree management\n */\n private initialize(): void {\n const dbPath = join(homedir(), '.stackmemory', 'worktrees.db');\n const errorHandler = createErrorHandler({\n operation: 'initialize',\n dbPath,\n });\n\n try {\n this.db = new Database(dbPath);\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS worktrees (\n id TEXT PRIMARY KEY,\n path TEXT NOT NULL UNIQUE,\n branch TEXT NOT NULL,\n commit TEXT,\n is_main BOOLEAN,\n is_bare BOOLEAN,\n is_detached BOOLEAN,\n linked_path TEXT,\n context_id TEXT UNIQUE,\n project_id TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE TABLE IF NOT EXISTS worktree_contexts (\n context_id TEXT PRIMARY KEY,\n worktree_id TEXT NOT NULL,\n project_id TEXT,\n branch TEXT,\n context_path TEXT,\n db_path TEXT,\n last_synced DATETIME,\n metadata JSON,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (worktree_id) REFERENCES worktrees(id)\n );\n\n CREATE TABLE IF NOT EXISTS context_sync (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n source_context TEXT,\n target_context TEXT,\n sync_type TEXT, -- 'push', 'pull', 'merge'\n data JSON,\n synced_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE INDEX IF NOT EXISTS idx_worktrees_project ON worktrees(project_id);\n CREATE INDEX IF NOT EXISTS idx_contexts_worktree ON worktree_contexts(worktree_id);\n `);\n } catch (error) {\n errorHandler(error);\n }\n }\n\n /**\n * Load configuration\n */\n private loadConfig(): WorktreeConfig {\n if (existsSync(this.configPath)) {\n try {\n return JSON.parse(readFileSync(this.configPath, 'utf-8'));\n } catch (error) {\n logger.error('Failed to load worktree config', error as Error);\n }\n }\n\n // Default config\n return {\n enabled: false,\n autoDetect: true,\n isolateContexts: true,\n shareGlobalContext: false,\n syncInterval: 15,\n maxWorktrees: 10,\n };\n }\n\n /**\n * Save configuration\n */\n saveConfig(config: Partial<WorktreeConfig>): void {\n this.config = { ...this.config, ...config };\n \n const configDir = dirname(this.configPath);\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n \n writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));\n \n // Reinitialize if just enabled\n if (config.enabled && !this.db) {\n this.initialize();\n }\n \n logger.info('Worktree configuration updated', { config: this.config });\n }\n\n /**\n * Detect git worktrees in current repository\n */\n detectWorktrees(repoPath?: string): WorktreeInfo[] {\n const path = repoPath || process.cwd();\n \n try {\n // Get worktree list\n const output = execSync('git worktree list --porcelain', {\n cwd: path,\n encoding: 'utf-8',\n });\n\n const worktrees: WorktreeInfo[] = [];\n const lines = output.split('\\n');\n let currentWorktree: Partial<WorktreeInfo> = {};\n\n for (const line of lines) {\n if (line.startsWith('worktree ')) {\n if (currentWorktree.path) {\n worktrees.push(this.finalizeWorktreeInfo(currentWorktree));\n }\n currentWorktree = { path: line.substring(9) };\n } else if (line.startsWith('HEAD ')) {\n currentWorktree.commit = line.substring(5);\n } else if (line.startsWith('branch ')) {\n currentWorktree.branch = line.substring(7);\n } else if (line === 'bare') {\n currentWorktree.isBare = true;\n } else if (line === 'detached') {\n currentWorktree.isDetached = true;\n }\n }\n\n // Add last worktree\n if (currentWorktree.path) {\n worktrees.push(this.finalizeWorktreeInfo(currentWorktree));\n }\n\n // Determine main worktree\n if (worktrees.length > 0) {\n const mainPath = this.getMainWorktreePath(path);\n worktrees.forEach(wt => {\n wt.isMainWorktree = wt.path === mainPath;\n if (!wt.isMainWorktree) {\n wt.linkedPath = mainPath;\n }\n });\n }\n\n // Cache results\n worktrees.forEach(wt => {\n this.worktreeCache.set(wt.path, wt);\n if (this.config.enabled) {\n this.saveWorktree(wt);\n }\n });\n\n logger.info(`Detected ${worktrees.length} worktrees`, { \n count: worktrees.length,\n branches: worktrees.map(w => w.branch).filter(Boolean)\n });\n\n return worktrees;\n } catch (error) {\n logger.debug('Not a git repository or git worktree not available');\n return [];\n }\n }\n\n /**\n * Get main worktree path\n */\n private getMainWorktreePath(path: string): string {\n try {\n const gitDir = execSync('git rev-parse --git-common-dir', {\n cwd: path,\n encoding: 'utf-8',\n }).trim();\n\n // If it's a worktree, find the main repo\n if (gitDir.includes('/.git/worktrees/')) {\n const mainGitDir = gitDir.replace(/\\/\\.git\\/worktrees\\/.*$/, '');\n return mainGitDir;\n }\n\n // It's the main worktree\n return dirname(gitDir);\n } catch {\n return path;\n }\n }\n\n /**\n * Finalize worktree info with defaults\n */\n private finalizeWorktreeInfo(partial: Partial<WorktreeInfo>): WorktreeInfo {\n return {\n path: partial.path || '',\n branch: partial.branch || 'detached',\n commit: partial.commit || '',\n isMainWorktree: partial.isMainWorktree || false,\n isBare: partial.isBare || false,\n isDetached: partial.isDetached || false,\n linkedPath: partial.linkedPath,\n contextId: this.generateContextId(partial.path || '', partial.branch || ''),\n };\n }\n\n /**\n * Generate unique context ID for worktree\n */\n private generateContextId(path: string, branch: string): string {\n const repoName = basename(dirname(path));\n const sanitizedBranch = branch.replace(/[^a-zA-Z0-9-]/g, '_');\n return `${repoName}-${sanitizedBranch}-${Buffer.from(path).toString('base64').substring(0, 8)}`;\n }\n\n /**\n * Save worktree to database\n */\n private async saveWorktree(worktree: WorktreeInfo): Promise<void> {\n if (!this.db) return;\n\n const projectManager = ProjectManager.getInstance();\n const project = await projectManager.detectProject(worktree.path);\n\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO worktrees \n (id, path, branch, commit, is_main, is_bare, is_detached, linked_path, context_id, project_id, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)\n `);\n\n stmt.run(\n worktree.contextId,\n worktree.path,\n worktree.branch,\n worktree.commit,\n worktree.isMainWorktree ? 1 : 0,\n worktree.isBare ? 1 : 0,\n worktree.isDetached ? 1 : 0,\n worktree.linkedPath,\n worktree.contextId,\n project.id\n );\n }\n\n /**\n * Get or create context for worktree\n */\n getWorktreeContext(worktreePath: string): WorktreeContext {\n // Check cache\n const cached = this.contextMap.get(worktreePath);\n if (cached) {\n return cached;\n }\n\n const worktree = this.worktreeCache.get(worktreePath) || \n this.detectWorktrees(worktreePath).find(w => w.path === worktreePath);\n\n if (!worktree) {\n throw new Error(`No worktree found at path: ${worktreePath}`);\n }\n\n // Create isolated context path\n const contextBasePath = this.config.isolateContexts\n ? join(homedir(), '.stackmemory', 'worktrees', worktree.contextId)\n : join(worktreePath, '.stackmemory');\n\n // Ensure directory exists\n if (!existsSync(contextBasePath)) {\n mkdirSync(contextBasePath, { recursive: true });\n }\n\n const context: WorktreeContext = {\n worktreeId: worktree.contextId,\n projectId: '', // Will be filled by project manager\n branch: worktree.branch,\n contextPath: contextBasePath,\n dbPath: join(contextBasePath, 'context.db'),\n lastSynced: new Date(),\n metadata: {\n isMainWorktree: worktree.isMainWorktree,\n linkedPath: worktree.linkedPath,\n },\n };\n\n // Save to database\n if (this.db && this.config.enabled) {\n this.saveContext(context);\n }\n\n // Cache it\n this.contextMap.set(worktreePath, context);\n\n logger.info('Created worktree context', {\n worktree: worktree.branch,\n path: contextBasePath,\n });\n\n return context;\n }\n\n /**\n * Save context to database\n */\n private saveContext(context: WorktreeContext): void {\n if (!this.db) return;\n\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO worktree_contexts\n (context_id, worktree_id, project_id, branch, context_path, db_path, last_synced, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n stmt.run(\n context.worktreeId,\n context.worktreeId,\n context.projectId,\n context.branch,\n context.contextPath,\n context.dbPath,\n context.lastSynced.toISOString(),\n JSON.stringify(context.metadata)\n );\n }\n\n /**\n * Sync contexts between worktrees\n */\n async syncContexts(sourceWorktree: string, targetWorktree: string, syncType: 'push' | 'pull' | 'merge' = 'merge'): Promise<void> {\n const source = this.getWorktreeContext(sourceWorktree);\n const target = this.getWorktreeContext(targetWorktree);\n\n logger.info('Syncing contexts between worktrees', {\n source: source.branch,\n target: target.branch,\n type: syncType,\n });\n\n // Open both databases\n const sourceDb = new Database(source.dbPath);\n const targetDb = new Database(target.dbPath);\n\n try {\n // Get contexts from source\n const contexts = sourceDb.prepare(`\n SELECT * FROM contexts \n WHERE created_at > datetime('now', '-7 days')\n ORDER BY created_at DESC\n `).all();\n\n // Sync based on type\n if (syncType === 'push' || syncType === 'merge') {\n this.mergeContexts(contexts, targetDb, syncType === 'merge');\n }\n\n if (syncType === 'pull') {\n const targetContexts = targetDb.prepare(`\n SELECT * FROM contexts \n WHERE created_at > datetime('now', '-7 days')\n ORDER BY created_at DESC\n `).all();\n \n this.mergeContexts(targetContexts, sourceDb, false);\n }\n\n // Log sync operation\n if (this.db) {\n const stmt = this.db.prepare(`\n INSERT INTO context_sync (source_context, target_context, sync_type, data)\n VALUES (?, ?, ?, ?)\n `);\n\n stmt.run(\n source.worktreeId,\n target.worktreeId,\n syncType,\n JSON.stringify({ count: contexts.length })\n );\n }\n\n logger.info('Context sync completed', {\n synced: contexts.length,\n type: syncType,\n });\n } finally {\n sourceDb.close();\n targetDb.close();\n }\n }\n\n /**\n * Merge contexts into target database\n */\n private mergeContexts(contexts: any[], targetDb: Database.Database, bidirectional: boolean): void {\n const stmt = targetDb.prepare(`\n INSERT OR REPLACE INTO contexts (id, type, content, metadata, created_at)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n for (const ctx of contexts) {\n try {\n stmt.run(ctx.id, ctx.type, ctx.content, ctx.metadata, ctx.created_at);\n } catch (error) {\n logger.warn('Failed to merge context', { id: ctx.id, error });\n }\n }\n }\n\n /**\n * List all active worktrees\n */\n listActiveWorktrees(): WorktreeInfo[] {\n if (!this.db) {\n return Array.from(this.worktreeCache.values());\n }\n\n const stmt = this.db.prepare(`\n SELECT * FROM worktrees\n ORDER BY is_main DESC, branch ASC\n `);\n\n const rows = stmt.all() as any[];\n \n return rows.map(row => ({\n path: row.path,\n branch: row.branch,\n commit: row.commit,\n isMainWorktree: row.is_main === 1,\n isBare: row.is_bare === 1,\n isDetached: row.is_detached === 1,\n linkedPath: row.linked_path,\n contextId: row.context_id,\n }));\n }\n\n /**\n * Clean up stale worktree contexts\n */\n cleanupStaleContexts(): void {\n if (!this.db) return;\n\n const activeWorktrees = this.detectWorktrees();\n const activePaths = new Set(activeWorktrees.map(w => w.path));\n\n // Get all stored worktrees\n const stmt = this.db.prepare('SELECT * FROM worktrees');\n const stored = stmt.all() as any[];\n\n // Remove stale entries\n const deleteStmt = this.db.prepare('DELETE FROM worktrees WHERE id = ?');\n const deleteContextStmt = this.db.prepare('DELETE FROM worktree_contexts WHERE worktree_id = ?');\n\n for (const worktree of stored) {\n if (!activePaths.has(worktree.path)) {\n deleteStmt.run(worktree.id);\n deleteContextStmt.run(worktree.id);\n \n logger.info('Cleaned up stale worktree context', {\n path: worktree.path,\n branch: worktree.branch,\n });\n }\n }\n }\n\n /**\n * Get configuration\n */\n getConfig(): WorktreeConfig {\n return { ...this.config };\n }\n\n /**\n * Check if worktree support is enabled\n */\n isEnabled(): boolean {\n return this.config.enabled;\n }\n\n /**\n * Enable or disable worktree support\n */\n setEnabled(enabled: boolean): void {\n this.saveConfig({ enabled });\n }\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { AnalyticsService } from "../core/analytics-service.js";
|
|
3
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
4
|
+
class AnalyticsAPI {
|
|
5
|
+
router;
|
|
6
|
+
analyticsService;
|
|
7
|
+
wss;
|
|
8
|
+
constructor(projectPath) {
|
|
9
|
+
this.router = express.Router();
|
|
10
|
+
this.analyticsService = new AnalyticsService(projectPath);
|
|
11
|
+
this.setupRoutes();
|
|
12
|
+
}
|
|
13
|
+
setupRoutes() {
|
|
14
|
+
this.router.use(express.json());
|
|
15
|
+
this.router.get("/metrics", this.getMetrics.bind(this));
|
|
16
|
+
this.router.get("/tasks", this.getTasks.bind(this));
|
|
17
|
+
this.router.get("/team/:userId", this.getTeamMetrics.bind(this));
|
|
18
|
+
this.router.post("/tasks", this.addTask.bind(this));
|
|
19
|
+
this.router.put("/tasks/:taskId", this.updateTask.bind(this));
|
|
20
|
+
this.router.post("/sync", this.syncLinear.bind(this));
|
|
21
|
+
this.router.get("/export", this.exportMetrics.bind(this));
|
|
22
|
+
}
|
|
23
|
+
async getMetrics(req, res) {
|
|
24
|
+
try {
|
|
25
|
+
const query = this.parseQuery(req.query);
|
|
26
|
+
const dashboardState = await this.analyticsService.getDashboardState(query);
|
|
27
|
+
res.json({
|
|
28
|
+
success: true,
|
|
29
|
+
data: {
|
|
30
|
+
metrics: dashboardState.metrics,
|
|
31
|
+
lastUpdated: dashboardState.lastUpdated
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
} catch (error) {
|
|
35
|
+
this.handleError(res, error);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async getTasks(req, res) {
|
|
39
|
+
try {
|
|
40
|
+
const query = this.parseQuery(req.query);
|
|
41
|
+
const dashboardState = await this.analyticsService.getDashboardState(query);
|
|
42
|
+
res.json({
|
|
43
|
+
success: true,
|
|
44
|
+
data: {
|
|
45
|
+
tasks: dashboardState.recentTasks,
|
|
46
|
+
total: dashboardState.metrics.totalTasks
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.handleError(res, error);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async getTeamMetrics(req, res) {
|
|
54
|
+
try {
|
|
55
|
+
const { userId } = req.params;
|
|
56
|
+
const query = this.parseQuery(req.query);
|
|
57
|
+
if (userId === "all") {
|
|
58
|
+
const dashboardState = await this.analyticsService.getDashboardState(query);
|
|
59
|
+
res.json({
|
|
60
|
+
success: true,
|
|
61
|
+
data: dashboardState.teamMetrics
|
|
62
|
+
});
|
|
63
|
+
} else {
|
|
64
|
+
const dashboardState = await this.analyticsService.getDashboardState({
|
|
65
|
+
...query,
|
|
66
|
+
userIds: [userId]
|
|
67
|
+
});
|
|
68
|
+
const userMetrics = dashboardState.teamMetrics.find(
|
|
69
|
+
(m) => m.userId === userId
|
|
70
|
+
);
|
|
71
|
+
if (!userMetrics) {
|
|
72
|
+
res.status(404).json({
|
|
73
|
+
success: false,
|
|
74
|
+
error: "User metrics not found"
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
res.json({
|
|
79
|
+
success: true,
|
|
80
|
+
data: userMetrics
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
this.handleError(res, error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async addTask(req, res) {
|
|
88
|
+
try {
|
|
89
|
+
const task = {
|
|
90
|
+
...req.body,
|
|
91
|
+
createdAt: new Date(req.body.createdAt || Date.now()),
|
|
92
|
+
completedAt: req.body.completedAt ? new Date(req.body.completedAt) : void 0
|
|
93
|
+
};
|
|
94
|
+
await this.analyticsService.addTask(task);
|
|
95
|
+
res.status(201).json({
|
|
96
|
+
success: true,
|
|
97
|
+
message: "Task added successfully"
|
|
98
|
+
});
|
|
99
|
+
} catch (error) {
|
|
100
|
+
this.handleError(res, error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async updateTask(req, res) {
|
|
104
|
+
try {
|
|
105
|
+
const { taskId } = req.params;
|
|
106
|
+
const updates = req.body;
|
|
107
|
+
if (updates.completedAt) {
|
|
108
|
+
updates.completedAt = new Date(updates.completedAt);
|
|
109
|
+
}
|
|
110
|
+
await this.analyticsService.updateTask(taskId, updates);
|
|
111
|
+
res.json({
|
|
112
|
+
success: true,
|
|
113
|
+
message: "Task updated successfully"
|
|
114
|
+
});
|
|
115
|
+
} catch (error) {
|
|
116
|
+
this.handleError(res, error);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async syncLinear(req, res) {
|
|
120
|
+
try {
|
|
121
|
+
await this.analyticsService.syncLinearTasks();
|
|
122
|
+
res.json({
|
|
123
|
+
success: true,
|
|
124
|
+
message: "Linear tasks synced successfully"
|
|
125
|
+
});
|
|
126
|
+
} catch (error) {
|
|
127
|
+
this.handleError(res, error);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async exportMetrics(req, res) {
|
|
131
|
+
try {
|
|
132
|
+
const query = this.parseQuery(req.query);
|
|
133
|
+
const format = req.query.format || "json";
|
|
134
|
+
const dashboardState = await this.analyticsService.getDashboardState(query);
|
|
135
|
+
if (format === "csv") {
|
|
136
|
+
const csv = this.convertToCSV(dashboardState);
|
|
137
|
+
res.setHeader("Content-Type", "text/csv");
|
|
138
|
+
res.setHeader(
|
|
139
|
+
"Content-Disposition",
|
|
140
|
+
'attachment; filename="analytics-export.csv"'
|
|
141
|
+
);
|
|
142
|
+
res.send(csv);
|
|
143
|
+
} else {
|
|
144
|
+
res.json({
|
|
145
|
+
success: true,
|
|
146
|
+
data: dashboardState
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
this.handleError(res, error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
parseQuery(query) {
|
|
154
|
+
const result = {};
|
|
155
|
+
if (query.start && query.end) {
|
|
156
|
+
result.timeRange = {
|
|
157
|
+
start: new Date(query.start),
|
|
158
|
+
end: new Date(query.end),
|
|
159
|
+
preset: query.preset
|
|
160
|
+
};
|
|
161
|
+
} else if (query.preset) {
|
|
162
|
+
result.timeRange = this.getPresetTimeRange(query.preset);
|
|
163
|
+
}
|
|
164
|
+
if (query.users) {
|
|
165
|
+
result.userIds = Array.isArray(query.users) ? query.users : [query.users];
|
|
166
|
+
}
|
|
167
|
+
if (query.states) {
|
|
168
|
+
result.states = Array.isArray(query.states) ? query.states : [query.states];
|
|
169
|
+
}
|
|
170
|
+
if (query.priorities) {
|
|
171
|
+
result.priorities = Array.isArray(query.priorities) ? query.priorities : [query.priorities];
|
|
172
|
+
}
|
|
173
|
+
if (query.labels) {
|
|
174
|
+
result.labels = Array.isArray(query.labels) ? query.labels : [query.labels];
|
|
175
|
+
}
|
|
176
|
+
if (query.limit) {
|
|
177
|
+
result.limit = parseInt(query.limit);
|
|
178
|
+
}
|
|
179
|
+
if (query.offset) {
|
|
180
|
+
result.offset = parseInt(query.offset);
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
getPresetTimeRange(preset) {
|
|
185
|
+
const end = /* @__PURE__ */ new Date();
|
|
186
|
+
const start = /* @__PURE__ */ new Date();
|
|
187
|
+
switch (preset) {
|
|
188
|
+
case "today":
|
|
189
|
+
start.setHours(0, 0, 0, 0);
|
|
190
|
+
break;
|
|
191
|
+
case "7d":
|
|
192
|
+
start.setDate(start.getDate() - 7);
|
|
193
|
+
break;
|
|
194
|
+
case "30d":
|
|
195
|
+
start.setDate(start.getDate() - 30);
|
|
196
|
+
break;
|
|
197
|
+
case "90d":
|
|
198
|
+
start.setDate(start.getDate() - 90);
|
|
199
|
+
break;
|
|
200
|
+
default:
|
|
201
|
+
start.setDate(start.getDate() - 7);
|
|
202
|
+
}
|
|
203
|
+
return { start, end, preset };
|
|
204
|
+
}
|
|
205
|
+
convertToCSV(dashboardState) {
|
|
206
|
+
const tasks = dashboardState.recentTasks;
|
|
207
|
+
if (!tasks || tasks.length === 0) return "No data";
|
|
208
|
+
const headers = Object.keys(tasks[0]).join(",");
|
|
209
|
+
const rows = tasks.map(
|
|
210
|
+
(task) => Object.values(task).map((v) => typeof v === "object" ? JSON.stringify(v) : v).join(",")
|
|
211
|
+
);
|
|
212
|
+
return [headers, ...rows].join("\n");
|
|
213
|
+
}
|
|
214
|
+
handleError(res, error) {
|
|
215
|
+
console.error("Analytics API error:", error);
|
|
216
|
+
res.status(500).json({
|
|
217
|
+
success: false,
|
|
218
|
+
error: error.message || "Internal server error"
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
setupWebSocket(server) {
|
|
222
|
+
this.wss = new WebSocketServer({
|
|
223
|
+
server,
|
|
224
|
+
path: "/ws/analytics"
|
|
225
|
+
});
|
|
226
|
+
this.wss.on("connection", (ws) => {
|
|
227
|
+
console.log("WebSocket client connected to analytics");
|
|
228
|
+
const unsubscribe = this.analyticsService.subscribeToUpdates((state) => {
|
|
229
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
230
|
+
ws.send(
|
|
231
|
+
JSON.stringify({
|
|
232
|
+
type: "update",
|
|
233
|
+
data: state
|
|
234
|
+
})
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
ws.on("message", async (message) => {
|
|
239
|
+
try {
|
|
240
|
+
const data = JSON.parse(message);
|
|
241
|
+
if (data.type === "subscribe") {
|
|
242
|
+
const query = this.parseQuery(data.query || {});
|
|
243
|
+
const state = await this.analyticsService.getDashboardState(query);
|
|
244
|
+
ws.send(
|
|
245
|
+
JSON.stringify({
|
|
246
|
+
type: "initial",
|
|
247
|
+
data: state
|
|
248
|
+
})
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
} catch (error) {
|
|
252
|
+
ws.send(
|
|
253
|
+
JSON.stringify({
|
|
254
|
+
type: "error",
|
|
255
|
+
error: "Invalid message format"
|
|
256
|
+
})
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
ws.on("close", () => {
|
|
261
|
+
unsubscribe();
|
|
262
|
+
console.log("WebSocket client disconnected");
|
|
263
|
+
});
|
|
264
|
+
ws.on("error", (error) => {
|
|
265
|
+
console.error("WebSocket error:", error);
|
|
266
|
+
unsubscribe();
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
getRouter() {
|
|
271
|
+
return this.router;
|
|
272
|
+
}
|
|
273
|
+
close() {
|
|
274
|
+
this.analyticsService.close();
|
|
275
|
+
if (this.wss) {
|
|
276
|
+
this.wss.close();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
export {
|
|
281
|
+
AnalyticsAPI
|
|
282
|
+
};
|
|
283
|
+
//# sourceMappingURL=analytics-api.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/features/analytics/api/analytics-api.ts"],
|
|
4
|
+
"sourcesContent": ["import express, { Request, Response, Router } from 'express';\nimport { AnalyticsService } from '../core/analytics-service.js';\nimport { AnalyticsQuery, TimeRange } from '../types/metrics.js';\nimport { WebSocketServer, WebSocket } from 'ws';\nimport { Server } from 'http';\n\nexport class AnalyticsAPI {\n private router: Router;\n private analyticsService: AnalyticsService;\n private wss?: WebSocketServer;\n\n constructor(projectPath?: string) {\n this.router = express.Router();\n this.analyticsService = new AnalyticsService(projectPath);\n this.setupRoutes();\n }\n\n private setupRoutes(): void {\n this.router.use(express.json());\n\n this.router.get('/metrics', this.getMetrics.bind(this));\n this.router.get('/tasks', this.getTasks.bind(this));\n this.router.get('/team/:userId', this.getTeamMetrics.bind(this));\n this.router.post('/tasks', this.addTask.bind(this));\n this.router.put('/tasks/:taskId', this.updateTask.bind(this));\n this.router.post('/sync', this.syncLinear.bind(this));\n this.router.get('/export', this.exportMetrics.bind(this));\n }\n\n private async getMetrics(req: Request, res: Response): Promise<void> {\n try {\n const query = this.parseQuery(req.query);\n const dashboardState =\n await this.analyticsService.getDashboardState(query);\n\n res.json({\n success: true,\n data: {\n metrics: dashboardState.metrics,\n lastUpdated: dashboardState.lastUpdated,\n },\n });\n } catch (error) {\n this.handleError(res, error);\n }\n }\n\n private async getTasks(req: Request, res: Response): Promise<void> {\n try {\n const query = this.parseQuery(req.query);\n const dashboardState =\n await this.analyticsService.getDashboardState(query);\n\n res.json({\n success: true,\n data: {\n tasks: dashboardState.recentTasks,\n total: dashboardState.metrics.totalTasks,\n },\n });\n } catch (error) {\n this.handleError(res, error);\n }\n }\n\n private async getTeamMetrics(req: Request, res: Response): Promise<void> {\n try {\n const { userId } = req.params;\n const query = this.parseQuery(req.query);\n\n if (userId === 'all') {\n const dashboardState =\n await this.analyticsService.getDashboardState(query);\n res.json({\n success: true,\n data: dashboardState.teamMetrics,\n });\n } else {\n const dashboardState = await this.analyticsService.getDashboardState({\n ...query,\n userIds: [userId],\n });\n\n const userMetrics = dashboardState.teamMetrics.find(\n (m) => m.userId === userId\n );\n\n if (!userMetrics) {\n res.status(404).json({\n success: false,\n error: 'User metrics not found',\n });\n return;\n }\n\n res.json({\n success: true,\n data: userMetrics,\n });\n }\n } catch (error) {\n this.handleError(res, error);\n }\n }\n\n private async addTask(req: Request, res: Response): Promise<void> {\n try {\n const task = {\n ...req.body,\n createdAt: new Date(req.body.createdAt || Date.now()),\n completedAt: req.body.completedAt\n ? new Date(req.body.completedAt)\n : undefined,\n };\n\n await this.analyticsService.addTask(task);\n\n res.status(201).json({\n success: true,\n message: 'Task added successfully',\n });\n } catch (error) {\n this.handleError(res, error);\n }\n }\n\n private async updateTask(req: Request, res: Response): Promise<void> {\n try {\n const { taskId } = req.params;\n const updates = req.body;\n\n if (updates.completedAt) {\n updates.completedAt = new Date(updates.completedAt);\n }\n\n await this.analyticsService.updateTask(taskId, updates);\n\n res.json({\n success: true,\n message: 'Task updated successfully',\n });\n } catch (error) {\n this.handleError(res, error);\n }\n }\n\n private async syncLinear(req: Request, res: Response): Promise<void> {\n try {\n await this.analyticsService.syncLinearTasks();\n\n res.json({\n success: true,\n message: 'Linear tasks synced successfully',\n });\n } catch (error) {\n this.handleError(res, error);\n }\n }\n\n private async exportMetrics(req: Request, res: Response): Promise<void> {\n try {\n const query = this.parseQuery(req.query);\n const format = (req.query.format as 'json' | 'csv') || 'json';\n const dashboardState =\n await this.analyticsService.getDashboardState(query);\n\n if (format === 'csv') {\n const csv = this.convertToCSV(dashboardState);\n res.setHeader('Content-Type', 'text/csv');\n res.setHeader(\n 'Content-Disposition',\n 'attachment; filename=\"analytics-export.csv\"'\n );\n res.send(csv);\n } else {\n res.json({\n success: true,\n data: dashboardState,\n });\n }\n } catch (error) {\n this.handleError(res, error);\n }\n }\n\n private parseQuery(query: any): AnalyticsQuery {\n const result: AnalyticsQuery = {};\n\n if (query.start && query.end) {\n result.timeRange = {\n start: new Date(query.start),\n end: new Date(query.end),\n preset: query.preset,\n };\n } else if (query.preset) {\n result.timeRange = this.getPresetTimeRange(query.preset);\n }\n\n if (query.users) {\n result.userIds = Array.isArray(query.users) ? query.users : [query.users];\n }\n\n if (query.states) {\n result.states = Array.isArray(query.states)\n ? query.states\n : [query.states];\n }\n\n if (query.priorities) {\n result.priorities = Array.isArray(query.priorities)\n ? query.priorities\n : [query.priorities];\n }\n\n if (query.labels) {\n result.labels = Array.isArray(query.labels)\n ? query.labels\n : [query.labels];\n }\n\n if (query.limit) {\n result.limit = parseInt(query.limit);\n }\n\n if (query.offset) {\n result.offset = parseInt(query.offset);\n }\n\n return result;\n }\n\n private getPresetTimeRange(preset: string): TimeRange {\n const end = new Date();\n const start = new Date();\n\n switch (preset) {\n case 'today':\n start.setHours(0, 0, 0, 0);\n break;\n case '7d':\n start.setDate(start.getDate() - 7);\n break;\n case '30d':\n start.setDate(start.getDate() - 30);\n break;\n case '90d':\n start.setDate(start.getDate() - 90);\n break;\n default:\n start.setDate(start.getDate() - 7);\n }\n\n return { start, end, preset: preset as TimeRange['preset'] };\n }\n\n private convertToCSV(dashboardState: any): string {\n const tasks = dashboardState.recentTasks;\n if (!tasks || tasks.length === 0) return 'No data';\n\n const headers = Object.keys(tasks[0]).join(',');\n const rows = tasks.map((task: any) =>\n Object.values(task)\n .map((v) => (typeof v === 'object' ? JSON.stringify(v) : v))\n .join(',')\n );\n\n return [headers, ...rows].join('\\n');\n }\n\n private handleError(res: Response, error: any): void {\n console.error('Analytics API error:', error);\n res.status(500).json({\n success: false,\n error: error.message || 'Internal server error',\n });\n }\n\n setupWebSocket(server: Server): void {\n this.wss = new WebSocketServer({\n server,\n path: '/ws/analytics',\n });\n\n this.wss.on('connection', (ws: WebSocket) => {\n console.log('WebSocket client connected to analytics');\n\n const unsubscribe = this.analyticsService.subscribeToUpdates((state) => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(\n JSON.stringify({\n type: 'update',\n data: state,\n })\n );\n }\n });\n\n ws.on('message', async (message: string) => {\n try {\n const data = JSON.parse(message);\n\n if (data.type === 'subscribe') {\n const query = this.parseQuery(data.query || {});\n const state = await this.analyticsService.getDashboardState(query);\n\n ws.send(\n JSON.stringify({\n type: 'initial',\n data: state,\n })\n );\n }\n } catch (error) {\n ws.send(\n JSON.stringify({\n type: 'error',\n error: 'Invalid message format',\n })\n );\n }\n });\n\n ws.on('close', () => {\n unsubscribe();\n console.log('WebSocket client disconnected');\n });\n\n ws.on('error', (error) => {\n console.error('WebSocket error:', error);\n unsubscribe();\n });\n });\n }\n\n getRouter(): Router {\n return this.router;\n }\n\n close(): void {\n this.analyticsService.close();\n if (this.wss) {\n this.wss.close();\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { MetricsQueries } from "../queries/metrics-queries.js";
|
|
2
|
+
import { LinearClient } from "../../../integrations/linear/client.js";
|
|
3
|
+
import { PebblesTaskStore } from "../../tasks/pebbles-task-store.js";
|
|
4
|
+
import Database from "better-sqlite3";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import os from "os";
|
|
8
|
+
class AnalyticsService {
|
|
9
|
+
metricsQueries;
|
|
10
|
+
linearClient;
|
|
11
|
+
taskStore;
|
|
12
|
+
dbPath;
|
|
13
|
+
projectPath;
|
|
14
|
+
updateCallbacks = /* @__PURE__ */ new Set();
|
|
15
|
+
constructor(projectPath) {
|
|
16
|
+
this.projectPath = projectPath || process.cwd();
|
|
17
|
+
this.dbPath = path.join(this.projectPath, ".stackmemory", "analytics.db");
|
|
18
|
+
this.ensureDirectoryExists();
|
|
19
|
+
this.metricsQueries = new MetricsQueries(this.dbPath);
|
|
20
|
+
this.initializeTaskStore();
|
|
21
|
+
if (process.env.LINEAR_API_KEY) {
|
|
22
|
+
this.initializeLinearIntegration();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
initializeTaskStore() {
|
|
26
|
+
try {
|
|
27
|
+
const contextDbPath = path.join(
|
|
28
|
+
this.projectPath,
|
|
29
|
+
".stackmemory",
|
|
30
|
+
"context.db"
|
|
31
|
+
);
|
|
32
|
+
if (fs.existsSync(contextDbPath)) {
|
|
33
|
+
const db = new Database(contextDbPath);
|
|
34
|
+
this.taskStore = new PebblesTaskStore(this.projectPath, db);
|
|
35
|
+
}
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error("Failed to initialize task store:", error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
ensureDirectoryExists() {
|
|
41
|
+
const dir = path.dirname(this.dbPath);
|
|
42
|
+
if (!fs.existsSync(dir)) {
|
|
43
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async initializeLinearIntegration() {
|
|
47
|
+
try {
|
|
48
|
+
const configPath = path.join(
|
|
49
|
+
os.homedir(),
|
|
50
|
+
".stackmemory",
|
|
51
|
+
"linear-config.json"
|
|
52
|
+
);
|
|
53
|
+
if (fs.existsSync(configPath)) {
|
|
54
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
55
|
+
this.linearClient = new LinearClient(config);
|
|
56
|
+
await this.syncLinearTasks();
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error("Failed to initialize Linear integration:", error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async syncLinearTasks() {
|
|
63
|
+
await this.syncFromTaskStore();
|
|
64
|
+
if (this.linearClient) {
|
|
65
|
+
try {
|
|
66
|
+
const issues = await this.linearClient.getIssues({ limit: 100 });
|
|
67
|
+
for (const issue of issues) {
|
|
68
|
+
const task = {
|
|
69
|
+
id: issue.id,
|
|
70
|
+
title: issue.title,
|
|
71
|
+
state: this.mapLinearState(issue.state.type),
|
|
72
|
+
createdAt: new Date(issue.createdAt),
|
|
73
|
+
completedAt: issue.state.type === "completed" ? new Date(issue.updatedAt) : void 0,
|
|
74
|
+
estimatedEffort: issue.estimate ? issue.estimate * 60 : void 0,
|
|
75
|
+
assigneeId: issue.assignee?.id,
|
|
76
|
+
priority: this.mapLinearPriority(issue.priority),
|
|
77
|
+
labels: Array.isArray(issue.labels) ? issue.labels.map((l) => l.name) : issue.labels?.nodes?.map((l) => l.name) || [],
|
|
78
|
+
blockingIssues: []
|
|
79
|
+
};
|
|
80
|
+
this.metricsQueries.upsertTask(task);
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error("Failed to sync from Linear API:", error);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
await this.notifyUpdate();
|
|
87
|
+
}
|
|
88
|
+
async syncFromTaskStore() {
|
|
89
|
+
if (!this.taskStore) return 0;
|
|
90
|
+
try {
|
|
91
|
+
const allTasks = this.getAllTasksFromStore();
|
|
92
|
+
let synced = 0;
|
|
93
|
+
for (const task of allTasks) {
|
|
94
|
+
const analyticsTask = {
|
|
95
|
+
id: task.id,
|
|
96
|
+
title: task.title,
|
|
97
|
+
state: this.mapTaskStatus(task.status),
|
|
98
|
+
createdAt: new Date(task.created_at * 1e3),
|
|
99
|
+
completedAt: task.completed_at ? new Date(task.completed_at * 1e3) : void 0,
|
|
100
|
+
estimatedEffort: task.estimated_effort,
|
|
101
|
+
actualEffort: task.actual_effort,
|
|
102
|
+
assigneeId: task.assignee,
|
|
103
|
+
priority: task.priority,
|
|
104
|
+
labels: task.tags || [],
|
|
105
|
+
blockingIssues: task.depends_on || []
|
|
106
|
+
};
|
|
107
|
+
this.metricsQueries.upsertTask(analyticsTask);
|
|
108
|
+
synced++;
|
|
109
|
+
}
|
|
110
|
+
return synced;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error("Failed to sync from task store:", error);
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
getAllTasksFromStore() {
|
|
117
|
+
if (!this.taskStore) return [];
|
|
118
|
+
try {
|
|
119
|
+
const contextDbPath = path.join(
|
|
120
|
+
this.projectPath,
|
|
121
|
+
".stackmemory",
|
|
122
|
+
"context.db"
|
|
123
|
+
);
|
|
124
|
+
const db = new Database(contextDbPath);
|
|
125
|
+
const rows = db.prepare(
|
|
126
|
+
`
|
|
127
|
+
SELECT * FROM task_cache
|
|
128
|
+
ORDER BY created_at DESC
|
|
129
|
+
`
|
|
130
|
+
).all();
|
|
131
|
+
db.close();
|
|
132
|
+
return rows.map((row) => ({
|
|
133
|
+
id: row.id,
|
|
134
|
+
title: row.title,
|
|
135
|
+
description: row.description,
|
|
136
|
+
status: row.status,
|
|
137
|
+
priority: row.priority,
|
|
138
|
+
created_at: row.created_at,
|
|
139
|
+
completed_at: row.completed_at,
|
|
140
|
+
estimated_effort: row.estimated_effort,
|
|
141
|
+
actual_effort: row.actual_effort,
|
|
142
|
+
assignee: row.assignee,
|
|
143
|
+
tags: JSON.parse(row.tags || "[]"),
|
|
144
|
+
depends_on: JSON.parse(row.depends_on || "[]")
|
|
145
|
+
}));
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error("Failed to get all tasks:", error);
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
mapTaskStatus(status) {
|
|
152
|
+
const statusMap = {
|
|
153
|
+
pending: "todo",
|
|
154
|
+
in_progress: "in_progress",
|
|
155
|
+
completed: "completed",
|
|
156
|
+
blocked: "blocked",
|
|
157
|
+
cancelled: "blocked"
|
|
158
|
+
};
|
|
159
|
+
return statusMap[status] || "todo";
|
|
160
|
+
}
|
|
161
|
+
mapLinearState(linearState) {
|
|
162
|
+
const stateMap = {
|
|
163
|
+
backlog: "todo",
|
|
164
|
+
unstarted: "todo",
|
|
165
|
+
started: "in_progress",
|
|
166
|
+
completed: "completed",
|
|
167
|
+
done: "completed",
|
|
168
|
+
canceled: "blocked"
|
|
169
|
+
};
|
|
170
|
+
return stateMap[linearState.toLowerCase()] || "todo";
|
|
171
|
+
}
|
|
172
|
+
mapLinearPriority(priority) {
|
|
173
|
+
if (priority === 1) return "urgent";
|
|
174
|
+
if (priority === 2) return "high";
|
|
175
|
+
if (priority === 3) return "medium";
|
|
176
|
+
return "low";
|
|
177
|
+
}
|
|
178
|
+
async getDashboardState(query = {}) {
|
|
179
|
+
const timeRange = query.timeRange || this.getDefaultTimeRange();
|
|
180
|
+
const metrics = this.metricsQueries.getTaskMetrics({
|
|
181
|
+
...query,
|
|
182
|
+
timeRange
|
|
183
|
+
});
|
|
184
|
+
const recentTasks = this.metricsQueries.getRecentTasks({
|
|
185
|
+
...query,
|
|
186
|
+
limit: 20
|
|
187
|
+
});
|
|
188
|
+
const teamMetrics = await this.getTeamMetrics(query);
|
|
189
|
+
return {
|
|
190
|
+
metrics,
|
|
191
|
+
teamMetrics,
|
|
192
|
+
recentTasks,
|
|
193
|
+
timeRange,
|
|
194
|
+
teamFilter: query.userIds || [],
|
|
195
|
+
isLive: this.updateCallbacks.size > 0,
|
|
196
|
+
lastUpdated: /* @__PURE__ */ new Date()
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
async getTeamMetrics(query) {
|
|
200
|
+
const uniqueUserIds = /* @__PURE__ */ new Set();
|
|
201
|
+
const tasks = this.metricsQueries.getRecentTasks({ limit: 1e3 });
|
|
202
|
+
tasks.forEach((task) => {
|
|
203
|
+
if (task.assigneeId) {
|
|
204
|
+
uniqueUserIds.add(task.assigneeId);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
const teamMetrics = [];
|
|
208
|
+
const totalCompleted = tasks.filter((t) => t.state === "completed").length;
|
|
209
|
+
for (const userId of uniqueUserIds) {
|
|
210
|
+
const userQuery = { ...query, userIds: [userId] };
|
|
211
|
+
const individualMetrics = this.metricsQueries.getTaskMetrics(userQuery);
|
|
212
|
+
teamMetrics.push({
|
|
213
|
+
userId,
|
|
214
|
+
userName: await this.getUserName(userId),
|
|
215
|
+
individualMetrics,
|
|
216
|
+
contributionPercentage: totalCompleted > 0 ? individualMetrics.completedTasks / totalCompleted * 100 : 0,
|
|
217
|
+
lastActive: /* @__PURE__ */ new Date()
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return teamMetrics.sort(
|
|
221
|
+
(a, b) => b.contributionPercentage - a.contributionPercentage
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
async getUserName(userId) {
|
|
225
|
+
return userId;
|
|
226
|
+
}
|
|
227
|
+
getDefaultTimeRange() {
|
|
228
|
+
const end = /* @__PURE__ */ new Date();
|
|
229
|
+
const start = /* @__PURE__ */ new Date();
|
|
230
|
+
start.setDate(start.getDate() - 7);
|
|
231
|
+
return {
|
|
232
|
+
start,
|
|
233
|
+
end,
|
|
234
|
+
preset: "7d"
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
subscribeToUpdates(callback) {
|
|
238
|
+
this.updateCallbacks.add(callback);
|
|
239
|
+
return () => {
|
|
240
|
+
this.updateCallbacks.delete(callback);
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async notifyUpdate() {
|
|
244
|
+
const state = await this.getDashboardState();
|
|
245
|
+
this.updateCallbacks.forEach((callback) => callback(state));
|
|
246
|
+
}
|
|
247
|
+
async addTask(task) {
|
|
248
|
+
this.metricsQueries.upsertTask(task);
|
|
249
|
+
await this.notifyUpdate();
|
|
250
|
+
}
|
|
251
|
+
async updateTask(taskId, updates) {
|
|
252
|
+
const tasks = this.metricsQueries.getRecentTasks({ limit: 1 });
|
|
253
|
+
const existingTask = tasks.find((t) => t.id === taskId);
|
|
254
|
+
if (existingTask) {
|
|
255
|
+
const updatedTask = { ...existingTask, ...updates };
|
|
256
|
+
this.metricsQueries.upsertTask(updatedTask);
|
|
257
|
+
await this.notifyUpdate();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
close() {
|
|
261
|
+
this.metricsQueries.close();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
export {
|
|
265
|
+
AnalyticsService
|
|
266
|
+
};
|
|
267
|
+
//# sourceMappingURL=analytics-service.js.map
|