macro-agent 0.0.10 → 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 (518) 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 +56 -51
  16. package/.sudocode/specs.jsonl +8 -1
  17. package/CLAUDE.md +121 -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 +40 -1
  31. package/dist/agent/agent-manager.d.ts.map +1 -1
  32. package/dist/agent/agent-manager.js +172 -8
  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/wake.d.ts +15 -0
  38. package/dist/agent/wake.d.ts.map +1 -1
  39. package/dist/agent/wake.js +15 -0
  40. package/dist/agent/wake.js.map +1 -1
  41. package/dist/agent-detection/command-builder.d.ts +30 -0
  42. package/dist/agent-detection/command-builder.d.ts.map +1 -0
  43. package/dist/agent-detection/command-builder.js +71 -0
  44. package/dist/agent-detection/command-builder.js.map +1 -0
  45. package/dist/agent-detection/detector.d.ts +84 -0
  46. package/dist/agent-detection/detector.d.ts.map +1 -0
  47. package/dist/agent-detection/detector.js +240 -0
  48. package/dist/agent-detection/detector.js.map +1 -0
  49. package/dist/agent-detection/index.d.ts +12 -0
  50. package/dist/agent-detection/index.d.ts.map +1 -0
  51. package/dist/agent-detection/index.js +14 -0
  52. package/dist/agent-detection/index.js.map +1 -0
  53. package/dist/agent-detection/registry.d.ts +53 -0
  54. package/dist/agent-detection/registry.d.ts.map +1 -0
  55. package/dist/agent-detection/registry.js +177 -0
  56. package/dist/agent-detection/registry.js.map +1 -0
  57. package/dist/agent-detection/types.d.ts +121 -0
  58. package/dist/agent-detection/types.d.ts.map +1 -0
  59. package/dist/agent-detection/types.js +20 -0
  60. package/dist/agent-detection/types.js.map +1 -0
  61. package/dist/api/server.d.ts +5 -1
  62. package/dist/api/server.d.ts.map +1 -1
  63. package/dist/api/server.js +362 -0
  64. package/dist/api/server.js.map +1 -1
  65. package/dist/api/types.d.ts +50 -1
  66. package/dist/api/types.d.ts.map +1 -1
  67. package/dist/cli/acp.d.ts +2 -0
  68. package/dist/cli/acp.d.ts.map +1 -1
  69. package/dist/cli/acp.js +8 -1
  70. package/dist/cli/acp.js.map +1 -1
  71. package/dist/cli/index.js +29 -0
  72. package/dist/cli/index.js.map +1 -1
  73. package/dist/cli/mcp.js +38 -0
  74. package/dist/cli/mcp.js.map +1 -1
  75. package/dist/config/index.d.ts +2 -0
  76. package/dist/config/index.d.ts.map +1 -0
  77. package/dist/config/index.js +2 -0
  78. package/dist/config/index.js.map +1 -0
  79. package/dist/config/project-config.d.ts +46 -0
  80. package/dist/config/project-config.d.ts.map +1 -0
  81. package/dist/config/project-config.js +68 -0
  82. package/dist/config/project-config.js.map +1 -0
  83. package/dist/lifecycle/cascade.d.ts +1 -1
  84. package/dist/lifecycle/cascade.d.ts.map +1 -1
  85. package/dist/lifecycle/handlers/index.d.ts +4 -0
  86. package/dist/lifecycle/handlers/index.d.ts.map +1 -1
  87. package/dist/lifecycle/handlers/index.js +2 -0
  88. package/dist/lifecycle/handlers/index.js.map +1 -1
  89. package/dist/lifecycle/handlers/worker.d.ts +4 -0
  90. package/dist/lifecycle/handlers/worker.d.ts.map +1 -1
  91. package/dist/lifecycle/handlers/worker.js +35 -3
  92. package/dist/lifecycle/handlers/worker.js.map +1 -1
  93. package/dist/mail/conversation-map.d.ts +33 -0
  94. package/dist/mail/conversation-map.d.ts.map +1 -0
  95. package/dist/mail/conversation-map.js +61 -0
  96. package/dist/mail/conversation-map.js.map +1 -0
  97. package/dist/mail/index.d.ts +11 -0
  98. package/dist/mail/index.d.ts.map +1 -0
  99. package/dist/mail/index.js +11 -0
  100. package/dist/mail/index.js.map +1 -0
  101. package/dist/mail/mail-service.d.ts +85 -0
  102. package/dist/mail/mail-service.d.ts.map +1 -0
  103. package/dist/mail/mail-service.js +121 -0
  104. package/dist/mail/mail-service.js.map +1 -0
  105. package/dist/mail/stores/eventstore-conversation-store.d.ts +40 -0
  106. package/dist/mail/stores/eventstore-conversation-store.d.ts.map +1 -0
  107. package/dist/mail/stores/eventstore-conversation-store.js +131 -0
  108. package/dist/mail/stores/eventstore-conversation-store.js.map +1 -0
  109. package/dist/mail/stores/eventstore-participant-store.d.ts +43 -0
  110. package/dist/mail/stores/eventstore-participant-store.d.ts.map +1 -0
  111. package/dist/mail/stores/eventstore-participant-store.js +145 -0
  112. package/dist/mail/stores/eventstore-participant-store.js.map +1 -0
  113. package/dist/mail/stores/eventstore-thread-store.d.ts +46 -0
  114. package/dist/mail/stores/eventstore-thread-store.d.ts.map +1 -0
  115. package/dist/mail/stores/eventstore-thread-store.js +118 -0
  116. package/dist/mail/stores/eventstore-thread-store.js.map +1 -0
  117. package/dist/mail/stores/eventstore-turn-store.d.ts +47 -0
  118. package/dist/mail/stores/eventstore-turn-store.d.ts.map +1 -0
  119. package/dist/mail/stores/eventstore-turn-store.js +153 -0
  120. package/dist/mail/stores/eventstore-turn-store.js.map +1 -0
  121. package/dist/mail/stores/index.d.ts +12 -0
  122. package/dist/mail/stores/index.d.ts.map +1 -0
  123. package/dist/mail/stores/index.js +12 -0
  124. package/dist/mail/stores/index.js.map +1 -0
  125. package/dist/mail/stores/types.d.ts +146 -0
  126. package/dist/mail/stores/types.d.ts.map +1 -0
  127. package/dist/mail/stores/types.js +13 -0
  128. package/dist/mail/stores/types.js.map +1 -0
  129. package/dist/mail/turn-recorder.d.ts +30 -0
  130. package/dist/mail/turn-recorder.d.ts.map +1 -0
  131. package/dist/mail/turn-recorder.js +98 -0
  132. package/dist/mail/turn-recorder.js.map +1 -0
  133. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  134. package/dist/map/adapter/acp-over-map.js +32 -2
  135. package/dist/map/adapter/acp-over-map.js.map +1 -1
  136. package/dist/map/adapter/event-translator.d.ts.map +1 -1
  137. package/dist/map/adapter/event-translator.js +4 -0
  138. package/dist/map/adapter/event-translator.js.map +1 -1
  139. package/dist/map/adapter/extensions/agent-detection.d.ts +49 -0
  140. package/dist/map/adapter/extensions/agent-detection.d.ts.map +1 -0
  141. package/dist/map/adapter/extensions/agent-detection.js +91 -0
  142. package/dist/map/adapter/extensions/agent-detection.js.map +1 -0
  143. package/dist/map/adapter/extensions/index.d.ts +10 -1
  144. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  145. package/dist/map/adapter/extensions/index.js +39 -0
  146. package/dist/map/adapter/extensions/index.js.map +1 -1
  147. package/dist/map/adapter/extensions/resume.d.ts +47 -0
  148. package/dist/map/adapter/extensions/resume.d.ts.map +1 -0
  149. package/dist/map/adapter/extensions/resume.js +59 -0
  150. package/dist/map/adapter/extensions/resume.js.map +1 -0
  151. package/dist/map/adapter/extensions/workspace-files.d.ts +42 -0
  152. package/dist/map/adapter/extensions/workspace-files.d.ts.map +1 -0
  153. package/dist/map/adapter/extensions/workspace-files.js +338 -0
  154. package/dist/map/adapter/extensions/workspace-files.js.map +1 -0
  155. package/dist/map/adapter/mail-handler-adapter.d.ts +27 -0
  156. package/dist/map/adapter/mail-handler-adapter.d.ts.map +1 -0
  157. package/dist/map/adapter/mail-handler-adapter.js +292 -0
  158. package/dist/map/adapter/mail-handler-adapter.js.map +1 -0
  159. package/dist/map/adapter/map-adapter.d.ts +34 -10
  160. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  161. package/dist/map/adapter/map-adapter.js +110 -14
  162. package/dist/map/adapter/map-adapter.js.map +1 -1
  163. package/dist/map/adapter/rpc-handler.d.ts +4 -1
  164. package/dist/map/adapter/rpc-handler.d.ts.map +1 -1
  165. package/dist/map/adapter/rpc-handler.js +6 -0
  166. package/dist/map/adapter/rpc-handler.js.map +1 -1
  167. package/dist/map/index.d.ts +1 -0
  168. package/dist/map/index.d.ts.map +1 -1
  169. package/dist/map/index.js +2 -0
  170. package/dist/map/index.js.map +1 -1
  171. package/dist/map/types.d.ts +3 -1
  172. package/dist/map/types.d.ts.map +1 -1
  173. package/dist/map/types.js.map +1 -1
  174. package/dist/mcp/mcp-server.d.ts +6 -0
  175. package/dist/mcp/mcp-server.d.ts.map +1 -1
  176. package/dist/mcp/mcp-server.js +45 -0
  177. package/dist/mcp/mcp-server.js.map +1 -1
  178. package/dist/mcp/tools/claim_task.d.ts +35 -0
  179. package/dist/mcp/tools/claim_task.d.ts.map +1 -0
  180. package/dist/mcp/tools/claim_task.js +58 -0
  181. package/dist/mcp/tools/claim_task.js.map +1 -0
  182. package/dist/mcp/tools/done.d.ts +15 -2
  183. package/dist/mcp/tools/done.d.ts.map +1 -1
  184. package/dist/mcp/tools/done.js +45 -10
  185. package/dist/mcp/tools/done.js.map +1 -1
  186. package/dist/mcp/tools/list_claimable_tasks.d.ts +38 -0
  187. package/dist/mcp/tools/list_claimable_tasks.d.ts.map +1 -0
  188. package/dist/mcp/tools/list_claimable_tasks.js +63 -0
  189. package/dist/mcp/tools/list_claimable_tasks.js.map +1 -0
  190. package/dist/mcp/tools/unclaim_task.d.ts +31 -0
  191. package/dist/mcp/tools/unclaim_task.d.ts.map +1 -0
  192. package/dist/mcp/tools/unclaim_task.js +47 -0
  193. package/dist/mcp/tools/unclaim_task.js.map +1 -0
  194. package/dist/metrics/index.d.ts +2 -0
  195. package/dist/metrics/index.d.ts.map +1 -0
  196. package/dist/metrics/index.js +2 -0
  197. package/dist/metrics/index.js.map +1 -0
  198. package/dist/metrics/metrics.d.ts +79 -0
  199. package/dist/metrics/metrics.d.ts.map +1 -0
  200. package/dist/metrics/metrics.js +166 -0
  201. package/dist/metrics/metrics.js.map +1 -0
  202. package/dist/roles/capabilities.d.ts +1 -0
  203. package/dist/roles/capabilities.d.ts.map +1 -1
  204. package/dist/roles/capabilities.js +3 -0
  205. package/dist/roles/capabilities.js.map +1 -1
  206. package/dist/roles/types.d.ts +1 -1
  207. package/dist/roles/types.d.ts.map +1 -1
  208. package/dist/router/channels.d.ts +2 -4
  209. package/dist/router/channels.d.ts.map +1 -1
  210. package/dist/router/channels.js.map +1 -1
  211. package/dist/router/message-router.d.ts +85 -9
  212. package/dist/router/message-router.d.ts.map +1 -1
  213. package/dist/router/message-router.js +203 -14
  214. package/dist/router/message-router.js.map +1 -1
  215. package/dist/router/role-resolver.d.ts +10 -1
  216. package/dist/router/role-resolver.d.ts.map +1 -1
  217. package/dist/router/role-resolver.js +15 -1
  218. package/dist/router/role-resolver.js.map +1 -1
  219. package/dist/router/types.d.ts +30 -1
  220. package/dist/router/types.d.ts.map +1 -1
  221. package/dist/router/types.js.map +1 -1
  222. package/dist/server/combined-server.d.ts +6 -0
  223. package/dist/server/combined-server.d.ts.map +1 -1
  224. package/dist/server/combined-server.js +24 -2
  225. package/dist/server/combined-server.js.map +1 -1
  226. package/dist/store/event-store.d.ts +14 -1
  227. package/dist/store/event-store.d.ts.map +1 -1
  228. package/dist/store/event-store.js +456 -4
  229. package/dist/store/event-store.js.map +1 -1
  230. package/dist/store/types/agents.d.ts +1 -1
  231. package/dist/store/types/agents.d.ts.map +1 -1
  232. package/dist/store/types/conversations.d.ts +91 -0
  233. package/dist/store/types/conversations.d.ts.map +1 -0
  234. package/dist/store/types/conversations.js +8 -0
  235. package/dist/store/types/conversations.js.map +1 -0
  236. package/dist/store/types/events.d.ts +1 -1
  237. package/dist/store/types/events.d.ts.map +1 -1
  238. package/dist/store/types/events.js.map +1 -1
  239. package/dist/store/types/index.d.ts +2 -0
  240. package/dist/store/types/index.d.ts.map +1 -1
  241. package/dist/store/types/index.js +2 -0
  242. package/dist/store/types/index.js.map +1 -1
  243. package/dist/store/types/sessions.d.ts +44 -0
  244. package/dist/store/types/sessions.d.ts.map +1 -0
  245. package/dist/store/types/sessions.js +9 -0
  246. package/dist/store/types/sessions.js.map +1 -0
  247. package/dist/store/types/tasks.d.ts +2 -0
  248. package/dist/store/types/tasks.d.ts.map +1 -1
  249. package/dist/task/backend/memory.d.ts +4 -1
  250. package/dist/task/backend/memory.d.ts.map +1 -1
  251. package/dist/task/backend/memory.js +81 -0
  252. package/dist/task/backend/memory.js.map +1 -1
  253. package/dist/task/backend/types.d.ts +30 -0
  254. package/dist/task/backend/types.d.ts.map +1 -1
  255. package/dist/task/backend/types.js.map +1 -1
  256. package/dist/teams/index.d.ts +4 -0
  257. package/dist/teams/index.d.ts.map +1 -0
  258. package/dist/teams/index.js +4 -0
  259. package/dist/teams/index.js.map +1 -0
  260. package/dist/teams/team-loader.d.ts +20 -0
  261. package/dist/teams/team-loader.d.ts.map +1 -0
  262. package/dist/teams/team-loader.js +293 -0
  263. package/dist/teams/team-loader.js.map +1 -0
  264. package/dist/teams/team-runtime.d.ts +139 -0
  265. package/dist/teams/team-runtime.d.ts.map +1 -0
  266. package/dist/teams/team-runtime.js +613 -0
  267. package/dist/teams/team-runtime.js.map +1 -0
  268. package/dist/teams/types.d.ts +266 -0
  269. package/dist/teams/types.d.ts.map +1 -0
  270. package/dist/teams/types.js +20 -0
  271. package/dist/teams/types.js.map +1 -0
  272. package/dist/trigger/router/trigger-router.d.ts +30 -3
  273. package/dist/trigger/router/trigger-router.d.ts.map +1 -1
  274. package/dist/trigger/router/trigger-router.js +30 -3
  275. package/dist/trigger/router/trigger-router.js.map +1 -1
  276. package/dist/trigger/wake/types.d.ts +31 -5
  277. package/dist/trigger/wake/types.d.ts.map +1 -1
  278. package/dist/trigger/wake/types.js +19 -0
  279. package/dist/trigger/wake/types.js.map +1 -1
  280. package/dist/workspace/dataplane-adapter.d.ts +1 -1
  281. package/dist/workspace/dataplane-adapter.d.ts.map +1 -1
  282. package/dist/workspace/dataplane-adapter.js +1 -1
  283. package/dist/workspace/dataplane-adapter.js.map +1 -1
  284. package/dist/workspace/index.d.ts +1 -1
  285. package/dist/workspace/index.d.ts.map +1 -1
  286. package/dist/workspace/strategies/index.d.ts +6 -0
  287. package/dist/workspace/strategies/index.d.ts.map +1 -0
  288. package/dist/workspace/strategies/index.js +5 -0
  289. package/dist/workspace/strategies/index.js.map +1 -0
  290. package/dist/workspace/strategies/optimistic.d.ts +26 -0
  291. package/dist/workspace/strategies/optimistic.d.ts.map +1 -0
  292. package/dist/workspace/strategies/optimistic.js +121 -0
  293. package/dist/workspace/strategies/optimistic.js.map +1 -0
  294. package/dist/workspace/strategies/queue.d.ts +26 -0
  295. package/dist/workspace/strategies/queue.d.ts.map +1 -0
  296. package/dist/workspace/strategies/queue.js +67 -0
  297. package/dist/workspace/strategies/queue.js.map +1 -0
  298. package/dist/workspace/strategies/registry.d.ts +37 -0
  299. package/dist/workspace/strategies/registry.d.ts.map +1 -0
  300. package/dist/workspace/strategies/registry.js +63 -0
  301. package/dist/workspace/strategies/registry.js.map +1 -0
  302. package/dist/workspace/strategies/trunk.d.ts +20 -0
  303. package/dist/workspace/strategies/trunk.d.ts.map +1 -0
  304. package/dist/workspace/strategies/trunk.js +108 -0
  305. package/dist/workspace/strategies/trunk.js.map +1 -0
  306. package/dist/workspace/strategies/types.d.ts +104 -0
  307. package/dist/workspace/strategies/types.d.ts.map +1 -0
  308. package/dist/workspace/strategies/types.js +11 -0
  309. package/dist/workspace/strategies/types.js.map +1 -0
  310. package/dist/workspace/types.d.ts +1 -1
  311. package/dist/workspace/types.d.ts.map +1 -1
  312. package/dist/workspace/workspace-manager.d.ts +1 -1
  313. package/dist/workspace/workspace-manager.d.ts.map +1 -1
  314. package/docs/implementation-details.md +1127 -0
  315. package/docs/implementation-summary.md +448 -0
  316. package/docs/mail-integration.md +608 -0
  317. package/docs/plan-self-driving-support.md +433 -0
  318. package/docs/spec-self-driving-support.md +462 -0
  319. package/docs/team-templates.md +860 -0
  320. package/docs/teams.md +233 -0
  321. package/package.json +5 -3
  322. package/src/acp/__tests__/integration.test.ts +161 -1
  323. package/src/acp/__tests__/macro-agent.test.ts +95 -0
  324. package/src/acp/__tests__/session-persistence.test.ts +276 -0
  325. package/src/acp/macro-agent.ts +79 -7
  326. package/src/acp/session-mapper.ts +108 -1
  327. package/src/acp/types.ts +33 -1
  328. package/src/agent/agent-manager.ts +278 -6
  329. package/src/agent/types.ts +27 -0
  330. package/src/agent/wake.ts +15 -0
  331. package/src/agent-detection/__tests__/command-builder.test.ts +336 -0
  332. package/src/agent-detection/__tests__/detector.test.ts +768 -0
  333. package/src/agent-detection/__tests__/registry.test.ts +254 -0
  334. package/src/agent-detection/command-builder.ts +90 -0
  335. package/src/agent-detection/detector.ts +307 -0
  336. package/src/agent-detection/index.ts +36 -0
  337. package/src/agent-detection/registry.ts +200 -0
  338. package/src/agent-detection/types.ts +184 -0
  339. package/src/api/__tests__/conversation-api.test.ts +468 -0
  340. package/src/api/server.ts +425 -1
  341. package/src/api/types.ts +64 -1
  342. package/src/cli/acp.ts +9 -1
  343. package/src/cli/index.ts +44 -0
  344. package/src/cli/mcp.ts +47 -0
  345. package/src/config/index.ts +9 -0
  346. package/src/config/project-config.ts +107 -0
  347. package/src/lifecycle/cascade.ts +1 -1
  348. package/src/lifecycle/handlers/index.ts +8 -0
  349. package/src/lifecycle/handlers/worker.ts +48 -3
  350. package/src/mail/__tests__/conversation-lifecycle.test.ts +409 -0
  351. package/src/mail/__tests__/eventstore-stores.test.ts +1073 -0
  352. package/src/mail/__tests__/mail-full-agent.e2e.test.ts +575 -0
  353. package/src/mail/__tests__/mail-integration.test.ts +759 -0
  354. package/src/mail/__tests__/mail-map-protocol.e2e.test.ts +1068 -0
  355. package/src/mail/__tests__/mail-service.test.ts +506 -0
  356. package/src/mail/__tests__/turn-recorder.test.ts +328 -0
  357. package/src/mail/conversation-map.ts +107 -0
  358. package/src/mail/index.ts +25 -0
  359. package/src/mail/mail-service.ts +257 -0
  360. package/src/mail/stores/eventstore-conversation-store.ts +146 -0
  361. package/src/mail/stores/eventstore-participant-store.ts +172 -0
  362. package/src/mail/stores/eventstore-thread-store.ts +129 -0
  363. package/src/mail/stores/eventstore-turn-store.ts +173 -0
  364. package/src/mail/stores/index.ts +12 -0
  365. package/src/mail/stores/types.ts +160 -0
  366. package/src/mail/turn-recorder.ts +124 -0
  367. package/src/map/README.md +79 -0
  368. package/src/map/adapter/__tests__/extensions.test.ts +359 -0
  369. package/src/map/adapter/__tests__/map-adapter.test.ts +90 -0
  370. package/src/map/adapter/__tests__/workspace-files.test.ts +673 -0
  371. package/src/map/adapter/acp-over-map.ts +45 -2
  372. package/src/map/adapter/event-translator.ts +4 -0
  373. package/src/map/adapter/extensions/agent-detection.ts +201 -0
  374. package/src/map/adapter/extensions/index.ts +63 -0
  375. package/src/map/adapter/extensions/resume.ts +114 -0
  376. package/src/map/adapter/extensions/workspace-files.ts +449 -0
  377. package/src/map/adapter/mail-handler-adapter.ts +429 -0
  378. package/src/map/adapter/map-adapter.ts +173 -27
  379. package/src/map/adapter/rpc-handler.ts +8 -1
  380. package/src/map/index.ts +3 -0
  381. package/src/map/types.ts +3 -1
  382. package/src/mcp/mcp-server.ts +67 -0
  383. package/src/mcp/tools/claim_task.ts +86 -0
  384. package/src/mcp/tools/done.ts +59 -10
  385. package/src/mcp/tools/list_claimable_tasks.ts +93 -0
  386. package/src/mcp/tools/unclaim_task.ts +71 -0
  387. package/src/metrics/index.ts +9 -0
  388. package/src/metrics/metrics.ts +280 -0
  389. package/src/roles/capabilities.ts +3 -0
  390. package/src/roles/types.ts +2 -1
  391. package/src/router/README.md +120 -0
  392. package/src/router/__tests__/message-router.test.ts +561 -0
  393. package/src/router/channels.ts +3 -4
  394. package/src/router/message-router.ts +308 -22
  395. package/src/router/role-resolver.ts +22 -1
  396. package/src/router/types.ts +36 -1
  397. package/src/server/combined-server.ts +36 -2
  398. package/src/store/README.md +134 -0
  399. package/src/store/event-store.ts +546 -3
  400. package/src/store/types/agents.ts +1 -1
  401. package/src/store/types/conversations.ts +129 -0
  402. package/src/store/types/events.ts +5 -1
  403. package/src/store/types/index.ts +2 -0
  404. package/src/store/types/sessions.ts +53 -0
  405. package/src/store/types/tasks.ts +3 -0
  406. package/src/task/backend/memory.ts +116 -0
  407. package/src/task/backend/types.ts +43 -0
  408. package/src/teams/__tests__/cross-subsystem.integration.test.ts +983 -0
  409. package/src/teams/__tests__/e2e/team-runtime.e2e.test.ts +553 -0
  410. package/src/teams/__tests__/team-system.test.ts +1280 -0
  411. package/src/teams/index.ts +13 -0
  412. package/src/teams/team-loader.ts +434 -0
  413. package/src/teams/team-runtime.ts +727 -0
  414. package/src/teams/types.ts +377 -0
  415. package/src/trigger/router/trigger-router.ts +30 -3
  416. package/src/trigger/wake/types.ts +32 -5
  417. package/src/trigger/wake/wake-manager.ts +2 -2
  418. package/src/workspace/dataplane-adapter.ts +1 -1
  419. package/src/workspace/index.ts +1 -1
  420. package/src/workspace/strategies/index.ts +18 -0
  421. package/src/workspace/strategies/optimistic.ts +136 -0
  422. package/src/workspace/strategies/queue.ts +81 -0
  423. package/src/workspace/strategies/registry.ts +89 -0
  424. package/src/workspace/strategies/trunk.ts +123 -0
  425. package/src/workspace/strategies/types.ts +145 -0
  426. package/src/workspace/types.ts +1 -1
  427. package/src/workspace/workspace-manager.ts +1 -1
  428. package/.claude/settings.local.json +0 -59
  429. package/dist/map/utils/address-translation.d.ts +0 -99
  430. package/dist/map/utils/address-translation.d.ts.map +0 -1
  431. package/dist/map/utils/address-translation.js +0 -285
  432. package/dist/map/utils/address-translation.js.map +0 -1
  433. package/dist/map/utils/index.d.ts +0 -7
  434. package/dist/map/utils/index.d.ts.map +0 -1
  435. package/dist/map/utils/index.js +0 -7
  436. package/dist/map/utils/index.js.map +0 -1
  437. package/openspec/AGENTS.md +0 -456
  438. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/design.md +0 -128
  439. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/proposal.md +0 -49
  440. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/agent-manager/spec.md +0 -150
  441. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/cli-api/spec.md +0 -258
  442. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/event-store/spec.md +0 -160
  443. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/mcp-tools/spec.md +0 -224
  444. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/message-router/spec.md +0 -153
  445. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/task-manager/spec.md +0 -136
  446. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/tasks.md +0 -147
  447. package/openspec/project.md +0 -31
  448. package/openspec/specs/agent-manager/spec.md +0 -154
  449. package/openspec/specs/cli-api/spec.md +0 -262
  450. package/openspec/specs/event-store/spec.md +0 -164
  451. package/openspec/specs/mcp-tools/spec.md +0 -228
  452. package/openspec/specs/message-router/spec.md +0 -157
  453. package/openspec/specs/task-manager/spec.md +0 -140
  454. package/references/acp-factory-ref/CHANGELOG.md +0 -33
  455. package/references/acp-factory-ref/LICENSE +0 -21
  456. package/references/acp-factory-ref/README.md +0 -341
  457. package/references/acp-factory-ref/package-lock.json +0 -3102
  458. package/references/acp-factory-ref/package.json +0 -96
  459. package/references/acp-factory-ref/python/CHANGELOG.md +0 -33
  460. package/references/acp-factory-ref/python/LICENSE +0 -21
  461. package/references/acp-factory-ref/python/Makefile +0 -57
  462. package/references/acp-factory-ref/python/README.md +0 -253
  463. package/references/acp-factory-ref/python/pyproject.toml +0 -73
  464. package/references/acp-factory-ref/python/tests/__init__.py +0 -0
  465. package/references/acp-factory-ref/python/tests/e2e/__init__.py +0 -1
  466. package/references/acp-factory-ref/python/tests/e2e/test_codex_e2e.py +0 -349
  467. package/references/acp-factory-ref/python/tests/e2e/test_gemini_e2e.py +0 -165
  468. package/references/acp-factory-ref/python/tests/e2e/test_opencode_e2e.py +0 -296
  469. package/references/acp-factory-ref/python/tests/test_client_handler.py +0 -543
  470. package/references/acp-factory-ref/python/tests/test_pushable.py +0 -199
  471. package/references/claude-code-acp/.github/workflows/ci.yml +0 -45
  472. package/references/claude-code-acp/.github/workflows/publish.yml +0 -34
  473. package/references/claude-code-acp/.prettierrc.json +0 -4
  474. package/references/claude-code-acp/CHANGELOG.md +0 -249
  475. package/references/claude-code-acp/LICENSE +0 -222
  476. package/references/claude-code-acp/README.md +0 -53
  477. package/references/claude-code-acp/docs/RELEASES.md +0 -24
  478. package/references/claude-code-acp/eslint.config.js +0 -48
  479. package/references/claude-code-acp/package-lock.json +0 -4570
  480. package/references/claude-code-acp/package.json +0 -88
  481. package/references/claude-code-acp/scripts/release.sh +0 -119
  482. package/references/claude-code-acp/src/acp-agent.ts +0 -2065
  483. package/references/claude-code-acp/src/index.ts +0 -26
  484. package/references/claude-code-acp/src/lib.ts +0 -38
  485. package/references/claude-code-acp/src/mcp-server.ts +0 -911
  486. package/references/claude-code-acp/src/settings.ts +0 -522
  487. package/references/claude-code-acp/src/tests/.claude/commands/quick-math.md +0 -5
  488. package/references/claude-code-acp/src/tests/.claude/commands/say-hello.md +0 -6
  489. package/references/claude-code-acp/src/tests/acp-agent-fork.test.ts +0 -479
  490. package/references/claude-code-acp/src/tests/acp-agent.test.ts +0 -1502
  491. package/references/claude-code-acp/src/tests/extract-lines.test.ts +0 -103
  492. package/references/claude-code-acp/src/tests/fork-session.test.ts +0 -335
  493. package/references/claude-code-acp/src/tests/replace-and-calculate-location.test.ts +0 -334
  494. package/references/claude-code-acp/src/tests/settings.test.ts +0 -617
  495. package/references/claude-code-acp/src/tests/skills-options.test.ts +0 -187
  496. package/references/claude-code-acp/src/tests/tools.test.ts +0 -318
  497. package/references/claude-code-acp/src/tests/typescript-declarations.test.ts +0 -558
  498. package/references/claude-code-acp/src/tools.ts +0 -819
  499. package/references/claude-code-acp/src/utils.ts +0 -171
  500. package/references/claude-code-acp/tsconfig.json +0 -18
  501. package/references/claude-code-acp/vitest.config.ts +0 -19
  502. package/references/multi-agent-protocol/.sudocode/issues.jsonl +0 -82
  503. package/references/multi-agent-protocol/.sudocode/specs.jsonl +0 -9
  504. package/references/multi-agent-protocol/LICENSE +0 -21
  505. package/references/multi-agent-protocol/README.md +0 -113
  506. package/references/multi-agent-protocol/docs/00-design-specification.md +0 -460
  507. package/references/multi-agent-protocol/docs/01-open-questions.md +0 -1050
  508. package/references/multi-agent-protocol/docs/02-wire-protocol.md +0 -296
  509. package/references/multi-agent-protocol/docs/03-streaming-semantics.md +0 -252
  510. package/references/multi-agent-protocol/docs/04-error-handling.md +0 -231
  511. package/references/multi-agent-protocol/docs/05-connection-model.md +0 -244
  512. package/references/multi-agent-protocol/docs/06-visibility-permissions.md +0 -243
  513. package/references/multi-agent-protocol/docs/07-federation.md +0 -259
  514. package/references/multi-agent-protocol/docs/08-macro-agent-migration.md +0 -253
  515. package/references/multi-agent-protocol/package-lock.json +0 -3239
  516. package/references/multi-agent-protocol/package.json +0 -56
  517. package/references/multi-agent-protocol/schema/meta.json +0 -337
  518. package/references/multi-agent-protocol/schema/schema.json +0 -1828
@@ -0,0 +1,727 @@
1
+ /**
2
+ * Team Runtime
3
+ *
4
+ * Wires a loaded TeamManifest into the running system: registers roles,
5
+ * sets up integration strategy, configures communication topology,
6
+ * and manages the team lifecycle.
7
+ *
8
+ * @module teams/team-runtime
9
+ */
10
+
11
+ import type { EventStore } from "../store/event-store.js";
12
+ import type { MessageRouter } from "../router/message-router.js";
13
+ import type { AgentManager, SpawnInterceptor } from "../agent/agent-manager.js";
14
+ import type { RoleRegistry } from "../roles/types.js";
15
+ import type { SpawnAgentOptions } from "../agent/types.js";
16
+ import type { AgentId } from "../store/types/index.js";
17
+ import type {
18
+ TeamManifest,
19
+ McpServerEntry,
20
+ PeerConnection,
21
+ } from "./types.js";
22
+ import type { IntegrationStrategy } from "../workspace/strategies/types.js";
23
+
24
+ // =============================================================================
25
+ // Types
26
+ // =============================================================================
27
+
28
+ export interface TeamServices {
29
+ agentManager: AgentManager;
30
+ messageRouter: MessageRouter;
31
+ eventStore: EventStore;
32
+ }
33
+
34
+ export interface TeamBootstrapResult {
35
+ rootId: string;
36
+ companionIds: string[];
37
+ }
38
+
39
+ // =============================================================================
40
+ // TeamRuntime
41
+ // =============================================================================
42
+
43
+ export class TeamRuntime {
44
+ private rootAgentId?: string;
45
+ private companionAgentIds: string[] = [];
46
+ private roleRegistry: RoleRegistry;
47
+ private lifecycleUnsubscribe?: () => void;
48
+ private integrationStrategy?: IntegrationStrategy;
49
+
50
+ /** Role name → spawned agent ID mapping (populated during bootstrap) */
51
+ private roleAgentMap = new Map<string, AgentId>();
52
+
53
+ /** Peer connections that couldn't be wired at bootstrap (target role not yet spawned) */
54
+ private pendingPeerRoutes: PeerConnection[] = [];
55
+
56
+ /** Per-agent signal filters from peer connections. Key: "fromAgentId→toAgentId" */
57
+ private peerSignalFilters = new Map<string, string[]>();
58
+
59
+ /** Reverse mapping: agent ID → role name (for signal filter lookups) */
60
+ private agentRoleMap = new Map<AgentId, string>();
61
+
62
+ /** Lifecycle unsubscribe for deferred peer wiring */
63
+ private peerWiringUnsubscribe?: () => void;
64
+
65
+ constructor(
66
+ private readonly manifest: TeamManifest,
67
+ private readonly services: TeamServices
68
+ ) {
69
+ this.roleRegistry = services.agentManager.getRoleRegistry();
70
+ }
71
+
72
+ // ─────────────────────────────────────────────────────────────
73
+ // Initialization
74
+ // ─────────────────────────────────────────────────────────────
75
+
76
+ /**
77
+ * Wire team configuration into running services.
78
+ *
79
+ * 1. Register team roles into RoleRegistry
80
+ * 2. Store team_config event in EventStore (for MCP subprocess discovery)
81
+ * 3. Register spawn interceptor on AgentManager
82
+ */
83
+ async initialize(): Promise<void> {
84
+ const { agentManager, eventStore } = this.services;
85
+
86
+ // 1. Register team roles into RoleRegistry (custom layer, highest priority)
87
+ for (const [, resolved] of this.manifest._resolvedRoles) {
88
+ this.roleRegistry.registerRole(resolved.roleDefinition);
89
+ }
90
+
91
+ // 2. Store team config in EventStore for cross-process access (RD2)
92
+ const taskMode = this.manifest.macro_agent.task_assignment?.mode ?? "push";
93
+ const strategyName = this.manifest.macro_agent.integration?.strategy ?? "queue";
94
+ const strategyConfig = this.manifest.macro_agent.integration?.config ?? {};
95
+ const enforcement = this.manifest.communication.enforcement ?? "permissive";
96
+
97
+ // Serialize resolved roles for MCP subprocess capability checks
98
+ const serializedRoles: Record<string, { name: string; capabilities: string[]; tools?: object; lifecycle?: object; description?: string }> = {};
99
+ for (const [name, resolved] of this.manifest._resolvedRoles) {
100
+ const rd = resolved.roleDefinition;
101
+ serializedRoles[name] = {
102
+ name: rd.name,
103
+ capabilities: [...rd.capabilities],
104
+ ...(rd.tools && { tools: rd.tools }),
105
+ ...(rd.lifecycle && { lifecycle: rd.lifecycle }),
106
+ ...(rd.description && { description: rd.description }),
107
+ };
108
+ }
109
+
110
+ eventStore.emit({
111
+ type: "status",
112
+ source: { agent_id: "system" },
113
+ payload: {
114
+ status_type: "discovery",
115
+ summary: `Team '${this.manifest.name}' initialized`,
116
+ team_config: {
117
+ teamName: this.manifest.name,
118
+ strategy: strategyName,
119
+ strategyConfig,
120
+ taskMode,
121
+ enforcement,
122
+ roles: serializedRoles,
123
+ peerRoutes: this.manifest.communication.routing?.peers ?? [],
124
+ emissions: this.manifest.communication.emissions ?? {},
125
+ },
126
+ },
127
+ });
128
+
129
+ await eventStore.persist();
130
+
131
+ // 2b. Instantiate integration strategy and call lifecycle hook
132
+ try {
133
+ const { defaultStrategyRegistry } = await import("../workspace/strategies/registry.js");
134
+ this.integrationStrategy = defaultStrategyRegistry.get(strategyName, strategyConfig as Record<string, unknown>);
135
+ if (this.integrationStrategy.initialize) {
136
+ await this.integrationStrategy.initialize();
137
+ }
138
+ } catch {
139
+ // Strategy instantiation is best-effort — queue strategy needs merge queue set later
140
+ }
141
+
142
+ // 3. Register spawn interceptor
143
+ agentManager.setSpawnInterceptor(this.createSpawnInterceptor());
144
+ }
145
+
146
+ // ─────────────────────────────────────────────────────────────
147
+ // Bootstrap
148
+ // ─────────────────────────────────────────────────────────────
149
+
150
+ /**
151
+ * Spawn root and companion agents per the team topology.
152
+ */
153
+ async bootstrap(): Promise<TeamBootstrapResult> {
154
+ const { agentManager, messageRouter } = this.services;
155
+ const { topology } = this.manifest;
156
+
157
+ // 1. Spawn root agent
158
+ const rootPrompt = this.getPromptForTopologyNode(topology.root);
159
+ const root = await agentManager.spawn({
160
+ task: rootPrompt
161
+ ? `[${this.manifest.name}] ${topology.root.role}`
162
+ : `Team ${this.manifest.name} root: ${topology.root.role}`,
163
+ parent: null,
164
+ role: topology.root.role,
165
+ config: {
166
+ model: topology.root.config?.model,
167
+ },
168
+ customPrompt: rootPrompt,
169
+ interactionPatterns: this.getInteractionPatterns(),
170
+ });
171
+ this.rootAgentId = root.id;
172
+
173
+ // 2. Spawn companions (peers, not children)
174
+ const companionIds: string[] = [];
175
+ for (const companion of topology.companions ?? []) {
176
+ const companionPrompt = this.getPromptForTopologyNode(companion);
177
+ const agent = await agentManager.spawn({
178
+ task: `[${this.manifest.name}] ${companion.role}`,
179
+ parent: null,
180
+ role: companion.role,
181
+ config: {
182
+ model: companion.config?.model,
183
+ },
184
+ customPrompt: companionPrompt,
185
+ interactionPatterns: this.getInteractionPatterns(),
186
+ });
187
+ companionIds.push(agent.id);
188
+ }
189
+ this.companionAgentIds = companionIds;
190
+
191
+ // 3. Build role↔agent mappings and wire peer subscriptions
192
+ this.roleAgentMap.set(topology.root.role, root.id as AgentId);
193
+ this.agentRoleMap.set(root.id as AgentId, topology.root.role);
194
+ for (let i = 0; i < (topology.companions ?? []).length; i++) {
195
+ this.roleAgentMap.set(topology.companions![i].role, companionIds[i] as AgentId);
196
+ this.agentRoleMap.set(companionIds[i] as AgentId, topology.companions![i].role);
197
+ }
198
+ this.wirePeerRoutes();
199
+
200
+ // 4. Install signal filter on message router
201
+ this.installSignalFilter();
202
+
203
+ // 5. Install emission validator on message router
204
+ this.installEmissionValidator();
205
+
206
+ // 6. Set up continuation monitoring for daemon agents (P4.2)
207
+ this.monitorContinuations();
208
+
209
+ return {
210
+ rootId: root.id,
211
+ companionIds,
212
+ };
213
+ }
214
+
215
+ // ─────────────────────────────────────────────────────────────
216
+ // Teardown
217
+ // ─────────────────────────────────────────────────────────────
218
+
219
+ /**
220
+ * Tear down team: remove spawn interceptor, stop continuation monitoring.
221
+ */
222
+ async teardown(): Promise<void> {
223
+ this.services.agentManager.setSpawnInterceptor(null);
224
+ if (this.lifecycleUnsubscribe) {
225
+ this.lifecycleUnsubscribe();
226
+ this.lifecycleUnsubscribe = undefined;
227
+ }
228
+ if (this.peerWiringUnsubscribe) {
229
+ this.peerWiringUnsubscribe();
230
+ this.peerWiringUnsubscribe = undefined;
231
+ }
232
+ // Call strategy lifecycle close hook
233
+ if (this.integrationStrategy?.close) {
234
+ try {
235
+ await this.integrationStrategy.close();
236
+ } catch {
237
+ // Best-effort cleanup
238
+ }
239
+ }
240
+ }
241
+
242
+ // ─────────────────────────────────────────────────────────────
243
+ // Getters
244
+ // ─────────────────────────────────────────────────────────────
245
+
246
+ /** Get task assignment mode */
247
+ getTaskMode(): "push" | "pull" {
248
+ return this.manifest.macro_agent.task_assignment?.mode ?? "push";
249
+ }
250
+
251
+ /** Get integration strategy name */
252
+ getStrategyName(): string {
253
+ return this.manifest.macro_agent.integration?.strategy ?? "queue";
254
+ }
255
+
256
+ /** Get the active manifest (for API) */
257
+ getManifest(): TeamManifest {
258
+ return this.manifest;
259
+ }
260
+
261
+ /** Get root agent ID (after bootstrap) */
262
+ getRootAgentId(): string | undefined {
263
+ return this.rootAgentId;
264
+ }
265
+
266
+ /** Get companion agent IDs (after bootstrap) */
267
+ getCompanionAgentIds(): string[] {
268
+ return [...this.companionAgentIds];
269
+ }
270
+
271
+ /** Get the instantiated integration strategy (after initialize) */
272
+ getIntegrationStrategy(): IntegrationStrategy | undefined {
273
+ return this.integrationStrategy;
274
+ }
275
+
276
+ /** Get signal filters for peer connections (for use by signal filtering - i-3o8g) */
277
+ getPeerSignalFilters(): ReadonlyMap<string, string[]> {
278
+ return this.peerSignalFilters;
279
+ }
280
+
281
+ // ─────────────────────────────────────────────────────────────
282
+ // Continuation Monitoring (P4.2)
283
+ // ─────────────────────────────────────────────────────────────
284
+
285
+ /**
286
+ * Monitor agent lifecycle events for auto-continuation of daemon agents.
287
+ *
288
+ * When a root or companion agent terminates unexpectedly and the team's
289
+ * lifecycle config enables continuations, automatically spawn a continuation.
290
+ */
291
+ private monitorContinuations(): void {
292
+ const lifecycleConfig = this.manifest.macro_agent.lifecycle;
293
+ if (!lifecycleConfig?.continuations?.enabled) return;
294
+
295
+ const { agentManager } = this.services;
296
+ const monitoredAgents = new Set([
297
+ this.rootAgentId,
298
+ ...this.companionAgentIds,
299
+ ]);
300
+
301
+ this.lifecycleUnsubscribe = agentManager.onLifecycleEvent((event) => {
302
+ if (event.type !== "stopped") return;
303
+ if (!monitoredAgents.has(event.agent.id)) return;
304
+
305
+ // Only auto-continue on unexpected stops (not explicit completion)
306
+ const reason = (event as { reason?: string }).reason;
307
+ if (reason === "completed" || reason === "cancelled") return;
308
+
309
+ // Schedule auto-continuation (async, fire-and-forget)
310
+ setTimeout(async () => {
311
+ try {
312
+ const newAgent = await agentManager.continueAgent(event.agent.id);
313
+ // Update monitoring set
314
+ monitoredAgents.delete(event.agent.id);
315
+ monitoredAgents.add(newAgent.id);
316
+
317
+ if (event.agent.id === this.rootAgentId) {
318
+ this.rootAgentId = newAgent.id;
319
+ } else {
320
+ const idx = this.companionAgentIds.indexOf(event.agent.id);
321
+ if (idx >= 0) {
322
+ this.companionAgentIds[idx] = newAgent.id;
323
+ }
324
+ }
325
+ } catch {
326
+ // Failed to continue — agent is gone
327
+ }
328
+ }, 1000);
329
+ });
330
+ }
331
+
332
+ // ─────────────────────────────────────────────────────────────
333
+ // Spawn Interceptor
334
+ // ─────────────────────────────────────────────────────────────
335
+
336
+ /**
337
+ * Create the spawn interceptor that injects team context into spawn options.
338
+ */
339
+ private createSpawnInterceptor(): SpawnInterceptor {
340
+ return (options: SpawnAgentOptions): SpawnAgentOptions => {
341
+ const roleName = options.role;
342
+ if (!roleName) return options;
343
+
344
+ const resolved = this.manifest._resolvedRoles.get(roleName);
345
+ if (!resolved) return options; // Unknown role — pass through
346
+
347
+ // Compute topics from communication topology
348
+ const teamTopics = this.getTopicsForRole(roleName);
349
+
350
+ // Get MCP servers for this role
351
+ const teamMcpServers = this.getMcpServersForRole(roleName);
352
+
353
+ // Get prompt from role definition or topology
354
+ const teamPrompt = this.getPromptForRole(roleName);
355
+
356
+ // Build team env vars
357
+ const teamEnv: Record<string, string> = {
358
+ MACRO_TEAM_NAME: this.manifest.name,
359
+ MACRO_TASK_MODE: this.getTaskMode(),
360
+ };
361
+ const strategyName = this.getStrategyName();
362
+ if (strategyName) {
363
+ teamEnv.MACRO_INTEGRATION_STRATEGY = strategyName;
364
+ }
365
+
366
+ return {
367
+ ...options,
368
+ // Merge topics
369
+ topics: [
370
+ ...(options.topics ?? []),
371
+ ...teamTopics,
372
+ ],
373
+ // Merge config
374
+ config: {
375
+ ...options.config,
376
+ mcpServers: [
377
+ ...(options.config?.mcpServers ?? []),
378
+ ...teamMcpServers.map((s) => ({
379
+ name: s.name,
380
+ command: s.command,
381
+ args: s.args,
382
+ env: s.env,
383
+ })),
384
+ ],
385
+ env: {
386
+ ...options.config?.env,
387
+ ...teamEnv,
388
+ },
389
+ },
390
+ // Set team prompt (only if not already provided by caller)
391
+ customPrompt: options.customPrompt ?? teamPrompt,
392
+ // Set interaction patterns (only if not already provided)
393
+ interactionPatterns: options.interactionPatterns ?? this.getInteractionPatterns(),
394
+ };
395
+ };
396
+ }
397
+
398
+ // ─────────────────────────────────────────────────────────────
399
+ // Communication Topology Helpers
400
+ // ─────────────────────────────────────────────────────────────
401
+
402
+ /**
403
+ * Get topic names a role should subscribe to based on communication config.
404
+ */
405
+ private getTopicsForRole(roleName: string): string[] {
406
+ const topics: string[] = [];
407
+ const subs = this.manifest.communication.subscriptions?.[roleName] ?? [];
408
+
409
+ for (const sub of subs) {
410
+ // Channel name becomes the topic name
411
+ if (!topics.includes(sub.channel)) {
412
+ topics.push(sub.channel);
413
+ }
414
+ }
415
+
416
+ return topics;
417
+ }
418
+
419
+ /**
420
+ * Get MCP servers configured for a role.
421
+ */
422
+ private getMcpServersForRole(roleName: string): McpServerEntry[] {
423
+ return this.manifest._mcpServers.get(roleName) ?? [];
424
+ }
425
+
426
+ /**
427
+ * Get the loaded prompt content for a role.
428
+ */
429
+ private getPromptForRole(roleName: string): string | undefined {
430
+ const resolved = this.manifest._resolvedRoles.get(roleName);
431
+ if (!resolved?.prompt) return undefined;
432
+ return this.manifest._loadedPrompts.get(resolved.prompt);
433
+ }
434
+
435
+ /**
436
+ * Get the prompt for a topology node (root or companion).
437
+ */
438
+ private getPromptForTopologyNode(
439
+ node: { role: string; prompt?: string }
440
+ ): string | undefined {
441
+ // Prefer topology-level prompt reference
442
+ if (node.prompt) {
443
+ return this.manifest._loadedPrompts.get(node.prompt);
444
+ }
445
+ // Fall back to role-level prompt
446
+ return this.getPromptForRole(node.role);
447
+ }
448
+
449
+ /**
450
+ * Generate interaction pattern injection sections based on team config.
451
+ */
452
+ private getInteractionPatterns(): string[] {
453
+ const patterns: string[] = [];
454
+ const taskMode = this.getTaskMode();
455
+
456
+ if (taskMode === "pull") {
457
+ const pullConfig = this.manifest.macro_agent.task_assignment?.pull;
458
+ const idleTimeout = pullConfig?.idle_timeout_s ?? 300;
459
+
460
+ patterns.push(`## Task Claiming
461
+
462
+ You operate in PULL mode. After completing a task:
463
+ 1. Call done() with your results
464
+ 2. Call claim_task() to get your next task
465
+ 3. If no tasks available, wait briefly and retry
466
+ 4. After ${idleTimeout} seconds idle, call done() to exit gracefully
467
+
468
+ Claim and execute independently — do not wait for instructions.`);
469
+ }
470
+
471
+ const strategy = this.getStrategyName();
472
+ if (strategy === "trunk") {
473
+ patterns.push(`## Integration
474
+
475
+ Your changes are integrated via trunk-based development. When you call done(),
476
+ your work is pushed directly to the integration branch. If there's a conflict,
477
+ the system will rebase and retry automatically. Write small, focused changes
478
+ to minimize conflict probability.`);
479
+ } else if (strategy === "optimistic") {
480
+ patterns.push(`## Integration
481
+
482
+ Your changes are integrated optimistically. They are pushed immediately and
483
+ validated asynchronously. If validation fails, a fixup task will be created.
484
+ Focus on correctness — your changes go live immediately.`);
485
+ }
486
+
487
+ return patterns;
488
+ }
489
+
490
+ // ─────────────────────────────────────────────────────────────
491
+ // Signal Filtering
492
+ // ─────────────────────────────────────────────────────────────
493
+
494
+ /**
495
+ * Install a signal filter on the message router.
496
+ *
497
+ * Combines two filter sources:
498
+ * 1. Channel subscription filters (per-role, per-topic): from communication.subscriptions
499
+ * 2. Peer connection filters (per-agent-pair): from communication.routing.peers
500
+ *
501
+ * Status events with no details.signal always pass through (backwards compat).
502
+ */
503
+ private installSignalFilter(): void {
504
+ const { messageRouter } = this.services;
505
+
506
+ // Pre-compute per-role allowed signals from channel subscriptions.
507
+ // Key: role name, Value: Set of allowed signal names.
508
+ // If a role has any subscription without a signals filter, it receives all signals.
509
+ const roleAllowedSignals = new Map<string, Set<string> | "all">();
510
+
511
+ for (const [roleName, subs] of Object.entries(this.manifest.communication.subscriptions ?? {})) {
512
+ let allowed: Set<string> | "all" = new Set<string>();
513
+
514
+ for (const sub of subs) {
515
+ if (!sub.signals || sub.signals.length === 0) {
516
+ // No filter on this subscription — role receives all signals
517
+ allowed = "all";
518
+ break;
519
+ }
520
+ for (const sig of sub.signals) {
521
+ (allowed as Set<string>).add(sig);
522
+ }
523
+ }
524
+
525
+ roleAllowedSignals.set(roleName, allowed);
526
+ }
527
+
528
+ if (messageRouter.setSignalFilter) {
529
+ messageRouter.setSignalFilter((from, to, signal) => {
530
+ // Untagged status events always pass through
531
+ if (!signal) return true;
532
+
533
+ // Check peer connection filter (directional: from→to)
534
+ const peerFilter = this.peerSignalFilters.get(`${from}→${to}`);
535
+ if (peerFilter) {
536
+ return peerFilter.includes(signal);
537
+ }
538
+
539
+ // Check channel subscription filter for recipient's role
540
+ const recipientRole = this.agentRoleMap.get(to);
541
+ if (recipientRole) {
542
+ const allowed = roleAllowedSignals.get(recipientRole);
543
+ if (allowed && allowed !== "all") {
544
+ return allowed.has(signal);
545
+ }
546
+ }
547
+
548
+ // No filter configured — allow delivery
549
+ return true;
550
+ });
551
+ }
552
+ }
553
+
554
+ // ─────────────────────────────────────────────────────────────
555
+ // Emission Validation
556
+ // ─────────────────────────────────────────────────────────────
557
+
558
+ /**
559
+ * Install emission validator on the message router.
560
+ * Checks whether an agent's emitted signal is in its role's allowed emissions list.
561
+ * Behavior depends on enforcement mode: strict (reject), permissive (warn), audit (record).
562
+ */
563
+ private installEmissionValidator(): void {
564
+ const { messageRouter } = this.services;
565
+ const emissions = this.manifest.communication.emissions;
566
+ const enforcement = this.manifest.communication.enforcement ?? "permissive";
567
+
568
+ // No emissions config — nothing to enforce
569
+ if (!emissions || Object.keys(emissions).length === 0) return;
570
+
571
+ if (messageRouter.setEmissionValidator) {
572
+ messageRouter.setEmissionValidator((agentId, signal) => {
573
+ // Untagged status events are always allowed
574
+ if (!signal) return { action: "allow" };
575
+
576
+ const role = this.agentRoleMap.get(agentId);
577
+ if (!role) return { action: "allow" };
578
+
579
+ const allowedSignals = emissions[role];
580
+ if (!allowedSignals) return { action: "allow" };
581
+
582
+ if (allowedSignals.includes(signal)) {
583
+ return { action: "allow" };
584
+ }
585
+
586
+ // Signal not in allowed list — enforce
587
+ const message = `Agent '${agentId}' (role: ${role}) emitted disallowed signal '${signal}'. Allowed: [${allowedSignals.join(", ")}]`;
588
+
589
+ switch (enforcement) {
590
+ case "strict":
591
+ return { action: "reject", message };
592
+ case "audit":
593
+ return { action: "audit", message };
594
+ case "permissive":
595
+ default:
596
+ return { action: "warn", message };
597
+ }
598
+ });
599
+ }
600
+ }
601
+
602
+ // ─────────────────────────────────────────────────────────────
603
+ // Peer Routing
604
+ // ─────────────────────────────────────────────────────────────
605
+
606
+ /**
607
+ * Wire peer subscriptions from communication config.
608
+ * Falls back to legacy bidirectional subtree subs when no peers config exists.
609
+ */
610
+ private wirePeerRoutes(): void {
611
+ const peers = this.manifest.communication.routing?.peers;
612
+
613
+ if (!peers || peers.length === 0) {
614
+ // Fallback: hardcoded mutual subtree subscriptions (backwards compat)
615
+ this.setupLegacyPeerSubscriptions();
616
+ return;
617
+ }
618
+
619
+ this.pendingPeerRoutes = [];
620
+
621
+ for (const peer of peers) {
622
+ const fromAgent = this.roleAgentMap.get(peer.from);
623
+ const toAgent = this.roleAgentMap.get(peer.to);
624
+
625
+ if (!fromAgent || !toAgent) {
626
+ // One or both roles not yet spawned — defer
627
+ this.pendingPeerRoutes.push(peer);
628
+ continue;
629
+ }
630
+
631
+ this.wireSinglePeerRoute(peer, fromAgent, toAgent);
632
+ }
633
+
634
+ // If there are pending routes, set up lifecycle listener for deferred wiring
635
+ if (this.pendingPeerRoutes.length > 0) {
636
+ this.setupDeferredPeerWiring();
637
+ }
638
+ }
639
+
640
+ /**
641
+ * Wire a single peer connection based on its `via` type.
642
+ */
643
+ private wireSinglePeerRoute(
644
+ peer: PeerConnection,
645
+ fromAgent: AgentId,
646
+ toAgent: AgentId
647
+ ): void {
648
+ const { messageRouter } = this.services;
649
+
650
+ switch (peer.via) {
651
+ case "direct":
652
+ // Directional: from receives status events from to's subtree
653
+ messageRouter.subscribe(fromAgent, { type: "subtree", target: toAgent });
654
+ break;
655
+
656
+ case "topic": {
657
+ // Both agents share a named topic
658
+ const topicName = `peer:${peer.from}:${peer.to}`;
659
+ messageRouter.subscribe(fromAgent, { type: "topic", target: topicName });
660
+ messageRouter.subscribe(toAgent, { type: "topic", target: topicName });
661
+ break;
662
+ }
663
+
664
+ case "scope":
665
+ // from subscribes to to's role channel
666
+ messageRouter.subscribe(fromAgent, { type: "role", target: peer.to });
667
+ break;
668
+ }
669
+
670
+ // Store signal filter if specified
671
+ if (peer.signals && peer.signals.length > 0) {
672
+ const key = `${fromAgent}→${toAgent}`;
673
+ this.peerSignalFilters.set(key, peer.signals);
674
+ }
675
+ }
676
+
677
+ /**
678
+ * Legacy bidirectional subtree subscriptions between root and companions.
679
+ * Used when no `routing.peers` config is defined (backwards compat).
680
+ */
681
+ private setupLegacyPeerSubscriptions(): void {
682
+ const { messageRouter } = this.services;
683
+
684
+ if (!this.rootAgentId) return;
685
+ for (const companionId of this.companionAgentIds) {
686
+ messageRouter.subscribe(this.rootAgentId as AgentId, { type: "subtree", target: companionId as AgentId });
687
+ messageRouter.subscribe(companionId as AgentId, { type: "subtree", target: this.rootAgentId as AgentId });
688
+ }
689
+ }
690
+
691
+ /**
692
+ * Listen for agent spawns and wire pending peer routes when roles become available.
693
+ */
694
+ private setupDeferredPeerWiring(): void {
695
+ const { agentManager } = this.services;
696
+
697
+ this.peerWiringUnsubscribe = agentManager.onLifecycleEvent((event) => {
698
+ if (event.type !== "spawned") return;
699
+ const role = event.agent.role;
700
+ if (!role) return;
701
+
702
+ // Update role↔agent mappings
703
+ this.roleAgentMap.set(role, event.agent.id as AgentId);
704
+ this.agentRoleMap.set(event.agent.id as AgentId, role);
705
+
706
+ // Try to wire any pending routes involving this role
707
+ const stillPending: PeerConnection[] = [];
708
+ for (const peer of this.pendingPeerRoutes) {
709
+ const fromAgent = this.roleAgentMap.get(peer.from);
710
+ const toAgent = this.roleAgentMap.get(peer.to);
711
+
712
+ if (fromAgent && toAgent) {
713
+ this.wireSinglePeerRoute(peer, fromAgent, toAgent);
714
+ } else {
715
+ stillPending.push(peer);
716
+ }
717
+ }
718
+ this.pendingPeerRoutes = stillPending;
719
+
720
+ // All wired — unsubscribe
721
+ if (stillPending.length === 0 && this.peerWiringUnsubscribe) {
722
+ this.peerWiringUnsubscribe();
723
+ this.peerWiringUnsubscribe = undefined;
724
+ }
725
+ });
726
+ }
727
+ }