@stackmemoryai/stackmemory 0.2.7 → 0.2.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 (297) hide show
  1. package/README.md +25 -8
  2. package/dist/scripts/cancel-duplicate-tasks.js +2 -1
  3. package/dist/scripts/cancel-duplicate-tasks.js.map +1 -1
  4. package/dist/scripts/list-linear-tasks.js +3 -4
  5. package/dist/scripts/list-linear-tasks.js.map +1 -1
  6. package/dist/scripts/merge-linear-duplicates-safe.js +4 -2
  7. package/dist/scripts/merge-linear-duplicates-safe.js.map +1 -1
  8. package/dist/scripts/show-linear-summary.js +4 -1
  9. package/dist/scripts/show-linear-summary.js.map +1 -1
  10. package/dist/scripts/status.js +6 -2
  11. package/dist/scripts/status.js.map +1 -1
  12. package/dist/src/cli/auto-detect.js.map +1 -1
  13. package/dist/src/cli/claude-sm.js.map +1 -1
  14. package/dist/src/cli/commands/config.d.ts +6 -0
  15. package/dist/src/cli/commands/config.d.ts.map +1 -0
  16. package/dist/src/cli/commands/config.js +224 -0
  17. package/dist/src/cli/commands/config.js.map +1 -0
  18. package/dist/src/cli/commands/linear.d.ts.map +1 -1
  19. package/dist/src/cli/commands/linear.js +123 -47
  20. package/dist/src/cli/commands/linear.js.map +1 -1
  21. package/dist/src/cli/index.d.ts.map +1 -1
  22. package/dist/src/cli/index.js +48 -1
  23. package/dist/src/cli/index.js.map +1 -1
  24. package/dist/src/core/config/config-manager.d.ts +95 -0
  25. package/dist/src/core/config/config-manager.d.ts.map +1 -0
  26. package/dist/src/core/config/config-manager.js +359 -0
  27. package/dist/src/core/config/config-manager.js.map +1 -0
  28. package/dist/src/core/config/types.d.ts +72 -0
  29. package/dist/src/core/config/types.d.ts.map +1 -0
  30. package/dist/src/core/config/types.js +127 -0
  31. package/dist/src/core/config/types.js.map +1 -0
  32. package/dist/src/core/context/compaction-handler.d.ts +119 -0
  33. package/dist/src/core/context/compaction-handler.d.ts.map +1 -0
  34. package/dist/src/core/context/compaction-handler.js +306 -0
  35. package/dist/src/core/context/compaction-handler.js.map +1 -0
  36. package/dist/src/core/context/model-aware-compaction.d.ts +101 -0
  37. package/dist/src/core/context/model-aware-compaction.d.ts.map +1 -0
  38. package/dist/src/core/context/model-aware-compaction.js +616 -0
  39. package/dist/src/core/context/model-aware-compaction.js.map +1 -0
  40. package/dist/src/core/query/query-parser.d.ts +104 -0
  41. package/dist/src/core/query/query-parser.d.ts.map +1 -0
  42. package/dist/src/core/query/query-parser.js +347 -0
  43. package/dist/src/core/query/query-parser.js.map +1 -0
  44. package/dist/src/core/retrieval/index.d.ts +8 -0
  45. package/dist/src/core/retrieval/index.d.ts.map +1 -0
  46. package/dist/src/core/retrieval/index.js +8 -0
  47. package/dist/src/core/retrieval/index.js.map +1 -0
  48. package/dist/src/core/retrieval/llm-context-retrieval.d.ts +71 -0
  49. package/dist/src/core/retrieval/llm-context-retrieval.d.ts.map +1 -0
  50. package/dist/src/core/retrieval/llm-context-retrieval.js +545 -0
  51. package/dist/src/core/retrieval/llm-context-retrieval.js.map +1 -0
  52. package/dist/src/core/retrieval/summary-generator.d.ts +63 -0
  53. package/dist/src/core/retrieval/summary-generator.d.ts.map +1 -0
  54. package/dist/src/core/retrieval/summary-generator.js +622 -0
  55. package/dist/src/core/retrieval/summary-generator.js.map +1 -0
  56. package/dist/src/core/retrieval/types.d.ts +257 -0
  57. package/dist/src/core/retrieval/types.d.ts.map +1 -0
  58. package/dist/src/core/retrieval/types.js +18 -0
  59. package/dist/src/core/retrieval/types.js.map +1 -0
  60. package/dist/src/core/trace/trace-detector.d.ts +108 -0
  61. package/dist/src/core/trace/trace-detector.d.ts.map +1 -0
  62. package/dist/src/core/trace/trace-detector.demo.d.ts +5 -0
  63. package/dist/src/core/trace/trace-detector.demo.d.ts.map +1 -0
  64. package/dist/src/core/trace/trace-detector.demo.js +145 -0
  65. package/dist/src/core/trace/trace-detector.demo.js.map +1 -0
  66. package/dist/src/core/trace/trace-detector.js +425 -0
  67. package/dist/src/core/trace/trace-detector.js.map +1 -0
  68. package/dist/src/core/trace/trace-store.d.ts +60 -0
  69. package/dist/src/core/trace/trace-store.d.ts.map +1 -0
  70. package/dist/src/core/trace/trace-store.js +323 -0
  71. package/dist/src/core/trace/trace-store.js.map +1 -0
  72. package/dist/src/core/trace/types.d.ts +81 -0
  73. package/dist/src/core/trace/types.d.ts.map +1 -0
  74. package/dist/src/core/trace/types.js +70 -0
  75. package/dist/src/core/trace/types.js.map +1 -0
  76. package/dist/src/integrations/linear/sync-manager.d.ts +76 -0
  77. package/dist/src/integrations/linear/sync-manager.d.ts.map +1 -0
  78. package/dist/src/integrations/linear/sync-manager.js +223 -0
  79. package/dist/src/integrations/linear/sync-manager.js.map +1 -0
  80. package/dist/src/integrations/mcp/server.d.ts +8 -0
  81. package/dist/src/integrations/mcp/server.d.ts.map +1 -1
  82. package/dist/src/integrations/mcp/server.js +368 -16
  83. package/dist/src/integrations/mcp/server.js.map +1 -1
  84. package/dist/src/integrations/mcp/trace-test.d.ts +5 -0
  85. package/dist/src/integrations/mcp/trace-test.d.ts.map +1 -0
  86. package/dist/src/integrations/mcp/trace-test.js +54 -0
  87. package/dist/src/integrations/mcp/trace-test.js.map +1 -0
  88. package/dist/src/services/config-service.d.ts +1 -1
  89. package/dist/src/services/config-service.d.ts.map +1 -1
  90. package/dist/src/services/config-service.js.map +1 -1
  91. package/dist/src/types/task.d.ts +11 -1
  92. package/dist/src/types/task.d.ts.map +1 -1
  93. package/dist/src/utils/logger.d.ts +4 -4
  94. package/dist/src/utils/logger.d.ts.map +1 -1
  95. package/dist/src/utils/logger.js.map +1 -1
  96. package/package.json +9 -8
  97. package/dist/attention-scoring/src/attention-tracker.d.ts +0 -79
  98. package/dist/attention-scoring/src/attention-tracker.d.ts.map +0 -1
  99. package/dist/attention-scoring/src/attention-tracker.js +0 -488
  100. package/dist/attention-scoring/src/attention-tracker.js.map +0 -1
  101. package/dist/attention-scoring/src/mcp-integration.d.ts +0 -56
  102. package/dist/attention-scoring/src/mcp-integration.d.ts.map +0 -1
  103. package/dist/attention-scoring/src/mcp-integration.js +0 -369
  104. package/dist/attention-scoring/src/mcp-integration.js.map +0 -1
  105. package/dist/index.js +0 -382
  106. package/dist/p2p-sync/src/p2p-sync.d.ts +0 -81
  107. package/dist/p2p-sync/src/p2p-sync.d.ts.map +0 -1
  108. package/dist/p2p-sync/src/p2p-sync.js +0 -457
  109. package/dist/p2p-sync/src/p2p-sync.js.map +0 -1
  110. package/dist/p2p-sync/src/team-context-sync.d.ts +0 -99
  111. package/dist/p2p-sync/src/team-context-sync.d.ts.map +0 -1
  112. package/dist/p2p-sync/src/team-context-sync.js +0 -491
  113. package/dist/p2p-sync/src/team-context-sync.js.map +0 -1
  114. package/dist/scripts/merge-linear-duplicates.d.ts +0 -7
  115. package/dist/scripts/merge-linear-duplicates.d.ts.map +0 -1
  116. package/dist/scripts/merge-linear-duplicates.js +0 -126
  117. package/dist/scripts/merge-linear-duplicates.js.map +0 -1
  118. package/dist/src/analytics/api/analytics-api.d.ts +0 -24
  119. package/dist/src/analytics/api/analytics-api.d.ts.map +0 -1
  120. package/dist/src/analytics/api/analytics-api.js +0 -279
  121. package/dist/src/analytics/api/analytics-api.js.map +0 -1
  122. package/dist/src/analytics/core/analytics-service.d.ts +0 -23
  123. package/dist/src/analytics/core/analytics-service.d.ts.map +0 -1
  124. package/dist/src/analytics/core/analytics-service.js +0 -160
  125. package/dist/src/analytics/core/analytics-service.js.map +0 -1
  126. package/dist/src/analytics/index.d.ts +0 -12
  127. package/dist/src/analytics/index.d.ts.map +0 -1
  128. package/dist/src/analytics/index.js +0 -11
  129. package/dist/src/analytics/index.js.map +0 -1
  130. package/dist/src/analytics/queries/metrics-queries.d.ts +0 -11
  131. package/dist/src/analytics/queries/metrics-queries.d.ts.map +0 -1
  132. package/dist/src/analytics/queries/metrics-queries.js +0 -179
  133. package/dist/src/analytics/queries/metrics-queries.js.map +0 -1
  134. package/dist/src/analytics/types/metrics.d.ts +0 -60
  135. package/dist/src/analytics/types/metrics.d.ts.map +0 -1
  136. package/dist/src/analytics/types/metrics.js +0 -2
  137. package/dist/src/analytics/types/metrics.js.map +0 -1
  138. package/dist/src/beads/beads-task-store.d.ts +0 -117
  139. package/dist/src/beads/beads-task-store.d.ts.map +0 -1
  140. package/dist/src/beads/beads-task-store.js +0 -318
  141. package/dist/src/beads/beads-task-store.js.map +0 -1
  142. package/dist/src/beads/task-aware-context.d.ts +0 -103
  143. package/dist/src/beads/task-aware-context.d.ts.map +0 -1
  144. package/dist/src/beads/task-aware-context.js +0 -395
  145. package/dist/src/beads/task-aware-context.js.map +0 -1
  146. package/dist/src/beads-task-store.d.ts +0 -117
  147. package/dist/src/beads-task-store.d.ts.map +0 -1
  148. package/dist/src/beads-task-store.js +0 -318
  149. package/dist/src/beads-task-store.js.map +0 -1
  150. package/dist/src/cli/__tests__/index.test.d.ts +0 -5
  151. package/dist/src/cli/__tests__/index.test.d.ts.map +0 -1
  152. package/dist/src/cli/__tests__/index.test.js +0 -726
  153. package/dist/src/cli/__tests__/index.test.js.map +0 -1
  154. package/dist/src/cli/analytics-viewer.d.ts +0 -3
  155. package/dist/src/cli/analytics-viewer.d.ts.map +0 -1
  156. package/dist/src/cli/analytics-viewer.js +0 -89
  157. package/dist/src/cli/analytics-viewer.js.map +0 -1
  158. package/dist/src/cli/cli.d.ts +0 -7
  159. package/dist/src/cli/cli.d.ts.map +0 -1
  160. package/dist/src/cli/cli.js +0 -704
  161. package/dist/src/cli/cli.js.map +0 -1
  162. package/dist/src/cli/project-commands.d.ts +0 -8
  163. package/dist/src/cli/project-commands.d.ts.map +0 -1
  164. package/dist/src/cli/project-commands.js +0 -212
  165. package/dist/src/cli/project-commands.js.map +0 -1
  166. package/dist/src/cli.d.ts +0 -7
  167. package/dist/src/cli.d.ts.map +0 -1
  168. package/dist/src/cli.js +0 -73
  169. package/dist/src/cli.js.map +0 -1
  170. package/dist/src/core/context/__tests__/frame-manager.test.d.ts +0 -5
  171. package/dist/src/core/context/__tests__/frame-manager.test.d.ts.map +0 -1
  172. package/dist/src/core/context/__tests__/frame-manager.test.js +0 -892
  173. package/dist/src/core/context/__tests__/frame-manager.test.js.map +0 -1
  174. package/dist/src/core/error-handler.d.ts +0 -46
  175. package/dist/src/core/error-handler.d.ts.map +0 -1
  176. package/dist/src/core/error-handler.js +0 -212
  177. package/dist/src/core/error-handler.js.map +0 -1
  178. package/dist/src/core/errors/__tests__/error-handling.test.d.ts +0 -5
  179. package/dist/src/core/errors/__tests__/error-handling.test.d.ts.map +0 -1
  180. package/dist/src/core/errors/__tests__/error-handling.test.js +0 -239
  181. package/dist/src/core/errors/__tests__/error-handling.test.js.map +0 -1
  182. package/dist/src/core/frame-manager.d.ts +0 -106
  183. package/dist/src/core/frame-manager.d.ts.map +0 -1
  184. package/dist/src/core/frame-manager.js +0 -387
  185. package/dist/src/core/frame-manager.js.map +0 -1
  186. package/dist/src/core/logger.d.ts +0 -24
  187. package/dist/src/core/logger.d.ts.map +0 -1
  188. package/dist/src/core/logger.js +0 -121
  189. package/dist/src/core/logger.js.map +0 -1
  190. package/dist/src/core/logger.test.d.ts +0 -2
  191. package/dist/src/core/logger.test.d.ts.map +0 -1
  192. package/dist/src/core/logger.test.js +0 -31
  193. package/dist/src/core/logger.test.js.map +0 -1
  194. package/dist/src/core/progress-tracker.d.ts +0 -95
  195. package/dist/src/core/progress-tracker.d.ts.map +0 -1
  196. package/dist/src/core/progress-tracker.js +0 -178
  197. package/dist/src/core/progress-tracker.js.map +0 -1
  198. package/dist/src/core/project-manager.d.ts +0 -130
  199. package/dist/src/core/project-manager.d.ts.map +0 -1
  200. package/dist/src/core/project-manager.js +0 -582
  201. package/dist/src/core/project-manager.js.map +0 -1
  202. package/dist/src/core/update-checker.d.ts +0 -38
  203. package/dist/src/core/update-checker.d.ts.map +0 -1
  204. package/dist/src/core/update-checker.js +0 -156
  205. package/dist/src/core/update-checker.js.map +0 -1
  206. package/dist/src/error-handler.d.ts +0 -42
  207. package/dist/src/error-handler.d.ts.map +0 -1
  208. package/dist/src/error-handler.js +0 -155
  209. package/dist/src/error-handler.js.map +0 -1
  210. package/dist/src/features/tasks/__tests__/pebbles-task-store.test.d.ts +0 -5
  211. package/dist/src/features/tasks/__tests__/pebbles-task-store.test.d.ts.map +0 -1
  212. package/dist/src/features/tasks/__tests__/pebbles-task-store.test.js +0 -712
  213. package/dist/src/features/tasks/__tests__/pebbles-task-store.test.js.map +0 -1
  214. package/dist/src/frame-manager.d.ts +0 -106
  215. package/dist/src/frame-manager.d.ts.map +0 -1
  216. package/dist/src/frame-manager.js +0 -361
  217. package/dist/src/frame-manager.js.map +0 -1
  218. package/dist/src/integrations/browser-mcp.d.ts +0 -94
  219. package/dist/src/integrations/browser-mcp.d.ts.map +0 -1
  220. package/dist/src/integrations/browser-mcp.js +0 -431
  221. package/dist/src/integrations/browser-mcp.js.map +0 -1
  222. package/dist/src/integrations/linear/__tests__/auth.test.d.ts +0 -5
  223. package/dist/src/integrations/linear/__tests__/auth.test.d.ts.map +0 -1
  224. package/dist/src/integrations/linear/__tests__/auth.test.js +0 -517
  225. package/dist/src/integrations/linear/__tests__/auth.test.js.map +0 -1
  226. package/dist/src/integrations/linear/__tests__/sync-service.test.d.ts +0 -5
  227. package/dist/src/integrations/linear/__tests__/sync-service.test.d.ts.map +0 -1
  228. package/dist/src/integrations/linear/__tests__/sync-service.test.js +0 -700
  229. package/dist/src/integrations/linear/__tests__/sync-service.test.js.map +0 -1
  230. package/dist/src/integrations/linear-auth.d.ts +0 -99
  231. package/dist/src/integrations/linear-auth.d.ts.map +0 -1
  232. package/dist/src/integrations/linear-auth.js +0 -319
  233. package/dist/src/integrations/linear-auth.js.map +0 -1
  234. package/dist/src/integrations/linear-auto-sync.d.ts +0 -77
  235. package/dist/src/integrations/linear-auto-sync.d.ts.map +0 -1
  236. package/dist/src/integrations/linear-auto-sync.js +0 -268
  237. package/dist/src/integrations/linear-auto-sync.js.map +0 -1
  238. package/dist/src/integrations/linear-client.d.ts +0 -86
  239. package/dist/src/integrations/linear-client.d.ts.map +0 -1
  240. package/dist/src/integrations/linear-client.js +0 -277
  241. package/dist/src/integrations/linear-client.js.map +0 -1
  242. package/dist/src/integrations/linear-config.d.ts +0 -51
  243. package/dist/src/integrations/linear-config.d.ts.map +0 -1
  244. package/dist/src/integrations/linear-config.js +0 -103
  245. package/dist/src/integrations/linear-config.js.map +0 -1
  246. package/dist/src/integrations/linear-sync.d.ts +0 -97
  247. package/dist/src/integrations/linear-sync.d.ts.map +0 -1
  248. package/dist/src/integrations/linear-sync.js +0 -391
  249. package/dist/src/integrations/linear-sync.js.map +0 -1
  250. package/dist/src/integrations/mcp/__tests__/server.test.d.ts +0 -5
  251. package/dist/src/integrations/mcp/__tests__/server.test.d.ts.map +0 -1
  252. package/dist/src/integrations/mcp/__tests__/server.test.js +0 -790
  253. package/dist/src/integrations/mcp/__tests__/server.test.js.map +0 -1
  254. package/dist/src/logger.d.ts +0 -24
  255. package/dist/src/logger.d.ts.map +0 -1
  256. package/dist/src/logger.js +0 -120
  257. package/dist/src/logger.js.map +0 -1
  258. package/dist/src/mcp/mcp-server.d.ts +0 -40
  259. package/dist/src/mcp/mcp-server.d.ts.map +0 -1
  260. package/dist/src/mcp/mcp-server.js +0 -828
  261. package/dist/src/mcp/mcp-server.js.map +0 -1
  262. package/dist/src/mcp-server.d.ts +0 -32
  263. package/dist/src/mcp-server.d.ts.map +0 -1
  264. package/dist/src/mcp-server.js +0 -441
  265. package/dist/src/mcp-server.js.map +0 -1
  266. package/dist/src/pebbles/pebbles-task-store.d.ts +0 -117
  267. package/dist/src/pebbles/pebbles-task-store.d.ts.map +0 -1
  268. package/dist/src/pebbles/pebbles-task-store.js +0 -335
  269. package/dist/src/pebbles/pebbles-task-store.js.map +0 -1
  270. package/dist/src/pebbles/task-aware-context.d.ts +0 -103
  271. package/dist/src/pebbles/task-aware-context.d.ts.map +0 -1
  272. package/dist/src/pebbles/task-aware-context.js +0 -412
  273. package/dist/src/pebbles/task-aware-context.js.map +0 -1
  274. package/dist/src/railway/index.d.ts +0 -7
  275. package/dist/src/railway/index.d.ts.map +0 -1
  276. package/dist/src/railway/index.js +0 -401
  277. package/dist/src/railway/index.js.map +0 -1
  278. package/dist/src/runway/auth/auth-middleware.d.ts +0 -66
  279. package/dist/src/runway/auth/auth-middleware.d.ts.map +0 -1
  280. package/dist/src/runway/auth/auth-middleware.js +0 -337
  281. package/dist/src/runway/auth/auth-middleware.js.map +0 -1
  282. package/dist/src/runway/server/runway-mcp-server.d.ts +0 -46
  283. package/dist/src/runway/server/runway-mcp-server.d.ts.map +0 -1
  284. package/dist/src/runway/server/runway-mcp-server.js +0 -601
  285. package/dist/src/runway/server/runway-mcp-server.js.map +0 -1
  286. package/dist/src/runway.bak/auth/auth-middleware.d.ts +0 -66
  287. package/dist/src/runway.bak/auth/auth-middleware.d.ts.map +0 -1
  288. package/dist/src/runway.bak/auth/auth-middleware.js +0 -337
  289. package/dist/src/runway.bak/auth/auth-middleware.js.map +0 -1
  290. package/dist/src/runway.bak/server/runway-mcp-server.d.ts +0 -46
  291. package/dist/src/runway.bak/server/runway-mcp-server.d.ts.map +0 -1
  292. package/dist/src/runway.bak/server/runway-mcp-server.js +0 -601
  293. package/dist/src/runway.bak/server/runway-mcp-server.js.map +0 -1
  294. package/dist/src/task-aware-context.d.ts +0 -103
  295. package/dist/src/task-aware-context.d.ts.map +0 -1
  296. package/dist/src/task-aware-context.js +0 -395
  297. package/dist/src/task-aware-context.js.map +0 -1
@@ -1,700 +0,0 @@
1
- /**
2
- * Tests for LinearSyncService - Bidirectional sync with Linear
3
- */
4
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
5
- import { LinearSyncService } from '../sync-service.js';
6
- import { LinearClient } from '../client.js';
7
- import { ContextService } from '../../../services/context-service.js';
8
- import { ConfigService } from '../../../services/config-service.js';
9
- // Mock dependencies
10
- vi.mock('../client.js', () => ({
11
- LinearClient: vi.fn()
12
- }));
13
- vi.mock('../../../services/context-service.js', () => ({
14
- ContextService: vi.fn()
15
- }));
16
- vi.mock('../../../services/config-service.js', () => ({
17
- ConfigService: vi.fn()
18
- }));
19
- vi.mock('../../../utils/logger.js', () => ({
20
- Logger: vi.fn().mockImplementation(() => ({
21
- info: vi.fn(),
22
- error: vi.fn(),
23
- debug: vi.fn(),
24
- warn: vi.fn()
25
- }))
26
- }));
27
- describe('LinearSyncService', () => {
28
- let syncService;
29
- let mockLinearClient;
30
- let mockContextService;
31
- let mockConfigService;
32
- let originalEnv;
33
- beforeEach(() => {
34
- // Store original environment
35
- originalEnv = process.env;
36
- // Set required environment variable
37
- process.env.LINEAR_API_KEY = 'test-api-key';
38
- // Setup mocks
39
- mockLinearClient = {
40
- getIssues: vi.fn(),
41
- updateIssue: vi.fn(),
42
- createIssue: vi.fn()
43
- };
44
- mockContextService = {
45
- getTaskByExternalId: vi.fn(),
46
- updateTask: vi.fn(),
47
- createTask: vi.fn(),
48
- getTask: vi.fn(),
49
- deleteTask: vi.fn(),
50
- getAllTasks: vi.fn()
51
- };
52
- mockConfigService = {
53
- getConfig: vi.fn()
54
- };
55
- // Configure mock constructors
56
- LinearClient.mockImplementation(() => mockLinearClient);
57
- ContextService.mockImplementation(() => mockContextService);
58
- ConfigService.mockImplementation(() => mockConfigService);
59
- // Create sync service instance
60
- syncService = new LinearSyncService();
61
- });
62
- afterEach(() => {
63
- // Restore environment
64
- process.env = originalEnv;
65
- vi.clearAllMocks();
66
- });
67
- describe('Initialization', () => {
68
- it('should initialize with Linear API key from environment', () => {
69
- expect(LinearClient).toHaveBeenCalledWith({ apiKey: 'test-api-key' });
70
- });
71
- it('should throw error when LINEAR_API_KEY is not set', () => {
72
- delete process.env.LINEAR_API_KEY;
73
- expect(() => {
74
- new LinearSyncService();
75
- }).toThrow('LINEAR_API_KEY environment variable not set');
76
- });
77
- it('should initialize services correctly', () => {
78
- expect(ContextService).toHaveBeenCalled();
79
- expect(ConfigService).toHaveBeenCalled();
80
- });
81
- });
82
- describe('syncAllIssues', () => {
83
- beforeEach(() => {
84
- mockConfigService.getConfig.mockResolvedValue({
85
- integrations: {
86
- linear: {
87
- teamId: 'test-team-id'
88
- }
89
- }
90
- });
91
- });
92
- it('should sync all issues from Linear successfully', async () => {
93
- const mockIssues = [
94
- {
95
- id: 'issue-1',
96
- identifier: 'STA-1',
97
- title: 'Test Issue 1',
98
- description: 'Description 1',
99
- state: { type: 'unstarted' },
100
- priority: 2,
101
- url: 'https://linear.app/issue-1',
102
- team: { id: 'team-1', key: 'STA' },
103
- labels: [{ name: 'bug' }],
104
- updatedAt: new Date().toISOString()
105
- },
106
- {
107
- id: 'issue-2',
108
- identifier: 'STA-2',
109
- title: 'Test Issue 2',
110
- description: 'Description 2',
111
- state: { type: 'completed' },
112
- priority: 3,
113
- url: 'https://linear.app/issue-2',
114
- team: { id: 'team-1', key: 'STA' },
115
- labels: [],
116
- updatedAt: new Date().toISOString()
117
- }
118
- ];
119
- mockLinearClient.getIssues.mockResolvedValue(mockIssues);
120
- mockContextService.getTaskByExternalId.mockResolvedValue(null); // No existing tasks
121
- const result = await syncService.syncAllIssues();
122
- expect(result.created).toBe(2);
123
- expect(result.updated).toBe(0);
124
- expect(result.errors).toHaveLength(0);
125
- expect(mockContextService.createTask).toHaveBeenCalledTimes(2);
126
- });
127
- it('should update existing tasks when they have changes', async () => {
128
- const mockIssue = {
129
- id: 'issue-1',
130
- identifier: 'STA-1',
131
- title: 'Updated Title',
132
- description: 'Updated Description',
133
- state: { type: 'completed' },
134
- priority: 3,
135
- url: 'https://linear.app/issue-1',
136
- team: { id: 'team-1', key: 'STA' },
137
- labels: [{ name: 'feature' }],
138
- updatedAt: new Date().toISOString()
139
- };
140
- const existingTask = {
141
- id: 'local-task-1',
142
- title: 'Old Title',
143
- description: 'Old Description',
144
- status: 'todo',
145
- priority: 'high',
146
- externalId: 'issue-1'
147
- };
148
- mockLinearClient.getIssues.mockResolvedValue([mockIssue]);
149
- mockContextService.getTaskByExternalId.mockResolvedValue(existingTask);
150
- const result = await syncService.syncAllIssues();
151
- expect(result.created).toBe(0);
152
- expect(result.updated).toBe(1);
153
- expect(mockContextService.updateTask).toHaveBeenCalledWith('local-task-1', expect.objectContaining({
154
- title: 'Updated Title',
155
- description: 'Updated Description',
156
- status: 'done',
157
- priority: 'medium'
158
- }));
159
- });
160
- it('should skip tasks without changes', async () => {
161
- const mockIssue = {
162
- id: 'issue-1',
163
- identifier: 'STA-1',
164
- title: 'Same Title',
165
- description: 'Same Description',
166
- state: { type: 'unstarted' },
167
- priority: 2,
168
- url: 'https://linear.app/issue-1',
169
- team: { id: 'team-1', key: 'STA' },
170
- labels: [{ name: 'bug' }],
171
- updatedAt: new Date().toISOString()
172
- };
173
- const existingTask = {
174
- id: 'local-task-1',
175
- title: 'Same Title',
176
- description: 'Same Description',
177
- status: 'todo',
178
- priority: 'high',
179
- tags: ['bug'],
180
- externalId: 'issue-1'
181
- };
182
- mockLinearClient.getIssues.mockResolvedValue([mockIssue]);
183
- mockContextService.getTaskByExternalId.mockResolvedValue(existingTask);
184
- const result = await syncService.syncAllIssues();
185
- expect(result.created).toBe(0);
186
- expect(result.updated).toBe(0);
187
- expect(mockContextService.updateTask).not.toHaveBeenCalled();
188
- });
189
- it('should handle sync errors gracefully', async () => {
190
- const mockIssues = [
191
- {
192
- id: 'issue-1',
193
- identifier: 'STA-1',
194
- title: 'Test Issue',
195
- state: { type: 'unstarted' },
196
- team: { id: 'team-1', key: 'STA' },
197
- updatedAt: new Date().toISOString()
198
- }
199
- ];
200
- mockLinearClient.getIssues.mockResolvedValue(mockIssues);
201
- mockContextService.getTaskByExternalId.mockRejectedValue(new Error('Database error'));
202
- const result = await syncService.syncAllIssues();
203
- expect(result.errors).toHaveLength(1);
204
- expect(result.errors[0]).toContain('Failed to sync STA-1');
205
- });
206
- it('should throw error when Linear team ID is not configured', async () => {
207
- mockConfigService.getConfig.mockResolvedValue({
208
- integrations: {}
209
- });
210
- const result = await syncService.syncAllIssues();
211
- expect(result.errors).toContain('Linear team ID not configured');
212
- });
213
- it('should handle Linear API errors', async () => {
214
- mockConfigService.getConfig.mockResolvedValue({
215
- integrations: {
216
- linear: { teamId: 'test-team-id' }
217
- }
218
- });
219
- mockLinearClient.getIssues.mockRejectedValue(new Error('Linear API error'));
220
- const result = await syncService.syncAllIssues();
221
- expect(result.errors).toContain('Linear API error');
222
- });
223
- });
224
- describe('syncIssueToLocal', () => {
225
- it('should create new local task from Linear issue', async () => {
226
- const mockIssue = {
227
- id: 'issue-1',
228
- identifier: 'STA-1',
229
- title: 'New Issue',
230
- description: 'Issue description',
231
- state: { type: 'unstarted', id: 'state-1', name: 'Todo' },
232
- priority: 1,
233
- url: 'https://linear.app/issue-1',
234
- team: { id: 'team-1', key: 'STA' },
235
- labels: [{ name: 'bug' }, { name: 'urgent' }],
236
- project: { id: 'proj-1', name: 'Main Project' },
237
- assignee: { id: 'user-1', name: 'John Doe' },
238
- updatedAt: new Date().toISOString()
239
- };
240
- mockContextService.getTaskByExternalId.mockResolvedValue(null);
241
- const result = await syncService.syncIssueToLocal(mockIssue);
242
- expect(result).toBe('created');
243
- expect(mockContextService.createTask).toHaveBeenCalledWith({
244
- title: 'New Issue',
245
- description: 'Issue description',
246
- status: 'todo',
247
- priority: 'urgent',
248
- externalId: 'issue-1',
249
- externalIdentifier: 'STA-1',
250
- externalUrl: 'https://linear.app/issue-1',
251
- tags: ['bug', 'urgent'],
252
- metadata: {
253
- linear: {
254
- teamId: 'team-1',
255
- teamKey: 'STA',
256
- stateId: 'state-1',
257
- stateName: 'Todo',
258
- projectId: 'proj-1',
259
- projectName: 'Main Project',
260
- assigneeId: 'user-1',
261
- assigneeName: 'John Doe'
262
- }
263
- },
264
- updatedAt: expect.any(Date)
265
- });
266
- });
267
- it('should update existing local task', async () => {
268
- const mockIssue = {
269
- id: 'issue-1',
270
- identifier: 'STA-1',
271
- title: 'Updated Issue',
272
- description: 'Updated description',
273
- state: { type: 'started', id: 'state-2', name: 'In Progress' },
274
- priority: 2,
275
- url: 'https://linear.app/issue-1',
276
- team: { id: 'team-1', key: 'STA' },
277
- labels: [{ name: 'feature' }],
278
- updatedAt: new Date().toISOString()
279
- };
280
- const existingTask = {
281
- id: 'local-1',
282
- title: 'Old Title',
283
- description: 'Old description',
284
- status: 'todo',
285
- priority: 'low',
286
- tags: ['old-tag'],
287
- externalId: 'issue-1',
288
- createdAt: new Date(),
289
- updatedAt: new Date()
290
- };
291
- mockContextService.getTaskByExternalId.mockResolvedValue(existingTask);
292
- const result = await syncService.syncIssueToLocal(mockIssue);
293
- expect(result).toBe('updated');
294
- expect(mockContextService.updateTask).toHaveBeenCalledWith('local-1', {
295
- title: 'Updated Issue',
296
- description: 'Updated description',
297
- status: 'in_progress',
298
- priority: 'high',
299
- externalId: 'issue-1',
300
- externalIdentifier: 'STA-1',
301
- externalUrl: 'https://linear.app/issue-1',
302
- tags: ['feature'],
303
- metadata: {
304
- linear: {
305
- teamId: 'team-1',
306
- teamKey: 'STA',
307
- stateId: 'state-2',
308
- stateName: 'In Progress',
309
- projectId: undefined,
310
- projectName: undefined,
311
- assigneeId: undefined,
312
- assigneeName: undefined
313
- }
314
- },
315
- updatedAt: expect.any(Date)
316
- });
317
- });
318
- it('should handle sync errors and rethrow', async () => {
319
- const mockIssue = {
320
- id: 'issue-1',
321
- identifier: 'STA-1',
322
- title: 'Error Issue',
323
- state: { type: 'unstarted' },
324
- team: { id: 'team-1', key: 'STA' },
325
- updatedAt: new Date().toISOString()
326
- };
327
- mockContextService.getTaskByExternalId.mockRejectedValue(new Error('Database error'));
328
- await expect(syncService.syncIssueToLocal(mockIssue)).rejects.toThrow('Database error');
329
- });
330
- });
331
- describe('syncLocalToLinear', () => {
332
- it('should create new Linear issue from local task', async () => {
333
- const mockTask = {
334
- id: 'local-1',
335
- title: 'Local Task',
336
- description: 'Local description',
337
- status: 'todo',
338
- priority: 'high',
339
- tags: [],
340
- createdAt: new Date(),
341
- updatedAt: new Date()
342
- };
343
- const mockCreatedIssue = {
344
- id: 'issue-1',
345
- identifier: 'STA-1',
346
- title: 'Local Task',
347
- url: 'https://linear.app/issue-1'
348
- };
349
- mockContextService.getTask.mockResolvedValue(mockTask);
350
- mockLinearClient.createIssue.mockResolvedValue(mockCreatedIssue);
351
- const result = await syncService.syncLocalToLinear('local-1');
352
- expect(result).toEqual(mockCreatedIssue);
353
- expect(mockLinearClient.createIssue).toHaveBeenCalledWith({
354
- title: 'Local Task',
355
- description: 'Local description',
356
- priority: 3, // high -> 3
357
- stateId: undefined,
358
- projectId: undefined,
359
- assigneeId: undefined
360
- });
361
- expect(mockContextService.updateTask).toHaveBeenCalledWith('local-1', {
362
- externalId: 'issue-1'
363
- });
364
- });
365
- it('should update existing Linear issue', async () => {
366
- const mockTask = {
367
- id: 'local-1',
368
- title: 'Updated Local Task',
369
- description: 'Updated description',
370
- status: 'in_progress',
371
- priority: 'medium',
372
- tags: [],
373
- externalId: 'issue-1',
374
- metadata: {
375
- linear: {
376
- stateId: 'state-1',
377
- projectId: 'proj-1',
378
- assigneeId: 'user-1'
379
- }
380
- },
381
- createdAt: new Date(),
382
- updatedAt: new Date()
383
- };
384
- const mockUpdatedIssue = {
385
- id: 'issue-1',
386
- identifier: 'STA-1',
387
- title: 'Updated Local Task'
388
- };
389
- mockContextService.getTask.mockResolvedValue(mockTask);
390
- mockLinearClient.updateIssue.mockResolvedValue(mockUpdatedIssue);
391
- const result = await syncService.syncLocalToLinear('local-1');
392
- expect(result).toEqual(mockUpdatedIssue);
393
- expect(mockLinearClient.updateIssue).toHaveBeenCalledWith('issue-1', {
394
- title: 'Updated Local Task',
395
- description: 'Updated description',
396
- priority: 2, // medium -> 2
397
- stateId: 'state-1',
398
- projectId: 'proj-1',
399
- assigneeId: 'user-1'
400
- });
401
- });
402
- it('should throw error for non-existent task', async () => {
403
- mockContextService.getTask.mockResolvedValue(null);
404
- await expect(syncService.syncLocalToLinear('non-existent')).rejects.toThrow('Task non-existent not found');
405
- });
406
- it('should handle Linear API errors', async () => {
407
- const mockTask = {
408
- id: 'local-1',
409
- title: 'Task',
410
- description: 'Test task description',
411
- status: 'todo',
412
- priority: 'medium',
413
- tags: [],
414
- createdAt: new Date(),
415
- updatedAt: new Date()
416
- };
417
- mockContextService.getTask.mockResolvedValue(mockTask);
418
- mockLinearClient.createIssue.mockRejectedValue(new Error('Linear API error'));
419
- await expect(syncService.syncLocalToLinear('local-1')).rejects.toThrow('Linear API error');
420
- });
421
- });
422
- describe('removeLocalIssue', () => {
423
- it('should remove local task by Linear identifier', async () => {
424
- const mockTasks = [
425
- {
426
- id: 'local-1',
427
- title: 'Task 1',
428
- description: 'Task 1 description',
429
- status: 'todo',
430
- priority: 'medium',
431
- tags: [],
432
- externalIdentifier: 'STA-1',
433
- createdAt: new Date(),
434
- updatedAt: new Date()
435
- },
436
- {
437
- id: 'local-2',
438
- title: 'Task 2',
439
- description: 'Task 2 description',
440
- status: 'todo',
441
- priority: 'medium',
442
- tags: [],
443
- externalIdentifier: 'STA-2',
444
- createdAt: new Date(),
445
- updatedAt: new Date()
446
- }
447
- ];
448
- mockContextService.getAllTasks.mockResolvedValue(mockTasks);
449
- await syncService.removeLocalIssue('STA-1');
450
- expect(mockContextService.deleteTask).toHaveBeenCalledWith('local-1');
451
- });
452
- it('should handle non-existent identifier gracefully', async () => {
453
- mockContextService.getAllTasks.mockResolvedValue([]);
454
- await expect(syncService.removeLocalIssue('NON-EXISTENT')).resolves.not.toThrow();
455
- expect(mockContextService.deleteTask).not.toHaveBeenCalled();
456
- });
457
- it('should handle deletion errors', async () => {
458
- const mockTasks = [{
459
- id: 'local-1',
460
- title: 'Task',
461
- description: 'Task description',
462
- status: 'todo',
463
- priority: 'medium',
464
- tags: [],
465
- externalIdentifier: 'STA-1',
466
- createdAt: new Date(),
467
- updatedAt: new Date()
468
- }];
469
- mockContextService.getAllTasks.mockResolvedValue(mockTasks);
470
- mockContextService.deleteTask.mockRejectedValue(new Error('Delete error'));
471
- await expect(syncService.removeLocalIssue('STA-1')).rejects.toThrow('Delete error');
472
- });
473
- });
474
- describe('Status and Priority Mapping', () => {
475
- it('should map Linear states to task statuses correctly', () => {
476
- const testCases = [
477
- { linearState: 'backlog', expectedStatus: 'todo' },
478
- { linearState: 'triage', expectedStatus: 'todo' },
479
- { linearState: 'unstarted', expectedStatus: 'todo' },
480
- { linearState: 'todo', expectedStatus: 'todo' },
481
- { linearState: 'started', expectedStatus: 'in_progress' },
482
- { linearState: 'in_progress', expectedStatus: 'in_progress' },
483
- { linearState: 'completed', expectedStatus: 'done' },
484
- { linearState: 'done', expectedStatus: 'done' },
485
- { linearState: 'canceled', expectedStatus: 'cancelled' },
486
- { linearState: 'cancelled', expectedStatus: 'cancelled' },
487
- { linearState: 'unknown', expectedStatus: 'todo' }
488
- ];
489
- testCases.forEach(({ linearState, expectedStatus }) => {
490
- const mockIssue = {
491
- id: 'test-issue',
492
- identifier: 'TEST-1',
493
- title: 'Test',
494
- state: { type: linearState },
495
- team: { id: 'team-1', key: 'TEST' },
496
- updatedAt: new Date().toISOString()
497
- };
498
- mockContextService.getTaskByExternalId.mockResolvedValue(null);
499
- syncService.syncIssueToLocal(mockIssue);
500
- expect(mockContextService.createTask).toHaveBeenCalledWith(expect.objectContaining({ status: expectedStatus }));
501
- vi.clearAllMocks();
502
- });
503
- });
504
- it('should map Linear priorities to task priorities correctly', () => {
505
- const testCases = [
506
- { linearPriority: 1, expectedPriority: 'urgent' },
507
- { linearPriority: 2, expectedPriority: 'high' },
508
- { linearPriority: 3, expectedPriority: 'medium' },
509
- { linearPriority: 4, expectedPriority: 'low' },
510
- { linearPriority: undefined, expectedPriority: undefined }
511
- ];
512
- testCases.forEach(({ linearPriority, expectedPriority }) => {
513
- const mockIssue = {
514
- id: 'test-issue',
515
- identifier: 'TEST-1',
516
- title: 'Test',
517
- state: { type: 'unstarted' },
518
- priority: linearPriority,
519
- team: { id: 'team-1', key: 'TEST' },
520
- updatedAt: new Date().toISOString()
521
- };
522
- mockContextService.getTaskByExternalId.mockResolvedValue(null);
523
- syncService.syncIssueToLocal(mockIssue);
524
- expect(mockContextService.createTask).toHaveBeenCalledWith(expect.objectContaining({ priority: expectedPriority }));
525
- vi.clearAllMocks();
526
- });
527
- });
528
- it('should map task priorities to Linear priorities correctly', () => {
529
- const testCases = [
530
- { taskPriority: 'urgent', expectedLinearPriority: 4 },
531
- { taskPriority: 'high', expectedLinearPriority: 3 },
532
- { taskPriority: 'medium', expectedLinearPriority: 2 },
533
- { taskPriority: 'low', expectedLinearPriority: 1 },
534
- { taskPriority: undefined, expectedLinearPriority: 0 }
535
- ];
536
- testCases.forEach(({ taskPriority, expectedLinearPriority }) => {
537
- const mockTask = {
538
- id: 'local-1',
539
- title: 'Test Task',
540
- description: 'Test description',
541
- status: 'todo',
542
- priority: taskPriority,
543
- tags: [],
544
- createdAt: new Date(),
545
- updatedAt: new Date()
546
- };
547
- mockContextService.getTask.mockResolvedValue(mockTask);
548
- mockLinearClient.createIssue.mockResolvedValue({ id: 'created', identifier: 'TEST-1' });
549
- syncService.syncLocalToLinear('local-1');
550
- expect(mockLinearClient.createIssue).toHaveBeenCalledWith(expect.objectContaining({ priority: expectedLinearPriority }));
551
- vi.clearAllMocks();
552
- });
553
- });
554
- });
555
- describe('Change Detection', () => {
556
- it('should detect changes in title', () => {
557
- const existing = {
558
- id: '1',
559
- title: 'Old Title',
560
- description: 'Same',
561
- status: 'todo',
562
- priority: 'medium',
563
- tags: [],
564
- createdAt: new Date(),
565
- updatedAt: new Date()
566
- };
567
- const updated = {
568
- title: 'New Title',
569
- description: 'Same',
570
- status: 'todo',
571
- priority: 'medium',
572
- tags: []
573
- };
574
- mockContextService.getTaskByExternalId.mockResolvedValue(existing);
575
- const mockIssue = {
576
- id: 'issue-1',
577
- identifier: 'STA-1',
578
- title: 'New Title',
579
- description: 'Same',
580
- state: { type: 'unstarted' },
581
- priority: 2,
582
- team: { id: 'team-1', key: 'STA' },
583
- labels: [],
584
- updatedAt: new Date().toISOString()
585
- };
586
- syncService.syncIssueToLocal(mockIssue);
587
- expect(mockContextService.updateTask).toHaveBeenCalled();
588
- });
589
- it('should detect changes in tags', () => {
590
- const existing = {
591
- id: '1',
592
- title: 'Same',
593
- description: 'Same',
594
- status: 'todo',
595
- priority: 'medium',
596
- tags: ['old-tag'],
597
- createdAt: new Date(),
598
- updatedAt: new Date()
599
- };
600
- mockContextService.getTaskByExternalId.mockResolvedValue(existing);
601
- const mockIssue = {
602
- id: 'issue-1',
603
- identifier: 'STA-1',
604
- title: 'Same',
605
- description: 'Same',
606
- state: { type: 'unstarted' },
607
- priority: 2,
608
- team: { id: 'team-1', key: 'STA' },
609
- labels: [{ name: 'new-tag' }],
610
- updatedAt: new Date().toISOString()
611
- };
612
- syncService.syncIssueToLocal(mockIssue);
613
- expect(mockContextService.updateTask).toHaveBeenCalled();
614
- });
615
- it('should not update when no changes detected', () => {
616
- const existing = {
617
- id: '1',
618
- title: 'Same Title',
619
- description: 'Same Description',
620
- status: 'todo',
621
- priority: 'medium',
622
- tags: ['tag1'],
623
- createdAt: new Date(),
624
- updatedAt: new Date()
625
- };
626
- mockContextService.getTaskByExternalId.mockResolvedValue(existing);
627
- const mockIssue = {
628
- id: 'issue-1',
629
- identifier: 'STA-1',
630
- title: 'Same Title',
631
- description: 'Same Description',
632
- state: { type: 'unstarted' },
633
- priority: 2,
634
- team: { id: 'team-1', key: 'STA' },
635
- labels: [{ name: 'tag1' }],
636
- updatedAt: new Date().toISOString()
637
- };
638
- syncService.syncIssueToLocal(mockIssue);
639
- expect(mockContextService.updateTask).not.toHaveBeenCalled();
640
- });
641
- });
642
- describe('Error Recovery and Edge Cases', () => {
643
- it('should handle partial sync failures gracefully', async () => {
644
- const mockIssues = [
645
- { id: 'issue-1', identifier: 'STA-1', title: 'Good Issue', state: { type: 'unstarted' }, team: { id: 'team-1', key: 'STA' }, updatedAt: new Date().toISOString() },
646
- { id: 'issue-2', identifier: 'STA-2', title: 'Bad Issue', state: { type: 'unstarted' }, team: { id: 'team-1', key: 'STA' }, updatedAt: new Date().toISOString() }
647
- ];
648
- mockConfigService.getConfig.mockResolvedValue({
649
- integrations: { linear: { teamId: 'test-team-id' } }
650
- });
651
- mockLinearClient.getIssues.mockResolvedValue(mockIssues);
652
- mockContextService.getTaskByExternalId.mockResolvedValue(null);
653
- // First issue succeeds, second fails
654
- mockContextService.createTask
655
- .mockResolvedValueOnce('success')
656
- .mockRejectedValueOnce(new Error('Creation failed'));
657
- const result = await syncService.syncAllIssues();
658
- expect(result.created).toBe(1);
659
- expect(result.errors).toHaveLength(1);
660
- expect(result.errors[0]).toContain('Failed to sync STA-2');
661
- });
662
- it('should handle empty issues list', async () => {
663
- mockConfigService.getConfig.mockResolvedValue({
664
- integrations: { linear: { teamId: 'test-team-id' } }
665
- });
666
- mockLinearClient.getIssues.mockResolvedValue([]);
667
- const result = await syncService.syncAllIssues();
668
- expect(result.created).toBe(0);
669
- expect(result.updated).toBe(0);
670
- expect(result.errors).toHaveLength(0);
671
- });
672
- it('should handle malformed Linear issues', async () => {
673
- const malformedIssue = {
674
- // Missing required fields
675
- id: 'issue-1',
676
- title: null,
677
- state: null,
678
- team: null
679
- };
680
- mockConfigService.getConfig.mockResolvedValue({
681
- integrations: { linear: { teamId: 'test-team-id' } }
682
- });
683
- mockLinearClient.getIssues.mockResolvedValue([malformedIssue]);
684
- const result = await syncService.syncAllIssues();
685
- expect(result.errors).toHaveLength(1);
686
- });
687
- it('should handle network timeouts gracefully', async () => {
688
- mockConfigService.getConfig.mockResolvedValue({
689
- integrations: { linear: { teamId: 'test-team-id' } }
690
- });
691
- const timeoutError = new Error('Request timeout');
692
- timeoutError.name = 'TimeoutError';
693
- mockLinearClient.getIssues.mockRejectedValue(timeoutError);
694
- const result = await syncService.syncAllIssues();
695
- expect(result.errors).toHaveLength(1);
696
- expect(result.errors[0]).toContain('Request timeout');
697
- });
698
- });
699
- });
700
- //# sourceMappingURL=sync-service.test.js.map