macro-agent 0.1.0 → 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 (337) 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 +15 -0
  6. package/dist/acp/macro-agent.d.ts.map +1 -1
  7. package/dist/acp/macro-agent.js +131 -35
  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 +17 -0
  53. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  54. package/dist/map/adapter/acp-over-map.js +384 -23
  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 +3 -0
  95. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  96. package/dist/map/adapter/map-adapter.js +258 -35
  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 +2 -1
  131. package/dist/store/event-store.d.ts.map +1 -1
  132. package/dist/store/event-store.js +69 -20
  133. package/dist/store/event-store.js.map +1 -1
  134. package/dist/store/types/agents.d.ts +18 -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__/integration.test.ts +56 -31
  197. package/src/acp/__tests__/macro-agent.test.ts +16 -7
  198. package/src/acp/macro-agent.ts +170 -36
  199. package/src/acp/types.ts +46 -1
  200. package/src/agent/__tests__/agent-manager.test.ts +228 -2
  201. package/src/agent/agent-manager.ts +714 -261
  202. package/src/agent/types.ts +3 -1
  203. package/src/api/server.ts +41 -7
  204. package/src/auth/__tests__/token.test.ts +100 -0
  205. package/src/auth/index.ts +1 -0
  206. package/src/auth/token.ts +82 -0
  207. package/src/cli/__tests__/acp.test.ts +1 -1
  208. package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
  209. package/src/cli/acp.ts +130 -72
  210. package/src/cli/index.ts +120 -14
  211. package/src/cli/mcp.ts +311 -207
  212. package/src/cli/parse-args.ts +54 -0
  213. package/src/cli/stable-instance-id.ts +14 -0
  214. package/src/config/project-config.ts +190 -27
  215. package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
  216. package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +22 -4
  217. package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
  218. package/src/map/adapter/__tests__/acp-over-map-history.test.ts +263 -0
  219. package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
  220. package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
  221. package/src/map/adapter/__tests__/event-log.test.ts +527 -0
  222. package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
  223. package/src/map/adapter/__tests__/extensions.test.ts +408 -0
  224. package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
  225. package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
  226. package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
  227. package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
  228. package/src/map/adapter/acp-over-map.ts +678 -66
  229. package/src/map/adapter/connection-manager.ts +3 -0
  230. package/src/map/adapter/event-log.ts +208 -0
  231. package/src/map/adapter/event-translator.ts +6 -6
  232. package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
  233. package/src/map/adapter/extensions/index.ts +60 -0
  234. package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
  235. package/src/map/adapter/extensions/task.ts +11 -0
  236. package/src/map/adapter/extensions/update-metadata.ts +126 -0
  237. package/src/map/adapter/index.ts +28 -0
  238. package/src/map/adapter/interface.ts +2 -0
  239. package/src/map/adapter/map-adapter.ts +312 -47
  240. package/src/map/adapter/subscription-manager.ts +5 -1
  241. package/src/map/adapter/types.ts +2 -0
  242. package/src/mcp/__tests__/map-client.test.ts +386 -0
  243. package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
  244. package/src/mcp/__tests__/mcp-server.test.ts +100 -1
  245. package/src/mcp/map-client.ts +177 -0
  246. package/src/mcp/mcp-server.ts +191 -100
  247. package/src/mcp/types.ts +6 -1
  248. package/src/metrics/metrics.ts +1 -1
  249. package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
  250. package/src/roles/__tests__/config-loader.test.ts +7 -7
  251. package/src/roles/capabilities.ts +17 -7
  252. package/src/roles/config-loader.ts +6 -6
  253. package/src/roles/registry.ts +2 -2
  254. package/src/server/__tests__/combined-server.test.ts +94 -21
  255. package/src/server/combined-server.ts +189 -33
  256. package/src/steering/__tests__/steering-integration.test.ts +1 -1
  257. package/src/store/__tests__/event-store.test.ts +196 -1
  258. package/src/store/__tests__/instance.test.ts +3 -3
  259. package/src/store/event-store.ts +80 -21
  260. package/src/store/types/agents.ts +15 -0
  261. package/src/store/types/events.ts +1 -1
  262. package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
  263. package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
  264. package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
  265. package/src/task/backend/index.ts +156 -106
  266. package/src/task/backend/memory.ts +4 -0
  267. package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
  268. package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
  269. package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
  270. package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
  271. package/src/task/backend/opentasks/backend.ts +1323 -0
  272. package/src/task/backend/opentasks/client.ts +652 -0
  273. package/src/task/backend/opentasks/daemon-manager.ts +253 -0
  274. package/src/task/backend/opentasks/index.ts +69 -0
  275. package/src/task/backend/opentasks/mapping.ts +94 -0
  276. package/src/task/backend/types.ts +42 -66
  277. package/src/task/backend/unified-tool-provider.ts +779 -0
  278. package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
  279. package/src/teams/team-loader.ts +3 -3
  280. package/src/teams/team-runtime.ts +2 -0
  281. package/test_fixtures/README.md +2 -3
  282. package/test_fixtures/fixtures/index.ts +0 -3
  283. package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
  284. package/test_fixtures/fixtures/repos/index.ts +1 -3
  285. package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
  286. package/test_fixtures/fixtures/repos/types.ts +0 -11
  287. package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
  288. package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
  289. package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
  290. package/vitest.config.ts +1 -1
  291. package/vitest.e2e.config.ts +1 -1
  292. package/vitest.setup.ts +1 -30
  293. package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
  294. package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
  295. package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
  296. package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
  297. package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
  298. package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
  299. package/.macro-agent/teams/self-driving/team.yaml +0 -103
  300. package/.macro-agent/teams/structured/prompts/developer.md +0 -26
  301. package/.macro-agent/teams/structured/prompts/lead.md +0 -25
  302. package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
  303. package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
  304. package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
  305. package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
  306. package/.macro-agent/teams/structured/team.yaml +0 -89
  307. package/docs/sudocode-integration.md +0 -383
  308. package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
  309. package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
  310. package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
  311. package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
  312. package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
  313. package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
  314. package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
  315. package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
  316. package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
  317. package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
  318. package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
  319. package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
  320. package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
  321. package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
  322. package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
  323. package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
  324. package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
  325. package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
  326. package/src/task/backend/sudocode/backend.ts +0 -1237
  327. package/src/task/backend/sudocode/client.ts +0 -515
  328. package/src/task/backend/sudocode/index.ts +0 -120
  329. package/src/task/backend/sudocode/mapping.ts +0 -93
  330. package/src/task/backend/sudocode/server-client.ts +0 -522
  331. package/src/task/backend/sudocode/standalone-client.ts +0 -623
  332. package/src/task/backend/sudocode/sync-policy.ts +0 -387
  333. package/src/task/backend/sudocode/tools.ts +0 -896
  334. package/src/task/backend/tool-provider.ts +0 -506
  335. package/test_fixtures/fixtures/sudocode/index.ts +0 -29
  336. package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
  337. 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
- });