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
@@ -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
+ });