@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/integrations/linear/__tests__/sync-service.test.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Tests for LinearSyncService - Bidirectional sync with Linear\n */\n\nimport { describe, it, expect, beforeEach, afterEach, vi, Mock } from 'vitest';\nimport { LinearSyncService, SyncResult } from '../sync-service.js';\nimport { LinearClient } from '../client.js';\nimport { ContextService } from '../../../services/context-service.js';\nimport { ConfigService } from '../../../services/config-service.js';\nimport { TaskStatus, TaskPriority, Task } from '../../../types/task.js';\n\n// Create mock instances that can be configured\nconst mockLinearClientInstance = {\n getIssues: vi.fn(),\n updateIssue: vi.fn(),\n createIssue: vi.fn(),\n};\n\nconst mockContextServiceInstance = {\n getTaskByExternalId: vi.fn(),\n updateTask: vi.fn(),\n createTask: vi.fn(),\n getTask: vi.fn(),\n deleteTask: vi.fn(),\n getAllTasks: vi.fn(),\n};\n\nconst mockConfigServiceInstance = {\n getConfig: vi.fn(),\n};\n\n// Mock dependencies using class syntax\nvi.mock('../client.js', () => ({\n LinearClient: class {\n getIssues = mockLinearClientInstance.getIssues;\n updateIssue = mockLinearClientInstance.updateIssue;\n createIssue = mockLinearClientInstance.createIssue;\n },\n}));\n\nvi.mock('../../../services/context-service.js', () => ({\n ContextService: class {\n getTaskByExternalId = mockContextServiceInstance.getTaskByExternalId;\n updateTask = mockContextServiceInstance.updateTask;\n createTask = mockContextServiceInstance.createTask;\n getTask = mockContextServiceInstance.getTask;\n deleteTask = mockContextServiceInstance.deleteTask;\n getAllTasks = mockContextServiceInstance.getAllTasks;\n },\n}));\n\nvi.mock('../../../services/config-service.js', () => ({\n ConfigService: class {\n getConfig = mockConfigServiceInstance.getConfig;\n },\n}));\n\nvi.mock('../../../utils/logger.js', () => ({\n Logger: class {\n info = vi.fn();\n error = vi.fn();\n debug = vi.fn();\n warn = vi.fn();\n },\n}));\n\ndescribe('LinearSyncService', () => {\n let syncService: LinearSyncService;\n let originalEnv: NodeJS.ProcessEnv;\n\n beforeEach(() => {\n // Store original environment\n originalEnv = process.env;\n\n // Set required environment variable\n process.env.LINEAR_API_KEY = 'test-api-key';\n\n // Reset mock functions\n mockLinearClientInstance.getIssues.mockReset();\n mockLinearClientInstance.updateIssue.mockReset();\n mockLinearClientInstance.createIssue.mockReset();\n mockContextServiceInstance.getTaskByExternalId.mockReset();\n mockContextServiceInstance.updateTask.mockReset();\n mockContextServiceInstance.createTask.mockReset();\n mockContextServiceInstance.getTask.mockReset();\n mockContextServiceInstance.deleteTask.mockReset();\n mockContextServiceInstance.getAllTasks.mockReset();\n mockConfigServiceInstance.getConfig.mockReset();\n\n // Create sync service instance\n syncService = new LinearSyncService();\n });\n\n afterEach(() => {\n // Restore environment\n process.env = originalEnv;\n });\n\n // Aliases for cleaner test code\n const mockLinearClient = mockLinearClientInstance;\n const mockContextService = mockContextServiceInstance;\n const mockConfigService = mockConfigServiceInstance;\n\n describe('Initialization', () => {\n it('should initialize with Linear API key from environment', () => {\n // syncService is already created in beforeEach, just verify it works\n expect(syncService).toBeDefined();\n });\n\n it('should throw error when LINEAR_API_KEY is not set', () => {\n delete process.env.LINEAR_API_KEY;\n\n expect(() => {\n new LinearSyncService();\n }).toThrow('LINEAR_API_KEY environment variable not set');\n });\n\n it('should initialize services correctly', () => {\n // Just verify the service is created successfully\n expect(syncService).toBeDefined();\n });\n });\n\n describe('syncAllIssues', () => {\n beforeEach(() => {\n mockConfigService.getConfig.mockResolvedValue({\n integrations: {\n linear: {\n teamId: 'test-team-id',\n },\n },\n });\n });\n\n it('should sync all issues from Linear successfully', async () => {\n const mockIssues = [\n {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Test Issue 1',\n description: 'Description 1',\n state: { type: 'unstarted' },\n priority: 2,\n url: 'https://linear.app/issue-1',\n team: { id: 'team-1', key: 'STA' },\n labels: [{ name: 'bug' }],\n updatedAt: new Date().toISOString(),\n },\n {\n id: 'issue-2',\n identifier: 'STA-2',\n title: 'Test Issue 2',\n description: 'Description 2',\n state: { type: 'completed' },\n priority: 3,\n url: 'https://linear.app/issue-2',\n team: { id: 'team-1', key: 'STA' },\n labels: [],\n updatedAt: new Date().toISOString(),\n },\n ];\n\n mockLinearClient.getIssues.mockResolvedValue(mockIssues);\n mockContextService.getTaskByExternalId.mockResolvedValue(null); // No existing tasks\n\n const result = await syncService.syncAllIssues();\n\n expect(result.created).toBe(2);\n expect(result.updated).toBe(0);\n expect(result.errors).toHaveLength(0);\n expect(mockContextService.createTask).toHaveBeenCalledTimes(2);\n });\n\n it('should update existing tasks when they have changes', async () => {\n const mockIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Updated Title',\n description: 'Updated Description',\n state: { type: 'completed' },\n priority: 3,\n url: 'https://linear.app/issue-1',\n team: { id: 'team-1', key: 'STA' },\n labels: [{ name: 'feature' }],\n updatedAt: new Date().toISOString(),\n };\n\n const existingTask: Partial<Task> = {\n id: 'local-task-1',\n title: 'Old Title',\n description: 'Old Description',\n status: 'todo',\n priority: 'high',\n externalId: 'issue-1',\n };\n\n mockLinearClient.getIssues.mockResolvedValue([mockIssue]);\n mockContextService.getTaskByExternalId.mockResolvedValue(existingTask);\n\n const result = await syncService.syncAllIssues();\n\n expect(result.created).toBe(0);\n expect(result.updated).toBe(1);\n expect(mockContextService.updateTask).toHaveBeenCalledWith(\n 'local-task-1',\n expect.objectContaining({\n title: 'Updated Title',\n description: 'Updated Description',\n status: 'done',\n priority: 'medium',\n })\n );\n });\n\n it('should skip tasks without changes', async () => {\n const mockIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Same Title',\n description: 'Same Description',\n state: { type: 'unstarted' },\n priority: 2,\n url: 'https://linear.app/issue-1',\n team: { id: 'team-1', key: 'STA' },\n labels: [{ name: 'bug' }],\n updatedAt: new Date().toISOString(),\n };\n\n const existingTask: Partial<Task> = {\n id: 'local-task-1',\n title: 'Same Title',\n description: 'Same Description',\n status: 'todo',\n priority: 'high',\n tags: ['bug'],\n externalId: 'issue-1',\n };\n\n mockLinearClient.getIssues.mockResolvedValue([mockIssue]);\n mockContextService.getTaskByExternalId.mockResolvedValue(existingTask);\n\n const result = await syncService.syncAllIssues();\n\n expect(result.created).toBe(0);\n expect(result.updated).toBe(0);\n expect(mockContextService.updateTask).not.toHaveBeenCalled();\n });\n\n it('should handle sync errors gracefully', async () => {\n const mockIssues = [\n {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Test Issue',\n state: { type: 'unstarted' },\n team: { id: 'team-1', key: 'STA' },\n updatedAt: new Date().toISOString(),\n },\n ];\n\n mockLinearClient.getIssues.mockResolvedValue(mockIssues);\n mockContextService.getTaskByExternalId.mockRejectedValue(\n new Error('Database error')\n );\n\n const result = await syncService.syncAllIssues();\n\n expect(result.errors).toHaveLength(1);\n expect(result.errors[0]).toContain('Failed to sync STA-1');\n });\n\n it('should throw error when Linear team ID is not configured', async () => {\n mockConfigService.getConfig.mockResolvedValue({\n integrations: {},\n });\n\n const result = await syncService.syncAllIssues();\n\n expect(result.errors).toContain('Linear team ID not configured');\n });\n\n it('should handle Linear API errors', async () => {\n mockConfigService.getConfig.mockResolvedValue({\n integrations: {\n linear: { teamId: 'test-team-id' },\n },\n });\n\n mockLinearClient.getIssues.mockRejectedValue(\n new Error('Linear API error')\n );\n\n const result = await syncService.syncAllIssues();\n\n expect(result.errors).toContain('Linear API error');\n });\n });\n\n describe('syncIssueToLocal', () => {\n it('should create new local task from Linear issue', async () => {\n const mockIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'New Issue',\n description: 'Issue description',\n state: { type: 'unstarted', id: 'state-1', name: 'Todo' },\n priority: 1,\n url: 'https://linear.app/issue-1',\n team: { id: 'team-1', key: 'STA' },\n labels: [{ name: 'bug' }, { name: 'urgent' }],\n project: { id: 'proj-1', name: 'Main Project' },\n assignee: { id: 'user-1', name: 'John Doe' },\n updatedAt: new Date().toISOString(),\n };\n\n mockContextService.getTaskByExternalId.mockResolvedValue(null);\n\n const result = await syncService.syncIssueToLocal(mockIssue);\n\n expect(result).toBe('created');\n expect(mockContextService.createTask).toHaveBeenCalledWith(\n expect.objectContaining({\n title: 'New Issue',\n description: 'Issue description',\n status: 'todo',\n priority: 'urgent',\n externalId: 'issue-1',\n externalIdentifier: 'STA-1',\n externalUrl: 'https://linear.app/issue-1',\n tags: ['bug', 'urgent'],\n metadata: {\n linear: {\n stateId: 'state-1',\n stateName: 'Todo',\n assigneeId: 'user-1',\n assigneeName: 'John Doe',\n },\n },\n })\n );\n });\n\n it('should update existing local task', async () => {\n const mockIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Updated Issue',\n description: 'Updated description',\n state: { type: 'started', id: 'state-2', name: 'In Progress' },\n priority: 2,\n url: 'https://linear.app/issue-1',\n team: { id: 'team-1', key: 'STA' },\n labels: [{ name: 'feature' }],\n updatedAt: new Date().toISOString(),\n };\n\n const existingTask: Task = {\n id: 'local-1',\n title: 'Old Title',\n description: 'Old description',\n status: 'todo',\n priority: 'low',\n tags: ['old-tag'],\n externalId: 'issue-1',\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n mockContextService.getTaskByExternalId.mockResolvedValue(existingTask);\n\n const result = await syncService.syncIssueToLocal(mockIssue);\n\n expect(result).toBe('updated');\n expect(mockContextService.updateTask).toHaveBeenCalledWith(\n 'local-1',\n expect.objectContaining({\n title: 'Updated Issue',\n description: 'Updated description',\n status: 'in_progress',\n priority: 'high',\n externalId: 'issue-1',\n externalIdentifier: 'STA-1',\n externalUrl: 'https://linear.app/issue-1',\n tags: ['feature'],\n metadata: {\n linear: {\n stateId: 'state-2',\n stateName: 'In Progress',\n assigneeId: undefined,\n assigneeName: undefined,\n },\n },\n })\n );\n });\n\n it('should handle sync errors and rethrow', async () => {\n const mockIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Error Issue',\n state: { type: 'unstarted' },\n team: { id: 'team-1', key: 'STA' },\n updatedAt: new Date().toISOString(),\n };\n\n mockContextService.getTaskByExternalId.mockRejectedValue(\n new Error('Database error')\n );\n\n await expect(syncService.syncIssueToLocal(mockIssue)).rejects.toThrow(\n 'Database error'\n );\n });\n });\n\n describe('syncLocalToLinear', () => {\n beforeEach(() => {\n mockConfigService.getConfig.mockResolvedValue({\n integrations: {\n linear: {\n teamId: 'test-team-id',\n },\n },\n });\n });\n\n it('should create new Linear issue from local task', async () => {\n const mockTask: Task = {\n id: 'local-1',\n title: 'Local Task',\n description: 'Local description',\n status: 'todo',\n priority: 'high',\n tags: [],\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n const mockCreatedIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Local Task',\n url: 'https://linear.app/issue-1',\n };\n\n mockContextService.getTask.mockResolvedValue(mockTask);\n mockLinearClient.createIssue.mockResolvedValue(mockCreatedIssue);\n\n const result = await syncService.syncLocalToLinear('local-1');\n\n expect(result).toEqual(mockCreatedIssue);\n expect(mockLinearClient.createIssue).toHaveBeenCalledWith({\n title: 'Local Task',\n description: 'Local description',\n teamId: 'test-team-id',\n priority: 2, // high -> 2\n });\n expect(mockContextService.updateTask).toHaveBeenCalledWith('local-1', {\n externalId: 'issue-1',\n });\n });\n\n it('should update existing Linear issue', async () => {\n const mockTask: Task = {\n id: 'local-1',\n title: 'Updated Local Task',\n description: 'Updated description',\n status: 'in_progress',\n priority: 'medium',\n tags: [],\n externalId: 'issue-1',\n metadata: {\n linear: {\n stateId: 'state-1',\n projectId: 'proj-1',\n assigneeId: 'user-1',\n },\n },\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n const mockUpdatedIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Updated Local Task',\n };\n\n mockContextService.getTask.mockResolvedValue(mockTask);\n mockLinearClient.updateIssue.mockResolvedValue(mockUpdatedIssue);\n\n const result = await syncService.syncLocalToLinear('local-1');\n\n expect(result).toEqual(mockUpdatedIssue);\n expect(mockLinearClient.updateIssue).toHaveBeenCalledWith('issue-1', {\n title: 'Updated Local Task',\n description: 'Updated description',\n priority: 3, // medium -> 3\n stateId: 'state-1',\n });\n });\n\n it('should throw error for non-existent task', async () => {\n mockContextService.getTask.mockResolvedValue(null);\n\n await expect(\n syncService.syncLocalToLinear('non-existent')\n ).rejects.toThrow('Task non-existent not found');\n });\n\n it('should handle Linear API errors', async () => {\n const mockTask: Task = {\n id: 'local-1',\n title: 'Task',\n description: 'Test task description',\n status: 'todo',\n priority: 'medium',\n tags: [],\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n mockContextService.getTask.mockResolvedValue(mockTask);\n mockLinearClient.createIssue.mockRejectedValue(\n new Error('Linear API error')\n );\n\n await expect(syncService.syncLocalToLinear('local-1')).rejects.toThrow(\n 'Linear API error'\n );\n });\n });\n\n describe('removeLocalIssue', () => {\n it('should remove local task by Linear identifier', async () => {\n const mockTasks: Task[] = [\n {\n id: 'local-1',\n title: 'Task 1',\n description: 'Task 1 description',\n status: 'todo',\n priority: 'medium',\n tags: [],\n externalIdentifier: 'STA-1',\n createdAt: new Date(),\n updatedAt: new Date(),\n },\n {\n id: 'local-2',\n title: 'Task 2',\n description: 'Task 2 description',\n status: 'todo',\n priority: 'medium',\n tags: [],\n externalIdentifier: 'STA-2',\n createdAt: new Date(),\n updatedAt: new Date(),\n },\n ];\n\n mockContextService.getAllTasks.mockResolvedValue(mockTasks);\n\n await syncService.removeLocalIssue('STA-1');\n\n expect(mockContextService.deleteTask).toHaveBeenCalledWith('local-1');\n });\n\n it('should handle non-existent identifier gracefully', async () => {\n mockContextService.getAllTasks.mockResolvedValue([]);\n\n await expect(\n syncService.removeLocalIssue('NON-EXISTENT')\n ).resolves.not.toThrow();\n expect(mockContextService.deleteTask).not.toHaveBeenCalled();\n });\n\n it('should handle deletion errors', async () => {\n const mockTasks: Task[] = [\n {\n id: 'local-1',\n title: 'Task',\n description: 'Task description',\n status: 'todo',\n priority: 'medium',\n tags: [],\n externalIdentifier: 'STA-1',\n createdAt: new Date(),\n updatedAt: new Date(),\n },\n ];\n\n mockContextService.getAllTasks.mockResolvedValue(mockTasks);\n mockContextService.deleteTask.mockRejectedValue(\n new Error('Delete error')\n );\n\n await expect(syncService.removeLocalIssue('STA-1')).rejects.toThrow(\n 'Delete error'\n );\n });\n });\n\n describe('Status and Priority Mapping', () => {\n beforeEach(() => {\n mockConfigService.getConfig.mockResolvedValue({\n integrations: {\n linear: {\n teamId: 'test-team-id',\n },\n },\n });\n });\n\n it('should map Linear states to task statuses correctly', async () => {\n const testCases = [\n { linearState: 'backlog', expectedStatus: 'todo' },\n { linearState: 'triage', expectedStatus: 'todo' },\n { linearState: 'unstarted', expectedStatus: 'todo' },\n { linearState: 'todo', expectedStatus: 'todo' },\n { linearState: 'started', expectedStatus: 'in_progress' },\n { linearState: 'in_progress', expectedStatus: 'in_progress' },\n { linearState: 'completed', expectedStatus: 'done' },\n { linearState: 'done', expectedStatus: 'done' },\n { linearState: 'canceled', expectedStatus: 'cancelled' },\n { linearState: 'cancelled', expectedStatus: 'cancelled' },\n { linearState: 'unknown', expectedStatus: 'todo' },\n ];\n\n for (const { linearState, expectedStatus } of testCases) {\n const mockIssue = {\n id: 'test-issue',\n identifier: 'TEST-1',\n title: 'Test',\n state: { type: linearState },\n team: { id: 'team-1', key: 'TEST' },\n updatedAt: new Date().toISOString(),\n };\n\n mockContextService.getTaskByExternalId.mockResolvedValue(null);\n\n await syncService.syncIssueToLocal(mockIssue);\n\n expect(mockContextService.createTask).toHaveBeenCalledWith(\n expect.objectContaining({ status: expectedStatus })\n );\n\n mockContextService.createTask.mockClear();\n mockContextService.getTaskByExternalId.mockClear();\n }\n });\n\n it('should map Linear priorities to task priorities correctly', async () => {\n const testCases = [\n { linearPriority: 1, expectedPriority: 'urgent' },\n { linearPriority: 2, expectedPriority: 'high' },\n { linearPriority: 3, expectedPriority: 'medium' },\n { linearPriority: 4, expectedPriority: 'low' },\n { linearPriority: undefined, expectedPriority: undefined },\n ];\n\n for (const { linearPriority, expectedPriority } of testCases) {\n const mockIssue = {\n id: 'test-issue',\n identifier: 'TEST-1',\n title: 'Test',\n state: { type: 'unstarted' },\n priority: linearPriority,\n team: { id: 'team-1', key: 'TEST' },\n updatedAt: new Date().toISOString(),\n };\n\n mockContextService.getTaskByExternalId.mockResolvedValue(null);\n\n await syncService.syncIssueToLocal(mockIssue);\n\n expect(mockContextService.createTask).toHaveBeenCalledWith(\n expect.objectContaining({ priority: expectedPriority })\n );\n\n mockContextService.createTask.mockClear();\n mockContextService.getTaskByExternalId.mockClear();\n }\n });\n\n it('should map task priorities to Linear priorities correctly', async () => {\n const testCases = [\n { taskPriority: 'urgent' as TaskPriority, expectedLinearPriority: 1 },\n { taskPriority: 'high' as TaskPriority, expectedLinearPriority: 2 },\n { taskPriority: 'medium' as TaskPriority, expectedLinearPriority: 3 },\n { taskPriority: 'low' as TaskPriority, expectedLinearPriority: 4 },\n { taskPriority: undefined, expectedLinearPriority: 0 },\n ];\n\n for (const { taskPriority, expectedLinearPriority } of testCases) {\n const mockTask: Task = {\n id: 'local-1',\n title: 'Test Task',\n description: 'Test description',\n status: 'todo',\n priority: taskPriority,\n tags: [],\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n mockContextService.getTask.mockResolvedValue(mockTask);\n mockLinearClient.createIssue.mockResolvedValue({\n id: 'created',\n identifier: 'TEST-1',\n });\n\n await syncService.syncLocalToLinear('local-1');\n\n expect(mockLinearClient.createIssue).toHaveBeenCalledWith(\n expect.objectContaining({ priority: expectedLinearPriority })\n );\n\n mockLinearClient.createIssue.mockClear();\n mockContextService.getTask.mockClear();\n mockContextService.updateTask.mockClear();\n }\n });\n });\n\n describe('Change Detection', () => {\n it('should detect changes in title', async () => {\n const existing: Task = {\n id: '1',\n title: 'Old Title',\n description: 'Same',\n status: 'todo',\n priority: 'medium',\n tags: [],\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n mockContextService.getTaskByExternalId.mockResolvedValue(existing);\n\n const mockIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'New Title',\n description: 'Same',\n state: { type: 'unstarted' },\n priority: 2,\n team: { id: 'team-1', key: 'STA' },\n labels: [],\n updatedAt: new Date().toISOString(),\n };\n\n await syncService.syncIssueToLocal(mockIssue);\n\n expect(mockContextService.updateTask).toHaveBeenCalled();\n });\n\n it('should detect changes in tags', async () => {\n const existing: Task = {\n id: '1',\n title: 'Same',\n description: 'Same',\n status: 'todo',\n priority: 'medium',\n tags: ['old-tag'],\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n mockContextService.getTaskByExternalId.mockResolvedValue(existing);\n\n const mockIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Same',\n description: 'Same',\n state: { type: 'unstarted' },\n priority: 2,\n team: { id: 'team-1', key: 'STA' },\n labels: [{ name: 'new-tag' }],\n updatedAt: new Date().toISOString(),\n };\n\n await syncService.syncIssueToLocal(mockIssue);\n\n expect(mockContextService.updateTask).toHaveBeenCalled();\n });\n\n it('should not update when no changes detected', async () => {\n const existing: Task = {\n id: '1',\n title: 'Same Title',\n description: 'Same Description',\n status: 'todo',\n priority: 'high', // Linear priority 2 maps to 'high'\n tags: ['tag1'],\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n mockContextService.getTaskByExternalId.mockResolvedValue(existing);\n\n const mockIssue = {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Same Title',\n description: 'Same Description',\n state: { type: 'unstarted' },\n priority: 2, // Maps to 'high'\n team: { id: 'team-1', key: 'STA' },\n labels: [{ name: 'tag1' }],\n updatedAt: new Date().toISOString(),\n };\n\n await syncService.syncIssueToLocal(mockIssue);\n\n expect(mockContextService.updateTask).not.toHaveBeenCalled();\n });\n });\n\n describe('Error Recovery and Edge Cases', () => {\n it('should handle partial sync failures gracefully', async () => {\n const mockIssues = [\n {\n id: 'issue-1',\n identifier: 'STA-1',\n title: 'Good Issue',\n state: { type: 'unstarted' },\n team: { id: 'team-1', key: 'STA' },\n updatedAt: new Date().toISOString(),\n },\n {\n id: 'issue-2',\n identifier: 'STA-2',\n title: 'Bad Issue',\n state: { type: 'unstarted' },\n team: { id: 'team-1', key: 'STA' },\n updatedAt: new Date().toISOString(),\n },\n ];\n\n mockConfigService.getConfig.mockResolvedValue({\n integrations: { linear: { teamId: 'test-team-id' } },\n });\n\n mockLinearClient.getIssues.mockResolvedValue(mockIssues);\n mockContextService.getTaskByExternalId.mockResolvedValue(null);\n\n // First issue succeeds, second fails\n mockContextService.createTask\n .mockResolvedValueOnce('success')\n .mockRejectedValueOnce(new Error('Creation failed'));\n\n const result = await syncService.syncAllIssues();\n\n expect(result.created).toBe(1);\n expect(result.errors).toHaveLength(1);\n expect(result.errors[0]).toContain('Failed to sync STA-2');\n });\n\n it('should handle empty issues list', async () => {\n mockConfigService.getConfig.mockResolvedValue({\n integrations: { linear: { teamId: 'test-team-id' } },\n });\n\n mockLinearClient.getIssues.mockResolvedValue([]);\n\n const result = await syncService.syncAllIssues();\n\n expect(result.created).toBe(0);\n expect(result.updated).toBe(0);\n expect(result.errors).toHaveLength(0);\n });\n\n it('should handle malformed Linear issues', async () => {\n const malformedIssue = {\n // Missing required fields\n id: 'issue-1',\n title: null,\n state: null,\n team: null,\n };\n\n mockConfigService.getConfig.mockResolvedValue({\n integrations: { linear: { teamId: 'test-team-id' } },\n });\n\n mockLinearClient.getIssues.mockResolvedValue([malformedIssue]);\n\n const result = await syncService.syncAllIssues();\n\n expect(result.errors).toHaveLength(1);\n });\n\n it('should handle network timeouts gracefully', async () => {\n mockConfigService.getConfig.mockResolvedValue({\n integrations: { linear: { teamId: 'test-team-id' } },\n });\n\n const timeoutError = new Error('Request timeout');\n timeoutError.name = 'TimeoutError';\n\n mockLinearClient.getIssues.mockRejectedValue(timeoutError);\n\n const result = await syncService.syncAllIssues();\n\n expect(result.errors).toHaveLength(1);\n expect(result.errors[0]).toContain('Request timeout');\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "AAIA,SAAS,UAAU,IAAI,QAAQ,YAAY,WAAW,UAAgB;AACtE,SAAS,yBAAqC;AAO9C,MAAM,2BAA2B;AAAA,EAC/B,WAAW,GAAG,GAAG;AAAA,EACjB,aAAa,GAAG,GAAG;AAAA,EACnB,aAAa,GAAG,GAAG;AACrB;AAEA,MAAM,6BAA6B;AAAA,EACjC,qBAAqB,GAAG,GAAG;AAAA,EAC3B,YAAY,GAAG,GAAG;AAAA,EAClB,YAAY,GAAG,GAAG;AAAA,EAClB,SAAS,GAAG,GAAG;AAAA,EACf,YAAY,GAAG,GAAG;AAAA,EAClB,aAAa,GAAG,GAAG;AACrB;AAEA,MAAM,4BAA4B;AAAA,EAChC,WAAW,GAAG,GAAG;AACnB;AAGA,GAAG,KAAK,gBAAgB,OAAO;AAAA,EAC7B,cAAc,MAAM;AAAA,IAClB,YAAY,yBAAyB;AAAA,IACrC,cAAc,yBAAyB;AAAA,IACvC,cAAc,yBAAyB;AAAA,EACzC;AACF,EAAE;AAEF,GAAG,KAAK,wCAAwC,OAAO;AAAA,EACrD,gBAAgB,MAAM;AAAA,IACpB,sBAAsB,2BAA2B;AAAA,IACjD,aAAa,2BAA2B;AAAA,IACxC,aAAa,2BAA2B;AAAA,IACxC,UAAU,2BAA2B;AAAA,IACrC,aAAa,2BAA2B;AAAA,IACxC,cAAc,2BAA2B;AAAA,EAC3C;AACF,EAAE;AAEF,GAAG,KAAK,uCAAuC,OAAO;AAAA,EACpD,eAAe,MAAM;AAAA,IACnB,YAAY,0BAA0B;AAAA,EACxC;AACF,EAAE;AAEF,GAAG,KAAK,4BAA4B,OAAO;AAAA,EACzC,QAAQ,MAAM;AAAA,IACZ,OAAO,GAAG,GAAG;AAAA,IACb,QAAQ,GAAG,GAAG;AAAA,IACd,QAAQ,GAAG,GAAG;AAAA,IACd,OAAO,GAAG,GAAG;AAAA,EACf;AACF,EAAE;AAEF,SAAS,qBAAqB,MAAM;AAClC,MAAI;AACJ,MAAI;AAEJ,aAAW,MAAM;AAEf,kBAAc,QAAQ;AAGtB,YAAQ,IAAI,iBAAiB;AAG7B,6BAAyB,UAAU,UAAU;AAC7C,6BAAyB,YAAY,UAAU;AAC/C,6BAAyB,YAAY,UAAU;AAC/C,+BAA2B,oBAAoB,UAAU;AACzD,+BAA2B,WAAW,UAAU;AAChD,+BAA2B,WAAW,UAAU;AAChD,+BAA2B,QAAQ,UAAU;AAC7C,+BAA2B,WAAW,UAAU;AAChD,+BAA2B,YAAY,UAAU;AACjD,8BAA0B,UAAU,UAAU;AAG9C,kBAAc,IAAI,kBAAkB;AAAA,EACtC,CAAC;AAED,YAAU,MAAM;AAEd,YAAQ,MAAM;AAAA,EAChB,CAAC;AAGD,QAAM,mBAAmB;AACzB,QAAM,qBAAqB;AAC3B,QAAM,oBAAoB;AAE1B,WAAS,kBAAkB,MAAM;AAC/B,OAAG,0DAA0D,MAAM;AAEjE,aAAO,WAAW,EAAE,YAAY;AAAA,IAClC,CAAC;AAED,OAAG,qDAAqD,MAAM;AAC5D,aAAO,QAAQ,IAAI;AAEnB,aAAO,MAAM;AACX,YAAI,kBAAkB;AAAA,MACxB,CAAC,EAAE,QAAQ,6CAA6C;AAAA,IAC1D,CAAC;AAED,OAAG,wCAAwC,MAAM;AAE/C,aAAO,WAAW,EAAE,YAAY;AAAA,IAClC,CAAC;AAAA,EACH,CAAC;AAED,WAAS,iBAAiB,MAAM;AAC9B,eAAW,MAAM;AACf,wBAAkB,UAAU,kBAAkB;AAAA,QAC5C,cAAc;AAAA,UACZ,QAAQ;AAAA,YACN,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,OAAG,mDAAmD,YAAY;AAChE,YAAM,aAAa;AAAA,QACjB;AAAA,UACE,IAAI;AAAA,UACJ,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO,EAAE,MAAM,YAAY;AAAA,UAC3B,UAAU;AAAA,UACV,KAAK;AAAA,UACL,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,UACjC,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAC;AAAA,UACxB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO,EAAE,MAAM,YAAY;AAAA,UAC3B,UAAU;AAAA,UACV,KAAK;AAAA,UACL,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,UACjC,QAAQ,CAAC;AAAA,UACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,MACF;AAEA,uBAAiB,UAAU,kBAAkB,UAAU;AACvD,yBAAmB,oBAAoB,kBAAkB,IAAI;AAE7D,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,OAAO,EAAE,KAAK,CAAC;AAC7B,aAAO,OAAO,OAAO,EAAE,KAAK,CAAC;AAC7B,aAAO,OAAO,MAAM,EAAE,aAAa,CAAC;AACpC,aAAO,mBAAmB,UAAU,EAAE,sBAAsB,CAAC;AAAA,IAC/D,CAAC;AAED,OAAG,uDAAuD,YAAY;AACpE,YAAM,YAAY;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO,EAAE,MAAM,YAAY;AAAA,QAC3B,UAAU;AAAA,QACV,KAAK;AAAA,QACL,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,QACjC,QAAQ,CAAC,EAAE,MAAM,UAAU,CAAC;AAAA,QAC5B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAEA,YAAM,eAA8B;AAAA,QAClC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,YAAY;AAAA,MACd;AAEA,uBAAiB,UAAU,kBAAkB,CAAC,SAAS,CAAC;AACxD,yBAAmB,oBAAoB,kBAAkB,YAAY;AAErE,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,OAAO,EAAE,KAAK,CAAC;AAC7B,aAAO,OAAO,OAAO,EAAE,KAAK,CAAC;AAC7B,aAAO,mBAAmB,UAAU,EAAE;AAAA,QACpC;AAAA,QACA,OAAO,iBAAiB;AAAA,UACtB,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,OAAG,qCAAqC,YAAY;AAClD,YAAM,YAAY;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO,EAAE,MAAM,YAAY;AAAA,QAC3B,UAAU;AAAA,QACV,KAAK;AAAA,QACL,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,QACjC,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAC;AAAA,QACxB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAEA,YAAM,eAA8B;AAAA,QAClC,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,MAAM,CAAC,KAAK;AAAA,QACZ,YAAY;AAAA,MACd;AAEA,uBAAiB,UAAU,kBAAkB,CAAC,SAAS,CAAC;AACxD,yBAAmB,oBAAoB,kBAAkB,YAAY;AAErE,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,OAAO,EAAE,KAAK,CAAC;AAC7B,aAAO,OAAO,OAAO,EAAE,KAAK,CAAC;AAC7B,aAAO,mBAAmB,UAAU,EAAE,IAAI,iBAAiB;AAAA,IAC7D,CAAC;AAED,OAAG,wCAAwC,YAAY;AACrD,YAAM,aAAa;AAAA,QACjB;AAAA,UACE,IAAI;AAAA,UACJ,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,OAAO,EAAE,MAAM,YAAY;AAAA,UAC3B,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,UACjC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,MACF;AAEA,uBAAiB,UAAU,kBAAkB,UAAU;AACvD,yBAAmB,oBAAoB;AAAA,QACrC,IAAI,MAAM,gBAAgB;AAAA,MAC5B;AAEA,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,MAAM,EAAE,aAAa,CAAC;AACpC,aAAO,OAAO,OAAO,CAAC,CAAC,EAAE,UAAU,sBAAsB;AAAA,IAC3D,CAAC;AAED,OAAG,4DAA4D,YAAY;AACzE,wBAAkB,UAAU,kBAAkB;AAAA,QAC5C,cAAc,CAAC;AAAA,MACjB,CAAC;AAED,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,MAAM,EAAE,UAAU,+BAA+B;AAAA,IACjE,CAAC;AAED,OAAG,mCAAmC,YAAY;AAChD,wBAAkB,UAAU,kBAAkB;AAAA,QAC5C,cAAc;AAAA,UACZ,QAAQ,EAAE,QAAQ,eAAe;AAAA,QACnC;AAAA,MACF,CAAC;AAED,uBAAiB,UAAU;AAAA,QACzB,IAAI,MAAM,kBAAkB;AAAA,MAC9B;AAEA,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,MAAM,EAAE,UAAU,kBAAkB;AAAA,IACpD,CAAC;AAAA,EACH,CAAC;AAED,WAAS,oBAAoB,MAAM;AACjC,OAAG,kDAAkD,YAAY;AAC/D,YAAM,YAAY;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO,EAAE,MAAM,aAAa,IAAI,WAAW,MAAM,OAAO;AAAA,QACxD,UAAU;AAAA,QACV,KAAK;AAAA,QACL,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,QACjC,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,EAAE,MAAM,SAAS,CAAC;AAAA,QAC5C,SAAS,EAAE,IAAI,UAAU,MAAM,eAAe;AAAA,QAC9C,UAAU,EAAE,IAAI,UAAU,MAAM,WAAW;AAAA,QAC3C,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAEA,yBAAmB,oBAAoB,kBAAkB,IAAI;AAE7D,YAAM,SAAS,MAAM,YAAY,iBAAiB,SAAS;AAE3D,aAAO,MAAM,EAAE,KAAK,SAAS;AAC7B,aAAO,mBAAmB,UAAU,EAAE;AAAA,QACpC,OAAO,iBAAiB;AAAA,UACtB,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,oBAAoB;AAAA,UACpB,aAAa;AAAA,UACb,MAAM,CAAC,OAAO,QAAQ;AAAA,UACtB,UAAU;AAAA,YACR,QAAQ;AAAA,cACN,SAAS;AAAA,cACT,WAAW;AAAA,cACX,YAAY;AAAA,cACZ,cAAc;AAAA,YAChB;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,OAAG,qCAAqC,YAAY;AAClD,YAAM,YAAY;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO,EAAE,MAAM,WAAW,IAAI,WAAW,MAAM,cAAc;AAAA,QAC7D,UAAU;AAAA,QACV,KAAK;AAAA,QACL,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,QACjC,QAAQ,CAAC,EAAE,MAAM,UAAU,CAAC;AAAA,QAC5B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAEA,YAAM,eAAqB;AAAA,QACzB,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,MAAM,CAAC,SAAS;AAAA,QAChB,YAAY;AAAA,QACZ,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB;AAEA,yBAAmB,oBAAoB,kBAAkB,YAAY;AAErE,YAAM,SAAS,MAAM,YAAY,iBAAiB,SAAS;AAE3D,aAAO,MAAM,EAAE,KAAK,SAAS;AAC7B,aAAO,mBAAmB,UAAU,EAAE;AAAA,QACpC;AAAA,QACA,OAAO,iBAAiB;AAAA,UACtB,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,oBAAoB;AAAA,UACpB,aAAa;AAAA,UACb,MAAM,CAAC,SAAS;AAAA,UAChB,UAAU;AAAA,YACR,QAAQ;AAAA,cACN,SAAS;AAAA,cACT,WAAW;AAAA,cACX,YAAY;AAAA,cACZ,cAAc;AAAA,YAChB;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,OAAG,yCAAyC,YAAY;AACtD,YAAM,YAAY;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,OAAO,EAAE,MAAM,YAAY;AAAA,QAC3B,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,QACjC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAEA,yBAAmB,oBAAoB;AAAA,QACrC,IAAI,MAAM,gBAAgB;AAAA,MAC5B;AAEA,YAAM,OAAO,YAAY,iBAAiB,SAAS,CAAC,EAAE,QAAQ;AAAA,QAC5D;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,WAAS,qBAAqB,MAAM;AAClC,eAAW,MAAM;AACf,wBAAkB,UAAU,kBAAkB;AAAA,QAC5C,cAAc;AAAA,UACZ,QAAQ;AAAA,YACN,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,OAAG,kDAAkD,YAAY;AAC/D,YAAM,WAAiB;AAAA,QACrB,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,MAAM,CAAC;AAAA,QACP,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB;AAEA,YAAM,mBAAmB;AAAA,QACvB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,KAAK;AAAA,MACP;AAEA,yBAAmB,QAAQ,kBAAkB,QAAQ;AACrD,uBAAiB,YAAY,kBAAkB,gBAAgB;AAE/D,YAAM,SAAS,MAAM,YAAY,kBAAkB,SAAS;AAE5D,aAAO,MAAM,EAAE,QAAQ,gBAAgB;AACvC,aAAO,iBAAiB,WAAW,EAAE,qBAAqB;AAAA,QACxD,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA;AAAA,MACZ,CAAC;AACD,aAAO,mBAAmB,UAAU,EAAE,qBAAqB,WAAW;AAAA,QACpE,YAAY;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAED,OAAG,uCAAuC,YAAY;AACpD,YAAM,WAAiB;AAAA,QACrB,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,MAAM,CAAC;AAAA,QACP,YAAY;AAAA,QACZ,UAAU;AAAA,UACR,QAAQ;AAAA,YACN,SAAS;AAAA,YACT,WAAW;AAAA,YACX,YAAY;AAAA,UACd;AAAA,QACF;AAAA,QACA,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB;AAEA,YAAM,mBAAmB;AAAA,QACvB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,MACT;AAEA,yBAAmB,QAAQ,kBAAkB,QAAQ;AACrD,uBAAiB,YAAY,kBAAkB,gBAAgB;AAE/D,YAAM,SAAS,MAAM,YAAY,kBAAkB,SAAS;AAE5D,aAAO,MAAM,EAAE,QAAQ,gBAAgB;AACvC,aAAO,iBAAiB,WAAW,EAAE,qBAAqB,WAAW;AAAA,QACnE,OAAO;AAAA,QACP,aAAa;AAAA,QACb,UAAU;AAAA;AAAA,QACV,SAAS;AAAA,MACX,CAAC;AAAA,IACH,CAAC;AAED,OAAG,4CAA4C,YAAY;AACzD,yBAAmB,QAAQ,kBAAkB,IAAI;AAEjD,YAAM;AAAA,QACJ,YAAY,kBAAkB,cAAc;AAAA,MAC9C,EAAE,QAAQ,QAAQ,6BAA6B;AAAA,IACjD,CAAC;AAED,OAAG,mCAAmC,YAAY;AAChD,YAAM,WAAiB;AAAA,QACrB,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,MAAM,CAAC;AAAA,QACP,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB;AAEA,yBAAmB,QAAQ,kBAAkB,QAAQ;AACrD,uBAAiB,YAAY;AAAA,QAC3B,IAAI,MAAM,kBAAkB;AAAA,MAC9B;AAEA,YAAM,OAAO,YAAY,kBAAkB,SAAS,CAAC,EAAE,QAAQ;AAAA,QAC7D;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,WAAS,oBAAoB,MAAM;AACjC,OAAG,iDAAiD,YAAY;AAC9D,YAAM,YAAoB;AAAA,QACxB;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,MAAM,CAAC;AAAA,UACP,oBAAoB;AAAA,UACpB,WAAW,oBAAI,KAAK;AAAA,UACpB,WAAW,oBAAI,KAAK;AAAA,QACtB;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,MAAM,CAAC;AAAA,UACP,oBAAoB;AAAA,UACpB,WAAW,oBAAI,KAAK;AAAA,UACpB,WAAW,oBAAI,KAAK;AAAA,QACtB;AAAA,MACF;AAEA,yBAAmB,YAAY,kBAAkB,SAAS;AAE1D,YAAM,YAAY,iBAAiB,OAAO;AAE1C,aAAO,mBAAmB,UAAU,EAAE,qBAAqB,SAAS;AAAA,IACtE,CAAC;AAED,OAAG,oDAAoD,YAAY;AACjE,yBAAmB,YAAY,kBAAkB,CAAC,CAAC;AAEnD,YAAM;AAAA,QACJ,YAAY,iBAAiB,cAAc;AAAA,MAC7C,EAAE,SAAS,IAAI,QAAQ;AACvB,aAAO,mBAAmB,UAAU,EAAE,IAAI,iBAAiB;AAAA,IAC7D,CAAC;AAED,OAAG,iCAAiC,YAAY;AAC9C,YAAM,YAAoB;AAAA,QACxB;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,MAAM,CAAC;AAAA,UACP,oBAAoB;AAAA,UACpB,WAAW,oBAAI,KAAK;AAAA,UACpB,WAAW,oBAAI,KAAK;AAAA,QACtB;AAAA,MACF;AAEA,yBAAmB,YAAY,kBAAkB,SAAS;AAC1D,yBAAmB,WAAW;AAAA,QAC5B,IAAI,MAAM,cAAc;AAAA,MAC1B;AAEA,YAAM,OAAO,YAAY,iBAAiB,OAAO,CAAC,EAAE,QAAQ;AAAA,QAC1D;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,WAAS,+BAA+B,MAAM;AAC5C,eAAW,MAAM;AACf,wBAAkB,UAAU,kBAAkB;AAAA,QAC5C,cAAc;AAAA,UACZ,QAAQ;AAAA,YACN,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,OAAG,uDAAuD,YAAY;AACpE,YAAM,YAAY;AAAA,QAChB,EAAE,aAAa,WAAW,gBAAgB,OAAO;AAAA,QACjD,EAAE,aAAa,UAAU,gBAAgB,OAAO;AAAA,QAChD,EAAE,aAAa,aAAa,gBAAgB,OAAO;AAAA,QACnD,EAAE,aAAa,QAAQ,gBAAgB,OAAO;AAAA,QAC9C,EAAE,aAAa,WAAW,gBAAgB,cAAc;AAAA,QACxD,EAAE,aAAa,eAAe,gBAAgB,cAAc;AAAA,QAC5D,EAAE,aAAa,aAAa,gBAAgB,OAAO;AAAA,QACnD,EAAE,aAAa,QAAQ,gBAAgB,OAAO;AAAA,QAC9C,EAAE,aAAa,YAAY,gBAAgB,YAAY;AAAA,QACvD,EAAE,aAAa,aAAa,gBAAgB,YAAY;AAAA,QACxD,EAAE,aAAa,WAAW,gBAAgB,OAAO;AAAA,MACnD;AAEA,iBAAW,EAAE,aAAa,eAAe,KAAK,WAAW;AACvD,cAAM,YAAY;AAAA,UAChB,IAAI;AAAA,UACJ,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,OAAO,EAAE,MAAM,YAAY;AAAA,UAC3B,MAAM,EAAE,IAAI,UAAU,KAAK,OAAO;AAAA,UAClC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAEA,2BAAmB,oBAAoB,kBAAkB,IAAI;AAE7D,cAAM,YAAY,iBAAiB,SAAS;AAE5C,eAAO,mBAAmB,UAAU,EAAE;AAAA,UACpC,OAAO,iBAAiB,EAAE,QAAQ,eAAe,CAAC;AAAA,QACpD;AAEA,2BAAmB,WAAW,UAAU;AACxC,2BAAmB,oBAAoB,UAAU;AAAA,MACnD;AAAA,IACF,CAAC;AAED,OAAG,6DAA6D,YAAY;AAC1E,YAAM,YAAY;AAAA,QAChB,EAAE,gBAAgB,GAAG,kBAAkB,SAAS;AAAA,QAChD,EAAE,gBAAgB,GAAG,kBAAkB,OAAO;AAAA,QAC9C,EAAE,gBAAgB,GAAG,kBAAkB,SAAS;AAAA,QAChD,EAAE,gBAAgB,GAAG,kBAAkB,MAAM;AAAA,QAC7C,EAAE,gBAAgB,QAAW,kBAAkB,OAAU;AAAA,MAC3D;AAEA,iBAAW,EAAE,gBAAgB,iBAAiB,KAAK,WAAW;AAC5D,cAAM,YAAY;AAAA,UAChB,IAAI;AAAA,UACJ,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,OAAO,EAAE,MAAM,YAAY;AAAA,UAC3B,UAAU;AAAA,UACV,MAAM,EAAE,IAAI,UAAU,KAAK,OAAO;AAAA,UAClC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAEA,2BAAmB,oBAAoB,kBAAkB,IAAI;AAE7D,cAAM,YAAY,iBAAiB,SAAS;AAE5C,eAAO,mBAAmB,UAAU,EAAE;AAAA,UACpC,OAAO,iBAAiB,EAAE,UAAU,iBAAiB,CAAC;AAAA,QACxD;AAEA,2BAAmB,WAAW,UAAU;AACxC,2BAAmB,oBAAoB,UAAU;AAAA,MACnD;AAAA,IACF,CAAC;AAED,OAAG,6DAA6D,YAAY;AAC1E,YAAM,YAAY;AAAA,QAChB,EAAE,cAAc,UAA0B,wBAAwB,EAAE;AAAA,QACpE,EAAE,cAAc,QAAwB,wBAAwB,EAAE;AAAA,QAClE,EAAE,cAAc,UAA0B,wBAAwB,EAAE;AAAA,QACpE,EAAE,cAAc,OAAuB,wBAAwB,EAAE;AAAA,QACjE,EAAE,cAAc,QAAW,wBAAwB,EAAE;AAAA,MACvD;AAEA,iBAAW,EAAE,cAAc,uBAAuB,KAAK,WAAW;AAChE,cAAM,WAAiB;AAAA,UACrB,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,MAAM,CAAC;AAAA,UACP,WAAW,oBAAI,KAAK;AAAA,UACpB,WAAW,oBAAI,KAAK;AAAA,QACtB;AAEA,2BAAmB,QAAQ,kBAAkB,QAAQ;AACrD,yBAAiB,YAAY,kBAAkB;AAAA,UAC7C,IAAI;AAAA,UACJ,YAAY;AAAA,QACd,CAAC;AAED,cAAM,YAAY,kBAAkB,SAAS;AAE7C,eAAO,iBAAiB,WAAW,EAAE;AAAA,UACnC,OAAO,iBAAiB,EAAE,UAAU,uBAAuB,CAAC;AAAA,QAC9D;AAEA,yBAAiB,YAAY,UAAU;AACvC,2BAAmB,QAAQ,UAAU;AACrC,2BAAmB,WAAW,UAAU;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,WAAS,oBAAoB,MAAM;AACjC,OAAG,kCAAkC,YAAY;AAC/C,YAAM,WAAiB;AAAA,QACrB,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,MAAM,CAAC;AAAA,QACP,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB;AAEA,yBAAmB,oBAAoB,kBAAkB,QAAQ;AAEjE,YAAM,YAAY;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO,EAAE,MAAM,YAAY;AAAA,QAC3B,UAAU;AAAA,QACV,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,QACjC,QAAQ,CAAC;AAAA,QACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAEA,YAAM,YAAY,iBAAiB,SAAS;AAE5C,aAAO,mBAAmB,UAAU,EAAE,iBAAiB;AAAA,IACzD,CAAC;AAED,OAAG,iCAAiC,YAAY;AAC9C,YAAM,WAAiB;AAAA,QACrB,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,MAAM,CAAC,SAAS;AAAA,QAChB,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB;AAEA,yBAAmB,oBAAoB,kBAAkB,QAAQ;AAEjE,YAAM,YAAY;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO,EAAE,MAAM,YAAY;AAAA,QAC3B,UAAU;AAAA,QACV,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,QACjC,QAAQ,CAAC,EAAE,MAAM,UAAU,CAAC;AAAA,QAC5B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAEA,YAAM,YAAY,iBAAiB,SAAS;AAE5C,aAAO,mBAAmB,UAAU,EAAE,iBAAiB;AAAA,IACzD,CAAC;AAED,OAAG,8CAA8C,YAAY;AAC3D,YAAM,WAAiB;AAAA,QACrB,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA;AAAA,QACV,MAAM,CAAC,MAAM;AAAA,QACb,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB;AAEA,yBAAmB,oBAAoB,kBAAkB,QAAQ;AAEjE,YAAM,YAAY;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO,EAAE,MAAM,YAAY;AAAA,QAC3B,UAAU;AAAA;AAAA,QACV,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,QACjC,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;AAAA,QACzB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAEA,YAAM,YAAY,iBAAiB,SAAS;AAE5C,aAAO,mBAAmB,UAAU,EAAE,IAAI,iBAAiB;AAAA,IAC7D,CAAC;AAAA,EACH,CAAC;AAED,WAAS,iCAAiC,MAAM;AAC9C,OAAG,kDAAkD,YAAY;AAC/D,YAAM,aAAa;AAAA,QACjB;AAAA,UACE,IAAI;AAAA,UACJ,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,OAAO,EAAE,MAAM,YAAY;AAAA,UAC3B,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,UACjC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,QACA;AAAA,UACE,IAAI;AAAA,UACJ,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,OAAO,EAAE,MAAM,YAAY;AAAA,UAC3B,MAAM,EAAE,IAAI,UAAU,KAAK,MAAM;AAAA,UACjC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,MACF;AAEA,wBAAkB,UAAU,kBAAkB;AAAA,QAC5C,cAAc,EAAE,QAAQ,EAAE,QAAQ,eAAe,EAAE;AAAA,MACrD,CAAC;AAED,uBAAiB,UAAU,kBAAkB,UAAU;AACvD,yBAAmB,oBAAoB,kBAAkB,IAAI;AAG7D,yBAAmB,WAChB,sBAAsB,SAAS,EAC/B,sBAAsB,IAAI,MAAM,iBAAiB,CAAC;AAErD,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,OAAO,EAAE,KAAK,CAAC;AAC7B,aAAO,OAAO,MAAM,EAAE,aAAa,CAAC;AACpC,aAAO,OAAO,OAAO,CAAC,CAAC,EAAE,UAAU,sBAAsB;AAAA,IAC3D,CAAC;AAED,OAAG,mCAAmC,YAAY;AAChD,wBAAkB,UAAU,kBAAkB;AAAA,QAC5C,cAAc,EAAE,QAAQ,EAAE,QAAQ,eAAe,EAAE;AAAA,MACrD,CAAC;AAED,uBAAiB,UAAU,kBAAkB,CAAC,CAAC;AAE/C,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,OAAO,EAAE,KAAK,CAAC;AAC7B,aAAO,OAAO,OAAO,EAAE,KAAK,CAAC;AAC7B,aAAO,OAAO,MAAM,EAAE,aAAa,CAAC;AAAA,IACtC,CAAC;AAED,OAAG,yCAAyC,YAAY;AACtD,YAAM,iBAAiB;AAAA;AAAA,QAErB,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAEA,wBAAkB,UAAU,kBAAkB;AAAA,QAC5C,cAAc,EAAE,QAAQ,EAAE,QAAQ,eAAe,EAAE;AAAA,MACrD,CAAC;AAED,uBAAiB,UAAU,kBAAkB,CAAC,cAAc,CAAC;AAE7D,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,MAAM,EAAE,aAAa,CAAC;AAAA,IACtC,CAAC;AAED,OAAG,6CAA6C,YAAY;AAC1D,wBAAkB,UAAU,kBAAkB;AAAA,QAC5C,cAAc,EAAE,QAAQ,EAAE,QAAQ,eAAe,EAAE;AAAA,MACrD,CAAC;AAED,YAAM,eAAe,IAAI,MAAM,iBAAiB;AAChD,mBAAa,OAAO;AAEpB,uBAAiB,UAAU,kBAAkB,YAAY;AAEzD,YAAM,SAAS,MAAM,YAAY,cAAc;AAE/C,aAAO,OAAO,MAAM,EAAE,aAAa,CAAC;AACpC,aAAO,OAAO,OAAO,CAAC,CAAC,EAAE,UAAU,iBAAiB;AAAA,IACtD,CAAC;AAAA,EACH,CAAC;AACH,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "crypto";
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { logger } from "../../core/monitoring/logger.js";
|
|
5
|
+
class LinearAuthManager {
|
|
6
|
+
configPath;
|
|
7
|
+
tokensPath;
|
|
8
|
+
config;
|
|
9
|
+
constructor(projectRoot) {
|
|
10
|
+
const configDir = join(projectRoot, ".stackmemory");
|
|
11
|
+
this.configPath = join(configDir, "linear-config.json");
|
|
12
|
+
this.tokensPath = join(configDir, "linear-tokens.json");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Check if Linear integration is configured
|
|
16
|
+
*/
|
|
17
|
+
isConfigured() {
|
|
18
|
+
return existsSync(this.configPath) && existsSync(this.tokensPath);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Save OAuth application configuration
|
|
22
|
+
*/
|
|
23
|
+
saveConfig(config) {
|
|
24
|
+
writeFileSync(this.configPath, JSON.stringify(config, null, 2));
|
|
25
|
+
this.config = config;
|
|
26
|
+
logger.info("Linear OAuth configuration saved");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Load OAuth configuration
|
|
30
|
+
*/
|
|
31
|
+
loadConfig() {
|
|
32
|
+
if (!existsSync(this.configPath)) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const configData = readFileSync(this.configPath, "utf8");
|
|
37
|
+
this.config = JSON.parse(configData);
|
|
38
|
+
return this.config;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
logger.error("Failed to load Linear configuration:", error);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Generate OAuth authorization URL with PKCE
|
|
46
|
+
*/
|
|
47
|
+
generateAuthUrl(state) {
|
|
48
|
+
if (!this.config) {
|
|
49
|
+
throw new Error("Linear OAuth configuration not loaded");
|
|
50
|
+
}
|
|
51
|
+
const codeVerifier = randomBytes(32).toString("base64url");
|
|
52
|
+
const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");
|
|
53
|
+
const params = new URLSearchParams({
|
|
54
|
+
client_id: this.config.clientId,
|
|
55
|
+
redirect_uri: this.config.redirectUri,
|
|
56
|
+
response_type: "code",
|
|
57
|
+
scope: this.config.scopes.join(" "),
|
|
58
|
+
code_challenge: codeChallenge,
|
|
59
|
+
code_challenge_method: "S256",
|
|
60
|
+
actor: "app"
|
|
61
|
+
// Enable actor authorization for service accounts
|
|
62
|
+
});
|
|
63
|
+
if (state) {
|
|
64
|
+
params.set("state", state);
|
|
65
|
+
}
|
|
66
|
+
const authUrl = `https://linear.app/oauth/authorize?${params.toString()}`;
|
|
67
|
+
return { url: authUrl, codeVerifier };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Exchange authorization code for access token
|
|
71
|
+
*/
|
|
72
|
+
async exchangeCodeForToken(authCode, codeVerifier) {
|
|
73
|
+
if (!this.config) {
|
|
74
|
+
throw new Error("Linear OAuth configuration not loaded");
|
|
75
|
+
}
|
|
76
|
+
const tokenUrl = "https://api.linear.app/oauth/token";
|
|
77
|
+
const body = new URLSearchParams({
|
|
78
|
+
grant_type: "authorization_code",
|
|
79
|
+
client_id: this.config.clientId,
|
|
80
|
+
client_secret: this.config.clientSecret,
|
|
81
|
+
redirect_uri: this.config.redirectUri,
|
|
82
|
+
code: authCode,
|
|
83
|
+
code_verifier: codeVerifier
|
|
84
|
+
});
|
|
85
|
+
const response = await fetch(tokenUrl, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: {
|
|
88
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
89
|
+
Accept: "application/json"
|
|
90
|
+
},
|
|
91
|
+
body: body.toString()
|
|
92
|
+
});
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
const errorText = await response.text();
|
|
95
|
+
throw new Error(`Token exchange failed: ${response.status} ${errorText}`);
|
|
96
|
+
}
|
|
97
|
+
const result = await response.json();
|
|
98
|
+
const expiresAt = Date.now() + result.expiresIn * 1e3;
|
|
99
|
+
const tokens = {
|
|
100
|
+
accessToken: result.accessToken,
|
|
101
|
+
refreshToken: result.refreshToken,
|
|
102
|
+
expiresAt,
|
|
103
|
+
scope: result.scope.split(" ")
|
|
104
|
+
};
|
|
105
|
+
this.saveTokens(tokens);
|
|
106
|
+
return tokens;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Refresh access token using refresh token
|
|
110
|
+
*/
|
|
111
|
+
async refreshAccessToken() {
|
|
112
|
+
if (!this.config) {
|
|
113
|
+
throw new Error("Linear OAuth configuration not loaded");
|
|
114
|
+
}
|
|
115
|
+
const currentTokens = this.loadTokens();
|
|
116
|
+
if (!currentTokens?.refreshToken) {
|
|
117
|
+
throw new Error("No refresh token available");
|
|
118
|
+
}
|
|
119
|
+
const tokenUrl = "https://api.linear.app/oauth/token";
|
|
120
|
+
const body = new URLSearchParams({
|
|
121
|
+
grant_type: "refresh_token",
|
|
122
|
+
client_id: this.config.clientId,
|
|
123
|
+
client_secret: this.config.clientSecret,
|
|
124
|
+
refresh_token: currentTokens.refreshToken
|
|
125
|
+
});
|
|
126
|
+
const response = await fetch(tokenUrl, {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: {
|
|
129
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
130
|
+
Accept: "application/json"
|
|
131
|
+
},
|
|
132
|
+
body: body.toString()
|
|
133
|
+
});
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
const errorText = await response.text();
|
|
136
|
+
throw new Error(`Token refresh failed: ${response.status} ${errorText}`);
|
|
137
|
+
}
|
|
138
|
+
const result = await response.json();
|
|
139
|
+
const tokens = {
|
|
140
|
+
accessToken: result.accessToken,
|
|
141
|
+
refreshToken: result.refreshToken || currentTokens.refreshToken,
|
|
142
|
+
expiresAt: Date.now() + result.expiresIn * 1e3,
|
|
143
|
+
scope: result.scope.split(" ")
|
|
144
|
+
};
|
|
145
|
+
this.saveTokens(tokens);
|
|
146
|
+
return tokens;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get valid access token (refresh if needed)
|
|
150
|
+
*/
|
|
151
|
+
async getValidToken() {
|
|
152
|
+
const tokens = this.loadTokens();
|
|
153
|
+
if (!tokens) {
|
|
154
|
+
throw new Error("No Linear tokens found. Please complete OAuth setup.");
|
|
155
|
+
}
|
|
156
|
+
const fiveMinutes = 5 * 60 * 1e3;
|
|
157
|
+
if (tokens.expiresAt - Date.now() < fiveMinutes) {
|
|
158
|
+
logger.info("Linear token expiring soon, refreshing...");
|
|
159
|
+
const newTokens = await this.refreshAccessToken();
|
|
160
|
+
return newTokens.accessToken;
|
|
161
|
+
}
|
|
162
|
+
return tokens.accessToken;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Save tokens to file
|
|
166
|
+
*/
|
|
167
|
+
saveTokens(tokens) {
|
|
168
|
+
writeFileSync(this.tokensPath, JSON.stringify(tokens, null, 2));
|
|
169
|
+
logger.info("Linear tokens saved");
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Load tokens from file
|
|
173
|
+
*/
|
|
174
|
+
loadTokens() {
|
|
175
|
+
if (!existsSync(this.tokensPath)) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
const tokensData = readFileSync(this.tokensPath, "utf8");
|
|
180
|
+
return JSON.parse(tokensData);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
logger.error("Failed to load Linear tokens:", error);
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Clear stored tokens and config
|
|
188
|
+
*/
|
|
189
|
+
clearAuth() {
|
|
190
|
+
if (existsSync(this.tokensPath)) {
|
|
191
|
+
writeFileSync(this.tokensPath, "");
|
|
192
|
+
}
|
|
193
|
+
if (existsSync(this.configPath)) {
|
|
194
|
+
writeFileSync(this.configPath, "");
|
|
195
|
+
}
|
|
196
|
+
logger.info("Linear authentication cleared");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const DEFAULT_LINEAR_SCOPES = [
|
|
200
|
+
"read",
|
|
201
|
+
// Read issues, projects, teams
|
|
202
|
+
"write",
|
|
203
|
+
// Create and update issues
|
|
204
|
+
"admin"
|
|
205
|
+
// Manage team settings and workflows
|
|
206
|
+
];
|
|
207
|
+
class LinearOAuthSetup {
|
|
208
|
+
authManager;
|
|
209
|
+
constructor(projectRoot) {
|
|
210
|
+
this.authManager = new LinearAuthManager(projectRoot);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Interactive setup for Linear OAuth
|
|
214
|
+
*/
|
|
215
|
+
async setupInteractive() {
|
|
216
|
+
const config = {
|
|
217
|
+
clientId: process.env.LINEAR_CLIENT_ID || "",
|
|
218
|
+
clientSecret: process.env.LINEAR_CLIENT_SECRET || "",
|
|
219
|
+
redirectUri: process.env.LINEAR_REDIRECT_URI || "http://localhost:3456/auth/linear/callback",
|
|
220
|
+
scopes: DEFAULT_LINEAR_SCOPES
|
|
221
|
+
};
|
|
222
|
+
if (!config.clientId || !config.clientSecret) {
|
|
223
|
+
return {
|
|
224
|
+
authUrl: "",
|
|
225
|
+
instructions: [
|
|
226
|
+
"1. Create a Linear OAuth application at https://linear.app/settings/api",
|
|
227
|
+
"2. Set redirect URI to: http://localhost:3456/auth/linear/callback",
|
|
228
|
+
"3. Copy your Client ID and Client Secret",
|
|
229
|
+
"4. Set environment variables:",
|
|
230
|
+
' export LINEAR_CLIENT_ID="your_client_id"',
|
|
231
|
+
' export LINEAR_CLIENT_SECRET="your_client_secret"',
|
|
232
|
+
"5. Re-run this setup command"
|
|
233
|
+
]
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
this.authManager.saveConfig(config);
|
|
237
|
+
const { url, codeVerifier } = this.authManager.generateAuthUrl();
|
|
238
|
+
process.env._LINEAR_CODE_VERIFIER = codeVerifier;
|
|
239
|
+
return {
|
|
240
|
+
authUrl: url,
|
|
241
|
+
instructions: [
|
|
242
|
+
"1. Open this URL in your browser:",
|
|
243
|
+
url,
|
|
244
|
+
"",
|
|
245
|
+
"2. Approve the StackMemory integration",
|
|
246
|
+
"3. Copy the authorization code from the redirect URL",
|
|
247
|
+
"4. Run: stackmemory linear authorize <code>"
|
|
248
|
+
]
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Complete OAuth flow with authorization code
|
|
253
|
+
*/
|
|
254
|
+
async completeAuth(authCode) {
|
|
255
|
+
try {
|
|
256
|
+
const codeVerifier = process.env._LINEAR_CODE_VERIFIER;
|
|
257
|
+
if (!codeVerifier) {
|
|
258
|
+
throw new Error(
|
|
259
|
+
"Code verifier not found. Please restart the setup process."
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
await this.authManager.exchangeCodeForToken(authCode, codeVerifier);
|
|
263
|
+
delete process.env._LINEAR_CODE_VERIFIER;
|
|
264
|
+
logger.info("Linear OAuth setup completed successfully!");
|
|
265
|
+
return true;
|
|
266
|
+
} catch (error) {
|
|
267
|
+
logger.error("Failed to complete Linear OAuth setup:", error);
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Test the Linear connection
|
|
273
|
+
*/
|
|
274
|
+
async testConnection() {
|
|
275
|
+
try {
|
|
276
|
+
const token = await this.authManager.getValidToken();
|
|
277
|
+
const response = await fetch("https://api.linear.app/graphql", {
|
|
278
|
+
method: "POST",
|
|
279
|
+
headers: {
|
|
280
|
+
Authorization: `Bearer ${token}`,
|
|
281
|
+
"Content-Type": "application/json"
|
|
282
|
+
},
|
|
283
|
+
body: JSON.stringify({
|
|
284
|
+
query: "query { viewer { id name email } }"
|
|
285
|
+
})
|
|
286
|
+
});
|
|
287
|
+
if (response.ok) {
|
|
288
|
+
const result = await response.json();
|
|
289
|
+
if (result.data?.viewer) {
|
|
290
|
+
logger.info(
|
|
291
|
+
`Connected to Linear as: ${result.data.viewer.name} (${result.data.viewer.email})`
|
|
292
|
+
);
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return false;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
logger.error("Linear connection test failed:", error);
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
export {
|
|
304
|
+
DEFAULT_LINEAR_SCOPES,
|
|
305
|
+
LinearAuthManager,
|
|
306
|
+
LinearOAuthSetup
|
|
307
|
+
};
|
|
308
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/integrations/linear/auth.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Linear OAuth Authentication Setup\n * Handles initial OAuth flow and token management for Linear integration\n */\n\nimport { createHash, randomBytes } from 'crypto';\nimport { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { logger } from '../../core/monitoring/logger.js';\n\nexport interface LinearAuthConfig {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n scopes: string[];\n}\n\nexport interface LinearTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number; // Unix timestamp\n scope: string[];\n}\n\nexport interface LinearAuthResult {\n accessToken: string;\n refreshToken?: string;\n expiresIn: number;\n scope: string;\n tokenType: string;\n}\n\nexport class LinearAuthManager {\n private configPath: string;\n private tokensPath: string;\n private config?: LinearAuthConfig;\n\n constructor(projectRoot: string) {\n const configDir = join(projectRoot, '.stackmemory');\n this.configPath = join(configDir, 'linear-config.json');\n this.tokensPath = join(configDir, 'linear-tokens.json');\n }\n\n /**\n * Check if Linear integration is configured\n */\n isConfigured(): boolean {\n return existsSync(this.configPath) && existsSync(this.tokensPath);\n }\n\n /**\n * Save OAuth application configuration\n */\n saveConfig(config: LinearAuthConfig): void {\n writeFileSync(this.configPath, JSON.stringify(config, null, 2));\n this.config = config;\n logger.info('Linear OAuth configuration saved');\n }\n\n /**\n * Load OAuth configuration\n */\n loadConfig(): LinearAuthConfig | null {\n if (!existsSync(this.configPath)) {\n return null;\n }\n\n try {\n const configData = readFileSync(this.configPath, 'utf8');\n this.config = JSON.parse(configData);\n return this.config!;\n } catch (error) {\n logger.error('Failed to load Linear configuration:', error as Error);\n return null;\n }\n }\n\n /**\n * Generate OAuth authorization URL with PKCE\n */\n generateAuthUrl(state?: string): { url: string; codeVerifier: string } {\n if (!this.config) {\n throw new Error('Linear OAuth configuration not loaded');\n }\n\n // Generate PKCE parameters\n const codeVerifier = randomBytes(32).toString('base64url');\n const codeChallenge = createHash('sha256')\n .update(codeVerifier)\n .digest('base64url');\n\n const params = new URLSearchParams({\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n response_type: 'code',\n scope: this.config.scopes.join(' '),\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n actor: 'app', // Enable actor authorization for service accounts\n });\n\n if (state) {\n params.set('state', state);\n }\n\n const authUrl = `https://linear.app/oauth/authorize?${params.toString()}`;\n\n return { url: authUrl, codeVerifier };\n }\n\n /**\n * Exchange authorization code for access token\n */\n async exchangeCodeForToken(\n authCode: string,\n codeVerifier: string\n ): Promise<LinearTokens> {\n if (!this.config) {\n throw new Error('Linear OAuth configuration not loaded');\n }\n\n const tokenUrl = 'https://api.linear.app/oauth/token';\n\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n redirect_uri: this.config.redirectUri,\n code: authCode,\n code_verifier: codeVerifier,\n });\n\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n },\n body: body.toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed: ${response.status} ${errorText}`);\n }\n\n const result = (await response.json()) as LinearAuthResult;\n\n // Calculate expiration time (tokens expire in 24 hours)\n const expiresAt = Date.now() + result.expiresIn * 1000;\n\n const tokens: LinearTokens = {\n accessToken: result.accessToken,\n refreshToken: result.refreshToken,\n expiresAt,\n scope: result.scope.split(' '),\n };\n\n this.saveTokens(tokens);\n return tokens;\n }\n\n /**\n * Refresh access token using refresh token\n */\n async refreshAccessToken(): Promise<LinearTokens> {\n if (!this.config) {\n throw new Error('Linear OAuth configuration not loaded');\n }\n\n const currentTokens = this.loadTokens();\n if (!currentTokens?.refreshToken) {\n throw new Error('No refresh token available');\n }\n\n const tokenUrl = 'https://api.linear.app/oauth/token';\n\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n refresh_token: currentTokens.refreshToken,\n });\n\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n },\n body: body.toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed: ${response.status} ${errorText}`);\n }\n\n const result = (await response.json()) as LinearAuthResult;\n\n const tokens: LinearTokens = {\n accessToken: result.accessToken,\n refreshToken: result.refreshToken || currentTokens.refreshToken,\n expiresAt: Date.now() + result.expiresIn * 1000,\n scope: result.scope.split(' '),\n };\n\n this.saveTokens(tokens);\n return tokens;\n }\n\n /**\n * Get valid access token (refresh if needed)\n */\n async getValidToken(): Promise<string> {\n const tokens = this.loadTokens();\n if (!tokens) {\n throw new Error('No Linear tokens found. Please complete OAuth setup.');\n }\n\n // Check if token expires in next 5 minutes\n const fiveMinutes = 5 * 60 * 1000;\n if (tokens.expiresAt - Date.now() < fiveMinutes) {\n logger.info('Linear token expiring soon, refreshing...');\n const newTokens = await this.refreshAccessToken();\n return newTokens.accessToken;\n }\n\n return tokens.accessToken;\n }\n\n /**\n * Save tokens to file\n */\n private saveTokens(tokens: LinearTokens): void {\n writeFileSync(this.tokensPath, JSON.stringify(tokens, null, 2));\n logger.info('Linear tokens saved');\n }\n\n /**\n * Load tokens from file\n */\n loadTokens(): LinearTokens | null {\n if (!existsSync(this.tokensPath)) {\n return null;\n }\n\n try {\n const tokensData = readFileSync(this.tokensPath, 'utf8');\n return JSON.parse(tokensData);\n } catch (error) {\n logger.error('Failed to load Linear tokens:', error as Error);\n return null;\n }\n }\n\n /**\n * Clear stored tokens and config\n */\n clearAuth(): void {\n if (existsSync(this.tokensPath)) {\n writeFileSync(this.tokensPath, '');\n }\n if (existsSync(this.configPath)) {\n writeFileSync(this.configPath, '');\n }\n logger.info('Linear authentication cleared');\n }\n}\n\n/**\n * Default Linear OAuth scopes for task management\n */\nexport const DEFAULT_LINEAR_SCOPES = [\n 'read', // Read issues, projects, teams\n 'write', // Create and update issues\n 'admin', // Manage team settings and workflows\n];\n\n/**\n * Linear OAuth setup helper\n */\nexport class LinearOAuthSetup {\n private authManager: LinearAuthManager;\n\n constructor(projectRoot: string) {\n this.authManager = new LinearAuthManager(projectRoot);\n }\n\n /**\n * Interactive setup for Linear OAuth\n */\n async setupInteractive(): Promise<{\n authUrl: string;\n instructions: string[];\n }> {\n // For now, we'll provide manual setup instructions\n // In a full implementation, this could open a browser or use a local server\n\n const config: LinearAuthConfig = {\n clientId: process.env.LINEAR_CLIENT_ID || '',\n clientSecret: process.env.LINEAR_CLIENT_SECRET || '',\n redirectUri:\n process.env.LINEAR_REDIRECT_URI ||\n 'http://localhost:3456/auth/linear/callback',\n scopes: DEFAULT_LINEAR_SCOPES,\n };\n\n if (!config.clientId || !config.clientSecret) {\n return {\n authUrl: '',\n instructions: [\n '1. Create a Linear OAuth application at https://linear.app/settings/api',\n '2. Set redirect URI to: http://localhost:3456/auth/linear/callback',\n '3. Copy your Client ID and Client Secret',\n '4. Set environment variables:',\n ' export LINEAR_CLIENT_ID=\"your_client_id\"',\n ' export LINEAR_CLIENT_SECRET=\"your_client_secret\"',\n '5. Re-run this setup command',\n ],\n };\n }\n\n this.authManager.saveConfig(config);\n\n const { url, codeVerifier } = this.authManager.generateAuthUrl();\n\n // Store code verifier temporarily (in a real app, this would be in a secure session store)\n process.env._LINEAR_CODE_VERIFIER = codeVerifier;\n\n return {\n authUrl: url,\n instructions: [\n '1. Open this URL in your browser:',\n url,\n '',\n '2. Approve the StackMemory integration',\n '3. Copy the authorization code from the redirect URL',\n '4. Run: stackmemory linear authorize <code>',\n ],\n };\n }\n\n /**\n * Complete OAuth flow with authorization code\n */\n async completeAuth(authCode: string): Promise<boolean> {\n try {\n const codeVerifier = process.env._LINEAR_CODE_VERIFIER;\n if (!codeVerifier) {\n throw new Error(\n 'Code verifier not found. Please restart the setup process.'\n );\n }\n\n await this.authManager.exchangeCodeForToken(authCode, codeVerifier);\n delete process.env._LINEAR_CODE_VERIFIER;\n\n logger.info('Linear OAuth setup completed successfully!');\n return true;\n } catch (error) {\n logger.error('Failed to complete Linear OAuth setup:', error as Error);\n return false;\n }\n }\n\n /**\n * Test the Linear connection\n */\n async testConnection(): Promise<boolean> {\n try {\n const token = await this.authManager.getValidToken();\n\n // Test with a simple GraphQL query\n const response = await fetch('https://api.linear.app/graphql', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n query: 'query { viewer { id name email } }',\n }),\n });\n\n if (response.ok) {\n const result = (await response.json()) as {\n data?: { viewer?: { id: string; name: string; email: string } };\n };\n if (result.data?.viewer) {\n logger.info(\n `Connected to Linear as: ${result.data.viewer.name} (${result.data.viewer.email})`\n );\n return true;\n }\n }\n\n return false;\n } catch (error) {\n logger.error('Linear connection test failed:', error as Error);\n return false;\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|