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
@@ -0,0 +1,524 @@
1
+ /**
2
+ * E2E Tests for UnifiedTaskToolProvider with real OpenTasks daemon
3
+ *
4
+ * Starts a real opentasks daemon, connects via IPCOpenTasksClient,
5
+ * creates an OpenTasksTaskBackend, and exercises all 7 tools end-to-end.
6
+ *
7
+ * Requires: opentasks@0.0.3+ installed
8
+ *
9
+ * @module task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test
10
+ */
11
+
12
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
13
+ import * as fs from "fs";
14
+ import * as path from "path";
15
+ import * as os from "os";
16
+ import { createEventStore, type EventStore } from "../../../../store/event-store.js";
17
+ import { OpenTasksTaskBackend } from "../../opentasks/backend.js";
18
+ import { IPCOpenTasksClient } from "../../opentasks/client.js";
19
+ import {
20
+ UnifiedTaskToolProvider,
21
+ type GetToolContext,
22
+ } from "../../unified-tool-provider.js";
23
+ import type { MCPToolDefinition } from "../../types.js";
24
+
25
+ // =============================================================================
26
+ // Helpers
27
+ // =============================================================================
28
+
29
+ const TEST_AGENT_ID = "agent_e2e_test";
30
+ const getContext: GetToolContext = () => ({ agent_id: TEST_AGENT_ID });
31
+
32
+ function findTool(
33
+ tools: MCPToolDefinition[],
34
+ name: string
35
+ ): MCPToolDefinition {
36
+ const tool = tools.find((t) => t.name === name);
37
+ if (!tool) throw new Error(`Tool not found: ${name}`);
38
+ return tool;
39
+ }
40
+
41
+ /**
42
+ * Wait for a condition with timeout
43
+ */
44
+ async function waitFor(
45
+ condition: () => Promise<boolean> | boolean,
46
+ timeoutMs = 5000,
47
+ intervalMs = 100
48
+ ): Promise<void> {
49
+ const start = Date.now();
50
+ while (Date.now() - start < timeoutMs) {
51
+ if (await condition()) return;
52
+ await new Promise((r) => setTimeout(r, intervalMs));
53
+ }
54
+ throw new Error(`Timed out after ${timeoutMs}ms`);
55
+ }
56
+
57
+ // =============================================================================
58
+ // Test Suite
59
+ // =============================================================================
60
+
61
+ describe("UnifiedTaskToolProvider E2E with real OpenTasks", () => {
62
+ let tempDir: string;
63
+ let locationPath: string;
64
+ let daemon: any;
65
+ let socketPath: string;
66
+ let eventStore: EventStore;
67
+ let otClient: IPCOpenTasksClient;
68
+ let backend: OpenTasksTaskBackend;
69
+ let provider: UnifiedTaskToolProvider;
70
+
71
+ beforeAll(async () => {
72
+ // Create temp directory for opentasks data
73
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "macro-e2e-opentasks-"));
74
+ locationPath = path.join(tempDir, ".opentasks");
75
+ fs.mkdirSync(locationPath, { recursive: true });
76
+
77
+ const registryPath = path.join(tempDir, "registry.json");
78
+
79
+ // Start a real opentasks daemon
80
+ const opentasks = await import("opentasks");
81
+
82
+ daemon = await opentasks.createDaemonWithStore({
83
+ locationPath,
84
+ version: "0.0.3",
85
+ registryPath,
86
+ shutdownTimeoutMs: 2000,
87
+ });
88
+
89
+ await daemon.start();
90
+ socketPath = daemon.socketPath;
91
+
92
+ // Create macro-agent event store (in-memory)
93
+ eventStore = await createEventStore({ inMemory: true });
94
+
95
+ // Create IPCOpenTasksClient pointing at the real daemon
96
+ otClient = new IPCOpenTasksClient({
97
+ socketPath,
98
+ autoConnect: true,
99
+ timeout: 10000,
100
+ });
101
+ await otClient.connect();
102
+
103
+ // Create OpenTasks backend
104
+ backend = new OpenTasksTaskBackend(eventStore, otClient, {
105
+ socketPath,
106
+ syncStatus: true,
107
+ sourceLabel: "e2e-test",
108
+ });
109
+
110
+ // Create unified tool provider with all 7 tools
111
+ provider = new UnifiedTaskToolProvider(backend, getContext, otClient);
112
+ }, 30000);
113
+
114
+ afterAll(async () => {
115
+ // Teardown in reverse order
116
+ try {
117
+ otClient?.disconnect();
118
+ } catch { /* ignore */ }
119
+ try {
120
+ await daemon?.stop();
121
+ } catch { /* ignore */ }
122
+ try {
123
+ await eventStore?.close();
124
+ } catch { /* ignore */ }
125
+ try {
126
+ if (tempDir) fs.rmSync(tempDir, { recursive: true, force: true });
127
+ } catch { /* ignore */ }
128
+ }, 15000);
129
+
130
+ // ─────────────────────────────────────────────────────────────────────────────
131
+ // Tool Exposure
132
+ // ─────────────────────────────────────────────────────────────────────────────
133
+
134
+ it("should expose all 8 tools with OpenTasks client", () => {
135
+ const tools = provider.getTools();
136
+ expect(tools).toHaveLength(8);
137
+ expect(tools.map((t) => t.name)).toEqual([
138
+ "create_task",
139
+ "get_task",
140
+ "list_tasks",
141
+ "assign_task",
142
+ "task",
143
+ "link",
144
+ "annotate",
145
+ "list_providers",
146
+ ]);
147
+ });
148
+
149
+ // ─────────────────────────────────────────────────────────────────────────────
150
+ // Core CRUD Tools (real backend → real daemon)
151
+ // ─────────────────────────────────────────────────────────────────────────────
152
+
153
+ describe("create_task → get_task roundtrip", () => {
154
+ let createdTaskId: string;
155
+
156
+ it("should create a task via create_task tool", async () => {
157
+ const tool = findTool(provider.getTools(), "create_task");
158
+ const result = (await tool.handler({
159
+ description: "E2E test task",
160
+ })) as { task_id: string; status: string; external_id?: string };
161
+
162
+ expect(result.task_id).toMatch(/^task_/);
163
+ expect(result.status).toBe("pending");
164
+ createdTaskId = result.task_id;
165
+ });
166
+
167
+ it("should retrieve the task via get_task tool", async () => {
168
+ const tool = findTool(provider.getTools(), "get_task");
169
+ const result = (await tool.handler({
170
+ task_id: createdTaskId,
171
+ })) as { id: string; description: string; status: string };
172
+
173
+ expect(result.id).toBe(createdTaskId);
174
+ expect(result.description).toBe("E2E test task");
175
+ expect(result.status).toBe("pending");
176
+ });
177
+ });
178
+
179
+ describe("list_tasks", () => {
180
+ it("should list tasks with filters", async () => {
181
+ const createTool = findTool(provider.getTools(), "create_task");
182
+ const listTool = findTool(provider.getTools(), "list_tasks");
183
+
184
+ // Create a couple tasks
185
+ await createTool.handler({ description: "List test A" });
186
+ await createTool.handler({ description: "List test B" });
187
+
188
+ const result = (await listTool.handler({})) as {
189
+ tasks: Array<{ id: string; description: string }>;
190
+ total: number;
191
+ };
192
+
193
+ expect(result.total).toBeGreaterThanOrEqual(2);
194
+ expect(result.tasks.some((t) => t.description === "List test A")).toBe(true);
195
+ expect(result.tasks.some((t) => t.description === "List test B")).toBe(true);
196
+ });
197
+ });
198
+
199
+ describe("assign_task", () => {
200
+ it("should assign a task to an agent", async () => {
201
+ const createTool = findTool(provider.getTools(), "create_task");
202
+ const assignTool = findTool(provider.getTools(), "assign_task");
203
+ const getTool = findTool(provider.getTools(), "get_task");
204
+
205
+ // Create
206
+ const created = (await createTool.handler({
207
+ description: "Assign test task",
208
+ })) as { task_id: string };
209
+
210
+ // Assign
211
+ const assignResult = (await assignTool.handler({
212
+ task_id: created.task_id,
213
+ agent_id: "agent_worker_1",
214
+ })) as { assigned_agent: string; assigned: boolean };
215
+
216
+ expect(assignResult.assigned_agent).toBe("agent_worker_1");
217
+ expect(assignResult.assigned).toBe(true);
218
+
219
+ // Verify
220
+ const task = (await getTool.handler({
221
+ task_id: created.task_id,
222
+ })) as { assigned_agent: string; status: string };
223
+
224
+ expect(task.assigned_agent).toBe("agent_worker_1");
225
+ expect(task.status).toBe("assigned");
226
+ });
227
+ });
228
+
229
+ // ─────────────────────────────────────────────────────────────────────────────
230
+ // OpenTasks Graph Tools (real daemon)
231
+ // ─────────────────────────────────────────────────────────────────────────────
232
+
233
+ describe("task tool", () => {
234
+ it("should transition a task through its lifecycle and sync to EventStore", async () => {
235
+ const createTool = findTool(provider.getTools(), "create_task");
236
+ const taskTool = findTool(provider.getTools(), "task");
237
+ const getTool = findTool(provider.getTools(), "get_task");
238
+
239
+ const created = (await createTool.handler({
240
+ description: "Lifecycle test task",
241
+ })) as { task_id: string; external_id?: string };
242
+
243
+ const taskDetails = (await getTool.handler({
244
+ task_id: created.task_id,
245
+ })) as { external_id?: string; status: string };
246
+
247
+ const externalId = taskDetails.external_id;
248
+ expect(externalId).toBeDefined();
249
+ expect(taskDetails.status).toBe("pending");
250
+
251
+ // Start the task via opentasks daemon
252
+ const startResult = await taskTool.handler({
253
+ transition: { id: externalId, action: "start" },
254
+ });
255
+ expect(startResult).toBeDefined();
256
+
257
+ // Verify EventStore was synced — get_task reads from EventStore
258
+ const afterStart = (await getTool.handler({
259
+ task_id: created.task_id,
260
+ })) as { status: string };
261
+ expect(afterStart.status).toBe("in_progress");
262
+
263
+ // Complete the task via opentasks daemon
264
+ const completeResult = await taskTool.handler({
265
+ transition: { id: externalId, action: "complete" },
266
+ });
267
+ expect(completeResult).toBeDefined();
268
+
269
+ // Verify EventStore was synced
270
+ const afterComplete = (await getTool.handler({
271
+ task_id: created.task_id,
272
+ })) as { status: string };
273
+ expect(afterComplete.status).toBe("completed");
274
+ });
275
+
276
+ it("should sync task assignment via task tool to EventStore", async () => {
277
+ const createTool = findTool(provider.getTools(), "create_task");
278
+ const taskTool = findTool(provider.getTools(), "task");
279
+ const getTool = findTool(provider.getTools(), "get_task");
280
+
281
+ const created = (await createTool.handler({
282
+ description: "Assign sync test task",
283
+ })) as { task_id: string };
284
+
285
+ const taskDetails = (await getTool.handler({
286
+ task_id: created.task_id,
287
+ })) as { external_id: string };
288
+
289
+ // Assign via task tool (opentasks daemon path)
290
+ await taskTool.handler({
291
+ assign: { id: taskDetails.external_id, assignee: "agent_worker_2" },
292
+ });
293
+
294
+ // Verify EventStore was synced
295
+ const afterAssign = (await getTool.handler({
296
+ task_id: created.task_id,
297
+ })) as { assigned_agent: string };
298
+ expect(afterAssign.assigned_agent).toBe("agent_worker_2");
299
+ });
300
+
301
+ it("should query ready tasks", async () => {
302
+ const createTool = findTool(provider.getTools(), "create_task");
303
+ const taskTool = findTool(provider.getTools(), "task");
304
+
305
+ // Create a fresh task (should be ready since no blockers)
306
+ await createTool.handler({ description: "Ready test task" });
307
+
308
+ const readyResult = (await taskTool.handler({
309
+ ready: {},
310
+ })) as { type?: string; items?: unknown[] };
311
+
312
+ expect(readyResult).toBeDefined();
313
+ });
314
+
315
+ it("should get valid actions for a task", async () => {
316
+ const createTool = findTool(provider.getTools(), "create_task");
317
+ const taskTool = findTool(provider.getTools(), "task");
318
+ const getTool = findTool(provider.getTools(), "get_task");
319
+
320
+ const created = (await createTool.handler({
321
+ description: "Valid actions test",
322
+ })) as { task_id: string };
323
+
324
+ const taskDetails = (await getTool.handler({
325
+ task_id: created.task_id,
326
+ })) as { external_id?: string };
327
+
328
+ const result = await taskTool.handler({
329
+ validActions: { id: taskDetails.external_id! },
330
+ });
331
+
332
+ expect(result).toBeDefined();
333
+ });
334
+ });
335
+
336
+ describe("link tool", () => {
337
+ it("should create and remove edges between tasks", async () => {
338
+ const createTool = findTool(provider.getTools(), "create_task");
339
+ const linkTool = findTool(provider.getTools(), "link");
340
+ const getTool = findTool(provider.getTools(), "get_task");
341
+
342
+ // Create two tasks
343
+ const blocker = (await createTool.handler({
344
+ description: "Blocker task",
345
+ })) as { task_id: string };
346
+ const blocked = (await createTool.handler({
347
+ description: "Blocked task",
348
+ })) as { task_id: string };
349
+
350
+ // Get external IDs
351
+ const blockerDetails = (await getTool.handler({
352
+ task_id: blocker.task_id,
353
+ })) as { external_id: string };
354
+ const blockedDetails = (await getTool.handler({
355
+ task_id: blocked.task_id,
356
+ })) as { external_id: string };
357
+
358
+ // Create a "blocks" edge
359
+ const createResult = (await linkTool.handler({
360
+ from_id: blockerDetails.external_id,
361
+ to_id: blockedDetails.external_id,
362
+ type: "blocks",
363
+ })) as { created: boolean };
364
+
365
+ expect(createResult.created).toBe(true);
366
+
367
+ // Remove the edge
368
+ const removeResult = (await linkTool.handler({
369
+ from_id: blockerDetails.external_id,
370
+ to_id: blockedDetails.external_id,
371
+ type: "blocks",
372
+ remove: true,
373
+ })) as { removed: boolean };
374
+
375
+ expect(removeResult.removed).toBe(true);
376
+ });
377
+ });
378
+
379
+ describe("annotate tool", () => {
380
+ it("should create feedback on a task", async () => {
381
+ const createTool = findTool(provider.getTools(), "create_task");
382
+ const annotateTool = findTool(provider.getTools(), "annotate");
383
+ const getTool = findTool(provider.getTools(), "get_task");
384
+
385
+ // Create a task
386
+ const created = (await createTool.handler({
387
+ description: "Feedback target task",
388
+ })) as { task_id: string };
389
+
390
+ const details = (await getTool.handler({
391
+ task_id: created.task_id,
392
+ })) as { external_id: string };
393
+
394
+ // Add a comment
395
+ const annotateResult = (await annotateTool.handler({
396
+ target_id: details.external_id,
397
+ content: "E2E test feedback comment",
398
+ feedback_type: "comment",
399
+ })) as { feedback_id: string; created: boolean; type: string };
400
+
401
+ expect(annotateResult.created).toBe(true);
402
+ expect(annotateResult.type).toBe("comment");
403
+ expect(annotateResult.feedback_id).toBeDefined();
404
+ });
405
+
406
+ it("should resolve feedback", async () => {
407
+ const createTool = findTool(provider.getTools(), "create_task");
408
+ const annotateTool = findTool(provider.getTools(), "annotate");
409
+ const getTool = findTool(provider.getTools(), "get_task");
410
+
411
+ const created = (await createTool.handler({
412
+ description: "Resolve feedback target",
413
+ })) as { task_id: string };
414
+
415
+ const details = (await getTool.handler({
416
+ task_id: created.task_id,
417
+ })) as { external_id: string };
418
+
419
+ // Create feedback
420
+ const feedback = (await annotateTool.handler({
421
+ target_id: details.external_id,
422
+ content: "Feedback to resolve",
423
+ feedback_type: "suggestion",
424
+ })) as { feedback_id: string };
425
+
426
+ // Resolve it
427
+ const resolveResult = (await annotateTool.handler({
428
+ target_id: details.external_id,
429
+ resolve: feedback.feedback_id,
430
+ })) as { resolved: boolean; feedback_id: string };
431
+
432
+ expect(resolveResult.resolved).toBe(true);
433
+ expect(resolveResult.feedback_id).toBe(feedback.feedback_id);
434
+ });
435
+ });
436
+
437
+ // ─────────────────────────────────────────────────────────────────────────────
438
+ // Full Workflow
439
+ // ─────────────────────────────────────────────────────────────────────────────
440
+
441
+ describe("full workflow", () => {
442
+ it("should execute a complete task lifecycle: create → assign → link → annotate → transition", async () => {
443
+ const tools = provider.getTools();
444
+ const createTool = findTool(tools, "create_task");
445
+ const getTool = findTool(tools, "get_task");
446
+ const assignTool = findTool(tools, "assign_task");
447
+ const linkTool = findTool(tools, "link");
448
+ const annotateTool = findTool(tools, "annotate");
449
+ const taskTool = findTool(tools, "task");
450
+
451
+ // 1. Create parent and child tasks
452
+ const parent = (await createTool.handler({
453
+ description: "Full workflow parent task",
454
+ })) as { task_id: string };
455
+
456
+ const child = (await createTool.handler({
457
+ description: "Full workflow child task",
458
+ parent_task: parent.task_id,
459
+ })) as { task_id: string };
460
+
461
+ // 2. Get external IDs
462
+ const parentDetails = (await getTool.handler({
463
+ task_id: parent.task_id,
464
+ })) as { external_id: string };
465
+
466
+ const childDetails = (await getTool.handler({
467
+ task_id: child.task_id,
468
+ })) as { external_id: string };
469
+
470
+ expect(parentDetails.external_id).toBeDefined();
471
+ expect(childDetails.external_id).toBeDefined();
472
+
473
+ // 3. Create a "blocks" link: parent blocks child
474
+ const linkResult = (await linkTool.handler({
475
+ from_id: parentDetails.external_id,
476
+ to_id: childDetails.external_id,
477
+ type: "blocks",
478
+ })) as { created: boolean };
479
+
480
+ expect(linkResult.created).toBe(true);
481
+
482
+ // 4. Assign parent task
483
+ const assignResult = (await assignTool.handler({
484
+ task_id: parent.task_id,
485
+ agent_id: TEST_AGENT_ID,
486
+ })) as { assigned: boolean };
487
+
488
+ expect(assignResult.assigned).toBe(true);
489
+
490
+ // 5. Add feedback on the parent
491
+ const feedbackResult = (await annotateTool.handler({
492
+ target_id: parentDetails.external_id,
493
+ content: "Starting work on this task",
494
+ feedback_type: "comment",
495
+ })) as { created: boolean; feedback_id: string };
496
+
497
+ expect(feedbackResult.created).toBe(true);
498
+
499
+ // 6. Start parent via task tool
500
+ const startResult = (await taskTool.handler({
501
+ transition: { id: parentDetails.external_id, action: "start" },
502
+ })) as { success: boolean };
503
+
504
+ expect(startResult).toBeDefined();
505
+
506
+ // 7. Complete parent via task tool
507
+ const completeResult = (await taskTool.handler({
508
+ transition: { id: parentDetails.external_id, action: "complete" },
509
+ })) as { success: boolean };
510
+
511
+ expect(completeResult).toBeDefined();
512
+
513
+ // 8. Verify parent is completed in EventStore (syncExternalTransition)
514
+ const finalParent = (await getTool.handler({
515
+ task_id: parent.task_id,
516
+ })) as { status: string; external_id: string; assigned_agent: string };
517
+
518
+ expect(finalParent).toBeDefined();
519
+ expect(finalParent.external_id).toBe(parentDetails.external_id);
520
+ expect(finalParent.status).toBe("completed");
521
+ expect(finalParent.assigned_agent).toBe(TEST_AGENT_ID);
522
+ });
523
+ });
524
+ });