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,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
+ }