@stackmemoryai/stackmemory 0.3.6 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/dist/agents/core/agent-task-manager.js +5 -5
  2. package/dist/agents/core/agent-task-manager.js.map +2 -2
  3. package/dist/agents/verifiers/base-verifier.js +2 -2
  4. package/dist/agents/verifiers/base-verifier.js.map +2 -2
  5. package/dist/agents/verifiers/formatter-verifier.js.map +2 -2
  6. package/dist/agents/verifiers/llm-judge.js.map +2 -2
  7. package/dist/cli/claude-sm.js +13 -13
  8. package/dist/cli/claude-sm.js.map +2 -2
  9. package/dist/cli/codex-sm.js +13 -13
  10. package/dist/cli/codex-sm.js.map +2 -2
  11. package/dist/cli/commands/agent.js.map +2 -2
  12. package/dist/cli/commands/chromadb.js +261 -46
  13. package/dist/cli/commands/chromadb.js.map +2 -2
  14. package/dist/cli/commands/clear.js +10 -3
  15. package/dist/cli/commands/clear.js.map +2 -2
  16. package/dist/cli/commands/config.js +43 -33
  17. package/dist/cli/commands/config.js.map +2 -2
  18. package/dist/cli/commands/context.js +13 -2
  19. package/dist/cli/commands/context.js.map +2 -2
  20. package/dist/cli/commands/dashboard.js +41 -13
  21. package/dist/cli/commands/dashboard.js.map +2 -2
  22. package/dist/cli/commands/gc.js +251 -0
  23. package/dist/cli/commands/gc.js.map +7 -0
  24. package/dist/cli/commands/handoff.js +12 -1
  25. package/dist/cli/commands/handoff.js.map +2 -2
  26. package/dist/cli/commands/infinite-storage.js +92 -40
  27. package/dist/cli/commands/infinite-storage.js.map +2 -2
  28. package/dist/cli/commands/linear-create.js +49 -10
  29. package/dist/cli/commands/linear-create.js.map +2 -2
  30. package/dist/cli/commands/linear-list.js +45 -11
  31. package/dist/cli/commands/linear-list.js.map +2 -2
  32. package/dist/cli/commands/linear-migrate.js +29 -5
  33. package/dist/cli/commands/linear-migrate.js.map +2 -2
  34. package/dist/cli/commands/linear-test.js +26 -7
  35. package/dist/cli/commands/linear-test.js.map +2 -2
  36. package/dist/cli/commands/linear-unified.js +350 -0
  37. package/dist/cli/commands/linear-unified.js.map +7 -0
  38. package/dist/cli/commands/linear.js +17 -6
  39. package/dist/cli/commands/linear.js.map +2 -2
  40. package/dist/cli/commands/monitor.js.map +2 -2
  41. package/dist/cli/commands/onboard.js +35 -8
  42. package/dist/cli/commands/onboard.js.map +2 -2
  43. package/dist/cli/commands/quality.js +2 -7
  44. package/dist/cli/commands/quality.js.map +2 -2
  45. package/dist/cli/commands/search.js.map +2 -2
  46. package/dist/cli/commands/session.js +23 -6
  47. package/dist/cli/commands/session.js.map +2 -2
  48. package/dist/cli/commands/skills.js +84 -28
  49. package/dist/cli/commands/skills.js.map +2 -2
  50. package/dist/cli/commands/storage.js +119 -38
  51. package/dist/cli/commands/storage.js.map +2 -2
  52. package/dist/cli/commands/tasks.js.map +2 -2
  53. package/dist/cli/commands/tui.js +13 -2
  54. package/dist/cli/commands/tui.js.map +2 -2
  55. package/dist/cli/commands/webhook.js +71 -21
  56. package/dist/cli/commands/webhook.js.map +2 -2
  57. package/dist/cli/commands/workflow.js +11 -7
  58. package/dist/cli/commands/workflow.js.map +2 -2
  59. package/dist/cli/commands/worktree.js +34 -13
  60. package/dist/cli/commands/worktree.js.map +2 -2
  61. package/dist/cli/index.js +7 -5
  62. package/dist/cli/index.js.map +2 -2
  63. package/dist/core/config/config-manager.js.map +2 -2
  64. package/dist/core/config/types.js.map +1 -1
  65. package/dist/core/context/auto-context.js +10 -6
  66. package/dist/core/context/auto-context.js.map +2 -2
  67. package/dist/core/context/compaction-handler.js.map +2 -2
  68. package/dist/core/context/context-bridge.js.map +2 -2
  69. package/dist/core/context/dual-stack-manager.js.map +2 -2
  70. package/dist/core/context/frame-database.js +13 -3
  71. package/dist/core/context/frame-database.js.map +2 -2
  72. package/dist/core/context/frame-digest.js +7 -5
  73. package/dist/core/context/frame-digest.js.map +2 -2
  74. package/dist/core/context/frame-handoff-manager.js.map +2 -2
  75. package/dist/core/context/frame-manager.js +12 -1
  76. package/dist/core/context/frame-manager.js.map +2 -2
  77. package/dist/core/context/frame-stack.js +16 -5
  78. package/dist/core/context/frame-stack.js.map +2 -2
  79. package/dist/core/context/incremental-gc.js +286 -0
  80. package/dist/core/context/incremental-gc.js.map +7 -0
  81. package/dist/core/context/index.js.map +1 -1
  82. package/dist/core/context/permission-manager.js +12 -1
  83. package/dist/core/context/permission-manager.js.map +2 -2
  84. package/dist/core/context/refactored-frame-manager.js +12 -3
  85. package/dist/core/context/refactored-frame-manager.js.map +2 -2
  86. package/dist/core/context/shared-context-layer.js +16 -3
  87. package/dist/core/context/shared-context-layer.js.map +2 -2
  88. package/dist/core/context/stack-merge-resolver.js.map +2 -2
  89. package/dist/core/context/validation.js.map +2 -2
  90. package/dist/core/database/batch-operations.js +112 -86
  91. package/dist/core/database/batch-operations.js.map +2 -2
  92. package/dist/core/database/connection-pool.js.map +2 -2
  93. package/dist/core/database/migration-manager.js.map +2 -2
  94. package/dist/core/database/paradedb-adapter.js.map +2 -2
  95. package/dist/core/database/query-cache.js +19 -9
  96. package/dist/core/database/query-cache.js.map +2 -2
  97. package/dist/core/database/query-router.js.map +2 -2
  98. package/dist/core/database/sqlite-adapter.js +1 -1
  99. package/dist/core/database/sqlite-adapter.js.map +2 -2
  100. package/dist/core/digest/enhanced-hybrid-digest.js +8 -2
  101. package/dist/core/digest/enhanced-hybrid-digest.js.map +2 -2
  102. package/dist/core/errors/recovery.js +9 -2
  103. package/dist/core/errors/recovery.js.map +2 -2
  104. package/dist/core/frame/workflow-templates-stub.js.map +1 -1
  105. package/dist/core/frame/workflow-templates.js +40 -1
  106. package/dist/core/frame/workflow-templates.js.map +2 -2
  107. package/dist/core/merge/resolution-engine.js.map +2 -2
  108. package/dist/core/monitoring/error-handler.js.map +2 -2
  109. package/dist/core/monitoring/logger.js +19 -3
  110. package/dist/core/monitoring/logger.js.map +2 -2
  111. package/dist/core/monitoring/metrics.js +13 -2
  112. package/dist/core/monitoring/metrics.js.map +2 -2
  113. package/dist/core/monitoring/progress-tracker.js +12 -1
  114. package/dist/core/monitoring/progress-tracker.js.map +2 -2
  115. package/dist/core/monitoring/session-monitor.js.map +2 -2
  116. package/dist/core/performance/context-cache.js.map +2 -2
  117. package/dist/core/performance/lazy-context-loader.js +24 -20
  118. package/dist/core/performance/lazy-context-loader.js.map +2 -2
  119. package/dist/core/performance/monitor.js.map +2 -2
  120. package/dist/core/performance/optimized-frame-context.js +27 -12
  121. package/dist/core/performance/optimized-frame-context.js.map +2 -2
  122. package/dist/core/performance/performance-benchmark.js +10 -6
  123. package/dist/core/performance/performance-benchmark.js.map +2 -2
  124. package/dist/core/performance/performance-profiler.js +63 -15
  125. package/dist/core/performance/performance-profiler.js.map +2 -2
  126. package/dist/core/performance/streaming-jsonl-parser.js +5 -1
  127. package/dist/core/performance/streaming-jsonl-parser.js.map +2 -2
  128. package/dist/core/persistence/postgres-adapter.js.map +2 -2
  129. package/dist/core/projects/project-manager.js +14 -20
  130. package/dist/core/projects/project-manager.js.map +2 -2
  131. package/dist/core/retrieval/context-retriever.js.map +2 -2
  132. package/dist/core/retrieval/graph-retrieval.js.map +2 -2
  133. package/dist/core/retrieval/llm-context-retrieval.js.map +2 -2
  134. package/dist/core/retrieval/retrieval-benchmarks.js.map +2 -2
  135. package/dist/core/retrieval/summary-generator.js.map +2 -2
  136. package/dist/core/session/clear-survival-stub.js +5 -1
  137. package/dist/core/session/clear-survival-stub.js.map +2 -2
  138. package/dist/core/session/clear-survival.js +35 -0
  139. package/dist/core/session/clear-survival.js.map +2 -2
  140. package/dist/core/session/handoff-generator.js.map +2 -2
  141. package/dist/core/session/index.js.map +1 -1
  142. package/dist/core/session/session-manager.js +16 -5
  143. package/dist/core/session/session-manager.js.map +2 -2
  144. package/dist/core/skills/skill-storage.js +13 -2
  145. package/dist/core/skills/skill-storage.js.map +2 -2
  146. package/dist/core/storage/chromadb-adapter.js +6 -2
  147. package/dist/core/storage/chromadb-adapter.js.map +2 -2
  148. package/dist/core/storage/chromadb-simple.js +17 -5
  149. package/dist/core/storage/chromadb-simple.js.map +2 -2
  150. package/dist/core/storage/infinite-storage.js +109 -46
  151. package/dist/core/storage/infinite-storage.js.map +2 -2
  152. package/dist/core/storage/railway-optimized-storage.js +67 -30
  153. package/dist/core/storage/railway-optimized-storage.js.map +2 -2
  154. package/dist/core/storage/remote-storage.js +53 -24
  155. package/dist/core/storage/remote-storage.js.map +2 -2
  156. package/dist/core/trace/cli-trace-wrapper.js +25 -7
  157. package/dist/core/trace/cli-trace-wrapper.js.map +2 -2
  158. package/dist/core/trace/db-trace-wrapper.js +96 -68
  159. package/dist/core/trace/db-trace-wrapper.js.map +2 -2
  160. package/dist/core/trace/debug-trace.js +44 -16
  161. package/dist/core/trace/debug-trace.js.map +2 -2
  162. package/dist/core/trace/index.js +50 -35
  163. package/dist/core/trace/index.js.map +2 -2
  164. package/dist/core/trace/linear-api-wrapper.js +10 -5
  165. package/dist/core/trace/linear-api-wrapper.js.map +2 -2
  166. package/dist/core/trace/trace-demo.js +26 -11
  167. package/dist/core/trace/trace-demo.js.map +2 -2
  168. package/dist/core/trace/trace-detector.js +9 -2
  169. package/dist/core/trace/trace-detector.js.map +2 -2
  170. package/dist/core/trace/trace-store.js.map +2 -2
  171. package/dist/core/trace/types.js.map +1 -1
  172. package/dist/core/utils/compression.js.map +1 -1
  173. package/dist/core/utils/update-checker.js.map +2 -2
  174. package/dist/core/worktree/worktree-manager.js +18 -7
  175. package/dist/core/worktree/worktree-manager.js.map +2 -2
  176. package/dist/features/analytics/api/analytics-api.js.map +2 -2
  177. package/dist/features/analytics/core/analytics-service.js +12 -1
  178. package/dist/features/analytics/core/analytics-service.js.map +2 -2
  179. package/dist/features/analytics/queries/metrics-queries.js +1 -1
  180. package/dist/features/analytics/queries/metrics-queries.js.map +2 -2
  181. package/dist/features/tasks/pebbles-task-store.js.map +2 -2
  182. package/dist/features/tui/components/analytics-panel.js +36 -15
  183. package/dist/features/tui/components/analytics-panel.js.map +2 -2
  184. package/dist/features/tui/components/pr-tracker.js +19 -7
  185. package/dist/features/tui/components/pr-tracker.js.map +2 -2
  186. package/dist/features/tui/components/session-monitor.js +22 -9
  187. package/dist/features/tui/components/session-monitor.js.map +2 -2
  188. package/dist/features/tui/components/subagent-fleet.js +20 -13
  189. package/dist/features/tui/components/subagent-fleet.js.map +2 -2
  190. package/dist/features/tui/components/task-board.js +666 -2
  191. package/dist/features/tui/components/task-board.js.map +2 -2
  192. package/dist/features/tui/index.js +16 -5
  193. package/dist/features/tui/index.js.map +2 -2
  194. package/dist/features/tui/services/data-service.js +30 -15
  195. package/dist/features/tui/services/data-service.js.map +2 -2
  196. package/dist/features/tui/services/linear-task-reader.js +3 -1
  197. package/dist/features/tui/services/linear-task-reader.js.map +2 -2
  198. package/dist/features/tui/services/websocket-client.js +16 -3
  199. package/dist/features/tui/services/websocket-client.js.map +2 -2
  200. package/dist/features/tui/terminal-compat.js +33 -18
  201. package/dist/features/tui/terminal-compat.js.map +2 -2
  202. package/dist/features/web/client/stores/task-store.js.map +2 -2
  203. package/dist/features/web/server/index.js +31 -12
  204. package/dist/features/web/server/index.js.map +2 -2
  205. package/dist/integrations/claude-code/enhanced-pre-clear-hooks.js.map +2 -2
  206. package/dist/integrations/claude-code/lifecycle-hooks.js.map +2 -2
  207. package/dist/integrations/claude-code/post-task-hooks.js.map +2 -2
  208. package/dist/integrations/linear/auth.js +17 -6
  209. package/dist/integrations/linear/auth.js.map +2 -2
  210. package/dist/integrations/linear/auto-sync.js.map +2 -2
  211. package/dist/integrations/linear/client.js.map +2 -2
  212. package/dist/integrations/linear/config.js.map +2 -2
  213. package/dist/integrations/linear/migration.js.map +2 -2
  214. package/dist/integrations/linear/oauth-server.js +13 -2
  215. package/dist/integrations/linear/oauth-server.js.map +2 -2
  216. package/dist/integrations/linear/rest-client.js.map +2 -2
  217. package/dist/integrations/linear/sync-enhanced.js +202 -0
  218. package/dist/integrations/linear/sync-enhanced.js.map +7 -0
  219. package/dist/integrations/linear/sync-manager.js.map +2 -2
  220. package/dist/integrations/linear/sync-service.js +24 -14
  221. package/dist/integrations/linear/sync-service.js.map +2 -2
  222. package/dist/integrations/linear/sync.js +196 -3
  223. package/dist/integrations/linear/sync.js.map +2 -2
  224. package/dist/integrations/linear/unified-sync.js +560 -0
  225. package/dist/integrations/linear/unified-sync.js.map +7 -0
  226. package/dist/integrations/linear/webhook-handler.js +12 -1
  227. package/dist/integrations/linear/webhook-handler.js.map +2 -2
  228. package/dist/integrations/linear/webhook-server.js +29 -19
  229. package/dist/integrations/linear/webhook-server.js.map +2 -2
  230. package/dist/integrations/linear/webhook.js +12 -1
  231. package/dist/integrations/linear/webhook.js.map +2 -2
  232. package/dist/integrations/mcp/handlers/context-handlers.js.map +2 -2
  233. package/dist/integrations/mcp/handlers/linear-handlers.js.map +2 -2
  234. package/dist/integrations/mcp/handlers/skill-handlers.js +13 -2
  235. package/dist/integrations/mcp/handlers/skill-handlers.js.map +2 -2
  236. package/dist/integrations/mcp/handlers/task-handlers.js.map +2 -2
  237. package/dist/integrations/mcp/handlers/trace-handlers.js.map +2 -2
  238. package/dist/integrations/mcp/middleware/tool-scoring.js.map +2 -2
  239. package/dist/integrations/mcp/refactored-server.js +15 -4
  240. package/dist/integrations/mcp/refactored-server.js.map +2 -2
  241. package/dist/integrations/mcp/server.js +12 -1
  242. package/dist/integrations/mcp/server.js.map +2 -2
  243. package/dist/integrations/mcp/tool-definitions.js.map +2 -2
  244. package/dist/integrations/pg-aiguide/embedding-provider.js +13 -2
  245. package/dist/integrations/pg-aiguide/embedding-provider.js.map +2 -2
  246. package/dist/integrations/pg-aiguide/semantic-search.js.map +2 -2
  247. package/dist/mcp/stackmemory-mcp-server.js +1 -1
  248. package/dist/mcp/stackmemory-mcp-server.js.map +2 -2
  249. package/dist/middleware/exponential-rate-limiter.js.map +2 -2
  250. package/dist/servers/production/auth-middleware.js +13 -2
  251. package/dist/servers/production/auth-middleware.js.map +2 -2
  252. package/dist/servers/railway/index.js +22 -11
  253. package/dist/servers/railway/index.js.map +2 -2
  254. package/dist/services/config-service.js +6 -7
  255. package/dist/services/config-service.js.map +2 -2
  256. package/dist/services/context-service.js +11 -12
  257. package/dist/services/context-service.js.map +2 -2
  258. package/dist/skills/claude-skills.js +108 -3
  259. package/dist/skills/claude-skills.js.map +2 -2
  260. package/dist/skills/dashboard-launcher.js.map +2 -2
  261. package/dist/skills/repo-ingestion-skill.js +561 -0
  262. package/dist/skills/repo-ingestion-skill.js.map +7 -0
  263. package/dist/utils/env.js +46 -0
  264. package/dist/utils/env.js.map +7 -0
  265. package/dist/utils/logger.js +1 -1
  266. package/dist/utils/logger.js.map +2 -2
  267. package/package.json +5 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/cli/commands/linear-list.ts"],
4
- "sourcesContent": ["/**\n * Simple Linear task list command using memory cache\n */\n\nimport chalk from 'chalk';\nimport { Command } from 'commander';\nimport { LinearRestClient } from '../../integrations/linear/rest-client.js';\n\nexport function registerLinearListCommand(parent: Command) {\n parent\n .command('linear:list')\n .alias('linear:ls')\n .description('List Linear tasks (fast, memory-cached)')\n .option('--limit <n>', 'Number of tasks to show', '20')\n .option('--status <status>', 'Filter by status (backlog, started, completed, etc.)')\n .option('--my', 'Show only tasks assigned to me')\n .option('--cache', 'Show cache stats only')\n .option('--refresh', 'Force refresh cache')\n .option('--count', 'Show count by status only')\n .action(async (options) => {\n try {\n const apiKey = process.env.LINEAR_API_KEY;\n if (!apiKey) {\n console.log(chalk.yellow('\u26A0 Set LINEAR_API_KEY environment variable'));\n return;\n }\n\n const restClient = new LinearRestClient(apiKey);\n\n // Show cache stats if requested\n if (options.cache) {\n const stats = restClient.getCacheStats();\n console.log(chalk.cyan('\uD83D\uDCCA Cache Stats:'));\n console.log(` Size: ${stats.size} tasks`);\n console.log(` Age: ${Math.round(stats.age / 1000)}s`);\n console.log(` Fresh: ${stats.fresh ? 'yes' : 'no'}`);\n console.log(` Last sync: ${new Date(stats.lastSync).toLocaleString()}`);\n return;\n }\n\n // Show counts only\n if (options.count) {\n const counts = await restClient.getTaskCounts();\n console.log(chalk.cyan('\uD83D\uDCCA Task Counts:'));\n Object.entries(counts)\n .sort(([,a], [,b]) => b - a)\n .forEach(([status, count]) => {\n console.log(` ${status}: ${count}`);\n });\n \n const cacheStats = restClient.getCacheStats();\n console.log(chalk.gray(`\\nCache: ${cacheStats.size} tasks, age: ${Math.round(cacheStats.age / 1000)}s`));\n return;\n }\n\n let tasks;\n if (options.my) {\n tasks = await restClient.getMyTasks();\n } else if (options.status) {\n tasks = await restClient.getTasksByStatus(options.status);\n } else {\n tasks = await restClient.getAllTasks(options.refresh);\n }\n\n if (!tasks || tasks.length === 0) {\n console.log(chalk.gray('No tasks found'));\n return;\n }\n\n // Limit results\n const limit = parseInt(options.limit);\n const displayTasks = tasks.slice(0, limit);\n\n console.log(chalk.cyan(`\\n\uD83D\uDCCB Linear Tasks (${displayTasks.length}/${tasks.length}):`));\n \n displayTasks.forEach((task) => {\n const priority = task.priority ? `P${task.priority}` : '';\n const assignee = task.assignee ? ` @${task.assignee.name}` : '';\n const statusColor = task.state.type === 'completed' ? chalk.green : \n task.state.type === 'started' ? chalk.yellow : chalk.gray;\n \n console.log(`${chalk.blue(task.identifier)} ${task.title}`);\n console.log(chalk.gray(` ${statusColor(task.state.name)} ${priority}${assignee}`));\n });\n\n const cacheStats = restClient.getCacheStats();\n console.log(chalk.gray(`\\n${displayTasks.length} shown, ${tasks.length} total \u2022 Cache: ${Math.round(cacheStats.age / 1000)}s old`));\n } catch (error) {\n console.error(\n chalk.red('Failed to list tasks:'),\n (error as Error).message\n );\n }\n });\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Simple Linear task list command using memory cache\n */\n\nimport chalk from 'chalk';\nimport { Command } from 'commander';\nimport { LinearRestClient } from '../../integrations/linear/rest-client.js';\n// Type-safe environment variable access\nfunction getEnv(key: string, defaultValue?: string): string {\n const value = process.env[key];\n if (value === undefined) {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Environment variable ${key} is required`);\n }\n return value;\n}\n\nfunction getOptionalEnv(key: string): string | undefined {\n return process.env[key];\n}\n\nexport function registerLinearListCommand(parent: Command) {\n parent\n .command('linear:list')\n .alias('linear:ls')\n .description('List Linear tasks (fast, memory-cached)')\n .option('--limit <n>', 'Number of tasks to show', '20')\n .option(\n '--status <status>',\n 'Filter by status (backlog, started, completed, etc.)'\n )\n .option('--my', 'Show only tasks assigned to me')\n .option('--cache', 'Show cache stats only')\n .option('--refresh', 'Force refresh cache')\n .option('--count', 'Show count by status only')\n .action(async (options) => {\n try {\n const apiKey = process.env['LINEAR_API_KEY'];\n if (!apiKey) {\n console.log(\n chalk.yellow('\u26A0 Set LINEAR_API_KEY environment variable')\n );\n return;\n }\n\n const restClient = new LinearRestClient(apiKey);\n\n // Show cache stats if requested\n if (options.cache) {\n const stats = restClient.getCacheStats();\n console.log(chalk.cyan('\uD83D\uDCCA Cache Stats:'));\n console.log(` Size: ${stats.size} tasks`);\n console.log(` Age: ${Math.round(stats.age / 1000)}s`);\n console.log(` Fresh: ${stats.fresh ? 'yes' : 'no'}`);\n console.log(\n ` Last sync: ${new Date(stats.lastSync).toLocaleString()}`\n );\n return;\n }\n\n // Show counts only\n if (options.count) {\n const counts = await restClient.getTaskCounts();\n console.log(chalk.cyan('\uD83D\uDCCA Task Counts:'));\n Object.entries(counts)\n .sort(([, a], [, b]) => b - a)\n .forEach(([status, count]) => {\n console.log(` ${status}: ${count}`);\n });\n\n const cacheStats = restClient.getCacheStats();\n console.log(\n chalk.gray(\n `\\nCache: ${cacheStats.size} tasks, age: ${Math.round(cacheStats.age / 1000)}s`\n )\n );\n return;\n }\n\n let tasks;\n if (options.my) {\n tasks = await restClient.getMyTasks();\n } else if (options.status) {\n tasks = await restClient.getTasksByStatus(options.status);\n } else {\n tasks = await restClient.getAllTasks(options.refresh);\n }\n\n if (!tasks || tasks.length === 0) {\n console.log(chalk.gray('No tasks found'));\n return;\n }\n\n // Limit results\n const limit = parseInt(options.limit);\n const displayTasks = tasks.slice(0, limit);\n\n console.log(\n chalk.cyan(\n `\\n\uD83D\uDCCB Linear Tasks (${displayTasks.length}/${tasks.length}):`\n )\n );\n\n displayTasks.forEach((task) => {\n const priority = task.priority ? `P${task.priority}` : '';\n const assignee = task.assignee ? ` @${task.assignee.name}` : '';\n const statusColor =\n task.state.type === 'completed'\n ? chalk.green\n : task.state.type === 'started'\n ? chalk.yellow\n : chalk.gray;\n\n console.log(`${chalk.blue(task.identifier)} ${task.title}`);\n console.log(\n chalk.gray(\n ` ${statusColor(task.state.name)} ${priority}${assignee}`\n )\n );\n });\n\n const cacheStats = restClient.getCacheStats();\n console.log(\n chalk.gray(\n `\\n${displayTasks.length} shown, ${tasks.length} total \u2022 Cache: ${Math.round(cacheStats.age / 1000)}s old`\n )\n );\n } catch (error: unknown) {\n console.error(\n chalk.red('Failed to list tasks:'),\n (error as Error).message\n );\n }\n });\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["cacheStats"]
7
7
  }
@@ -1,22 +1,46 @@
1
1
  import chalk from "chalk";
2
2
  import { runMigration } from "../../integrations/linear/migration.js";
3
+ function getEnv(key, defaultValue) {
4
+ const value = process.env[key];
5
+ if (value === void 0) {
6
+ if (defaultValue !== void 0) return defaultValue;
7
+ throw new Error(`Environment variable ${key} is required`);
8
+ }
9
+ return value;
10
+ }
11
+ function getOptionalEnv(key) {
12
+ return process.env[key];
13
+ }
3
14
  function registerLinearMigrateCommand(parent) {
4
- parent.command("linear:migrate").description("Migrate STA- tasks from LiftCL to new Linear workspace").option("--source-key <key>", "Source workspace Linear API key").option("--target-key <key>", "Target workspace Linear API key").option("--dry-run", "Preview migration without making changes").option("--delete-source", "Delete tasks from source after successful migration").option("--batch-size <n>", "Number of tasks per batch", "3").option("--delay <ms>", "Delay between batches in milliseconds", "3000").action(async (options) => {
15
+ parent.command("linear:migrate").description("Migrate STA- tasks from LiftCL to new Linear workspace").option("--source-key <key>", "Source workspace Linear API key").option("--target-key <key>", "Target workspace Linear API key").option("--dry-run", "Preview migration without making changes").option(
16
+ "--delete-source",
17
+ "Delete tasks from source after successful migration"
18
+ ).option("--batch-size <n>", "Number of tasks per batch", "3").option("--delay <ms>", "Delay between batches in milliseconds", "3000").action(async (options) => {
5
19
  try {
6
- const sourceKey = options.sourceKey || process.env.LINEAR_API_KEY;
20
+ const sourceKey = options.sourceKey || process.env["LINEAR_API_KEY"];
7
21
  const targetKey = options.targetKey;
8
22
  if (!sourceKey) {
9
- console.error(chalk.red("\u274C Source API key required. Use --source-key or set LINEAR_API_KEY"));
23
+ console.error(
24
+ chalk.red(
25
+ "\u274C Source API key required. Use --source-key or set LINEAR_API_KEY"
26
+ )
27
+ );
10
28
  return;
11
29
  }
12
30
  if (!targetKey) {
13
- console.error(chalk.red("\u274C Target API key required. Use --target-key"));
31
+ console.error(
32
+ chalk.red("\u274C Target API key required. Use --target-key")
33
+ );
14
34
  return;
15
35
  }
16
36
  console.log(chalk.blue("\u{1F680} Starting Linear Migration"));
17
37
  console.log(chalk.gray(" This will migrate all STA- prefixed tasks"));
18
38
  if (options.deleteSource) {
19
- console.log(chalk.yellow(" \u26A0\uFE0F Tasks will be DELETED from source after migration"));
39
+ console.log(
40
+ chalk.yellow(
41
+ " \u26A0\uFE0F Tasks will be DELETED from source after migration"
42
+ )
43
+ );
20
44
  }
21
45
  console.log();
22
46
  await runMigration({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/cli/commands/linear-migrate.ts"],
4
- "sourcesContent": ["/**\n * Linear Migration Command\n */\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { runMigration } from '../../integrations/linear/migration.js';\n\nexport function registerLinearMigrateCommand(parent: Command) {\n parent\n .command('linear:migrate')\n .description('Migrate STA- tasks from LiftCL to new Linear workspace')\n .option('--source-key <key>', 'Source workspace Linear API key')\n .option('--target-key <key>', 'Target workspace Linear API key') \n .option('--dry-run', 'Preview migration without making changes')\n .option('--delete-source', 'Delete tasks from source after successful migration')\n .option('--batch-size <n>', 'Number of tasks per batch', '3')\n .option('--delay <ms>', 'Delay between batches in milliseconds', '3000')\n .action(async (options) => {\n try {\n const sourceKey = options.sourceKey || process.env.LINEAR_API_KEY;\n const targetKey = options.targetKey;\n\n if (!sourceKey) {\n console.error(chalk.red('\u274C Source API key required. Use --source-key or set LINEAR_API_KEY'));\n return;\n }\n\n if (!targetKey) {\n console.error(chalk.red('\u274C Target API key required. Use --target-key'));\n return;\n }\n\n console.log(chalk.blue('\uD83D\uDE80 Starting Linear Migration'));\n console.log(chalk.gray(' This will migrate all STA- prefixed tasks'));\n if (options.deleteSource) {\n console.log(chalk.yellow(' \u26A0\uFE0F Tasks will be DELETED from source after migration'));\n }\n console.log();\n\n await runMigration({\n sourceApiKey: sourceKey,\n targetApiKey: targetKey,\n taskPrefix: 'STA-',\n deleteFromSource: options.deleteSource,\n dryRun: options.dryRun,\n batchSize: parseInt(options.batchSize),\n delayMs: parseInt(options.delay)\n });\n\n } catch (error) {\n console.error(chalk.red('Migration failed:'), (error as Error).message);\n process.exit(1);\n }\n });\n}"],
5
- "mappings": "AAKA,OAAO,WAAW;AAClB,SAAS,oBAAoB;AAEtB,SAAS,6BAA6B,QAAiB;AAC5D,SACG,QAAQ,gBAAgB,EACxB,YAAY,wDAAwD,EACpE,OAAO,sBAAsB,iCAAiC,EAC9D,OAAO,sBAAsB,iCAAiC,EAC9D,OAAO,aAAa,0CAA0C,EAC9D,OAAO,mBAAmB,qDAAqD,EAC/E,OAAO,oBAAoB,6BAA6B,GAAG,EAC3D,OAAO,gBAAgB,yCAAyC,MAAM,EACtE,OAAO,OAAO,YAAY;AACzB,QAAI;AACF,YAAM,YAAY,QAAQ,aAAa,QAAQ,IAAI;AACnD,YAAM,YAAY,QAAQ;AAE1B,UAAI,CAAC,WAAW;AACd,gBAAQ,MAAM,MAAM,IAAI,wEAAmE,CAAC;AAC5F;AAAA,MACF;AAEA,UAAI,CAAC,WAAW;AACd,gBAAQ,MAAM,MAAM,IAAI,kDAA6C,CAAC;AACtE;AAAA,MACF;AAEA,cAAQ,IAAI,MAAM,KAAK,qCAA8B,CAAC;AACtD,cAAQ,IAAI,MAAM,KAAK,8CAA8C,CAAC;AACtE,UAAI,QAAQ,cAAc;AACxB,gBAAQ,IAAI,MAAM,OAAO,oEAA0D,CAAC;AAAA,MACtF;AACA,cAAQ,IAAI;AAEZ,YAAM,aAAa;AAAA,QACjB,cAAc;AAAA,QACd,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,kBAAkB,QAAQ;AAAA,QAC1B,QAAQ,QAAQ;AAAA,QAChB,WAAW,SAAS,QAAQ,SAAS;AAAA,QACrC,SAAS,SAAS,QAAQ,KAAK;AAAA,MACjC,CAAC;AAAA,IAEH,SAAS,OAAO;AACd,cAAQ,MAAM,MAAM,IAAI,mBAAmB,GAAI,MAAgB,OAAO;AACtE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;",
4
+ "sourcesContent": ["/**\n * Linear Migration Command\n */\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { runMigration } from '../../integrations/linear/migration.js';\n// Type-safe environment variable access\nfunction getEnv(key: string, defaultValue?: string): string {\n const value = process.env[key];\n if (value === undefined) {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Environment variable ${key} is required`);\n }\n return value;\n}\n\nfunction getOptionalEnv(key: string): string | undefined {\n return process.env[key];\n}\n\nexport function registerLinearMigrateCommand(parent: Command) {\n parent\n .command('linear:migrate')\n .description('Migrate STA- tasks from LiftCL to new Linear workspace')\n .option('--source-key <key>', 'Source workspace Linear API key')\n .option('--target-key <key>', 'Target workspace Linear API key')\n .option('--dry-run', 'Preview migration without making changes')\n .option(\n '--delete-source',\n 'Delete tasks from source after successful migration'\n )\n .option('--batch-size <n>', 'Number of tasks per batch', '3')\n .option('--delay <ms>', 'Delay between batches in milliseconds', '3000')\n .action(async (options) => {\n try {\n const sourceKey = options.sourceKey || process.env['LINEAR_API_KEY'];\n const targetKey = options.targetKey;\n\n if (!sourceKey) {\n console.error(\n chalk.red(\n '\u274C Source API key required. Use --source-key or set LINEAR_API_KEY'\n )\n );\n return;\n }\n\n if (!targetKey) {\n console.error(\n chalk.red('\u274C Target API key required. Use --target-key')\n );\n return;\n }\n\n console.log(chalk.blue('\uD83D\uDE80 Starting Linear Migration'));\n console.log(chalk.gray(' This will migrate all STA- prefixed tasks'));\n if (options.deleteSource) {\n console.log(\n chalk.yellow(\n ' \u26A0\uFE0F Tasks will be DELETED from source after migration'\n )\n );\n }\n console.log();\n\n await runMigration({\n sourceApiKey: sourceKey,\n targetApiKey: targetKey,\n taskPrefix: 'STA-',\n deleteFromSource: options.deleteSource,\n dryRun: options.dryRun,\n batchSize: parseInt(options.batchSize),\n delayMs: parseInt(options.delay),\n });\n } catch (error: unknown) {\n console.error(chalk.red('Migration failed:'), (error as Error).message);\n process.exit(1);\n }\n });\n}\n"],
5
+ "mappings": "AAKA,OAAO,WAAW;AAClB,SAAS,oBAAoB;AAE7B,SAAS,OAAO,KAAa,cAA+B;AAC1D,QAAM,QAAQ,QAAQ,IAAI,GAAG;AAC7B,MAAI,UAAU,QAAW;AACvB,QAAI,iBAAiB,OAAW,QAAO;AACvC,UAAM,IAAI,MAAM,wBAAwB,GAAG,cAAc;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,SAAS,eAAe,KAAiC;AACvD,SAAO,QAAQ,IAAI,GAAG;AACxB;AAEO,SAAS,6BAA6B,QAAiB;AAC5D,SACG,QAAQ,gBAAgB,EACxB,YAAY,wDAAwD,EACpE,OAAO,sBAAsB,iCAAiC,EAC9D,OAAO,sBAAsB,iCAAiC,EAC9D,OAAO,aAAa,0CAA0C,EAC9D;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,oBAAoB,6BAA6B,GAAG,EAC3D,OAAO,gBAAgB,yCAAyC,MAAM,EACtE,OAAO,OAAO,YAAY;AACzB,QAAI;AACF,YAAM,YAAY,QAAQ,aAAa,QAAQ,IAAI,gBAAgB;AACnE,YAAM,YAAY,QAAQ;AAE1B,UAAI,CAAC,WAAW;AACd,gBAAQ;AAAA,UACN,MAAM;AAAA,YACJ;AAAA,UACF;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,CAAC,WAAW;AACd,gBAAQ;AAAA,UACN,MAAM,IAAI,kDAA6C;AAAA,QACzD;AACA;AAAA,MACF;AAEA,cAAQ,IAAI,MAAM,KAAK,qCAA8B,CAAC;AACtD,cAAQ,IAAI,MAAM,KAAK,8CAA8C,CAAC;AACtE,UAAI,QAAQ,cAAc;AACxB,gBAAQ;AAAA,UACN,MAAM;AAAA,YACJ;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,cAAQ,IAAI;AAEZ,YAAM,aAAa;AAAA,QACjB,cAAc;AAAA,QACd,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,kBAAkB,QAAQ;AAAA,QAC1B,QAAQ,QAAQ;AAAA,QAChB,WAAW,SAAS,QAAQ,SAAS;AAAA,QACrC,SAAS,SAAS,QAAQ,KAAK;AAAA,MACjC,CAAC;AAAA,IACH,SAAS,OAAgB;AACvB,cAAQ,MAAM,MAAM,IAAI,mBAAmB,GAAI,MAAgB,OAAO;AACtE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;",
6
6
  "names": []
7
7
  }
@@ -1,18 +1,31 @@
1
1
  import chalk from "chalk";
2
+ function getEnv(key, defaultValue) {
3
+ const value = process.env[key];
4
+ if (value === void 0) {
5
+ if (defaultValue !== void 0) return defaultValue;
6
+ throw new Error(`Environment variable ${key} is required`);
7
+ }
8
+ return value;
9
+ }
10
+ function getOptionalEnv(key) {
11
+ return process.env[key];
12
+ }
2
13
  function registerLinearTestCommand(parent) {
3
14
  parent.command("linear:test").description("Test Linear API connection").option("--api-key <key>", "Linear API key").action(async (options) => {
4
15
  try {
5
- const apiKey = options.apiKey || process.env.LINEAR_API_KEY;
16
+ const apiKey = options.apiKey || process.env["LINEAR_API_KEY"];
6
17
  if (!apiKey) {
7
18
  console.log(chalk.red("\u274C No API key provided"));
8
- console.log("Use --api-key or set LINEAR_API_KEY environment variable");
19
+ console.log(
20
+ "Use --api-key or set LINEAR_API_KEY environment variable"
21
+ );
9
22
  return;
10
23
  }
11
24
  console.log(chalk.yellow("\u{1F504} Testing Linear connection..."));
12
25
  const response = await fetch("https://api.linear.app/graphql", {
13
26
  method: "POST",
14
27
  headers: {
15
- "Authorization": apiKey,
28
+ Authorization: apiKey,
16
29
  "Content-Type": "application/json"
17
30
  },
18
31
  body: JSON.stringify({
@@ -35,13 +48,17 @@ function registerLinearTestCommand(parent) {
35
48
  })
36
49
  });
37
50
  if (!response.ok) {
38
- console.log(chalk.red(`\u274C API Error: ${response.status} ${response.statusText}`));
51
+ console.log(
52
+ chalk.red(`\u274C API Error: ${response.status} ${response.statusText}`)
53
+ );
39
54
  return;
40
55
  }
41
56
  const result = await response.json();
42
57
  if (result.errors) {
43
58
  console.log(chalk.red("\u274C GraphQL Errors:"));
44
- result.errors.forEach((err) => console.log(` - ${err.message}`));
59
+ result.errors.forEach(
60
+ (err) => console.log(` - ${err.message}`)
61
+ );
45
62
  return;
46
63
  }
47
64
  if (result.data?.viewer) {
@@ -62,7 +79,7 @@ function registerLinearTestCommand(parent) {
62
79
  const createResponse = await fetch("https://api.linear.app/graphql", {
63
80
  method: "POST",
64
81
  headers: {
65
- "Authorization": apiKey,
82
+ Authorization: apiKey,
66
83
  "Content-Type": "application/json"
67
84
  },
68
85
  body: JSON.stringify({
@@ -97,7 +114,9 @@ function registerLinearTestCommand(parent) {
97
114
  console.log(` ID: ${issue.identifier}`);
98
115
  console.log(` Title: ${issue.title}`);
99
116
  console.log(` URL: ${issue.url}`);
100
- console.log(chalk.gray("\n(You can delete this test issue from Linear)"));
117
+ console.log(
118
+ chalk.gray("\n(You can delete this test issue from Linear)")
119
+ );
101
120
  } else {
102
121
  console.log(chalk.yellow("\u26A0 Could not create test issue"));
103
122
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/cli/commands/linear-test.ts"],
4
- "sourcesContent": ["/**\n * Simple Linear sync test command\n */\n\nimport chalk from 'chalk';\nimport { Command } from 'commander';\n\nexport function registerLinearTestCommand(parent: Command) {\n parent\n .command('linear:test')\n .description('Test Linear API connection')\n .option('--api-key <key>', 'Linear API key')\n .action(async (options) => {\n try {\n const apiKey = options.apiKey || process.env.LINEAR_API_KEY;\n \n if (!apiKey) {\n console.log(chalk.red('\u274C No API key provided'));\n console.log('Use --api-key or set LINEAR_API_KEY environment variable');\n return;\n }\n \n console.log(chalk.yellow('\uD83D\uDD04 Testing Linear connection...'));\n \n // Simple GraphQL query to test connection\n const response = await fetch('https://api.linear.app/graphql', {\n method: 'POST',\n headers: {\n 'Authorization': apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n query: `\n query Me {\n viewer {\n id\n name\n email\n }\n teams {\n nodes {\n id\n key\n name\n }\n }\n }\n `\n }),\n });\n \n if (!response.ok) {\n console.log(chalk.red(`\u274C API Error: ${response.status} ${response.statusText}`));\n return;\n }\n \n const result: any = await response.json();\n \n if (result.errors) {\n console.log(chalk.red('\u274C GraphQL Errors:'));\n result.errors.forEach((err: any) => console.log(` - ${err.message}`));\n return;\n }\n \n if (result.data?.viewer) {\n console.log(chalk.green('\u2705 Connected to Linear!'));\n console.log(chalk.cyan('\\n\uD83D\uDC64 User:'));\n console.log(` Name: ${result.data.viewer.name}`);\n console.log(` Email: ${result.data.viewer.email}`);\n }\n \n if (result.data?.teams?.nodes?.length > 0) {\n console.log(chalk.cyan('\\n\uD83C\uDFE2 Teams:'));\n result.data.teams.nodes.forEach((team: any) => {\n console.log(` - ${team.name} (${team.key})`);\n });\n }\n \n // Test creating a sample issue (optional)\n console.log(chalk.yellow('\\n\uD83D\uDD04 Testing issue creation...'));\n \n if (result.data?.teams?.nodes?.length > 0) {\n const teamId = result.data.teams.nodes[0].id;\n \n const createResponse = await fetch('https://api.linear.app/graphql', {\n method: 'POST',\n headers: {\n 'Authorization': apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n query: `\n mutation CreateIssue($input: IssueCreateInput!) {\n issueCreate(input: $input) {\n success\n issue {\n id\n identifier\n title\n url\n }\n }\n }\n `,\n variables: {\n input: {\n teamId: teamId,\n title: '[TEST] StackMemory Integration Test',\n description: 'This is a test issue created by StackMemory to verify Linear integration.',\n priority: 4, // Low priority\n }\n }\n }),\n });\n \n const createResult: any = await createResponse.json();\n \n if (createResult.data?.issueCreate?.success) {\n const issue = createResult.data.issueCreate.issue;\n console.log(chalk.green('\u2705 Test issue created successfully!'));\n console.log(` ID: ${issue.identifier}`);\n console.log(` Title: ${issue.title}`);\n console.log(` URL: ${issue.url}`);\n \n // Optional: Delete the test issue\n console.log(chalk.gray('\\n(You can delete this test issue from Linear)'));\n } else {\n console.log(chalk.yellow('\u26A0 Could not create test issue'));\n }\n }\n \n console.log(chalk.green('\\n\u2705 Linear integration test completed!'));\n \n } catch (error) {\n console.error(chalk.red('\u274C Test failed:'), (error as Error).message);\n process.exit(1);\n }\n });\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Simple Linear sync test command\n */\n\nimport chalk from 'chalk';\nimport { Command } from 'commander';\n// Type-safe environment variable access\nfunction getEnv(key: string, defaultValue?: string): string {\n const value = process.env[key];\n if (value === undefined) {\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Environment variable ${key} is required`);\n }\n return value;\n}\n\nfunction getOptionalEnv(key: string): string | undefined {\n return process.env[key];\n}\n\nexport function registerLinearTestCommand(parent: Command) {\n parent\n .command('linear:test')\n .description('Test Linear API connection')\n .option('--api-key <key>', 'Linear API key')\n .action(async (options) => {\n try {\n const apiKey = options.apiKey || process.env['LINEAR_API_KEY'];\n\n if (!apiKey) {\n console.log(chalk.red('\u274C No API key provided'));\n console.log(\n 'Use --api-key or set LINEAR_API_KEY environment variable'\n );\n return;\n }\n\n console.log(chalk.yellow('\uD83D\uDD04 Testing Linear connection...'));\n\n // Simple GraphQL query to test connection\n const response = await fetch('https://api.linear.app/graphql', {\n method: 'POST',\n headers: {\n Authorization: apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n query: `\n query Me {\n viewer {\n id\n name\n email\n }\n teams {\n nodes {\n id\n key\n name\n }\n }\n }\n `,\n }),\n });\n\n if (!response.ok) {\n console.log(\n chalk.red(`\u274C API Error: ${response.status} ${response.statusText}`)\n );\n return;\n }\n\n const result: any = await response.json();\n\n if (result.errors) {\n console.log(chalk.red('\u274C GraphQL Errors:'));\n result.errors.forEach((err: any) =>\n console.log(` - ${err.message}`)\n );\n return;\n }\n\n if (result.data?.viewer) {\n console.log(chalk.green('\u2705 Connected to Linear!'));\n console.log(chalk.cyan('\\n\uD83D\uDC64 User:'));\n console.log(` Name: ${result.data.viewer.name}`);\n console.log(` Email: ${result.data.viewer.email}`);\n }\n\n if (result.data?.teams?.nodes?.length > 0) {\n console.log(chalk.cyan('\\n\uD83C\uDFE2 Teams:'));\n result.data.teams.nodes.forEach((team: any) => {\n console.log(` - ${team.name} (${team.key})`);\n });\n }\n\n // Test creating a sample issue (optional)\n console.log(chalk.yellow('\\n\uD83D\uDD04 Testing issue creation...'));\n\n if (result.data?.teams?.nodes?.length > 0) {\n const teamId = result.data.teams.nodes[0].id;\n\n const createResponse = await fetch('https://api.linear.app/graphql', {\n method: 'POST',\n headers: {\n Authorization: apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n query: `\n mutation CreateIssue($input: IssueCreateInput!) {\n issueCreate(input: $input) {\n success\n issue {\n id\n identifier\n title\n url\n }\n }\n }\n `,\n variables: {\n input: {\n teamId: teamId,\n title: '[TEST] StackMemory Integration Test',\n description:\n 'This is a test issue created by StackMemory to verify Linear integration.',\n priority: 4, // Low priority\n },\n },\n }),\n });\n\n const createResult: any = await createResponse.json();\n\n if (createResult.data?.issueCreate?.success) {\n const issue = createResult.data.issueCreate.issue;\n console.log(chalk.green('\u2705 Test issue created successfully!'));\n console.log(` ID: ${issue.identifier}`);\n console.log(` Title: ${issue.title}`);\n console.log(` URL: ${issue.url}`);\n\n // Optional: Delete the test issue\n console.log(\n chalk.gray('\\n(You can delete this test issue from Linear)')\n );\n } else {\n console.log(chalk.yellow('\u26A0 Could not create test issue'));\n }\n }\n\n console.log(chalk.green('\\n\u2705 Linear integration test completed!'));\n } catch (error: unknown) {\n console.error(chalk.red('\u274C Test failed:'), (error as Error).message);\n process.exit(1);\n }\n });\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,350 @@
1
+ import chalk from "chalk";
2
+ import {
3
+ UnifiedLinearSync
4
+ } from "../../integrations/linear/unified-sync.js";
5
+ import { LinearAuthManager } from "../../integrations/linear/auth.js";
6
+ import { LinearClient } from "../../integrations/linear/client.js";
7
+ import { PebblesTaskStore } from "../../features/tasks/pebbles-task-store.js";
8
+ import Database from "better-sqlite3";
9
+ import { join } from "path";
10
+ import { existsSync, readFileSync } from "fs";
11
+ import Table from "cli-table3";
12
+ import ora from "ora";
13
+ function registerUnifiedLinearCommands(parent) {
14
+ const linear = parent.command("linear").description(
15
+ "Unified Linear integration with duplicate detection and task planning"
16
+ );
17
+ linear.command("sync").description(
18
+ "Intelligent sync with Linear (duplicate detection, bidirectional, task planning)"
19
+ ).option(
20
+ "-d, --direction <dir>",
21
+ "Sync direction: bidirectional, to_linear, from_linear",
22
+ "bidirectional"
23
+ ).option("-t, --team <id>", "Linear team ID").option("--no-duplicates", "Disable duplicate detection").option(
24
+ "--merge-strategy <strategy>",
25
+ "Duplicate handling: merge_content, skip, create_anyway",
26
+ "merge_content"
27
+ ).option(
28
+ "--conflict <resolution>",
29
+ "Conflict resolution: newest_wins, linear_wins, local_wins",
30
+ "newest_wins"
31
+ ).option("--task-plan", "Enable task planning integration").option("--dry-run", "Preview changes without syncing").option("--daemon", "Run as background daemon").option("-i, --interval <minutes>", "Auto-sync interval", "15").option("--verbose", "Show detailed sync progress").action(async (options) => {
32
+ const spinner = ora("Initializing Linear sync...").start();
33
+ try {
34
+ const projectRoot = process.cwd();
35
+ const dbPath = join(projectRoot, ".stackmemory", "context.db");
36
+ if (!existsSync(dbPath)) {
37
+ spinner.fail("StackMemory not initialized");
38
+ console.log(chalk.yellow('Run "stackmemory init" first'));
39
+ return;
40
+ }
41
+ const db = new Database(dbPath);
42
+ const taskStore = new PebblesTaskStore(projectRoot, db);
43
+ const authManager = new LinearAuthManager(projectRoot);
44
+ const config = {
45
+ direction: options.direction,
46
+ defaultTeamId: options.team,
47
+ duplicateDetection: options.duplicates !== false,
48
+ mergeStrategy: options.mergeStrategy,
49
+ conflictResolution: options.conflict,
50
+ taskPlanningEnabled: options.taskPlan || false
51
+ };
52
+ const unifiedSync = new UnifiedLinearSync(
53
+ taskStore,
54
+ authManager,
55
+ projectRoot,
56
+ config
57
+ );
58
+ if (options.verbose) {
59
+ unifiedSync.on("sync:started", ({ config: config2 }) => {
60
+ spinner.text = `Syncing (${config2.direction})...`;
61
+ });
62
+ }
63
+ spinner.text = "Authenticating with Linear...";
64
+ await unifiedSync.initialize();
65
+ if (options.dryRun) {
66
+ spinner.info("Dry run mode - no changes will be made");
67
+ return;
68
+ }
69
+ if (options.daemon) {
70
+ spinner.succeed("Starting sync daemon");
71
+ console.log(chalk.cyan(`Sync interval: ${options.interval} minutes`));
72
+ console.log(chalk.gray("Press Ctrl+C to stop\n"));
73
+ const stats = await unifiedSync.sync();
74
+ displaySyncStats(stats);
75
+ const interval = setInterval(
76
+ async () => {
77
+ console.log(
78
+ chalk.yellow(
79
+ `
80
+ [${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] Running scheduled sync...`
81
+ )
82
+ );
83
+ try {
84
+ const stats2 = await unifiedSync.sync();
85
+ displaySyncStats(stats2);
86
+ } catch (error) {
87
+ console.error(
88
+ chalk.red("Sync failed:"),
89
+ error.message
90
+ );
91
+ }
92
+ },
93
+ parseInt(options.interval) * 60 * 1e3
94
+ );
95
+ process.on("SIGINT", () => {
96
+ console.log(chalk.yellow("\nStopping sync daemon..."));
97
+ clearInterval(interval);
98
+ db.close();
99
+ process.exit(0);
100
+ });
101
+ process.stdin.resume();
102
+ } else {
103
+ spinner.text = "Syncing tasks...";
104
+ const stats = await unifiedSync.sync();
105
+ spinner.succeed("Sync completed");
106
+ displaySyncStats(stats);
107
+ if (options.taskPlan) {
108
+ displayTaskPlan(projectRoot);
109
+ }
110
+ db.close();
111
+ }
112
+ } catch (error) {
113
+ spinner.fail("Sync failed");
114
+ console.error(chalk.red("Error:"), error.message);
115
+ if (options.verbose) {
116
+ console.error(error);
117
+ }
118
+ process.exit(1);
119
+ }
120
+ });
121
+ linear.command("status").description("Show Linear connection status and sync statistics").action(async () => {
122
+ try {
123
+ const authManager = new LinearAuthManager(process.cwd());
124
+ const hasAuth = authManager.isConfigured();
125
+ if (!hasAuth && !process.env.LINEAR_API_KEY) {
126
+ console.log(chalk.yellow("\u26A0 Not connected to Linear"));
127
+ console.log('Run "stackmemory linear auth" to connect');
128
+ return;
129
+ }
130
+ console.log(chalk.green("\u2713 Linear connection configured"));
131
+ const statsFile = join(
132
+ process.cwd(),
133
+ ".stackmemory",
134
+ "sync-stats.json"
135
+ );
136
+ if (existsSync(statsFile)) {
137
+ const stats = JSON.parse(readFileSync(statsFile, "utf8"));
138
+ console.log(chalk.cyan("\nLast sync:"));
139
+ console.log(` Time: ${new Date(stats.timestamp).toLocaleString()}`);
140
+ console.log(` Duration: ${stats.duration}ms`);
141
+ console.log(
142
+ ` To Linear: ${stats.toLinear.created} created, ${stats.toLinear.updated} updated`
143
+ );
144
+ console.log(
145
+ ` From Linear: ${stats.fromLinear.created} created, ${stats.fromLinear.updated} updated`
146
+ );
147
+ if (stats.toLinear.duplicatesMerged > 0) {
148
+ console.log(
149
+ chalk.green(
150
+ ` Duplicates prevented: ${stats.toLinear.duplicatesMerged}`
151
+ )
152
+ );
153
+ }
154
+ }
155
+ const planFile = join(process.cwd(), ".stackmemory", "task-plan.md");
156
+ if (existsSync(planFile)) {
157
+ console.log(chalk.cyan("\n\u2713 Task planning enabled"));
158
+ const reportFile = join(
159
+ process.cwd(),
160
+ ".stackmemory",
161
+ "task-report.md"
162
+ );
163
+ if (existsSync(reportFile)) {
164
+ console.log(` Report: ${reportFile}`);
165
+ }
166
+ }
167
+ } catch (error) {
168
+ console.error(
169
+ chalk.red("Status check failed:"),
170
+ error.message
171
+ );
172
+ }
173
+ });
174
+ linear.command("plan").description("View and manage task planning").option("--generate", "Generate task plan from current tasks").option("--report", "Show task report").action(async (options) => {
175
+ try {
176
+ const projectRoot = process.cwd();
177
+ if (options.generate) {
178
+ console.log(chalk.yellow("Generating task plan..."));
179
+ const dbPath = join(projectRoot, ".stackmemory", "context.db");
180
+ const db = new Database(dbPath);
181
+ const taskStore = new PebblesTaskStore(projectRoot, db);
182
+ const authManager = new LinearAuthManager(projectRoot);
183
+ const unifiedSync = new UnifiedLinearSync(
184
+ taskStore,
185
+ authManager,
186
+ projectRoot,
187
+ {
188
+ taskPlanningEnabled: true,
189
+ autoCreateTaskPlan: true
190
+ }
191
+ );
192
+ await unifiedSync.initialize();
193
+ await unifiedSync.sync();
194
+ console.log(chalk.green("\u2713 Task plan generated"));
195
+ db.close();
196
+ }
197
+ displayTaskPlan(projectRoot, options.report);
198
+ } catch (error) {
199
+ console.error(
200
+ chalk.red("Plan generation failed:"),
201
+ error.message
202
+ );
203
+ }
204
+ });
205
+ linear.command("duplicates").description("Check for and manage duplicate Linear issues").option("--check <title>", "Check if a title would create a duplicate").option("--merge", "Merge detected duplicates").option("--list", "List potential duplicates").action(async (options) => {
206
+ try {
207
+ const authManager = new LinearAuthManager(process.cwd());
208
+ const token = await authManager.getValidToken();
209
+ if (!token) {
210
+ console.log(chalk.red("Not authenticated with Linear"));
211
+ return;
212
+ }
213
+ const client = new LinearClient({
214
+ apiKey: token,
215
+ useBearer: authManager.isOAuth()
216
+ });
217
+ if (options.check) {
218
+ const { LinearDuplicateDetector } = await import("../../integrations/linear/sync-enhanced.js");
219
+ const detector = new LinearDuplicateDetector(client);
220
+ console.log(
221
+ chalk.yellow(`Checking for duplicates of: "${options.check}"`)
222
+ );
223
+ const result = await detector.checkForDuplicate(options.check);
224
+ if (result.isDuplicate && result.existingIssue) {
225
+ console.log(chalk.red("\u26A0 Duplicate detected!"));
226
+ console.log(
227
+ ` Issue: ${result.existingIssue.identifier} - ${result.existingIssue.title}`
228
+ );
229
+ console.log(
230
+ ` Similarity: ${Math.round((result.similarity || 0) * 100)}%`
231
+ );
232
+ console.log(` URL: ${result.existingIssue.url}`);
233
+ } else {
234
+ console.log(chalk.green("\u2713 No duplicates found"));
235
+ }
236
+ } else if (options.list) {
237
+ console.log(chalk.yellow("Scanning for potential duplicates..."));
238
+ console.log("Feature coming soon");
239
+ } else {
240
+ console.log("Specify --check, --merge, or --list");
241
+ }
242
+ } catch (error) {
243
+ console.error(
244
+ chalk.red("Duplicate check failed:"),
245
+ error.message
246
+ );
247
+ }
248
+ });
249
+ linear.command("auth").description("Authenticate with Linear").option("--api-key <key>", "Use API key").option("--oauth", "Use OAuth flow").action(async (options) => {
250
+ try {
251
+ const authManager = new LinearAuthManager(process.cwd());
252
+ if (options.apiKey) {
253
+ process.env.LINEAR_API_KEY = options.apiKey;
254
+ console.log(chalk.green("\u2713 API key configured"));
255
+ const client = new LinearClient({ apiKey: options.apiKey });
256
+ const user = await client.getViewer();
257
+ console.log(chalk.cyan(`Connected as: ${user.name} (${user.email})`));
258
+ } else {
259
+ console.log(chalk.cyan("Linear Authentication"));
260
+ console.log("\nOption 1: API Key (Recommended for automation)");
261
+ console.log(" 1. Go to: https://linear.app/settings/api");
262
+ console.log(" 2. Create a personal API key");
263
+ console.log(" 3. Run: stackmemory linear auth --api-key YOUR_KEY");
264
+ console.log("\nOption 2: OAuth (For user-facing apps)");
265
+ console.log(" Configure OAuth app and use linear-oauth-server");
266
+ }
267
+ } catch (error) {
268
+ console.error(
269
+ chalk.red("Authentication failed:"),
270
+ error.message
271
+ );
272
+ }
273
+ });
274
+ }
275
+ function displaySyncStats(stats) {
276
+ const table = new Table({
277
+ head: ["Direction", "Created", "Updated", "Merged", "Skipped"],
278
+ style: { head: ["cyan"] }
279
+ });
280
+ table.push(
281
+ [
282
+ "\u2192 Linear",
283
+ stats.toLinear.created,
284
+ stats.toLinear.updated,
285
+ stats.toLinear.duplicatesMerged,
286
+ stats.toLinear.skipped
287
+ ],
288
+ [
289
+ "\u2190 Linear",
290
+ stats.fromLinear.created,
291
+ stats.fromLinear.updated,
292
+ "-",
293
+ stats.fromLinear.skipped
294
+ ]
295
+ );
296
+ console.log("\n" + table.toString());
297
+ if (stats.conflicts.length > 0) {
298
+ console.log(chalk.yellow(`
299
+ \u26A0 Conflicts: ${stats.conflicts.length}`));
300
+ stats.conflicts.slice(0, 5).forEach((c) => {
301
+ console.log(` - ${c.reason}`);
302
+ });
303
+ }
304
+ if (stats.errors.length > 0) {
305
+ console.log(chalk.red(`
306
+ \u274C Errors: ${stats.errors.length}`));
307
+ stats.errors.slice(0, 5).forEach((e) => {
308
+ console.log(` - ${e.substring(0, 100)}`);
309
+ });
310
+ }
311
+ console.log(chalk.gray(`
312
+ Completed in ${stats.duration}ms`));
313
+ }
314
+ function displayTaskPlan(projectRoot, showReport = false) {
315
+ const reportFile = join(projectRoot, ".stackmemory", "task-report.md");
316
+ const planFile = join(projectRoot, ".stackmemory", "task-plan.json");
317
+ if (showReport && existsSync(reportFile)) {
318
+ const report = readFileSync(reportFile, "utf8");
319
+ console.log("\n" + report);
320
+ } else if (existsSync(planFile)) {
321
+ const plan = JSON.parse(readFileSync(planFile, "utf8"));
322
+ console.log(chalk.cyan("\n\u{1F4CB} Task Plan Overview"));
323
+ console.log(
324
+ `Last updated: ${new Date(plan.lastUpdated).toLocaleString()}
325
+ `
326
+ );
327
+ plan.phases.forEach((phase) => {
328
+ console.log(chalk.yellow(`${phase.name} (${phase.tasks.length})`));
329
+ console.log(chalk.gray(` ${phase.description}`));
330
+ if (phase.tasks.length > 0) {
331
+ phase.tasks.slice(0, 5).forEach((task) => {
332
+ const status = task.linearId ? "\u{1F517}" : " ";
333
+ console.log(` ${status} ${task.title}`);
334
+ });
335
+ if (phase.tasks.length > 5) {
336
+ console.log(chalk.gray(` ...and ${phase.tasks.length - 5} more`));
337
+ }
338
+ }
339
+ console.log();
340
+ });
341
+ } else {
342
+ console.log(
343
+ chalk.yellow("No task plan found. Run sync with --task-plan to generate.")
344
+ );
345
+ }
346
+ }
347
+ export {
348
+ registerUnifiedLinearCommands
349
+ };
350
+ //# sourceMappingURL=linear-unified.js.map