macro-agent 0.0.11 → 0.0.12

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 (408) hide show
  1. package/.macro-agent/teams/self-driving/prompts/grinder.md +27 -0
  2. package/.macro-agent/teams/self-driving/prompts/judge.md +27 -0
  3. package/.macro-agent/teams/self-driving/prompts/planner.md +33 -0
  4. package/.macro-agent/teams/self-driving/roles/grinder.yaml +17 -0
  5. package/.macro-agent/teams/self-driving/roles/judge.yaml +24 -0
  6. package/.macro-agent/teams/self-driving/roles/planner.yaml +18 -0
  7. package/.macro-agent/teams/self-driving/team.yaml +103 -0
  8. package/.macro-agent/teams/structured/prompts/developer.md +26 -0
  9. package/.macro-agent/teams/structured/prompts/lead.md +25 -0
  10. package/.macro-agent/teams/structured/prompts/reviewer.md +24 -0
  11. package/.macro-agent/teams/structured/roles/developer.yaml +12 -0
  12. package/.macro-agent/teams/structured/roles/lead.yaml +11 -0
  13. package/.macro-agent/teams/structured/roles/reviewer.yaml +19 -0
  14. package/.macro-agent/teams/structured/team.yaml +89 -0
  15. package/.sudocode/issues.jsonl +6 -0
  16. package/.sudocode/specs.jsonl +7 -0
  17. package/CLAUDE.md +110 -30
  18. package/README.md +60 -3
  19. package/dist/acp/macro-agent.d.ts +4 -0
  20. package/dist/acp/macro-agent.d.ts.map +1 -1
  21. package/dist/acp/macro-agent.js +50 -4
  22. package/dist/acp/macro-agent.js.map +1 -1
  23. package/dist/acp/session-mapper.d.ts +20 -1
  24. package/dist/acp/session-mapper.d.ts.map +1 -1
  25. package/dist/acp/session-mapper.js +90 -1
  26. package/dist/acp/session-mapper.js.map +1 -1
  27. package/dist/acp/types.d.ts +24 -1
  28. package/dist/acp/types.d.ts.map +1 -1
  29. package/dist/acp/types.js.map +1 -1
  30. package/dist/agent/agent-manager.d.ts +25 -1
  31. package/dist/agent/agent-manager.d.ts.map +1 -1
  32. package/dist/agent/agent-manager.js +93 -7
  33. package/dist/agent/agent-manager.js.map +1 -1
  34. package/dist/agent/types.d.ts +22 -0
  35. package/dist/agent/types.d.ts.map +1 -1
  36. package/dist/agent/types.js.map +1 -1
  37. package/dist/agent-detection/command-builder.d.ts +30 -0
  38. package/dist/agent-detection/command-builder.d.ts.map +1 -0
  39. package/dist/agent-detection/command-builder.js +71 -0
  40. package/dist/agent-detection/command-builder.js.map +1 -0
  41. package/dist/agent-detection/detector.d.ts +84 -0
  42. package/dist/agent-detection/detector.d.ts.map +1 -0
  43. package/dist/agent-detection/detector.js +240 -0
  44. package/dist/agent-detection/detector.js.map +1 -0
  45. package/dist/agent-detection/index.d.ts +12 -0
  46. package/dist/agent-detection/index.d.ts.map +1 -0
  47. package/dist/agent-detection/index.js +14 -0
  48. package/dist/agent-detection/index.js.map +1 -0
  49. package/dist/agent-detection/registry.d.ts +53 -0
  50. package/dist/agent-detection/registry.d.ts.map +1 -0
  51. package/dist/agent-detection/registry.js +177 -0
  52. package/dist/agent-detection/registry.js.map +1 -0
  53. package/dist/agent-detection/types.d.ts +121 -0
  54. package/dist/agent-detection/types.d.ts.map +1 -0
  55. package/dist/agent-detection/types.js +20 -0
  56. package/dist/agent-detection/types.js.map +1 -0
  57. package/dist/api/server.d.ts.map +1 -1
  58. package/dist/api/server.js +95 -0
  59. package/dist/api/server.js.map +1 -1
  60. package/dist/cli/index.js +29 -0
  61. package/dist/cli/index.js.map +1 -1
  62. package/dist/cli/mcp.js +38 -0
  63. package/dist/cli/mcp.js.map +1 -1
  64. package/dist/config/index.d.ts +2 -0
  65. package/dist/config/index.d.ts.map +1 -0
  66. package/dist/config/index.js +2 -0
  67. package/dist/config/index.js.map +1 -0
  68. package/dist/config/project-config.d.ts +46 -0
  69. package/dist/config/project-config.d.ts.map +1 -0
  70. package/dist/config/project-config.js +68 -0
  71. package/dist/config/project-config.js.map +1 -0
  72. package/dist/lifecycle/cascade.d.ts +1 -1
  73. package/dist/lifecycle/cascade.d.ts.map +1 -1
  74. package/dist/lifecycle/handlers/index.d.ts +4 -0
  75. package/dist/lifecycle/handlers/index.d.ts.map +1 -1
  76. package/dist/lifecycle/handlers/index.js +2 -0
  77. package/dist/lifecycle/handlers/index.js.map +1 -1
  78. package/dist/lifecycle/handlers/worker.d.ts +4 -0
  79. package/dist/lifecycle/handlers/worker.d.ts.map +1 -1
  80. package/dist/lifecycle/handlers/worker.js +35 -3
  81. package/dist/lifecycle/handlers/worker.js.map +1 -1
  82. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  83. package/dist/map/adapter/acp-over-map.js +32 -2
  84. package/dist/map/adapter/acp-over-map.js.map +1 -1
  85. package/dist/map/adapter/event-translator.d.ts.map +1 -1
  86. package/dist/map/adapter/event-translator.js +1 -0
  87. package/dist/map/adapter/event-translator.js.map +1 -1
  88. package/dist/map/adapter/extensions/agent-detection.d.ts +49 -0
  89. package/dist/map/adapter/extensions/agent-detection.d.ts.map +1 -0
  90. package/dist/map/adapter/extensions/agent-detection.js +91 -0
  91. package/dist/map/adapter/extensions/agent-detection.js.map +1 -0
  92. package/dist/map/adapter/extensions/index.d.ts +10 -1
  93. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  94. package/dist/map/adapter/extensions/index.js +39 -0
  95. package/dist/map/adapter/extensions/index.js.map +1 -1
  96. package/dist/map/adapter/extensions/resume.d.ts +47 -0
  97. package/dist/map/adapter/extensions/resume.d.ts.map +1 -0
  98. package/dist/map/adapter/extensions/resume.js +59 -0
  99. package/dist/map/adapter/extensions/resume.js.map +1 -0
  100. package/dist/map/adapter/extensions/workspace-files.d.ts +42 -0
  101. package/dist/map/adapter/extensions/workspace-files.d.ts.map +1 -0
  102. package/dist/map/adapter/extensions/workspace-files.js +338 -0
  103. package/dist/map/adapter/extensions/workspace-files.js.map +1 -0
  104. package/dist/mcp/mcp-server.d.ts +6 -0
  105. package/dist/mcp/mcp-server.d.ts.map +1 -1
  106. package/dist/mcp/mcp-server.js +45 -0
  107. package/dist/mcp/mcp-server.js.map +1 -1
  108. package/dist/mcp/tools/claim_task.d.ts +35 -0
  109. package/dist/mcp/tools/claim_task.d.ts.map +1 -0
  110. package/dist/mcp/tools/claim_task.js +58 -0
  111. package/dist/mcp/tools/claim_task.js.map +1 -0
  112. package/dist/mcp/tools/done.d.ts +11 -2
  113. package/dist/mcp/tools/done.d.ts.map +1 -1
  114. package/dist/mcp/tools/done.js +15 -10
  115. package/dist/mcp/tools/done.js.map +1 -1
  116. package/dist/mcp/tools/list_claimable_tasks.d.ts +38 -0
  117. package/dist/mcp/tools/list_claimable_tasks.d.ts.map +1 -0
  118. package/dist/mcp/tools/list_claimable_tasks.js +63 -0
  119. package/dist/mcp/tools/list_claimable_tasks.js.map +1 -0
  120. package/dist/mcp/tools/unclaim_task.d.ts +31 -0
  121. package/dist/mcp/tools/unclaim_task.d.ts.map +1 -0
  122. package/dist/mcp/tools/unclaim_task.js +47 -0
  123. package/dist/mcp/tools/unclaim_task.js.map +1 -0
  124. package/dist/metrics/index.d.ts +2 -0
  125. package/dist/metrics/index.d.ts.map +1 -0
  126. package/dist/metrics/index.js +2 -0
  127. package/dist/metrics/index.js.map +1 -0
  128. package/dist/metrics/metrics.d.ts +79 -0
  129. package/dist/metrics/metrics.d.ts.map +1 -0
  130. package/dist/metrics/metrics.js +166 -0
  131. package/dist/metrics/metrics.js.map +1 -0
  132. package/dist/roles/capabilities.d.ts +1 -0
  133. package/dist/roles/capabilities.d.ts.map +1 -1
  134. package/dist/roles/capabilities.js +3 -0
  135. package/dist/roles/capabilities.js.map +1 -1
  136. package/dist/roles/types.d.ts +1 -1
  137. package/dist/roles/types.d.ts.map +1 -1
  138. package/dist/router/message-router.d.ts +41 -0
  139. package/dist/router/message-router.d.ts.map +1 -1
  140. package/dist/router/message-router.js +136 -5
  141. package/dist/router/message-router.js.map +1 -1
  142. package/dist/store/event-store.d.ts +8 -1
  143. package/dist/store/event-store.d.ts.map +1 -1
  144. package/dist/store/event-store.js +120 -4
  145. package/dist/store/event-store.js.map +1 -1
  146. package/dist/store/types/agents.d.ts +1 -1
  147. package/dist/store/types/agents.d.ts.map +1 -1
  148. package/dist/store/types/events.d.ts +1 -1
  149. package/dist/store/types/events.d.ts.map +1 -1
  150. package/dist/store/types/events.js.map +1 -1
  151. package/dist/store/types/index.d.ts +1 -0
  152. package/dist/store/types/index.d.ts.map +1 -1
  153. package/dist/store/types/index.js +1 -0
  154. package/dist/store/types/index.js.map +1 -1
  155. package/dist/store/types/sessions.d.ts +44 -0
  156. package/dist/store/types/sessions.d.ts.map +1 -0
  157. package/dist/store/types/sessions.js +9 -0
  158. package/dist/store/types/sessions.js.map +1 -0
  159. package/dist/store/types/tasks.d.ts +2 -0
  160. package/dist/store/types/tasks.d.ts.map +1 -1
  161. package/dist/task/backend/memory.d.ts +4 -1
  162. package/dist/task/backend/memory.d.ts.map +1 -1
  163. package/dist/task/backend/memory.js +81 -0
  164. package/dist/task/backend/memory.js.map +1 -1
  165. package/dist/task/backend/types.d.ts +30 -0
  166. package/dist/task/backend/types.d.ts.map +1 -1
  167. package/dist/task/backend/types.js.map +1 -1
  168. package/dist/teams/index.d.ts +4 -0
  169. package/dist/teams/index.d.ts.map +1 -0
  170. package/dist/teams/index.js +4 -0
  171. package/dist/teams/index.js.map +1 -0
  172. package/dist/teams/team-loader.d.ts +20 -0
  173. package/dist/teams/team-loader.d.ts.map +1 -0
  174. package/dist/teams/team-loader.js +293 -0
  175. package/dist/teams/team-loader.js.map +1 -0
  176. package/dist/teams/team-runtime.d.ts +139 -0
  177. package/dist/teams/team-runtime.d.ts.map +1 -0
  178. package/dist/teams/team-runtime.js +613 -0
  179. package/dist/teams/team-runtime.js.map +1 -0
  180. package/dist/teams/types.d.ts +266 -0
  181. package/dist/teams/types.d.ts.map +1 -0
  182. package/dist/teams/types.js +20 -0
  183. package/dist/teams/types.js.map +1 -0
  184. package/dist/workspace/dataplane-adapter.d.ts +1 -1
  185. package/dist/workspace/dataplane-adapter.d.ts.map +1 -1
  186. package/dist/workspace/dataplane-adapter.js +1 -1
  187. package/dist/workspace/dataplane-adapter.js.map +1 -1
  188. package/dist/workspace/index.d.ts +1 -1
  189. package/dist/workspace/index.d.ts.map +1 -1
  190. package/dist/workspace/strategies/index.d.ts +6 -0
  191. package/dist/workspace/strategies/index.d.ts.map +1 -0
  192. package/dist/workspace/strategies/index.js +5 -0
  193. package/dist/workspace/strategies/index.js.map +1 -0
  194. package/dist/workspace/strategies/optimistic.d.ts +26 -0
  195. package/dist/workspace/strategies/optimistic.d.ts.map +1 -0
  196. package/dist/workspace/strategies/optimistic.js +121 -0
  197. package/dist/workspace/strategies/optimistic.js.map +1 -0
  198. package/dist/workspace/strategies/queue.d.ts +26 -0
  199. package/dist/workspace/strategies/queue.d.ts.map +1 -0
  200. package/dist/workspace/strategies/queue.js +67 -0
  201. package/dist/workspace/strategies/queue.js.map +1 -0
  202. package/dist/workspace/strategies/registry.d.ts +37 -0
  203. package/dist/workspace/strategies/registry.d.ts.map +1 -0
  204. package/dist/workspace/strategies/registry.js +63 -0
  205. package/dist/workspace/strategies/registry.js.map +1 -0
  206. package/dist/workspace/strategies/trunk.d.ts +20 -0
  207. package/dist/workspace/strategies/trunk.d.ts.map +1 -0
  208. package/dist/workspace/strategies/trunk.js +108 -0
  209. package/dist/workspace/strategies/trunk.js.map +1 -0
  210. package/dist/workspace/strategies/types.d.ts +104 -0
  211. package/dist/workspace/strategies/types.d.ts.map +1 -0
  212. package/dist/workspace/strategies/types.js +11 -0
  213. package/dist/workspace/strategies/types.js.map +1 -0
  214. package/dist/workspace/types.d.ts +1 -1
  215. package/dist/workspace/types.d.ts.map +1 -1
  216. package/dist/workspace/workspace-manager.d.ts +1 -1
  217. package/dist/workspace/workspace-manager.d.ts.map +1 -1
  218. package/docs/implementation-details.md +1127 -0
  219. package/docs/implementation-summary.md +448 -0
  220. package/docs/plan-self-driving-support.md +433 -0
  221. package/docs/spec-self-driving-support.md +462 -0
  222. package/docs/team-templates.md +860 -0
  223. package/docs/teams.md +233 -0
  224. package/package.json +4 -2
  225. package/src/acp/__tests__/integration.test.ts +161 -1
  226. package/src/acp/__tests__/macro-agent.test.ts +95 -0
  227. package/src/acp/__tests__/session-persistence.test.ts +276 -0
  228. package/src/acp/macro-agent.ts +79 -7
  229. package/src/acp/session-mapper.ts +108 -1
  230. package/src/acp/types.ts +33 -1
  231. package/src/agent/agent-manager.ts +158 -6
  232. package/src/agent/types.ts +27 -0
  233. package/src/agent-detection/__tests__/command-builder.test.ts +336 -0
  234. package/src/agent-detection/__tests__/detector.test.ts +768 -0
  235. package/src/agent-detection/__tests__/registry.test.ts +254 -0
  236. package/src/agent-detection/command-builder.ts +90 -0
  237. package/src/agent-detection/detector.ts +307 -0
  238. package/src/agent-detection/index.ts +36 -0
  239. package/src/agent-detection/registry.ts +200 -0
  240. package/src/agent-detection/types.ts +184 -0
  241. package/src/api/server.ts +110 -0
  242. package/src/cli/index.ts +44 -0
  243. package/src/cli/mcp.ts +47 -0
  244. package/src/config/index.ts +9 -0
  245. package/src/config/project-config.ts +107 -0
  246. package/src/lifecycle/cascade.ts +1 -1
  247. package/src/lifecycle/handlers/index.ts +8 -0
  248. package/src/lifecycle/handlers/worker.ts +48 -3
  249. package/src/map/adapter/__tests__/extensions.test.ts +359 -0
  250. package/src/map/adapter/__tests__/workspace-files.test.ts +673 -0
  251. package/src/map/adapter/acp-over-map.ts +45 -2
  252. package/src/map/adapter/event-translator.ts +1 -0
  253. package/src/map/adapter/extensions/agent-detection.ts +201 -0
  254. package/src/map/adapter/extensions/index.ts +63 -0
  255. package/src/map/adapter/extensions/resume.ts +114 -0
  256. package/src/map/adapter/extensions/workspace-files.ts +449 -0
  257. package/src/mcp/mcp-server.ts +67 -0
  258. package/src/mcp/tools/claim_task.ts +86 -0
  259. package/src/mcp/tools/done.ts +24 -10
  260. package/src/mcp/tools/list_claimable_tasks.ts +93 -0
  261. package/src/mcp/tools/unclaim_task.ts +71 -0
  262. package/src/metrics/index.ts +9 -0
  263. package/src/metrics/metrics.ts +280 -0
  264. package/src/roles/capabilities.ts +3 -0
  265. package/src/roles/types.ts +2 -1
  266. package/src/router/__tests__/message-router.test.ts +561 -0
  267. package/src/router/message-router.ts +223 -6
  268. package/src/store/event-store.ts +151 -3
  269. package/src/store/types/agents.ts +1 -1
  270. package/src/store/types/events.ts +2 -1
  271. package/src/store/types/index.ts +1 -0
  272. package/src/store/types/sessions.ts +53 -0
  273. package/src/store/types/tasks.ts +3 -0
  274. package/src/task/backend/memory.ts +116 -0
  275. package/src/task/backend/types.ts +43 -0
  276. package/src/teams/__tests__/cross-subsystem.integration.test.ts +983 -0
  277. package/src/teams/__tests__/e2e/team-runtime.e2e.test.ts +553 -0
  278. package/src/teams/__tests__/team-system.test.ts +1280 -0
  279. package/src/teams/index.ts +13 -0
  280. package/src/teams/team-loader.ts +434 -0
  281. package/src/teams/team-runtime.ts +727 -0
  282. package/src/teams/types.ts +377 -0
  283. package/src/workspace/dataplane-adapter.ts +1 -1
  284. package/src/workspace/index.ts +1 -1
  285. package/src/workspace/strategies/index.ts +18 -0
  286. package/src/workspace/strategies/optimistic.ts +136 -0
  287. package/src/workspace/strategies/queue.ts +81 -0
  288. package/src/workspace/strategies/registry.ts +89 -0
  289. package/src/workspace/strategies/trunk.ts +123 -0
  290. package/src/workspace/strategies/types.ts +145 -0
  291. package/src/workspace/types.ts +1 -1
  292. package/src/workspace/workspace-manager.ts +1 -1
  293. package/.claude/settings.local.json +0 -59
  294. package/dist/map/utils/address-translation.d.ts +0 -99
  295. package/dist/map/utils/address-translation.d.ts.map +0 -1
  296. package/dist/map/utils/address-translation.js +0 -285
  297. package/dist/map/utils/address-translation.js.map +0 -1
  298. package/dist/map/utils/index.d.ts +0 -7
  299. package/dist/map/utils/index.d.ts.map +0 -1
  300. package/dist/map/utils/index.js +0 -7
  301. package/dist/map/utils/index.js.map +0 -1
  302. package/references/acp-factory-ref/CHANGELOG.md +0 -33
  303. package/references/acp-factory-ref/LICENSE +0 -21
  304. package/references/acp-factory-ref/README.md +0 -341
  305. package/references/acp-factory-ref/package-lock.json +0 -3102
  306. package/references/acp-factory-ref/package.json +0 -96
  307. package/references/acp-factory-ref/python/CHANGELOG.md +0 -33
  308. package/references/acp-factory-ref/python/LICENSE +0 -21
  309. package/references/acp-factory-ref/python/Makefile +0 -57
  310. package/references/acp-factory-ref/python/README.md +0 -253
  311. package/references/acp-factory-ref/python/pyproject.toml +0 -73
  312. package/references/acp-factory-ref/python/tests/__init__.py +0 -0
  313. package/references/acp-factory-ref/python/tests/e2e/__init__.py +0 -1
  314. package/references/acp-factory-ref/python/tests/e2e/test_codex_e2e.py +0 -349
  315. package/references/acp-factory-ref/python/tests/e2e/test_gemini_e2e.py +0 -165
  316. package/references/acp-factory-ref/python/tests/e2e/test_opencode_e2e.py +0 -296
  317. package/references/acp-factory-ref/python/tests/test_client_handler.py +0 -543
  318. package/references/acp-factory-ref/python/tests/test_pushable.py +0 -199
  319. package/references/claude-code-acp/.github/workflows/ci.yml +0 -45
  320. package/references/claude-code-acp/.github/workflows/publish.yml +0 -34
  321. package/references/claude-code-acp/.prettierrc.json +0 -4
  322. package/references/claude-code-acp/CHANGELOG.md +0 -249
  323. package/references/claude-code-acp/LICENSE +0 -222
  324. package/references/claude-code-acp/README.md +0 -53
  325. package/references/claude-code-acp/docs/RELEASES.md +0 -24
  326. package/references/claude-code-acp/eslint.config.js +0 -48
  327. package/references/claude-code-acp/package-lock.json +0 -4570
  328. package/references/claude-code-acp/package.json +0 -88
  329. package/references/claude-code-acp/scripts/release.sh +0 -119
  330. package/references/claude-code-acp/src/acp-agent.ts +0 -2065
  331. package/references/claude-code-acp/src/index.ts +0 -26
  332. package/references/claude-code-acp/src/lib.ts +0 -38
  333. package/references/claude-code-acp/src/mcp-server.ts +0 -911
  334. package/references/claude-code-acp/src/settings.ts +0 -522
  335. package/references/claude-code-acp/src/tests/.claude/commands/quick-math.md +0 -5
  336. package/references/claude-code-acp/src/tests/.claude/commands/say-hello.md +0 -6
  337. package/references/claude-code-acp/src/tests/acp-agent-fork.test.ts +0 -479
  338. package/references/claude-code-acp/src/tests/acp-agent.test.ts +0 -1502
  339. package/references/claude-code-acp/src/tests/extract-lines.test.ts +0 -103
  340. package/references/claude-code-acp/src/tests/fork-session.test.ts +0 -335
  341. package/references/claude-code-acp/src/tests/replace-and-calculate-location.test.ts +0 -334
  342. package/references/claude-code-acp/src/tests/settings.test.ts +0 -617
  343. package/references/claude-code-acp/src/tests/skills-options.test.ts +0 -187
  344. package/references/claude-code-acp/src/tests/tools.test.ts +0 -318
  345. package/references/claude-code-acp/src/tests/typescript-declarations.test.ts +0 -558
  346. package/references/claude-code-acp/src/tools.ts +0 -819
  347. package/references/claude-code-acp/src/utils.ts +0 -171
  348. package/references/claude-code-acp/tsconfig.json +0 -18
  349. package/references/claude-code-acp/vitest.config.ts +0 -19
  350. package/references/multi-agent-protocol/.sudocode/issues.jsonl +0 -111
  351. package/references/multi-agent-protocol/.sudocode/specs.jsonl +0 -13
  352. package/references/multi-agent-protocol/LICENSE +0 -21
  353. package/references/multi-agent-protocol/README.md +0 -113
  354. package/references/multi-agent-protocol/docs/00-design-specification.md +0 -496
  355. package/references/multi-agent-protocol/docs/01-open-questions.md +0 -1050
  356. package/references/multi-agent-protocol/docs/02-wire-protocol.md +0 -296
  357. package/references/multi-agent-protocol/docs/03-streaming-semantics.md +0 -252
  358. package/references/multi-agent-protocol/docs/04-error-handling.md +0 -231
  359. package/references/multi-agent-protocol/docs/05-connection-model.md +0 -244
  360. package/references/multi-agent-protocol/docs/06-visibility-permissions.md +0 -243
  361. package/references/multi-agent-protocol/docs/07-federation.md +0 -259
  362. package/references/multi-agent-protocol/docs/08-macro-agent-migration.md +0 -253
  363. package/references/multi-agent-protocol/docs/09-authentication.md +0 -680
  364. package/references/multi-agent-protocol/docs/10-mail-protocol.md +0 -553
  365. package/references/multi-agent-protocol/docs/agent-iam-integration.md +0 -877
  366. package/references/multi-agent-protocol/docs/agentic-mesh-integration-draft.md +0 -459
  367. package/references/multi-agent-protocol/docs/git-transport-draft.md +0 -251
  368. package/references/multi-agent-protocol/docs-site/Gemfile +0 -22
  369. package/references/multi-agent-protocol/docs-site/README.md +0 -82
  370. package/references/multi-agent-protocol/docs-site/_config.yml +0 -91
  371. package/references/multi-agent-protocol/docs-site/_includes/head_custom.html +0 -20
  372. package/references/multi-agent-protocol/docs-site/_sass/color_schemes/map.scss +0 -42
  373. package/references/multi-agent-protocol/docs-site/_sass/custom/custom.scss +0 -34
  374. package/references/multi-agent-protocol/docs-site/examples/full-integration.md +0 -510
  375. package/references/multi-agent-protocol/docs-site/examples/index.md +0 -138
  376. package/references/multi-agent-protocol/docs-site/examples/simple-chat.md +0 -282
  377. package/references/multi-agent-protocol/docs-site/examples/task-queue.md +0 -399
  378. package/references/multi-agent-protocol/docs-site/getting-started/index.md +0 -98
  379. package/references/multi-agent-protocol/docs-site/getting-started/installation.md +0 -219
  380. package/references/multi-agent-protocol/docs-site/getting-started/overview.md +0 -172
  381. package/references/multi-agent-protocol/docs-site/getting-started/quickstart.md +0 -237
  382. package/references/multi-agent-protocol/docs-site/index.md +0 -136
  383. package/references/multi-agent-protocol/docs-site/protocol/authentication.md +0 -391
  384. package/references/multi-agent-protocol/docs-site/protocol/connection-model.md +0 -376
  385. package/references/multi-agent-protocol/docs-site/protocol/design.md +0 -284
  386. package/references/multi-agent-protocol/docs-site/protocol/error-handling.md +0 -312
  387. package/references/multi-agent-protocol/docs-site/protocol/federation.md +0 -449
  388. package/references/multi-agent-protocol/docs-site/protocol/index.md +0 -129
  389. package/references/multi-agent-protocol/docs-site/protocol/permissions.md +0 -398
  390. package/references/multi-agent-protocol/docs-site/protocol/streaming.md +0 -353
  391. package/references/multi-agent-protocol/docs-site/protocol/wire-protocol.md +0 -369
  392. package/references/multi-agent-protocol/docs-site/sdk/api/agent.md +0 -357
  393. package/references/multi-agent-protocol/docs-site/sdk/api/client.md +0 -380
  394. package/references/multi-agent-protocol/docs-site/sdk/api/index.md +0 -62
  395. package/references/multi-agent-protocol/docs-site/sdk/api/server.md +0 -453
  396. package/references/multi-agent-protocol/docs-site/sdk/api/types.md +0 -468
  397. package/references/multi-agent-protocol/docs-site/sdk/guides/agent.md +0 -375
  398. package/references/multi-agent-protocol/docs-site/sdk/guides/authentication.md +0 -405
  399. package/references/multi-agent-protocol/docs-site/sdk/guides/client.md +0 -352
  400. package/references/multi-agent-protocol/docs-site/sdk/guides/index.md +0 -89
  401. package/references/multi-agent-protocol/docs-site/sdk/guides/server.md +0 -360
  402. package/references/multi-agent-protocol/docs-site/sdk/guides/testing.md +0 -446
  403. package/references/multi-agent-protocol/docs-site/sdk/guides/transports.md +0 -363
  404. package/references/multi-agent-protocol/docs-site/sdk/index.md +0 -206
  405. package/references/multi-agent-protocol/package-lock.json +0 -3886
  406. package/references/multi-agent-protocol/package.json +0 -56
  407. package/references/multi-agent-protocol/schema/meta.json +0 -467
  408. package/references/multi-agent-protocol/schema/schema.json +0 -2558
@@ -0,0 +1,983 @@
1
+ /**
2
+ * Cross-Subsystem Integration Tests
3
+ *
4
+ * Tests interactions between subsystems:
5
+ * - Strategy ↔ Worker Handler
6
+ * - Task Backend claim/unclaim cycle
7
+ * - Team Config → Spawn Interceptor → Worker Done pipeline
8
+ * - Metrics ↔ EventStore realistic events
9
+ * - Pull mode lifecycle ↔ handler dispatch
10
+ * - Role resolution ↔ capability gating
11
+ */
12
+
13
+ import { describe, it, expect, vi, beforeEach } from "vitest";
14
+ import * as path from "path";
15
+ import { loadTeam } from "../team-loader.js";
16
+ import { TeamRuntime, type TeamServices } from "../team-runtime.js";
17
+ import { DefaultRoleRegistry } from "../../roles/registry.js";
18
+ import {
19
+ handleWorkerDone,
20
+ type WorkerHandlerDeps,
21
+ } from "../../lifecycle/handlers/worker.js";
22
+ import {
23
+ dispatchDone,
24
+ createHandlerRegistry,
25
+ type AllHandlerDeps,
26
+ } from "../../lifecycle/handlers/index.js";
27
+ import type {
28
+ LifecycleContext,
29
+ DoneArgs,
30
+ CleanupStatus,
31
+ } from "../../lifecycle/types.js";
32
+ import type {
33
+ IntegrationStrategy,
34
+ LandRequest,
35
+ LandResult,
36
+ } from "../../workspace/strategies/types.js";
37
+ import { defaultStrategyRegistry } from "../../workspace/strategies/registry.js";
38
+ import {
39
+ createClaimTaskHandler,
40
+ type ClaimTaskDeps,
41
+ } from "../../mcp/tools/claim_task.js";
42
+ import {
43
+ createUnclaimTaskHandler,
44
+ type UnclaimTaskDeps,
45
+ } from "../../mcp/tools/unclaim_task.js";
46
+ import {
47
+ createListClaimableTasksHandler,
48
+ } from "../../mcp/tools/list_claimable_tasks.js";
49
+ import type { TaskBackend, ClaimFilter, ExtendedTask } from "../../task/backend/types.js";
50
+ import type { ToolContext } from "../../mcp/types.js";
51
+ import {
52
+ getThroughputMetrics,
53
+ getUtilizationMetrics,
54
+ getErrorMetrics,
55
+ } from "../../metrics/index.js";
56
+ import {
57
+ TASK_CAPABILITIES,
58
+ CAPABILITY_TOOL_MAP,
59
+ } from "../../roles/capabilities.js";
60
+ import type { AgentManager, SpawnInterceptor } from "../../agent/agent-manager.js";
61
+ import type { MessageRouter } from "../../router/message-router.js";
62
+ import type { EventStore } from "../../store/event-store.js";
63
+ import type { SpawnAgentOptions } from "../../agent/types.js";
64
+ import type { Event, Agent } from "../../store/types/index.js";
65
+
66
+ // =============================================================================
67
+ // Shared Helpers
68
+ // =============================================================================
69
+
70
+ const PROJECT_ROOT = path.resolve(import.meta.dirname, "../../..");
71
+
72
+ function createMockEventStore(events: Event[] = []): EventStore & { _events: Event[] } {
73
+ return {
74
+ emit: vi.fn((input: Record<string, unknown>) => {
75
+ const event = {
76
+ id: `evt_${events.length}`,
77
+ type: input.type,
78
+ timestamp: Date.now(),
79
+ source: input.source,
80
+ target: input.target,
81
+ payload: input.payload,
82
+ } as unknown as Event;
83
+ events.push(event);
84
+ return event;
85
+ }),
86
+ persist: vi.fn().mockResolvedValue(undefined),
87
+ close: vi.fn().mockResolvedValue(undefined),
88
+ query: vi.fn((filter: { type?: string; after?: number }) => {
89
+ return events.filter((e) => {
90
+ if (filter.type && e.type !== filter.type) return false;
91
+ if (filter.after && e.timestamp < filter.after) return false;
92
+ return true;
93
+ });
94
+ }),
95
+ getAgent: vi.fn().mockReturnValue(null),
96
+ getTask: vi.fn().mockReturnValue(null),
97
+ listAgents: vi.fn().mockReturnValue([]),
98
+ onAgentChange: vi.fn(),
99
+ onTaskChange: vi.fn(),
100
+ instanceId: "test-instance",
101
+ _events: events,
102
+ } as unknown as EventStore & { _events: Event[] };
103
+ }
104
+
105
+ function createMockMessageRouter(): MessageRouter {
106
+ return {
107
+ sendToAddress: vi.fn().mockResolvedValue({ delivered: true }),
108
+ emitStatus: vi.fn(),
109
+ getMessages: vi.fn().mockReturnValue([]),
110
+ subscribe: vi.fn(),
111
+ unsubscribe: vi.fn(),
112
+ getSubscriptions: vi.fn().mockReturnValue([]),
113
+ setupDefaultSubscriptions: vi.fn(),
114
+ } as unknown as MessageRouter;
115
+ }
116
+
117
+ function createMockStrategy(
118
+ name: string,
119
+ landResult: LandResult = { status: "landed", commitHash: "abc123" }
120
+ ): IntegrationStrategy & { land: ReturnType<typeof vi.fn> } {
121
+ return {
122
+ name,
123
+ land: vi.fn().mockResolvedValue(landResult),
124
+ };
125
+ }
126
+
127
+ function createWorkerContext(overrides: Partial<LifecycleContext> = {}): LifecycleContext {
128
+ return {
129
+ agentId: "worker-1",
130
+ role: "worker",
131
+ taskId: "task-1",
132
+ workspacePath: "/tmp/test-workspace",
133
+ branch: "feature/test",
134
+ integrationBranch: "integration",
135
+ streamId: "stream-1",
136
+ ...overrides,
137
+ };
138
+ }
139
+
140
+ function createCleanupStatus(): CleanupStatus {
141
+ return { ready: true };
142
+ }
143
+
144
+ // =============================================================================
145
+ // Tests: Strategy ↔ Worker Handler Integration
146
+ // =============================================================================
147
+
148
+ describe("Strategy ↔ Worker Handler", () => {
149
+ let messageRouter: MessageRouter;
150
+ let agentManager: AgentManager;
151
+
152
+ beforeEach(() => {
153
+ messageRouter = createMockMessageRouter();
154
+ agentManager = {
155
+ getChildren: vi.fn().mockReturnValue([]),
156
+ } as unknown as AgentManager;
157
+ });
158
+
159
+ it("dispatches to integration strategy when configured", async () => {
160
+ const strategy = createMockStrategy("trunk");
161
+ const deps: WorkerHandlerDeps = {
162
+ messageRouter,
163
+ agentManager,
164
+ integrationStrategy: strategy,
165
+ };
166
+
167
+ const context = createWorkerContext();
168
+ const args: DoneArgs = { status: "completed", summary: "Done" };
169
+
170
+ const result = await handleWorkerDone(context, args, createCleanupStatus(), deps);
171
+
172
+ expect(strategy.land).toHaveBeenCalledTimes(1);
173
+ expect(strategy.land).toHaveBeenCalledWith(
174
+ expect.objectContaining({
175
+ sourceBranch: "feature/test",
176
+ targetBranch: "integration",
177
+ workspacePath: "/tmp/test-workspace",
178
+ agentId: "worker-1",
179
+ taskId: "task-1",
180
+ streamId: "stream-1",
181
+ })
182
+ );
183
+ expect(result.signalsEmitted).toContain("WORKER_INTEGRATED");
184
+ expect(result.shouldTerminate).toBe(true);
185
+ });
186
+
187
+ it("falls back to merge queue when no strategy configured", async () => {
188
+ const mergeQueue = {
189
+ submit: vi.fn().mockReturnValue("mr-1"),
190
+ };
191
+ const deps: WorkerHandlerDeps = {
192
+ messageRouter,
193
+ agentManager,
194
+ mergeQueue: mergeQueue as any,
195
+ // No integrationStrategy
196
+ };
197
+
198
+ const context = createWorkerContext();
199
+ const args: DoneArgs = { status: "completed" };
200
+
201
+ const result = await handleWorkerDone(context, args, createCleanupStatus(), deps);
202
+
203
+ expect(mergeQueue.submit).toHaveBeenCalledTimes(1);
204
+ expect(result.signalsEmitted).toContain("MERGE_REQUEST");
205
+ });
206
+
207
+ it("strategy takes priority over merge queue", async () => {
208
+ const strategy = createMockStrategy("trunk");
209
+ const mergeQueue = { submit: vi.fn() };
210
+ const deps: WorkerHandlerDeps = {
211
+ messageRouter,
212
+ agentManager,
213
+ integrationStrategy: strategy,
214
+ mergeQueue: mergeQueue as any,
215
+ };
216
+
217
+ const context = createWorkerContext();
218
+ const args: DoneArgs = { status: "completed" };
219
+
220
+ await handleWorkerDone(context, args, createCleanupStatus(), deps);
221
+
222
+ expect(strategy.land).toHaveBeenCalledTimes(1);
223
+ expect(mergeQueue.submit).not.toHaveBeenCalled();
224
+ });
225
+
226
+ it("handles strategy conflict result gracefully", async () => {
227
+ const strategy = createMockStrategy("trunk", {
228
+ status: "conflict",
229
+ conflictFiles: ["src/foo.ts"],
230
+ error: "Rebase conflict after 3 retries",
231
+ });
232
+ const deps: WorkerHandlerDeps = {
233
+ messageRouter,
234
+ agentManager,
235
+ integrationStrategy: strategy,
236
+ };
237
+
238
+ const context = createWorkerContext();
239
+ const args: DoneArgs = { status: "completed" };
240
+
241
+ const result = await handleWorkerDone(context, args, createCleanupStatus(), deps);
242
+
243
+ expect(result.warnings).toBeDefined();
244
+ expect(result.warnings!.some((w) => w.includes("conflict"))).toBe(true);
245
+ expect(result.signalsEmitted).not.toContain("WORKER_INTEGRATED");
246
+ });
247
+
248
+ it("handles strategy failure result gracefully", async () => {
249
+ const strategy = createMockStrategy("trunk", {
250
+ status: "failed",
251
+ error: "Push rejected",
252
+ });
253
+ const deps: WorkerHandlerDeps = {
254
+ messageRouter,
255
+ agentManager,
256
+ integrationStrategy: strategy,
257
+ };
258
+
259
+ const context = createWorkerContext();
260
+ const args: DoneArgs = { status: "completed" };
261
+
262
+ const result = await handleWorkerDone(context, args, createCleanupStatus(), deps);
263
+
264
+ expect(result.warnings).toBeDefined();
265
+ expect(result.warnings!.some((w) => w.includes("failed"))).toBe(true);
266
+ });
267
+
268
+ it("handles strategy exception gracefully", async () => {
269
+ const strategy = createMockStrategy("trunk");
270
+ strategy.land.mockRejectedValue(new Error("Git process crashed"));
271
+ const deps: WorkerHandlerDeps = {
272
+ messageRouter,
273
+ agentManager,
274
+ integrationStrategy: strategy,
275
+ };
276
+
277
+ const context = createWorkerContext();
278
+ const args: DoneArgs = { status: "completed" };
279
+
280
+ const result = await handleWorkerDone(context, args, createCleanupStatus(), deps);
281
+
282
+ // Should not throw — graceful degradation
283
+ expect(result.warnings).toBeDefined();
284
+ expect(result.warnings!.some((w) => w.includes("Git process crashed"))).toBe(true);
285
+ });
286
+
287
+ it("skips strategy when status is not completed", async () => {
288
+ const strategy = createMockStrategy("trunk");
289
+ const deps: WorkerHandlerDeps = {
290
+ messageRouter,
291
+ agentManager,
292
+ integrationStrategy: strategy,
293
+ };
294
+
295
+ const context = createWorkerContext();
296
+ const args: DoneArgs = { status: "failed", summary: "Build failed" };
297
+
298
+ await handleWorkerDone(context, args, createCleanupStatus(), deps);
299
+
300
+ expect(strategy.land).not.toHaveBeenCalled();
301
+ });
302
+ });
303
+
304
+ // =============================================================================
305
+ // Tests: Pull Mode Lifecycle
306
+ // =============================================================================
307
+
308
+ describe("Pull Mode ↔ Worker Handler", () => {
309
+ let messageRouter: MessageRouter;
310
+ let agentManager: AgentManager;
311
+
312
+ beforeEach(() => {
313
+ messageRouter = createMockMessageRouter();
314
+ agentManager = {
315
+ getChildren: vi.fn().mockReturnValue([]),
316
+ } as unknown as AgentManager;
317
+ });
318
+
319
+ it("pull mode workers stay alive after completion", async () => {
320
+ const strategy = createMockStrategy("trunk");
321
+ const deps: WorkerHandlerDeps = {
322
+ messageRouter,
323
+ agentManager,
324
+ integrationStrategy: strategy,
325
+ taskMode: "pull",
326
+ };
327
+
328
+ const context = createWorkerContext();
329
+ const args: DoneArgs = { status: "completed" };
330
+
331
+ const result = await handleWorkerDone(context, args, createCleanupStatus(), deps);
332
+
333
+ expect(result.shouldTerminate).toBe(false);
334
+ });
335
+
336
+ it("pull mode workers still terminate on failure", async () => {
337
+ const strategy = createMockStrategy("trunk");
338
+ const deps: WorkerHandlerDeps = {
339
+ messageRouter,
340
+ agentManager,
341
+ integrationStrategy: strategy,
342
+ taskMode: "pull",
343
+ };
344
+
345
+ const context = createWorkerContext();
346
+ const args: DoneArgs = { status: "failed", summary: "Error" };
347
+
348
+ const result = await handleWorkerDone(context, args, createCleanupStatus(), deps);
349
+
350
+ expect(result.shouldTerminate).toBe(true);
351
+ });
352
+
353
+ it("push mode workers always terminate", async () => {
354
+ const strategy = createMockStrategy("trunk");
355
+ const deps: WorkerHandlerDeps = {
356
+ messageRouter,
357
+ agentManager,
358
+ integrationStrategy: strategy,
359
+ taskMode: "push",
360
+ };
361
+
362
+ const context = createWorkerContext();
363
+ const args: DoneArgs = { status: "completed" };
364
+
365
+ const result = await handleWorkerDone(context, args, createCleanupStatus(), deps);
366
+
367
+ expect(result.shouldTerminate).toBe(true);
368
+ });
369
+
370
+ it("undefined taskMode defaults to terminate (push behavior)", async () => {
371
+ const strategy = createMockStrategy("trunk");
372
+ const deps: WorkerHandlerDeps = {
373
+ messageRouter,
374
+ agentManager,
375
+ integrationStrategy: strategy,
376
+ // taskMode undefined
377
+ };
378
+
379
+ const context = createWorkerContext();
380
+ const args: DoneArgs = { status: "completed" };
381
+
382
+ const result = await handleWorkerDone(context, args, createCleanupStatus(), deps);
383
+
384
+ expect(result.shouldTerminate).toBe(true);
385
+ });
386
+ });
387
+
388
+ // =============================================================================
389
+ // Tests: Handler Registry ↔ Team Roles
390
+ // =============================================================================
391
+
392
+ describe("Handler Registry ↔ Team Roles", () => {
393
+ it("team-defined roles dispatch to correct base handler", async () => {
394
+ const messageRouter = createMockMessageRouter();
395
+ const agentManager = {
396
+ getChildren: vi.fn().mockReturnValue([]),
397
+ } as unknown as AgentManager;
398
+
399
+ const strategy = createMockStrategy("trunk");
400
+ const deps: AllHandlerDeps = {
401
+ messageRouter,
402
+ agentManager,
403
+ integrationStrategy: strategy,
404
+ taskMode: "pull",
405
+ };
406
+
407
+ // "grinder" extends "worker" — should get the worker handler
408
+ const context = createWorkerContext({ role: "worker", agentId: "grinder-1" });
409
+ const args: DoneArgs = { status: "completed" };
410
+
411
+ const result = await dispatchDone(context, args, createCleanupStatus(), deps);
412
+
413
+ expect(strategy.land).toHaveBeenCalledTimes(1);
414
+ expect(result.shouldTerminate).toBe(false); // pull mode
415
+ });
416
+
417
+ it("monitor roles do not trigger strategy dispatch", async () => {
418
+ const messageRouter = createMockMessageRouter();
419
+ const agentManager = {
420
+ getChildren: vi.fn().mockReturnValue([]),
421
+ } as unknown as AgentManager;
422
+
423
+ const strategy = createMockStrategy("trunk");
424
+ const deps: AllHandlerDeps = {
425
+ messageRouter,
426
+ agentManager,
427
+ integrationStrategy: strategy,
428
+ };
429
+
430
+ const context: LifecycleContext = {
431
+ agentId: "judge-1",
432
+ role: "monitor",
433
+ };
434
+ const args: DoneArgs = { status: "completed", summary: "Health OK" };
435
+
436
+ const result = await dispatchDone(context, args, createCleanupStatus(), deps);
437
+
438
+ expect(strategy.land).not.toHaveBeenCalled();
439
+ expect(result.shouldTerminate).toBe(true);
440
+ });
441
+ });
442
+
443
+ // =============================================================================
444
+ // Tests: Task Backend Claim/Unclaim Cycle
445
+ // =============================================================================
446
+
447
+ describe("Task Claim/Unclaim Cycle via MCP Tools", () => {
448
+ function createMockTaskBackend(): TaskBackend {
449
+ const tasks: ExtendedTask[] = [
450
+ {
451
+ id: "task-1",
452
+ description: "Fix auth bug",
453
+ status: "pending",
454
+ created_at: Date.now() - 5000,
455
+ tags: ["bugfix"],
456
+ isBlocked: false,
457
+ } as ExtendedTask,
458
+ {
459
+ id: "task-2",
460
+ description: "Add feature X",
461
+ status: "pending",
462
+ created_at: Date.now() - 3000,
463
+ tags: ["feature"],
464
+ isBlocked: false,
465
+ } as ExtendedTask,
466
+ {
467
+ id: "task-3",
468
+ description: "Blocked task",
469
+ status: "pending",
470
+ created_at: Date.now() - 1000,
471
+ tags: ["bugfix"],
472
+ isBlocked: true,
473
+ } as ExtendedTask,
474
+ ];
475
+
476
+ return {
477
+ claim: vi.fn(async (agentId: string, filter?: ClaimFilter) => {
478
+ const candidates = tasks.filter((t) => {
479
+ if (t.status !== "pending" || t.isBlocked) return false;
480
+ if (t.assigned_agent) return false;
481
+ if (filter?.tags) {
482
+ const taskTags = t.tags ?? [];
483
+ if (!filter.tags.some((ft) => taskTags.includes(ft))) return false;
484
+ }
485
+ return true;
486
+ });
487
+ if (candidates.length === 0) return null;
488
+ const claimed = candidates[0];
489
+ claimed.status = "in_progress";
490
+ claimed.assigned_agent = agentId;
491
+ return claimed;
492
+ }),
493
+ unclaim: vi.fn(async (taskId: string) => {
494
+ const task = tasks.find((t) => t.id === taskId);
495
+ if (task) {
496
+ task.status = "pending";
497
+ task.assigned_agent = undefined;
498
+ }
499
+ }),
500
+ listClaimable: vi.fn(async (filter?: ClaimFilter) => {
501
+ return tasks.filter((t) => {
502
+ if (t.status !== "pending" || t.isBlocked) return false;
503
+ if (t.assigned_agent) return false;
504
+ if (filter?.tags) {
505
+ const taskTags = t.tags ?? [];
506
+ if (!filter.tags.some((ft) => taskTags.includes(ft))) return false;
507
+ }
508
+ return true;
509
+ });
510
+ }),
511
+ } as unknown as TaskBackend;
512
+ }
513
+
514
+ const toolContext: ToolContext = {
515
+ agent_id: "grinder-1",
516
+ session_id: "session-1",
517
+ } as ToolContext;
518
+
519
+ it("claim_task claims the first available task", async () => {
520
+ const backend = createMockTaskBackend();
521
+ const handler = createClaimTaskHandler(toolContext, { taskBackend: backend });
522
+
523
+ const result = await handler({});
524
+
525
+ expect(result.claimed).toBe(true);
526
+ expect(result.task).toBeDefined();
527
+ expect(result.task!.id).toBe("task-1");
528
+ expect(backend.claim).toHaveBeenCalledWith("grinder-1", {});
529
+ });
530
+
531
+ it("claim_task filters by tags", async () => {
532
+ const backend = createMockTaskBackend();
533
+ const handler = createClaimTaskHandler(toolContext, { taskBackend: backend });
534
+
535
+ const result = await handler({ tags: ["feature"] });
536
+
537
+ expect(result.claimed).toBe(true);
538
+ expect(result.task!.id).toBe("task-2");
539
+ });
540
+
541
+ it("claim_task returns not claimed when no tasks available", async () => {
542
+ const backend = createMockTaskBackend();
543
+ (backend.claim as ReturnType<typeof vi.fn>).mockResolvedValue(null);
544
+
545
+ const handler = createClaimTaskHandler(toolContext, { taskBackend: backend });
546
+ const result = await handler({});
547
+
548
+ expect(result.claimed).toBe(false);
549
+ expect(result.task).toBeUndefined();
550
+ });
551
+
552
+ it("unclaim_task returns task to pending pool", async () => {
553
+ const backend = createMockTaskBackend();
554
+ const unclaimHandler = createUnclaimTaskHandler(toolContext, {
555
+ taskBackend: backend,
556
+ });
557
+
558
+ const result = await unclaimHandler({ task_id: "task-1" });
559
+
560
+ expect(result.success).toBe(true);
561
+ expect(backend.unclaim).toHaveBeenCalledWith("task-1");
562
+ });
563
+
564
+ it("list_claimable_tasks returns only claimable tasks", async () => {
565
+ const backend = createMockTaskBackend();
566
+ const listHandler = createListClaimableTasksHandler(toolContext, {
567
+ taskBackend: backend,
568
+ });
569
+
570
+ const result = await listHandler({});
571
+
572
+ expect(result.tasks.length).toBe(2); // task-3 is blocked
573
+ expect(result.tasks.every((t: ExtendedTask) => !t.isBlocked)).toBe(true);
574
+ });
575
+
576
+ it("claim → unclaim → re-claim cycle works", async () => {
577
+ const backend = createMockTaskBackend();
578
+ const claimHandler = createClaimTaskHandler(toolContext, {
579
+ taskBackend: backend,
580
+ });
581
+ const unclaimHandler = createUnclaimTaskHandler(toolContext, {
582
+ taskBackend: backend,
583
+ });
584
+
585
+ // Claim task-1
586
+ const claim1 = await claimHandler({});
587
+ expect(claim1.claimed).toBe(true);
588
+ expect(claim1.task!.id).toBe("task-1");
589
+
590
+ // Unclaim task-1
591
+ await unclaimHandler({ task_id: "task-1" });
592
+
593
+ // Re-claim should get task-1 again (it's back to pending)
594
+ const claim2 = await claimHandler({});
595
+ expect(claim2.claimed).toBe(true);
596
+ expect(claim2.task!.id).toBe("task-1");
597
+ });
598
+
599
+ it("claim_task fails gracefully when backend lacks claim support", async () => {
600
+ const backend = {} as TaskBackend; // No claim method
601
+ const handler = createClaimTaskHandler(toolContext, { taskBackend: backend });
602
+
603
+ const result = await handler({});
604
+
605
+ expect(result.claimed).toBe(false);
606
+ expect(result.message).toContain("does not support");
607
+ });
608
+ });
609
+
610
+ // =============================================================================
611
+ // Tests: Metrics ↔ Realistic EventStore Events
612
+ // =============================================================================
613
+
614
+ describe("Metrics ↔ EventStore Integration", () => {
615
+ it("throughput metrics count task events correctly", () => {
616
+ const events: Event[] = [];
617
+ const now = Date.now();
618
+
619
+ // Simulate task events
620
+ events.push({
621
+ id: "e1", type: "task", timestamp: now - 1000,
622
+ source: { agent_id: "planner-1" },
623
+ payload: { action: "created", task_id: "t1" },
624
+ } as unknown as Event);
625
+ events.push({
626
+ id: "e2", type: "task", timestamp: now - 800,
627
+ source: { agent_id: "planner-1" },
628
+ payload: { action: "created", task_id: "t2" },
629
+ } as unknown as Event);
630
+ events.push({
631
+ id: "e3", type: "task", timestamp: now - 500,
632
+ source: { agent_id: "grinder-1" },
633
+ payload: { action: "completed", task_id: "t1" },
634
+ } as unknown as Event);
635
+ events.push({
636
+ id: "e4", type: "task", timestamp: now - 200,
637
+ source: { agent_id: "grinder-2" },
638
+ payload: { action: "failed", task_id: "t2" },
639
+ } as unknown as Event);
640
+
641
+ const store = createMockEventStore(events);
642
+
643
+ const metrics = getThroughputMetrics(store, 60000);
644
+
645
+ expect(metrics.tasksCreated).toBe(2);
646
+ expect(metrics.tasksCompleted).toBe(1);
647
+ expect(metrics.tasksFailed).toBe(1);
648
+ });
649
+
650
+ it("utilization metrics reflect active agents", () => {
651
+ const events: Event[] = [];
652
+ const now = Date.now();
653
+
654
+ events.push({
655
+ id: "e1", type: "spawn", timestamp: now - 5000,
656
+ source: { agent_id: "system" },
657
+ payload: { agent_id: "planner-1" },
658
+ } as unknown as Event);
659
+ events.push({
660
+ id: "e2", type: "spawn", timestamp: now - 3000,
661
+ source: { agent_id: "planner-1" },
662
+ payload: { agent_id: "grinder-1" },
663
+ } as unknown as Event);
664
+ events.push({
665
+ id: "e3", type: "terminate", timestamp: now - 1000,
666
+ source: { agent_id: "grinder-1" },
667
+ payload: { reason: "completed" },
668
+ } as unknown as Event);
669
+
670
+ const agents: Agent[] = [
671
+ { id: "planner-1", state: "running", role: "planner" } as unknown as Agent,
672
+ { id: "grinder-1", state: "stopped", role: "grinder" } as unknown as Agent,
673
+ ];
674
+
675
+ const store = createMockEventStore(events);
676
+ vi.mocked(store.listAgents).mockReturnValue(agents);
677
+
678
+ const metrics = getUtilizationMetrics(store, 60000);
679
+
680
+ expect(metrics.activeAgents).toBe(1);
681
+ expect(metrics.totalSpawned).toBe(2);
682
+ expect(metrics.totalStopped).toBe(1);
683
+ expect(metrics.agentsByRole).toEqual({ planner: 1 });
684
+ expect(metrics.agentsByState).toEqual({ running: 1, stopped: 1 });
685
+ });
686
+
687
+ it("error metrics capture both status and task failures", () => {
688
+ const events: Event[] = [];
689
+ const now = Date.now();
690
+
691
+ events.push({
692
+ id: "e1", type: "status", timestamp: now - 2000,
693
+ source: { agent_id: "grinder-1" },
694
+ payload: { status_type: "failed", summary: "OOM killed", details: { signal: "SIGKILL" } },
695
+ } as unknown as Event);
696
+ events.push({
697
+ id: "e2", type: "status", timestamp: now - 1500,
698
+ source: { agent_id: "grinder-2" },
699
+ payload: { status_type: "completed", summary: "Done" }, // Not an error
700
+ } as unknown as Event);
701
+ events.push({
702
+ id: "e3", type: "task", timestamp: now - 1000,
703
+ source: { agent_id: "grinder-3" },
704
+ payload: { action: "failed", task_id: "t5" },
705
+ } as unknown as Event);
706
+
707
+ const store = createMockEventStore(events);
708
+
709
+ const metrics = getErrorMetrics(store, 60000, 10);
710
+
711
+ expect(metrics.totalErrors).toBe(2);
712
+ expect(metrics.errorsByType["SIGKILL"]).toBe(1);
713
+ expect(metrics.errorsByType["task_failed"]).toBe(1);
714
+ expect(metrics.recentErrors).toHaveLength(2);
715
+ // Most recent first
716
+ expect(metrics.recentErrors[0].type).toBe("task_failed");
717
+ expect(metrics.recentErrors[1].type).toBe("SIGKILL");
718
+ });
719
+
720
+ it("metrics respect time window boundaries", () => {
721
+ const events: Event[] = [];
722
+ const now = Date.now();
723
+
724
+ // Event inside 10-second window
725
+ events.push({
726
+ id: "e1", type: "task", timestamp: now - 5000,
727
+ source: { agent_id: "a1" },
728
+ payload: { action: "completed", task_id: "t1" },
729
+ } as unknown as Event);
730
+ // Event outside 10-second window
731
+ events.push({
732
+ id: "e2", type: "task", timestamp: now - 30000,
733
+ source: { agent_id: "a1" },
734
+ payload: { action: "completed", task_id: "t2" },
735
+ } as unknown as Event);
736
+
737
+ const store = createMockEventStore(events);
738
+
739
+ const metrics = getThroughputMetrics(store, 10000);
740
+
741
+ expect(metrics.tasksCompleted).toBe(1); // Only the recent one
742
+ });
743
+ });
744
+
745
+ // =============================================================================
746
+ // Tests: Strategy Registry ↔ Team Config
747
+ // =============================================================================
748
+
749
+ describe("Strategy Registry ↔ Team Config", () => {
750
+ it("strategy registry can instantiate all strategies referenced by templates", async () => {
751
+ const roleRegistry = new DefaultRoleRegistry();
752
+
753
+ // Load self-driving template
754
+ const selfDriving = await loadTeam("self-driving", roleRegistry, PROJECT_ROOT);
755
+ const sdStrategy = selfDriving.macro_agent.integration!.strategy;
756
+ expect(defaultStrategyRegistry.has(sdStrategy)).toBe(true);
757
+
758
+ // Load structured template
759
+ const structured = await loadTeam("structured", roleRegistry, PROJECT_ROOT);
760
+ const stStrategy = structured.macro_agent.integration!.strategy;
761
+ expect(defaultStrategyRegistry.has(stStrategy)).toBe(true);
762
+
763
+ // Instantiate each
764
+ const trunkStrategy = defaultStrategyRegistry.get(sdStrategy, selfDriving.macro_agent.integration!.config);
765
+ expect(trunkStrategy.name).toBe("trunk");
766
+
767
+ const queueStrategy = defaultStrategyRegistry.get(stStrategy, structured.macro_agent.integration!.config);
768
+ expect(queueStrategy.name).toBe("queue");
769
+ });
770
+
771
+ it("custom strategy can be registered and resolved", () => {
772
+ defaultStrategyRegistry.register("custom-ci", (config) => ({
773
+ name: "custom-ci",
774
+ async land(request: LandRequest): Promise<LandResult> {
775
+ return { status: "landed", commitHash: "custom-hash" };
776
+ },
777
+ }));
778
+
779
+ expect(defaultStrategyRegistry.has("custom-ci")).toBe(true);
780
+ const strategy = defaultStrategyRegistry.get("custom-ci");
781
+ expect(strategy.name).toBe("custom-ci");
782
+ });
783
+ });
784
+
785
+ // =============================================================================
786
+ // Tests: Role Capability ↔ Tool Gating
787
+ // =============================================================================
788
+
789
+ describe("Role Capability ↔ Tool Gating", () => {
790
+ it("task.claim capability maps to all claim-related tools", () => {
791
+ const tools = CAPABILITY_TOOL_MAP[TASK_CAPABILITIES.CLAIM as keyof typeof CAPABILITY_TOOL_MAP];
792
+ expect(tools).toBeDefined();
793
+ expect(tools).toContain("claim_task");
794
+ expect(tools).toContain("unclaim_task");
795
+ expect(tools).toContain("list_claimable_tasks");
796
+ });
797
+
798
+ it("self-driving grinder role has task.claim capability", async () => {
799
+ const roleRegistry = new DefaultRoleRegistry();
800
+ const manifest = await loadTeam("self-driving", roleRegistry, PROJECT_ROOT);
801
+
802
+ const grinder = manifest._resolvedRoles.get("grinder");
803
+ expect(grinder!.capabilities).toContain("task.claim");
804
+
805
+ // Grinder inherits from worker — should still have worker capabilities
806
+ expect(grinder!.capabilities).toContain("file.read");
807
+ expect(grinder!.capabilities).toContain("file.write");
808
+ });
809
+
810
+ it("structured developer role does NOT have task.claim capability", async () => {
811
+ const roleRegistry = new DefaultRoleRegistry();
812
+ const manifest = await loadTeam("structured", roleRegistry, PROJECT_ROOT);
813
+
814
+ const developer = manifest._resolvedRoles.get("developer");
815
+ expect(developer!.capabilities).not.toContain("task.claim");
816
+ });
817
+
818
+ it("registered team roles are resolvable from RoleRegistry", async () => {
819
+ const roleRegistry = new DefaultRoleRegistry();
820
+ const eventStore = createMockEventStore();
821
+ const messageRouter = createMockMessageRouter();
822
+ let capturedInterceptor: SpawnInterceptor | null = null;
823
+ const agentManager = {
824
+ spawn: vi.fn().mockResolvedValue({ id: "agent_0" }),
825
+ getRoleRegistry: () => roleRegistry,
826
+ setSpawnInterceptor: vi.fn((i: SpawnInterceptor | null) => { capturedInterceptor = i; }),
827
+ onLifecycleEvent: vi.fn(() => () => {}),
828
+ getChildren: vi.fn().mockReturnValue([]),
829
+ } as unknown as AgentManager;
830
+
831
+ const manifest = await loadTeam("self-driving", roleRegistry, PROJECT_ROOT);
832
+ const runtime = new TeamRuntime(manifest, {
833
+ agentManager,
834
+ messageRouter,
835
+ eventStore,
836
+ });
837
+
838
+ await runtime.initialize();
839
+
840
+ // After initialization, team roles should be in the registry
841
+ const planner = roleRegistry.resolveRole("planner");
842
+ expect(planner).toBeDefined();
843
+ expect(planner.capabilities).toContain("task.claim");
844
+
845
+ const grinder = roleRegistry.resolveRole("grinder");
846
+ expect(grinder).toBeDefined();
847
+ expect(grinder.capabilities).toContain("task.claim");
848
+ expect(grinder.capabilities).toContain("git.push");
849
+ });
850
+ });
851
+
852
+ // =============================================================================
853
+ // Tests: Team Config → Worker Done Pipeline (end-to-end wiring)
854
+ // =============================================================================
855
+
856
+ describe("Team Config → Worker Done Pipeline", () => {
857
+ it("full pipeline: team config flows through handler registry to strategy", async () => {
858
+ const messageRouter = createMockMessageRouter();
859
+ const agentManager = {
860
+ getChildren: vi.fn().mockReturnValue([]),
861
+ } as unknown as AgentManager;
862
+ const strategy = createMockStrategy("trunk");
863
+
864
+ // Build deps as they would be wired from MCPServices → DoneToolDeps → AllHandlerDeps
865
+ const allDeps: AllHandlerDeps = {
866
+ messageRouter,
867
+ agentManager,
868
+ integrationStrategy: strategy,
869
+ taskMode: "pull",
870
+ };
871
+
872
+ // Create registry (this is what createDoneHandler does internally)
873
+ const registry = createHandlerRegistry(allDeps);
874
+
875
+ // Dispatch as a "grinder" (extends worker)
876
+ const context: LifecycleContext = {
877
+ agentId: "grinder-42",
878
+ role: "worker", // resolved base role
879
+ taskId: "task-99",
880
+ workspacePath: "/workspace/grinder-42",
881
+ branch: "feature/task-99",
882
+ integrationBranch: "main",
883
+ streamId: "stream-main",
884
+ };
885
+ const args: DoneArgs = { status: "completed", summary: "Implemented task-99" };
886
+
887
+ const result = await dispatchDone(
888
+ context,
889
+ args,
890
+ createCleanupStatus(),
891
+ allDeps,
892
+ registry
893
+ );
894
+
895
+ // Strategy should have been called
896
+ expect(strategy.land).toHaveBeenCalledWith(
897
+ expect.objectContaining({
898
+ agentId: "grinder-42",
899
+ taskId: "task-99",
900
+ sourceBranch: "feature/task-99",
901
+ targetBranch: "main",
902
+ })
903
+ );
904
+
905
+ // Pull mode: should not terminate
906
+ expect(result.shouldTerminate).toBe(false);
907
+
908
+ // Integration signal emitted
909
+ expect(result.signalsEmitted).toContain("WORKER_DONE");
910
+ expect(result.signalsEmitted).toContain("WORKER_INTEGRATED");
911
+ });
912
+
913
+ it("no strategy and no queue: emits signal but warns about missing queue", async () => {
914
+ const messageRouter = createMockMessageRouter();
915
+ const agentManager = {
916
+ getChildren: vi.fn().mockReturnValue([]),
917
+ } as unknown as AgentManager;
918
+
919
+ const allDeps: AllHandlerDeps = {
920
+ messageRouter,
921
+ agentManager,
922
+ // No strategy, no mergeQueue
923
+ };
924
+
925
+ const context = createWorkerContext();
926
+ const args: DoneArgs = { status: "completed" };
927
+
928
+ const result = await dispatchDone(
929
+ context,
930
+ args,
931
+ createCleanupStatus(),
932
+ allDeps
933
+ );
934
+
935
+ expect(result.signalsEmitted).toContain("WORKER_DONE");
936
+ expect(result.signalsEmitted).toContain("MERGE_REQUEST");
937
+ // Should mention "no queue configured" in cleanup actions
938
+ expect(result.cleanupActions?.some((a) => a.includes("no queue configured"))).toBe(true);
939
+ });
940
+ });
941
+
942
+ // =============================================================================
943
+ // Tests: Communication Topology Validation
944
+ // =============================================================================
945
+
946
+ describe("Communication Topology Validation", () => {
947
+ it("rejects templates with unknown role in subscriptions", async () => {
948
+ // This tests the loader's validation — not a runtime test
949
+ const roleRegistry = new DefaultRoleRegistry();
950
+
951
+ // self-driving template is valid — should load without error
952
+ const manifest = await loadTeam("self-driving", roleRegistry, PROJECT_ROOT);
953
+
954
+ // Verify all subscription roles exist in the roles list
955
+ for (const roleName of Object.keys(manifest.communication.subscriptions ?? {})) {
956
+ expect(manifest.roles).toContain(roleName);
957
+ }
958
+
959
+ // Verify all emission roles exist in the roles list
960
+ for (const roleName of Object.keys(manifest.communication.emissions ?? {})) {
961
+ expect(manifest.roles).toContain(roleName);
962
+ }
963
+
964
+ // Verify all peer routing roles exist
965
+ for (const peer of manifest.communication.routing?.peers ?? []) {
966
+ expect(manifest.roles).toContain(peer.from);
967
+ expect(manifest.roles).toContain(peer.to);
968
+ }
969
+ });
970
+
971
+ it("all subscribed channels exist in channel definitions", async () => {
972
+ const roleRegistry = new DefaultRoleRegistry();
973
+ const manifest = await loadTeam("self-driving", roleRegistry, PROJECT_ROOT);
974
+
975
+ const channelNames = new Set(Object.keys(manifest.communication.channels ?? {}));
976
+
977
+ for (const [, subs] of Object.entries(manifest.communication.subscriptions ?? {})) {
978
+ for (const sub of subs) {
979
+ expect(channelNames.has(sub.channel)).toBe(true);
980
+ }
981
+ }
982
+ });
983
+ });