macro-agent 0.0.17 → 0.1.1

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 (338) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/.sudocode/specs.jsonl +4 -0
  3. package/CLAUDE.md +16 -14
  4. package/README.md +11 -29
  5. package/dist/acp/macro-agent.d.ts +17 -0
  6. package/dist/acp/macro-agent.d.ts.map +1 -1
  7. package/dist/acp/macro-agent.js +183 -55
  8. package/dist/acp/macro-agent.js.map +1 -1
  9. package/dist/acp/types.d.ts +32 -1
  10. package/dist/acp/types.d.ts.map +1 -1
  11. package/dist/acp/types.js.map +1 -1
  12. package/dist/agent/agent-manager.d.ts +65 -1
  13. package/dist/agent/agent-manager.d.ts.map +1 -1
  14. package/dist/agent/agent-manager.js +464 -183
  15. package/dist/agent/agent-manager.js.map +1 -1
  16. package/dist/agent/types.d.ts +1 -1
  17. package/dist/agent/types.d.ts.map +1 -1
  18. package/dist/api/server.d.ts +3 -0
  19. package/dist/api/server.d.ts.map +1 -1
  20. package/dist/api/server.js +37 -6
  21. package/dist/api/server.js.map +1 -1
  22. package/dist/auth/index.d.ts +2 -0
  23. package/dist/auth/index.d.ts.map +1 -0
  24. package/dist/auth/index.js +2 -0
  25. package/dist/auth/index.js.map +1 -0
  26. package/dist/auth/token.d.ts +41 -0
  27. package/dist/auth/token.d.ts.map +1 -0
  28. package/dist/auth/token.js +73 -0
  29. package/dist/auth/token.js.map +1 -0
  30. package/dist/cli/acp.d.ts +2 -23
  31. package/dist/cli/acp.d.ts.map +1 -1
  32. package/dist/cli/acp.js +127 -61
  33. package/dist/cli/acp.js.map +1 -1
  34. package/dist/cli/index.js +147 -15
  35. package/dist/cli/index.js.map +1 -1
  36. package/dist/cli/mcp.d.ts +6 -0
  37. package/dist/cli/mcp.d.ts.map +1 -1
  38. package/dist/cli/mcp.js +268 -181
  39. package/dist/cli/mcp.js.map +1 -1
  40. package/dist/cli/parse-args.d.ts +20 -0
  41. package/dist/cli/parse-args.d.ts.map +1 -0
  42. package/dist/cli/parse-args.js +43 -0
  43. package/dist/cli/parse-args.js.map +1 -0
  44. package/dist/cli/stable-instance-id.d.ts +8 -0
  45. package/dist/cli/stable-instance-id.d.ts.map +1 -0
  46. package/dist/cli/stable-instance-id.js +14 -0
  47. package/dist/cli/stable-instance-id.js.map +1 -0
  48. package/dist/config/project-config.d.ts +74 -7
  49. package/dist/config/project-config.d.ts.map +1 -1
  50. package/dist/config/project-config.js +123 -20
  51. package/dist/config/project-config.js.map +1 -1
  52. package/dist/map/adapter/acp-over-map.d.ts +23 -0
  53. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  54. package/dist/map/adapter/acp-over-map.js +482 -55
  55. package/dist/map/adapter/acp-over-map.js.map +1 -1
  56. package/dist/map/adapter/connection-manager.d.ts.map +1 -1
  57. package/dist/map/adapter/connection-manager.js +3 -0
  58. package/dist/map/adapter/connection-manager.js.map +1 -1
  59. package/dist/map/adapter/event-log.d.ts +87 -0
  60. package/dist/map/adapter/event-log.d.ts.map +1 -0
  61. package/dist/map/adapter/event-log.js +122 -0
  62. package/dist/map/adapter/event-log.js.map +1 -0
  63. package/dist/map/adapter/event-translator.js +6 -6
  64. package/dist/map/adapter/event-translator.js.map +1 -1
  65. package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
  66. package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
  67. package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
  68. package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
  69. package/dist/map/adapter/extensions/index.d.ts +10 -1
  70. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  71. package/dist/map/adapter/extensions/index.js +34 -0
  72. package/dist/map/adapter/extensions/index.js.map +1 -1
  73. package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
  74. package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
  75. package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
  76. package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
  77. package/dist/map/adapter/extensions/rename.d.ts +29 -0
  78. package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
  79. package/dist/map/adapter/extensions/rename.js +49 -0
  80. package/dist/map/adapter/extensions/rename.js.map +1 -0
  81. package/dist/map/adapter/extensions/task.d.ts.map +1 -1
  82. package/dist/map/adapter/extensions/task.js +10 -0
  83. package/dist/map/adapter/extensions/task.js.map +1 -1
  84. package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
  85. package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
  86. package/dist/map/adapter/extensions/update-metadata.js +67 -0
  87. package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
  88. package/dist/map/adapter/index.d.ts +2 -1
  89. package/dist/map/adapter/index.d.ts.map +1 -1
  90. package/dist/map/adapter/index.js +8 -2
  91. package/dist/map/adapter/index.js.map +1 -1
  92. package/dist/map/adapter/interface.d.ts +2 -0
  93. package/dist/map/adapter/interface.d.ts.map +1 -1
  94. package/dist/map/adapter/map-adapter.d.ts +4 -0
  95. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  96. package/dist/map/adapter/map-adapter.js +302 -30
  97. package/dist/map/adapter/map-adapter.js.map +1 -1
  98. package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
  99. package/dist/map/adapter/subscription-manager.js +5 -1
  100. package/dist/map/adapter/subscription-manager.js.map +1 -1
  101. package/dist/map/adapter/types.d.ts +2 -0
  102. package/dist/map/adapter/types.d.ts.map +1 -1
  103. package/dist/mcp/map-client.d.ts +39 -0
  104. package/dist/mcp/map-client.d.ts.map +1 -0
  105. package/dist/mcp/map-client.js +129 -0
  106. package/dist/mcp/map-client.js.map +1 -0
  107. package/dist/mcp/mcp-server.d.ts +14 -0
  108. package/dist/mcp/mcp-server.d.ts.map +1 -1
  109. package/dist/mcp/mcp-server.js +113 -85
  110. package/dist/mcp/mcp-server.js.map +1 -1
  111. package/dist/mcp/types.d.ts +9 -1
  112. package/dist/mcp/types.d.ts.map +1 -1
  113. package/dist/mcp/types.js.map +1 -1
  114. package/dist/metrics/metrics.js +1 -1
  115. package/dist/metrics/metrics.js.map +1 -1
  116. package/dist/roles/capabilities.d.ts +3 -1
  117. package/dist/roles/capabilities.d.ts.map +1 -1
  118. package/dist/roles/capabilities.js +17 -7
  119. package/dist/roles/capabilities.js.map +1 -1
  120. package/dist/roles/config-loader.d.ts +6 -6
  121. package/dist/roles/config-loader.d.ts.map +1 -1
  122. package/dist/roles/config-loader.js +6 -6
  123. package/dist/roles/config-loader.js.map +1 -1
  124. package/dist/roles/registry.d.ts +2 -2
  125. package/dist/roles/registry.js +2 -2
  126. package/dist/server/combined-server.d.ts +20 -0
  127. package/dist/server/combined-server.d.ts.map +1 -1
  128. package/dist/server/combined-server.js +107 -8
  129. package/dist/server/combined-server.js.map +1 -1
  130. package/dist/store/event-store.d.ts +7 -1
  131. package/dist/store/event-store.d.ts.map +1 -1
  132. package/dist/store/event-store.js +91 -8
  133. package/dist/store/event-store.js.map +1 -1
  134. package/dist/store/types/agents.d.ts +23 -0
  135. package/dist/store/types/agents.d.ts.map +1 -1
  136. package/dist/store/types/events.d.ts +1 -1
  137. package/dist/store/types/events.d.ts.map +1 -1
  138. package/dist/task/backend/index.d.ts +47 -29
  139. package/dist/task/backend/index.d.ts.map +1 -1
  140. package/dist/task/backend/index.js +109 -71
  141. package/dist/task/backend/index.js.map +1 -1
  142. package/dist/task/backend/memory.d.ts +1 -0
  143. package/dist/task/backend/memory.d.ts.map +1 -1
  144. package/dist/task/backend/memory.js +3 -0
  145. package/dist/task/backend/memory.js.map +1 -1
  146. package/dist/task/backend/opentasks/backend.d.ts +140 -0
  147. package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
  148. package/dist/task/backend/opentasks/backend.js +1023 -0
  149. package/dist/task/backend/opentasks/backend.js.map +1 -0
  150. package/dist/task/backend/opentasks/client.d.ts +337 -0
  151. package/dist/task/backend/opentasks/client.d.ts.map +1 -0
  152. package/dist/task/backend/opentasks/client.js +225 -0
  153. package/dist/task/backend/opentasks/client.js.map +1 -0
  154. package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
  155. package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
  156. package/dist/task/backend/opentasks/daemon-manager.js +195 -0
  157. package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
  158. package/dist/task/backend/opentasks/index.d.ts +21 -0
  159. package/dist/task/backend/opentasks/index.d.ts.map +1 -0
  160. package/dist/task/backend/opentasks/index.js +21 -0
  161. package/dist/task/backend/opentasks/index.js.map +1 -0
  162. package/dist/task/backend/opentasks/mapping.d.ts +48 -0
  163. package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
  164. package/dist/task/backend/opentasks/mapping.js +77 -0
  165. package/dist/task/backend/opentasks/mapping.js.map +1 -0
  166. package/dist/task/backend/types.d.ts +33 -53
  167. package/dist/task/backend/types.d.ts.map +1 -1
  168. package/dist/task/backend/types.js +7 -11
  169. package/dist/task/backend/types.js.map +1 -1
  170. package/dist/task/backend/unified-tool-provider.d.ts +57 -0
  171. package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
  172. package/dist/task/backend/unified-tool-provider.js +623 -0
  173. package/dist/task/backend/unified-tool-provider.js.map +1 -0
  174. package/dist/teams/team-loader.d.ts +2 -2
  175. package/dist/teams/team-loader.js +3 -3
  176. package/dist/teams/team-loader.js.map +1 -1
  177. package/dist/teams/team-runtime.d.ts.map +1 -1
  178. package/dist/teams/team-runtime.js +2 -0
  179. package/dist/teams/team-runtime.js.map +1 -1
  180. package/docs/architecture.md +7 -6
  181. package/docs/configuration.md +26 -62
  182. package/docs/implementation-details.md +5 -5
  183. package/docs/implementation-summary.md +17 -17
  184. package/docs/plan-self-driving-support.md +4 -4
  185. package/docs/spec-self-driving-support.md +10 -10
  186. package/docs/team-templates.md +2 -2
  187. package/docs/teams.md +3 -3
  188. package/docs/troubleshooting.md +10 -11
  189. package/package.json +6 -4
  190. package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
  191. package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
  192. package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
  193. package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
  194. package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
  195. package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
  196. package/src/acp/__tests__/history.test.ts +8 -4
  197. package/src/acp/__tests__/integration.test.ts +56 -31
  198. package/src/acp/__tests__/macro-agent.test.ts +16 -7
  199. package/src/acp/macro-agent.ts +230 -62
  200. package/src/acp/types.ts +46 -1
  201. package/src/agent/__tests__/agent-manager.test.ts +228 -2
  202. package/src/agent/agent-manager.ts +714 -261
  203. package/src/agent/types.ts +3 -1
  204. package/src/api/server.ts +41 -7
  205. package/src/auth/__tests__/token.test.ts +100 -0
  206. package/src/auth/index.ts +1 -0
  207. package/src/auth/token.ts +82 -0
  208. package/src/cli/__tests__/acp.test.ts +1 -1
  209. package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
  210. package/src/cli/acp.ts +130 -72
  211. package/src/cli/index.ts +120 -14
  212. package/src/cli/mcp.ts +311 -207
  213. package/src/cli/parse-args.ts +54 -0
  214. package/src/cli/stable-instance-id.ts +14 -0
  215. package/src/config/project-config.ts +190 -27
  216. package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
  217. package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +820 -0
  218. package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
  219. package/src/map/adapter/__tests__/acp-over-map-history.test.ts +724 -2
  220. package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
  221. package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
  222. package/src/map/adapter/__tests__/event-log.test.ts +527 -0
  223. package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
  224. package/src/map/adapter/__tests__/extensions.test.ts +408 -0
  225. package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
  226. package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
  227. package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
  228. package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
  229. package/src/map/adapter/acp-over-map.ts +777 -92
  230. package/src/map/adapter/connection-manager.ts +3 -0
  231. package/src/map/adapter/event-log.ts +208 -0
  232. package/src/map/adapter/event-translator.ts +6 -6
  233. package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
  234. package/src/map/adapter/extensions/index.ts +60 -0
  235. package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
  236. package/src/map/adapter/extensions/task.ts +11 -0
  237. package/src/map/adapter/extensions/update-metadata.ts +126 -0
  238. package/src/map/adapter/index.ts +28 -0
  239. package/src/map/adapter/interface.ts +2 -0
  240. package/src/map/adapter/map-adapter.ts +373 -38
  241. package/src/map/adapter/subscription-manager.ts +5 -1
  242. package/src/map/adapter/types.ts +2 -0
  243. package/src/mcp/__tests__/map-client.test.ts +386 -0
  244. package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
  245. package/src/mcp/__tests__/mcp-server.test.ts +100 -1
  246. package/src/mcp/map-client.ts +177 -0
  247. package/src/mcp/mcp-server.ts +191 -100
  248. package/src/mcp/types.ts +6 -1
  249. package/src/metrics/metrics.ts +1 -1
  250. package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
  251. package/src/roles/__tests__/config-loader.test.ts +7 -7
  252. package/src/roles/capabilities.ts +17 -7
  253. package/src/roles/config-loader.ts +6 -6
  254. package/src/roles/registry.ts +2 -2
  255. package/src/server/__tests__/combined-server.test.ts +94 -21
  256. package/src/server/combined-server.ts +189 -33
  257. package/src/steering/__tests__/steering-integration.test.ts +1 -1
  258. package/src/store/__tests__/event-store.test.ts +236 -1
  259. package/src/store/__tests__/instance.test.ts +3 -3
  260. package/src/store/event-store.ts +109 -8
  261. package/src/store/types/agents.ts +16 -0
  262. package/src/store/types/events.ts +1 -1
  263. package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
  264. package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
  265. package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
  266. package/src/task/backend/index.ts +156 -106
  267. package/src/task/backend/memory.ts +4 -0
  268. package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
  269. package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
  270. package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
  271. package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
  272. package/src/task/backend/opentasks/backend.ts +1323 -0
  273. package/src/task/backend/opentasks/client.ts +652 -0
  274. package/src/task/backend/opentasks/daemon-manager.ts +253 -0
  275. package/src/task/backend/opentasks/index.ts +69 -0
  276. package/src/task/backend/opentasks/mapping.ts +94 -0
  277. package/src/task/backend/types.ts +42 -66
  278. package/src/task/backend/unified-tool-provider.ts +779 -0
  279. package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
  280. package/src/teams/team-loader.ts +3 -3
  281. package/src/teams/team-runtime.ts +2 -0
  282. package/test_fixtures/README.md +2 -3
  283. package/test_fixtures/fixtures/index.ts +0 -3
  284. package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
  285. package/test_fixtures/fixtures/repos/index.ts +1 -3
  286. package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
  287. package/test_fixtures/fixtures/repos/types.ts +0 -11
  288. package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
  289. package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
  290. package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
  291. package/vitest.config.ts +1 -1
  292. package/vitest.e2e.config.ts +1 -1
  293. package/vitest.setup.ts +1 -30
  294. package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
  295. package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
  296. package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
  297. package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
  298. package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
  299. package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
  300. package/.macro-agent/teams/self-driving/team.yaml +0 -103
  301. package/.macro-agent/teams/structured/prompts/developer.md +0 -26
  302. package/.macro-agent/teams/structured/prompts/lead.md +0 -25
  303. package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
  304. package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
  305. package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
  306. package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
  307. package/.macro-agent/teams/structured/team.yaml +0 -89
  308. package/docs/sudocode-integration.md +0 -383
  309. package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
  310. package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
  311. package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
  312. package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
  313. package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
  314. package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
  315. package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
  316. package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
  317. package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
  318. package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
  319. package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
  320. package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
  321. package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
  322. package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
  323. package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
  324. package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
  325. package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
  326. package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
  327. package/src/task/backend/sudocode/backend.ts +0 -1237
  328. package/src/task/backend/sudocode/client.ts +0 -515
  329. package/src/task/backend/sudocode/index.ts +0 -120
  330. package/src/task/backend/sudocode/mapping.ts +0 -93
  331. package/src/task/backend/sudocode/server-client.ts +0 -522
  332. package/src/task/backend/sudocode/standalone-client.ts +0 -623
  333. package/src/task/backend/sudocode/sync-policy.ts +0 -387
  334. package/src/task/backend/sudocode/tools.ts +0 -896
  335. package/src/task/backend/tool-provider.ts +0 -506
  336. package/test_fixtures/fixtures/sudocode/index.ts +0 -29
  337. package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
  338. package/test_fixtures/fixtures/sudocode/specs.ts +0 -159
@@ -1,396 +0,0 @@
1
- /**
2
- * Integration tests for StandaloneClient
3
- *
4
- * These tests use the real @sudocode-ai/cli package with a temp SQLite database
5
- * to verify that the StandaloneClient implementation works correctly.
6
- */
7
-
8
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
9
- import { mkdtempSync, rmSync } from "fs";
10
- import { tmpdir } from "os";
11
- import { join } from "path";
12
- import {
13
- StandaloneClient,
14
- createStandaloneClient,
15
- } from "../../standalone-client.js";
16
- import {
17
- createTestContext,
18
- createTestIssue,
19
- createTestSpec,
20
- createBlockingRelationship,
21
- createImplementsRelationship,
22
- type TestContext,
23
- } from "./test-utils.js";
24
-
25
- describe("StandaloneClient Integration", () => {
26
- let tmpDir: string;
27
- let client: StandaloneClient;
28
-
29
- beforeEach(async () => {
30
- // Create a fresh temp directory for each test
31
- tmpDir = mkdtempSync(join(tmpdir(), "sudocode-client-test-"));
32
- });
33
-
34
- afterEach(() => {
35
- // Clean up temp directory (client cleanup is handled per-describe block)
36
- if (tmpDir) {
37
- rmSync(tmpDir, { recursive: true, force: true });
38
- }
39
- });
40
-
41
- describe("Initialization", () => {
42
- it("should initialize with a new project directory", async () => {
43
- client = await createStandaloneClient({ projectPath: tmpDir });
44
- expect(client.isReady()).toBe(true);
45
- });
46
-
47
- it("should create .sudocode directory if it doesn't exist", async () => {
48
- const { existsSync } = await import("fs");
49
- expect(existsSync(join(tmpDir, ".sudocode"))).toBe(false);
50
-
51
- client = await createStandaloneClient({ projectPath: tmpDir });
52
-
53
- expect(existsSync(join(tmpDir, ".sudocode"))).toBe(true);
54
- expect(existsSync(join(tmpDir, ".sudocode", "cache.db"))).toBe(true);
55
- });
56
-
57
- it("should close cleanly", async () => {
58
- client = await createStandaloneClient({ projectPath: tmpDir });
59
- expect(client.isReady()).toBe(true);
60
-
61
- client.close();
62
-
63
- expect(client.isReady()).toBe(false);
64
- });
65
- });
66
-
67
- describe("Issue Operations", () => {
68
- let ctx: TestContext;
69
-
70
- beforeEach(async () => {
71
- // Create a test context and use its directory for the client
72
- ctx = createTestContext();
73
- tmpDir = ctx.tmpDir;
74
- client = await createStandaloneClient({ projectPath: tmpDir });
75
- });
76
-
77
- afterEach(() => {
78
- if (client) client.close();
79
- });
80
-
81
- it("should retrieve an issue created via CLI", async () => {
82
- // Create issue directly via CLI
83
- const createdIssue = createTestIssue(ctx, {
84
- title: "Test Issue",
85
- content: "Test content",
86
- });
87
-
88
- // Retrieve via client
89
- const issue = await client.getIssue(createdIssue.id);
90
-
91
- expect(issue).not.toBeNull();
92
- expect(issue!.id).toBe(createdIssue.id);
93
- expect(issue!.title).toBe("Test Issue");
94
- expect(issue!.content).toBe("Test content");
95
- });
96
-
97
- it("should return null for non-existent issue", async () => {
98
- const issue = await client.getIssue("i-nonexistent");
99
- expect(issue).toBeNull();
100
- });
101
-
102
- it("should list issues", async () => {
103
- createTestIssue(ctx, { title: "Issue 1", status: "open" });
104
- createTestIssue(ctx, { title: "Issue 2", status: "in_progress" });
105
- createTestIssue(ctx, { title: "Issue 3", status: "closed" });
106
-
107
- const issues = await client.listIssues();
108
- expect(issues).toHaveLength(3);
109
- });
110
-
111
- it("should filter issues by status", async () => {
112
- createTestIssue(ctx, { title: "Open Issue", status: "open" });
113
- createTestIssue(ctx, { title: "Closed Issue", status: "closed" });
114
-
115
- const openIssues = await client.listIssues({ status: "open" });
116
- expect(openIssues).toHaveLength(1);
117
- expect(openIssues[0].title).toBe("Open Issue");
118
- });
119
-
120
- it("should search issues by text", async () => {
121
- createTestIssue(ctx, { title: "Fix the bug", content: "A bug fix" });
122
- createTestIssue(ctx, { title: "Add feature", content: "New feature" });
123
-
124
- const bugIssues = await client.listIssues({ search: "bug" });
125
- expect(bugIssues).toHaveLength(1);
126
- expect(bugIssues[0].title).toBe("Fix the bug");
127
- });
128
-
129
- it("should get ready issues (no blockers)", async () => {
130
- const ready1 = createTestIssue(ctx, { title: "Ready 1", status: "open" });
131
- const blocker = createTestIssue(ctx, {
132
- title: "Blocker",
133
- status: "open",
134
- });
135
- const blocked = createTestIssue(ctx, {
136
- title: "Blocked",
137
- status: "open",
138
- });
139
-
140
- createBlockingRelationship(ctx.db, blocker.id, blocked.id);
141
-
142
- const readyIssues = await client.getReadyIssues();
143
- const readyIds = readyIssues.map((i) => i.id);
144
-
145
- expect(readyIds).toContain(ready1.id);
146
- expect(readyIds).toContain(blocker.id);
147
- expect(readyIds).not.toContain(blocked.id);
148
- });
149
-
150
- it("should update an issue", async () => {
151
- const issue = createTestIssue(ctx, {
152
- title: "Original",
153
- status: "open",
154
- });
155
-
156
- const updated = await client.updateIssue(issue.id, {
157
- title: "Updated",
158
- status: "in_progress",
159
- });
160
-
161
- expect(updated.title).toBe("Updated");
162
- expect(updated.status).toBe("in_progress");
163
-
164
- // Verify persistence
165
- const retrieved = await client.getIssue(issue.id);
166
- expect(retrieved!.title).toBe("Updated");
167
- expect(retrieved!.status).toBe("in_progress");
168
- });
169
- });
170
-
171
- describe("Relationship Operations", () => {
172
- let ctx: TestContext;
173
-
174
- beforeEach(async () => {
175
- ctx = createTestContext();
176
- tmpDir = ctx.tmpDir;
177
- client = await createStandaloneClient({ projectPath: tmpDir });
178
- });
179
-
180
- afterEach(() => {
181
- if (client) client.close();
182
- });
183
-
184
- it("should create a blocks relationship", async () => {
185
- const blocker = createTestIssue(ctx, { title: "Blocker" });
186
- const blocked = createTestIssue(ctx, { title: "Blocked" });
187
-
188
- await client.createLink(blocker.id, blocked.id, "blocks");
189
-
190
- // Verify the relationship was created
191
- const blockers = await client.getBlockers(blocked.id);
192
- expect(blockers).toHaveLength(1);
193
- expect(blockers[0].id).toBe(blocker.id);
194
- });
195
-
196
- it("should get blockers for an issue", async () => {
197
- const blocker1 = createTestIssue(ctx, { title: "Blocker 1" });
198
- const blocker2 = createTestIssue(ctx, { title: "Blocker 2" });
199
- const blocked = createTestIssue(ctx, { title: "Blocked" });
200
-
201
- createBlockingRelationship(ctx.db, blocker1.id, blocked.id);
202
- createBlockingRelationship(ctx.db, blocker2.id, blocked.id);
203
-
204
- const blockers = await client.getBlockers(blocked.id);
205
- expect(blockers).toHaveLength(2);
206
-
207
- const blockerIds = blockers.map((b) => b.id);
208
- expect(blockerIds).toContain(blocker1.id);
209
- expect(blockerIds).toContain(blocker2.id);
210
- });
211
-
212
- it("should get issues that a given issue blocks", async () => {
213
- const blocker = createTestIssue(ctx, { title: "Blocker" });
214
- const blocked1 = createTestIssue(ctx, { title: "Blocked 1" });
215
- const blocked2 = createTestIssue(ctx, { title: "Blocked 2" });
216
-
217
- createBlockingRelationship(ctx.db, blocker.id, blocked1.id);
218
- createBlockingRelationship(ctx.db, blocker.id, blocked2.id);
219
-
220
- const blocking = await client.getBlocking(blocker.id);
221
- expect(blocking).toHaveLength(2);
222
-
223
- const blockedIds = blocking.map((b) => b.id);
224
- expect(blockedIds).toContain(blocked1.id);
225
- expect(blockedIds).toContain(blocked2.id);
226
- });
227
-
228
- it("should remove a blocks relationship", async () => {
229
- const blocker = createTestIssue(ctx, { title: "Blocker" });
230
- const blocked = createTestIssue(ctx, { title: "Blocked" });
231
-
232
- createBlockingRelationship(ctx.db, blocker.id, blocked.id);
233
-
234
- // Verify relationship exists
235
- let blockers = await client.getBlockers(blocked.id);
236
- expect(blockers).toHaveLength(1);
237
-
238
- // Remove via client
239
- await client.removeLink(blocker.id, blocked.id, "blocks");
240
-
241
- // Verify relationship is gone
242
- blockers = await client.getBlockers(blocked.id);
243
- expect(blockers).toHaveLength(0);
244
- });
245
- });
246
-
247
- describe("Spec Operations", () => {
248
- let ctx: TestContext;
249
-
250
- beforeEach(async () => {
251
- ctx = createTestContext();
252
- tmpDir = ctx.tmpDir;
253
- client = await createStandaloneClient({ projectPath: tmpDir });
254
- });
255
-
256
- afterEach(() => {
257
- if (client) client.close();
258
- });
259
-
260
- it("should retrieve a spec created via CLI", async () => {
261
- const createdSpec = createTestSpec(ctx, {
262
- title: "Test Spec",
263
- content: "Spec content",
264
- });
265
-
266
- const spec = await client.getSpec(createdSpec.id);
267
-
268
- expect(spec).not.toBeNull();
269
- expect(spec!.id).toBe(createdSpec.id);
270
- expect(spec!.title).toBe("Test Spec");
271
- expect(spec!.content).toBe("Spec content");
272
- });
273
-
274
- it("should return null for non-existent spec", async () => {
275
- const spec = await client.getSpec("s-nonexistent");
276
- expect(spec).toBeNull();
277
- });
278
-
279
- it("should list specs", async () => {
280
- createTestSpec(ctx, { title: "Spec 1" });
281
- createTestSpec(ctx, { title: "Spec 2" });
282
- createTestSpec(ctx, { title: "Spec 3" });
283
-
284
- const specs = await client.listSpecs();
285
- expect(specs).toHaveLength(3);
286
- });
287
-
288
- it("should search specs by text", async () => {
289
- createTestSpec(ctx, { title: "Auth Spec", content: "Authentication" });
290
- createTestSpec(ctx, { title: "Database Spec", content: "Database design" });
291
-
292
- const authSpecs = await client.listSpecs({ search: "Auth" });
293
- expect(authSpecs).toHaveLength(1);
294
- expect(authSpecs[0].title).toBe("Auth Spec");
295
- });
296
- });
297
-
298
- describe("Issue-Spec Relationships", () => {
299
- let ctx: TestContext;
300
-
301
- beforeEach(async () => {
302
- ctx = createTestContext();
303
- tmpDir = ctx.tmpDir;
304
- client = await createStandaloneClient({ projectPath: tmpDir });
305
- });
306
-
307
- afterEach(() => {
308
- if (client) client.close();
309
- });
310
-
311
- it("should create an implements relationship via client", async () => {
312
- const spec = createTestSpec(ctx, { title: "Feature Spec" });
313
- const issue = createTestIssue(ctx, { title: "Implement Feature" });
314
-
315
- await client.createLink(issue.id, spec.id, "implements");
316
-
317
- // Note: We can't easily verify this without exposing relationship queries
318
- // but the operation should complete without error
319
- });
320
- });
321
-
322
- describe("Event Subscriptions", () => {
323
- let ctx: TestContext;
324
-
325
- beforeEach(async () => {
326
- ctx = createTestContext();
327
- tmpDir = ctx.tmpDir;
328
- client = await createStandaloneClient({
329
- projectPath: tmpDir,
330
- pollInterval: 100, // Fast polling for tests
331
- });
332
- });
333
-
334
- afterEach(() => {
335
- if (client) client.close();
336
- });
337
-
338
- it("should emit events when updating an issue", async () => {
339
- const issue = createTestIssue(ctx, { title: "Test", status: "open" });
340
-
341
- const events: Array<{ type: string; issueId: string }> = [];
342
- const unsubscribe = client.onIssueChange((event) => {
343
- events.push({ type: event.type, issueId: event.issueId });
344
- });
345
-
346
- // Update via client
347
- await client.updateIssue(issue.id, { status: "in_progress" });
348
-
349
- expect(events).toHaveLength(1);
350
- expect(events[0].type).toBe("status_changed");
351
- expect(events[0].issueId).toBe(issue.id);
352
-
353
- unsubscribe();
354
- });
355
-
356
- it("should filter events by issue ID", async () => {
357
- const issue1 = createTestIssue(ctx, { title: "Issue 1" });
358
- const issue2 = createTestIssue(ctx, { title: "Issue 2" });
359
-
360
- const events: string[] = [];
361
- const unsubscribe = client.onIssueChange(issue1.id, (event) => {
362
- events.push(event.issueId);
363
- });
364
-
365
- // Update both issues
366
- await client.updateIssue(issue1.id, { title: "Updated 1" });
367
- await client.updateIssue(issue2.id, { title: "Updated 2" });
368
-
369
- // Should only see events for issue1
370
- expect(events).toHaveLength(1);
371
- expect(events[0]).toBe(issue1.id);
372
-
373
- unsubscribe();
374
- });
375
-
376
- it("should unsubscribe correctly", async () => {
377
- const issue = createTestIssue(ctx, { title: "Test" });
378
-
379
- const events: string[] = [];
380
- const unsubscribe = client.onIssueChange((event) => {
381
- events.push(event.issueId);
382
- });
383
-
384
- // First update should be captured
385
- await client.updateIssue(issue.id, { title: "Update 1" });
386
- expect(events).toHaveLength(1);
387
-
388
- // Unsubscribe
389
- unsubscribe();
390
-
391
- // Second update should not be captured
392
- await client.updateIssue(issue.id, { title: "Update 2" });
393
- expect(events).toHaveLength(1);
394
- });
395
- });
396
- });