macro-agent 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/.sudocode/specs.jsonl +4 -0
  3. package/CLAUDE.md +16 -14
  4. package/README.md +11 -29
  5. package/dist/acp/macro-agent.d.ts +15 -0
  6. package/dist/acp/macro-agent.d.ts.map +1 -1
  7. package/dist/acp/macro-agent.js +131 -35
  8. package/dist/acp/macro-agent.js.map +1 -1
  9. package/dist/acp/types.d.ts +32 -1
  10. package/dist/acp/types.d.ts.map +1 -1
  11. package/dist/acp/types.js.map +1 -1
  12. package/dist/agent/agent-manager.d.ts +65 -1
  13. package/dist/agent/agent-manager.d.ts.map +1 -1
  14. package/dist/agent/agent-manager.js +464 -183
  15. package/dist/agent/agent-manager.js.map +1 -1
  16. package/dist/agent/types.d.ts +1 -1
  17. package/dist/agent/types.d.ts.map +1 -1
  18. package/dist/api/server.d.ts +3 -0
  19. package/dist/api/server.d.ts.map +1 -1
  20. package/dist/api/server.js +37 -6
  21. package/dist/api/server.js.map +1 -1
  22. package/dist/auth/index.d.ts +2 -0
  23. package/dist/auth/index.d.ts.map +1 -0
  24. package/dist/auth/index.js +2 -0
  25. package/dist/auth/index.js.map +1 -0
  26. package/dist/auth/token.d.ts +41 -0
  27. package/dist/auth/token.d.ts.map +1 -0
  28. package/dist/auth/token.js +73 -0
  29. package/dist/auth/token.js.map +1 -0
  30. package/dist/cli/acp.d.ts +2 -23
  31. package/dist/cli/acp.d.ts.map +1 -1
  32. package/dist/cli/acp.js +127 -61
  33. package/dist/cli/acp.js.map +1 -1
  34. package/dist/cli/index.js +147 -15
  35. package/dist/cli/index.js.map +1 -1
  36. package/dist/cli/mcp.d.ts +6 -0
  37. package/dist/cli/mcp.d.ts.map +1 -1
  38. package/dist/cli/mcp.js +268 -181
  39. package/dist/cli/mcp.js.map +1 -1
  40. package/dist/cli/parse-args.d.ts +20 -0
  41. package/dist/cli/parse-args.d.ts.map +1 -0
  42. package/dist/cli/parse-args.js +43 -0
  43. package/dist/cli/parse-args.js.map +1 -0
  44. package/dist/cli/stable-instance-id.d.ts +8 -0
  45. package/dist/cli/stable-instance-id.d.ts.map +1 -0
  46. package/dist/cli/stable-instance-id.js +14 -0
  47. package/dist/cli/stable-instance-id.js.map +1 -0
  48. package/dist/config/project-config.d.ts +74 -7
  49. package/dist/config/project-config.d.ts.map +1 -1
  50. package/dist/config/project-config.js +123 -20
  51. package/dist/config/project-config.js.map +1 -1
  52. package/dist/map/adapter/acp-over-map.d.ts +17 -0
  53. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  54. package/dist/map/adapter/acp-over-map.js +384 -23
  55. package/dist/map/adapter/acp-over-map.js.map +1 -1
  56. package/dist/map/adapter/connection-manager.d.ts.map +1 -1
  57. package/dist/map/adapter/connection-manager.js +3 -0
  58. package/dist/map/adapter/connection-manager.js.map +1 -1
  59. package/dist/map/adapter/event-log.d.ts +87 -0
  60. package/dist/map/adapter/event-log.d.ts.map +1 -0
  61. package/dist/map/adapter/event-log.js +122 -0
  62. package/dist/map/adapter/event-log.js.map +1 -0
  63. package/dist/map/adapter/event-translator.js +6 -6
  64. package/dist/map/adapter/event-translator.js.map +1 -1
  65. package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
  66. package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
  67. package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
  68. package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
  69. package/dist/map/adapter/extensions/index.d.ts +10 -1
  70. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  71. package/dist/map/adapter/extensions/index.js +34 -0
  72. package/dist/map/adapter/extensions/index.js.map +1 -1
  73. package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
  74. package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
  75. package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
  76. package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
  77. package/dist/map/adapter/extensions/rename.d.ts +29 -0
  78. package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
  79. package/dist/map/adapter/extensions/rename.js +49 -0
  80. package/dist/map/adapter/extensions/rename.js.map +1 -0
  81. package/dist/map/adapter/extensions/task.d.ts.map +1 -1
  82. package/dist/map/adapter/extensions/task.js +10 -0
  83. package/dist/map/adapter/extensions/task.js.map +1 -1
  84. package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
  85. package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
  86. package/dist/map/adapter/extensions/update-metadata.js +67 -0
  87. package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
  88. package/dist/map/adapter/index.d.ts +2 -1
  89. package/dist/map/adapter/index.d.ts.map +1 -1
  90. package/dist/map/adapter/index.js +8 -2
  91. package/dist/map/adapter/index.js.map +1 -1
  92. package/dist/map/adapter/interface.d.ts +2 -0
  93. package/dist/map/adapter/interface.d.ts.map +1 -1
  94. package/dist/map/adapter/map-adapter.d.ts +3 -0
  95. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  96. package/dist/map/adapter/map-adapter.js +258 -35
  97. package/dist/map/adapter/map-adapter.js.map +1 -1
  98. package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
  99. package/dist/map/adapter/subscription-manager.js +5 -1
  100. package/dist/map/adapter/subscription-manager.js.map +1 -1
  101. package/dist/map/adapter/types.d.ts +2 -0
  102. package/dist/map/adapter/types.d.ts.map +1 -1
  103. package/dist/mcp/map-client.d.ts +39 -0
  104. package/dist/mcp/map-client.d.ts.map +1 -0
  105. package/dist/mcp/map-client.js +129 -0
  106. package/dist/mcp/map-client.js.map +1 -0
  107. package/dist/mcp/mcp-server.d.ts +14 -0
  108. package/dist/mcp/mcp-server.d.ts.map +1 -1
  109. package/dist/mcp/mcp-server.js +113 -85
  110. package/dist/mcp/mcp-server.js.map +1 -1
  111. package/dist/mcp/types.d.ts +9 -1
  112. package/dist/mcp/types.d.ts.map +1 -1
  113. package/dist/mcp/types.js.map +1 -1
  114. package/dist/metrics/metrics.js +1 -1
  115. package/dist/metrics/metrics.js.map +1 -1
  116. package/dist/roles/capabilities.d.ts +3 -1
  117. package/dist/roles/capabilities.d.ts.map +1 -1
  118. package/dist/roles/capabilities.js +17 -7
  119. package/dist/roles/capabilities.js.map +1 -1
  120. package/dist/roles/config-loader.d.ts +6 -6
  121. package/dist/roles/config-loader.d.ts.map +1 -1
  122. package/dist/roles/config-loader.js +6 -6
  123. package/dist/roles/config-loader.js.map +1 -1
  124. package/dist/roles/registry.d.ts +2 -2
  125. package/dist/roles/registry.js +2 -2
  126. package/dist/server/combined-server.d.ts +20 -0
  127. package/dist/server/combined-server.d.ts.map +1 -1
  128. package/dist/server/combined-server.js +107 -8
  129. package/dist/server/combined-server.js.map +1 -1
  130. package/dist/store/event-store.d.ts +2 -1
  131. package/dist/store/event-store.d.ts.map +1 -1
  132. package/dist/store/event-store.js +69 -20
  133. package/dist/store/event-store.js.map +1 -1
  134. package/dist/store/types/agents.d.ts +18 -0
  135. package/dist/store/types/agents.d.ts.map +1 -1
  136. package/dist/store/types/events.d.ts +1 -1
  137. package/dist/store/types/events.d.ts.map +1 -1
  138. package/dist/task/backend/index.d.ts +47 -29
  139. package/dist/task/backend/index.d.ts.map +1 -1
  140. package/dist/task/backend/index.js +109 -71
  141. package/dist/task/backend/index.js.map +1 -1
  142. package/dist/task/backend/memory.d.ts +1 -0
  143. package/dist/task/backend/memory.d.ts.map +1 -1
  144. package/dist/task/backend/memory.js +3 -0
  145. package/dist/task/backend/memory.js.map +1 -1
  146. package/dist/task/backend/opentasks/backend.d.ts +140 -0
  147. package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
  148. package/dist/task/backend/opentasks/backend.js +1023 -0
  149. package/dist/task/backend/opentasks/backend.js.map +1 -0
  150. package/dist/task/backend/opentasks/client.d.ts +337 -0
  151. package/dist/task/backend/opentasks/client.d.ts.map +1 -0
  152. package/dist/task/backend/opentasks/client.js +225 -0
  153. package/dist/task/backend/opentasks/client.js.map +1 -0
  154. package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
  155. package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
  156. package/dist/task/backend/opentasks/daemon-manager.js +195 -0
  157. package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
  158. package/dist/task/backend/opentasks/index.d.ts +21 -0
  159. package/dist/task/backend/opentasks/index.d.ts.map +1 -0
  160. package/dist/task/backend/opentasks/index.js +21 -0
  161. package/dist/task/backend/opentasks/index.js.map +1 -0
  162. package/dist/task/backend/opentasks/mapping.d.ts +48 -0
  163. package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
  164. package/dist/task/backend/opentasks/mapping.js +77 -0
  165. package/dist/task/backend/opentasks/mapping.js.map +1 -0
  166. package/dist/task/backend/types.d.ts +33 -53
  167. package/dist/task/backend/types.d.ts.map +1 -1
  168. package/dist/task/backend/types.js +7 -11
  169. package/dist/task/backend/types.js.map +1 -1
  170. package/dist/task/backend/unified-tool-provider.d.ts +57 -0
  171. package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
  172. package/dist/task/backend/unified-tool-provider.js +623 -0
  173. package/dist/task/backend/unified-tool-provider.js.map +1 -0
  174. package/dist/teams/team-loader.d.ts +2 -2
  175. package/dist/teams/team-loader.js +3 -3
  176. package/dist/teams/team-loader.js.map +1 -1
  177. package/dist/teams/team-runtime.d.ts.map +1 -1
  178. package/dist/teams/team-runtime.js +2 -0
  179. package/dist/teams/team-runtime.js.map +1 -1
  180. package/docs/architecture.md +7 -6
  181. package/docs/configuration.md +26 -62
  182. package/docs/implementation-details.md +5 -5
  183. package/docs/implementation-summary.md +17 -17
  184. package/docs/plan-self-driving-support.md +4 -4
  185. package/docs/spec-self-driving-support.md +10 -10
  186. package/docs/team-templates.md +2 -2
  187. package/docs/teams.md +3 -3
  188. package/docs/troubleshooting.md +10 -11
  189. package/package.json +6 -4
  190. package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
  191. package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
  192. package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
  193. package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
  194. package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
  195. package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
  196. package/src/acp/__tests__/integration.test.ts +56 -31
  197. package/src/acp/__tests__/macro-agent.test.ts +16 -7
  198. package/src/acp/macro-agent.ts +170 -36
  199. package/src/acp/types.ts +46 -1
  200. package/src/agent/__tests__/agent-manager.test.ts +228 -2
  201. package/src/agent/agent-manager.ts +714 -261
  202. package/src/agent/types.ts +3 -1
  203. package/src/api/server.ts +41 -7
  204. package/src/auth/__tests__/token.test.ts +100 -0
  205. package/src/auth/index.ts +1 -0
  206. package/src/auth/token.ts +82 -0
  207. package/src/cli/__tests__/acp.test.ts +1 -1
  208. package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
  209. package/src/cli/acp.ts +130 -72
  210. package/src/cli/index.ts +120 -14
  211. package/src/cli/mcp.ts +311 -207
  212. package/src/cli/parse-args.ts +54 -0
  213. package/src/cli/stable-instance-id.ts +14 -0
  214. package/src/config/project-config.ts +190 -27
  215. package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
  216. package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +22 -4
  217. package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
  218. package/src/map/adapter/__tests__/acp-over-map-history.test.ts +263 -0
  219. package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
  220. package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
  221. package/src/map/adapter/__tests__/event-log.test.ts +527 -0
  222. package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
  223. package/src/map/adapter/__tests__/extensions.test.ts +408 -0
  224. package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
  225. package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
  226. package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
  227. package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
  228. package/src/map/adapter/acp-over-map.ts +678 -66
  229. package/src/map/adapter/connection-manager.ts +3 -0
  230. package/src/map/adapter/event-log.ts +208 -0
  231. package/src/map/adapter/event-translator.ts +6 -6
  232. package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
  233. package/src/map/adapter/extensions/index.ts +60 -0
  234. package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
  235. package/src/map/adapter/extensions/task.ts +11 -0
  236. package/src/map/adapter/extensions/update-metadata.ts +126 -0
  237. package/src/map/adapter/index.ts +28 -0
  238. package/src/map/adapter/interface.ts +2 -0
  239. package/src/map/adapter/map-adapter.ts +312 -47
  240. package/src/map/adapter/subscription-manager.ts +5 -1
  241. package/src/map/adapter/types.ts +2 -0
  242. package/src/mcp/__tests__/map-client.test.ts +386 -0
  243. package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
  244. package/src/mcp/__tests__/mcp-server.test.ts +100 -1
  245. package/src/mcp/map-client.ts +177 -0
  246. package/src/mcp/mcp-server.ts +191 -100
  247. package/src/mcp/types.ts +6 -1
  248. package/src/metrics/metrics.ts +1 -1
  249. package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
  250. package/src/roles/__tests__/config-loader.test.ts +7 -7
  251. package/src/roles/capabilities.ts +17 -7
  252. package/src/roles/config-loader.ts +6 -6
  253. package/src/roles/registry.ts +2 -2
  254. package/src/server/__tests__/combined-server.test.ts +94 -21
  255. package/src/server/combined-server.ts +189 -33
  256. package/src/steering/__tests__/steering-integration.test.ts +1 -1
  257. package/src/store/__tests__/event-store.test.ts +196 -1
  258. package/src/store/__tests__/instance.test.ts +3 -3
  259. package/src/store/event-store.ts +80 -21
  260. package/src/store/types/agents.ts +15 -0
  261. package/src/store/types/events.ts +1 -1
  262. package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
  263. package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
  264. package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
  265. package/src/task/backend/index.ts +156 -106
  266. package/src/task/backend/memory.ts +4 -0
  267. package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
  268. package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
  269. package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
  270. package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
  271. package/src/task/backend/opentasks/backend.ts +1323 -0
  272. package/src/task/backend/opentasks/client.ts +652 -0
  273. package/src/task/backend/opentasks/daemon-manager.ts +253 -0
  274. package/src/task/backend/opentasks/index.ts +69 -0
  275. package/src/task/backend/opentasks/mapping.ts +94 -0
  276. package/src/task/backend/types.ts +42 -66
  277. package/src/task/backend/unified-tool-provider.ts +779 -0
  278. package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
  279. package/src/teams/team-loader.ts +3 -3
  280. package/src/teams/team-runtime.ts +2 -0
  281. package/test_fixtures/README.md +2 -3
  282. package/test_fixtures/fixtures/index.ts +0 -3
  283. package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
  284. package/test_fixtures/fixtures/repos/index.ts +1 -3
  285. package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
  286. package/test_fixtures/fixtures/repos/types.ts +0 -11
  287. package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
  288. package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
  289. package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
  290. package/vitest.config.ts +1 -1
  291. package/vitest.e2e.config.ts +1 -1
  292. package/vitest.setup.ts +1 -30
  293. package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
  294. package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
  295. package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
  296. package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
  297. package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
  298. package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
  299. package/.macro-agent/teams/self-driving/team.yaml +0 -103
  300. package/.macro-agent/teams/structured/prompts/developer.md +0 -26
  301. package/.macro-agent/teams/structured/prompts/lead.md +0 -25
  302. package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
  303. package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
  304. package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
  305. package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
  306. package/.macro-agent/teams/structured/team.yaml +0 -89
  307. package/docs/sudocode-integration.md +0 -383
  308. package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
  309. package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
  310. package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
  311. package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
  312. package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
  313. package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
  314. package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
  315. package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
  316. package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
  317. package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
  318. package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
  319. package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
  320. package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
  321. package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
  322. package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
  323. package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
  324. package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
  325. package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
  326. package/src/task/backend/sudocode/backend.ts +0 -1237
  327. package/src/task/backend/sudocode/client.ts +0 -515
  328. package/src/task/backend/sudocode/index.ts +0 -120
  329. package/src/task/backend/sudocode/mapping.ts +0 -93
  330. package/src/task/backend/sudocode/server-client.ts +0 -522
  331. package/src/task/backend/sudocode/standalone-client.ts +0 -623
  332. package/src/task/backend/sudocode/sync-policy.ts +0 -387
  333. package/src/task/backend/sudocode/tools.ts +0 -896
  334. package/src/task/backend/tool-provider.ts +0 -506
  335. package/test_fixtures/fixtures/sudocode/index.ts +0 -29
  336. package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
  337. package/test_fixtures/fixtures/sudocode/specs.ts +0 -159
@@ -14,6 +14,8 @@ import {
14
14
  unregisterResumeExtension,
15
15
  registerAgentDetectionExtensions,
16
16
  unregisterAgentDetectionExtensions,
17
+ registerAgentLifecycleExtensions,
18
+ unregisterAgentLifecycleExtensions,
17
19
  registerMacroExtensions,
18
20
  MACRO_EXTENSION_METHODS,
19
21
  EXTENSION_CAPABILITIES,
@@ -22,6 +24,7 @@ import {
22
24
  type WorkspaceExtensionServices,
23
25
  type ResumeExtensionServices,
24
26
  type AgentDetectionExtensionServices,
27
+ type AgentLifecycleExtensionServices,
25
28
  } from "../extensions/index.js";
26
29
  import type { MAPAdapter, ExtensionHandler, ExtensionContext } from "../interface.js";
27
30
  import type { ParticipantCapabilities } from "../types.js";
@@ -891,6 +894,389 @@ describe("Agent Detection Extensions", () => {
891
894
  });
892
895
  });
893
896
 
897
+ // =============================================================================
898
+ // Agent Lifecycle Extension Tests
899
+ // =============================================================================
900
+
901
+ describe("Agent Lifecycle Extensions", () => {
902
+ let adapter: MAPAdapter & { handlers: Map<string, ExtensionHandler> };
903
+ let services: AgentLifecycleExtensionServices;
904
+
905
+ beforeEach(() => {
906
+ adapter = createMockAdapter();
907
+
908
+ services = {
909
+ getAgent: vi.fn().mockReturnValue({
910
+ id: "agent-1" as AgentId,
911
+ state: "running",
912
+ session_id: "session-1",
913
+ cwd: "/test/cwd",
914
+ }),
915
+ spawn: vi.fn().mockResolvedValue({
916
+ id: "agent-2" as AgentId,
917
+ session_id: "session-2",
918
+ }),
919
+ forkAgent: vi.fn().mockResolvedValue({
920
+ id: "agent-3" as AgentId,
921
+ session_id: "session-3",
922
+ session: { id: "provider-session-3" },
923
+ }),
924
+ prompt: vi.fn().mockReturnValue((async function* () {})()),
925
+ setPermissionMode: vi.fn().mockReturnValue(true),
926
+ getPermissionMode: vi.fn().mockReturnValue("default"),
927
+ respondToPermission: vi.fn().mockReturnValue(true),
928
+ onAgentRegistered: vi.fn(),
929
+ listHeadManagers: vi.fn().mockReturnValue([{ id: "head-1" as AgentId }]),
930
+ defaultCwd: "/default/cwd",
931
+ };
932
+ });
933
+
934
+ describe("registration", () => {
935
+ it("registers all agent lifecycle methods", () => {
936
+ registerAgentLifecycleExtensions(adapter, services);
937
+
938
+ expect(adapter.handlers.has("_macro/spawnAgent")).toBe(true);
939
+ expect(adapter.handlers.has("_macro/forkAgent")).toBe(true);
940
+ expect(adapter.handlers.has("_macro/setPermissionMode")).toBe(true);
941
+ expect(adapter.handlers.has("_macro/respondToPermission")).toBe(true);
942
+ });
943
+
944
+ it("unregisters all agent lifecycle methods", () => {
945
+ registerAgentLifecycleExtensions(adapter, services);
946
+ unregisterAgentLifecycleExtensions(adapter);
947
+
948
+ expect(adapter.handlers.has("_macro/spawnAgent")).toBe(false);
949
+ expect(adapter.handlers.has("_macro/forkAgent")).toBe(false);
950
+ expect(adapter.handlers.has("_macro/setPermissionMode")).toBe(false);
951
+ expect(adapter.handlers.has("_macro/respondToPermission")).toBe(false);
952
+ });
953
+ });
954
+
955
+ describe("_macro/spawnAgent", () => {
956
+ it("spawns an agent with explicit parentId", async () => {
957
+ registerAgentLifecycleExtensions(adapter, services);
958
+ const handler = adapter.handlers.get("_macro/spawnAgent")!;
959
+ const ctx = createMockContext({ canManageLifecycle: true });
960
+
961
+ const result = await handler(ctx, {
962
+ task: "Do something",
963
+ cwd: "/work/dir",
964
+ parentId: "parent-1",
965
+ topics: ["topic-a"],
966
+ config: { key: "value" },
967
+ });
968
+
969
+ expect(services.spawn).toHaveBeenCalledWith({
970
+ parent: "parent-1",
971
+ task: "Do something",
972
+ cwd: "/work/dir",
973
+ role: "worker",
974
+ topics: ["topic-a"],
975
+ config: { key: "value" },
976
+ });
977
+ expect(result).toHaveProperty("agentId", "agent-2");
978
+ expect(result).toHaveProperty("sessionId", "session-2");
979
+ });
980
+
981
+ it("falls back to head manager when no parentId provided", async () => {
982
+ registerAgentLifecycleExtensions(adapter, services);
983
+ const handler = adapter.handlers.get("_macro/spawnAgent")!;
984
+
985
+ await handler(createMockContext({ canManageLifecycle: true }), {
986
+ task: "Do something",
987
+ });
988
+
989
+ expect(services.spawn).toHaveBeenCalledWith(
990
+ expect.objectContaining({ parent: "head-1" })
991
+ );
992
+ });
993
+
994
+ it("uses defaultCwd when no cwd provided", async () => {
995
+ registerAgentLifecycleExtensions(adapter, services);
996
+ const handler = adapter.handlers.get("_macro/spawnAgent")!;
997
+
998
+ await handler(createMockContext({ canManageLifecycle: true }), {
999
+ task: "Do something",
1000
+ parentId: "parent-1",
1001
+ });
1002
+
1003
+ expect(services.spawn).toHaveBeenCalledWith(
1004
+ expect.objectContaining({ cwd: "/default/cwd" })
1005
+ );
1006
+ });
1007
+
1008
+ it("throws for missing task", async () => {
1009
+ registerAgentLifecycleExtensions(adapter, services);
1010
+ const handler = adapter.handlers.get("_macro/spawnAgent")!;
1011
+
1012
+ await expect(
1013
+ handler(createMockContext({ canManageLifecycle: true }), {})
1014
+ ).rejects.toThrow("task is required");
1015
+ });
1016
+
1017
+ it("throws when no parent available", async () => {
1018
+ (services.listHeadManagers as ReturnType<typeof vi.fn>).mockReturnValue([]);
1019
+
1020
+ registerAgentLifecycleExtensions(adapter, services);
1021
+ const handler = adapter.handlers.get("_macro/spawnAgent")!;
1022
+
1023
+ await expect(
1024
+ handler(createMockContext({ canManageLifecycle: true }), {
1025
+ task: "Do something",
1026
+ })
1027
+ ).rejects.toThrow("No parent agent available");
1028
+ });
1029
+
1030
+ it("notifies onAgentRegistered after spawn", async () => {
1031
+ registerAgentLifecycleExtensions(adapter, services);
1032
+ const handler = adapter.handlers.get("_macro/spawnAgent")!;
1033
+
1034
+ await handler(createMockContext({ canManageLifecycle: true }), {
1035
+ task: "Do something",
1036
+ parentId: "parent-1",
1037
+ });
1038
+
1039
+ expect(services.onAgentRegistered).toHaveBeenCalledWith(
1040
+ expect.objectContaining({
1041
+ id: "agent-2",
1042
+ role: "worker",
1043
+ parent: "parent-1",
1044
+ })
1045
+ );
1046
+ });
1047
+ });
1048
+
1049
+ describe("_macro/forkAgent", () => {
1050
+ it("forks an agent", async () => {
1051
+ registerAgentLifecycleExtensions(adapter, services);
1052
+ const handler = adapter.handlers.get("_macro/forkAgent")!;
1053
+
1054
+ const result = await handler(createMockContext({ canManageLifecycle: true }), {
1055
+ agentId: "agent-1",
1056
+ name: "forked-agent",
1057
+ cwd: "/fork/dir",
1058
+ });
1059
+
1060
+ expect(services.forkAgent).toHaveBeenCalledWith("agent-1", {
1061
+ name: "forked-agent",
1062
+ prompt: undefined,
1063
+ cwd: "/fork/dir",
1064
+ });
1065
+ expect(result).toHaveProperty("newAgentId", "agent-3");
1066
+ expect(result).toHaveProperty("newSessionId", "session-3");
1067
+ expect(result).toHaveProperty("originalAgentId", "agent-1");
1068
+ expect(result).toHaveProperty("providerSessionId", "provider-session-3");
1069
+ });
1070
+
1071
+ it("uses source agent cwd as fallback", async () => {
1072
+ registerAgentLifecycleExtensions(adapter, services);
1073
+ const handler = adapter.handlers.get("_macro/forkAgent")!;
1074
+
1075
+ await handler(createMockContext({ canManageLifecycle: true }), {
1076
+ agentId: "agent-1",
1077
+ });
1078
+
1079
+ expect(services.forkAgent).toHaveBeenCalledWith("agent-1", {
1080
+ name: undefined,
1081
+ prompt: undefined,
1082
+ cwd: "/test/cwd",
1083
+ });
1084
+ });
1085
+
1086
+ it("uses defaultCwd when source agent has no cwd", async () => {
1087
+ (services.getAgent as ReturnType<typeof vi.fn>).mockReturnValue({
1088
+ id: "agent-1" as AgentId,
1089
+ state: "running",
1090
+ cwd: null,
1091
+ });
1092
+
1093
+ registerAgentLifecycleExtensions(adapter, services);
1094
+ const handler = adapter.handlers.get("_macro/forkAgent")!;
1095
+
1096
+ await handler(createMockContext({ canManageLifecycle: true }), {
1097
+ agentId: "agent-1",
1098
+ });
1099
+
1100
+ expect(services.forkAgent).toHaveBeenCalledWith("agent-1",
1101
+ expect.objectContaining({ cwd: "/default/cwd" })
1102
+ );
1103
+ });
1104
+
1105
+ it("throws for missing agentId", async () => {
1106
+ registerAgentLifecycleExtensions(adapter, services);
1107
+ const handler = adapter.handlers.get("_macro/forkAgent")!;
1108
+
1109
+ await expect(
1110
+ handler(createMockContext({ canManageLifecycle: true }), {})
1111
+ ).rejects.toThrow("agentId is required");
1112
+ });
1113
+
1114
+ it("throws for non-existent agent", async () => {
1115
+ (services.getAgent as ReturnType<typeof vi.fn>).mockReturnValue(null);
1116
+
1117
+ registerAgentLifecycleExtensions(adapter, services);
1118
+ const handler = adapter.handlers.get("_macro/forkAgent")!;
1119
+
1120
+ await expect(
1121
+ handler(createMockContext({ canManageLifecycle: true }), { agentId: "missing" })
1122
+ ).rejects.toThrow("not found");
1123
+ });
1124
+
1125
+ it("fires prompt after fork when prompt is provided", async () => {
1126
+ registerAgentLifecycleExtensions(adapter, services);
1127
+ const handler = adapter.handlers.get("_macro/forkAgent")!;
1128
+
1129
+ await handler(createMockContext({ canManageLifecycle: true }), {
1130
+ agentId: "agent-1",
1131
+ prompt: "Start working",
1132
+ });
1133
+
1134
+ // prompt is fire-and-forget but should have been called
1135
+ expect(services.prompt).toHaveBeenCalledWith("agent-3", "Start working");
1136
+ });
1137
+
1138
+ it("notifies onAgentRegistered after fork", async () => {
1139
+ registerAgentLifecycleExtensions(adapter, services);
1140
+ const handler = adapter.handlers.get("_macro/forkAgent")!;
1141
+
1142
+ await handler(createMockContext({ canManageLifecycle: true }), {
1143
+ agentId: "agent-1",
1144
+ name: "forked",
1145
+ });
1146
+
1147
+ expect(services.onAgentRegistered).toHaveBeenCalledWith(
1148
+ expect.objectContaining({
1149
+ id: "agent-3",
1150
+ name: "forked",
1151
+ parent: "agent-1",
1152
+ })
1153
+ );
1154
+ });
1155
+ });
1156
+
1157
+ describe("_macro/setPermissionMode", () => {
1158
+ it("sets permission mode successfully", async () => {
1159
+ registerAgentLifecycleExtensions(adapter, services);
1160
+ const handler = adapter.handlers.get("_macro/setPermissionMode")!;
1161
+
1162
+ const result = await handler(createMockContext({ canManageLifecycle: true }), {
1163
+ agentId: "agent-1",
1164
+ permissionMode: "trust",
1165
+ });
1166
+
1167
+ expect(services.setPermissionMode).toHaveBeenCalledWith("agent-1", "trust");
1168
+ expect(result).toEqual({
1169
+ success: true,
1170
+ agentId: "agent-1",
1171
+ previousMode: "default",
1172
+ newMode: "trust",
1173
+ });
1174
+ });
1175
+
1176
+ it("returns error when no active session", async () => {
1177
+ (services.setPermissionMode as ReturnType<typeof vi.fn>).mockReturnValue(false);
1178
+
1179
+ registerAgentLifecycleExtensions(adapter, services);
1180
+ const handler = adapter.handlers.get("_macro/setPermissionMode")!;
1181
+
1182
+ const result = await handler(createMockContext({ canManageLifecycle: true }), {
1183
+ agentId: "agent-1",
1184
+ permissionMode: "trust",
1185
+ });
1186
+
1187
+ expect(result).toEqual({
1188
+ success: false,
1189
+ error: "No active session found for agent agent-1",
1190
+ });
1191
+ });
1192
+
1193
+ it("throws for missing agentId", async () => {
1194
+ registerAgentLifecycleExtensions(adapter, services);
1195
+ const handler = adapter.handlers.get("_macro/setPermissionMode")!;
1196
+
1197
+ await expect(
1198
+ handler(createMockContext({ canManageLifecycle: true }), { permissionMode: "trust" })
1199
+ ).rejects.toThrow("agentId and permissionMode are required");
1200
+ });
1201
+
1202
+ it("throws for missing permissionMode", async () => {
1203
+ registerAgentLifecycleExtensions(adapter, services);
1204
+ const handler = adapter.handlers.get("_macro/setPermissionMode")!;
1205
+
1206
+ await expect(
1207
+ handler(createMockContext({ canManageLifecycle: true }), { agentId: "agent-1" })
1208
+ ).rejects.toThrow("agentId and permissionMode are required");
1209
+ });
1210
+ });
1211
+
1212
+ describe("_macro/respondToPermission", () => {
1213
+ it("responds to permission request successfully", async () => {
1214
+ registerAgentLifecycleExtensions(adapter, services);
1215
+ const handler = adapter.handlers.get("_macro/respondToPermission")!;
1216
+
1217
+ const result = await handler(createMockContext({ canManageLifecycle: true }), {
1218
+ agentId: "agent-1",
1219
+ requestId: "req-1",
1220
+ optionId: "allow",
1221
+ });
1222
+
1223
+ expect(services.respondToPermission).toHaveBeenCalledWith("agent-1", "req-1", "allow");
1224
+ expect(result).toEqual({ success: true });
1225
+ });
1226
+
1227
+ it("returns failure when respondToPermission returns false", async () => {
1228
+ (services.respondToPermission as ReturnType<typeof vi.fn>).mockReturnValue(false);
1229
+
1230
+ registerAgentLifecycleExtensions(adapter, services);
1231
+ const handler = adapter.handlers.get("_macro/respondToPermission")!;
1232
+
1233
+ const result = await handler(createMockContext({ canManageLifecycle: true }), {
1234
+ agentId: "agent-1",
1235
+ requestId: "req-1",
1236
+ optionId: "deny",
1237
+ });
1238
+
1239
+ expect(result).toEqual({ success: false });
1240
+ });
1241
+
1242
+ it("throws for missing agentId", async () => {
1243
+ registerAgentLifecycleExtensions(adapter, services);
1244
+ const handler = adapter.handlers.get("_macro/respondToPermission")!;
1245
+
1246
+ await expect(
1247
+ handler(createMockContext({ canManageLifecycle: true }), {
1248
+ requestId: "req-1",
1249
+ optionId: "allow",
1250
+ })
1251
+ ).rejects.toThrow("agentId, requestId, and optionId are required");
1252
+ });
1253
+
1254
+ it("throws for missing requestId", async () => {
1255
+ registerAgentLifecycleExtensions(adapter, services);
1256
+ const handler = adapter.handlers.get("_macro/respondToPermission")!;
1257
+
1258
+ await expect(
1259
+ handler(createMockContext({ canManageLifecycle: true }), {
1260
+ agentId: "agent-1",
1261
+ optionId: "allow",
1262
+ })
1263
+ ).rejects.toThrow("agentId, requestId, and optionId are required");
1264
+ });
1265
+
1266
+ it("throws for missing optionId", async () => {
1267
+ registerAgentLifecycleExtensions(adapter, services);
1268
+ const handler = adapter.handlers.get("_macro/respondToPermission")!;
1269
+
1270
+ await expect(
1271
+ handler(createMockContext({ canManageLifecycle: true }), {
1272
+ agentId: "agent-1",
1273
+ requestId: "req-1",
1274
+ })
1275
+ ).rejects.toThrow("agentId, requestId, and optionId are required");
1276
+ });
1277
+ });
1278
+ });
1279
+
894
1280
  // =============================================================================
895
1281
  // Combined Registration Tests
896
1282
  // =============================================================================
@@ -938,6 +1324,16 @@ describe("registerMacroExtensions", () => {
938
1324
  isDetecting: vi.fn(),
939
1325
  getCachedResult: vi.fn(),
940
1326
  },
1327
+ agentLifecycle: {
1328
+ getAgent: vi.fn(),
1329
+ spawn: vi.fn(),
1330
+ forkAgent: vi.fn(),
1331
+ prompt: vi.fn(),
1332
+ setPermissionMode: vi.fn(),
1333
+ getPermissionMode: vi.fn(),
1334
+ respondToPermission: vi.fn(),
1335
+ listHeadManagers: vi.fn(),
1336
+ },
941
1337
  });
942
1338
 
943
1339
  expect(adapter.handlers.has("_macro/task/list")).toBe(true);
@@ -946,6 +1342,10 @@ describe("registerMacroExtensions", () => {
946
1342
  expect(adapter.handlers.has("_macro/resume")).toBe(true);
947
1343
  expect(adapter.handlers.has("_macro/agents/available")).toBe(true);
948
1344
  expect(adapter.handlers.has("_macro/agents/refresh")).toBe(true);
1345
+ expect(adapter.handlers.has("_macro/spawnAgent")).toBe(true);
1346
+ expect(adapter.handlers.has("_macro/forkAgent")).toBe(true);
1347
+ expect(adapter.handlers.has("_macro/setPermissionMode")).toBe(true);
1348
+ expect(adapter.handlers.has("_macro/respondToPermission")).toBe(true);
949
1349
  });
950
1350
  });
951
1351
 
@@ -962,6 +1362,10 @@ describe("MACRO_EXTENSION_METHODS", () => {
962
1362
  expect(MACRO_EXTENSION_METHODS).toContain("_macro/resume");
963
1363
  expect(MACRO_EXTENSION_METHODS).toContain("_macro/agents/available");
964
1364
  expect(MACRO_EXTENSION_METHODS).toContain("_macro/agents/refresh");
1365
+ expect(MACRO_EXTENSION_METHODS).toContain("_macro/spawnAgent");
1366
+ expect(MACRO_EXTENSION_METHODS).toContain("_macro/forkAgent");
1367
+ expect(MACRO_EXTENSION_METHODS).toContain("_macro/setPermissionMode");
1368
+ expect(MACRO_EXTENSION_METHODS).toContain("_macro/respondToPermission");
965
1369
  });
966
1370
  });
967
1371
 
@@ -975,5 +1379,9 @@ describe("EXTENSION_CAPABILITIES", () => {
975
1379
  expect(EXTENSION_CAPABILITIES["_macro/resume"]).toBe("canManageLifecycle");
976
1380
  expect(EXTENSION_CAPABILITIES["_macro/agents/available"]).toBe("canQuery");
977
1381
  expect(EXTENSION_CAPABILITIES["_macro/agents/refresh"]).toBe("canQuery");
1382
+ expect(EXTENSION_CAPABILITIES["_macro/spawnAgent"]).toBe("canManageLifecycle");
1383
+ expect(EXTENSION_CAPABILITIES["_macro/forkAgent"]).toBe("canManageLifecycle");
1384
+ expect(EXTENSION_CAPABILITIES["_macro/setPermissionMode"]).toBe("canManageLifecycle");
1385
+ expect(EXTENSION_CAPABILITIES["_macro/respondToPermission"]).toBe("canManageLifecycle");
978
1386
  });
979
1387
  });
@@ -562,6 +562,105 @@ describe("MAPAdapter", () => {
562
562
  // This should not throw - event is emitted to matching subscribers
563
563
  adapter.emitEvent(event);
564
564
  });
565
+
566
+ it("emits agent_registered events to underscore-format subscriptions", async () => {
567
+ // SDK clients subscribe with underscore format (e.g., "agent_registered")
568
+ await adapter.createSubscription(participantId, {
569
+ eventTypes: ["agent_registered"],
570
+ });
571
+
572
+ const event: EventNotification = {
573
+ eventId: "evt-reg-1",
574
+ type: "agent_registered",
575
+ timestamp: Date.now(),
576
+ data: {
577
+ agentId: "agent-new",
578
+ name: "Spawned Worker",
579
+ role: "worker",
580
+ parent: "agent-parent",
581
+ },
582
+ agentId: "agent-new" as AgentId,
583
+ };
584
+
585
+ // Should not throw - underscore event matches underscore subscription
586
+ adapter.emitEvent(event);
587
+ });
588
+
589
+ it("emits agent_state_changed events with data payload", async () => {
590
+ await adapter.createSubscription(participantId, {
591
+ eventTypes: ["agent_state_changed"],
592
+ });
593
+
594
+ const event: EventNotification = {
595
+ eventId: "evt-state-1",
596
+ type: "agent_state_changed",
597
+ timestamp: Date.now(),
598
+ agentId: "agent-1" as AgentId,
599
+ data: {
600
+ agentId: "agent-1",
601
+ current: "stopped",
602
+ previous: "running",
603
+ reason: "cancelled",
604
+ },
605
+ };
606
+
607
+ adapter.emitEvent(event);
608
+ });
609
+
610
+ it("emits agent_unregistered events with data payload", async () => {
611
+ await adapter.createSubscription(participantId, {
612
+ eventTypes: ["agent_unregistered"],
613
+ });
614
+
615
+ const event: EventNotification = {
616
+ eventId: "evt-unreg-1",
617
+ type: "agent_unregistered",
618
+ timestamp: Date.now(),
619
+ agentId: "agent-1" as AgentId,
620
+ data: {
621
+ agentId: "agent-1",
622
+ reason: "cancelled",
623
+ },
624
+ };
625
+
626
+ adapter.emitEvent(event);
627
+ });
628
+
629
+ it("logs agent lifecycle events in event log for replay", async () => {
630
+ const impl = adapter as MAPAdapterImpl;
631
+
632
+ // Emit agent_registered
633
+ impl.emitEvent({
634
+ eventId: "evt-1",
635
+ type: "agent_registered",
636
+ timestamp: 1000,
637
+ agentId: "agent-1" as AgentId,
638
+ data: { agentId: "agent-1", name: "Worker" },
639
+ });
640
+
641
+ // Emit agent_state_changed
642
+ impl.emitEvent({
643
+ eventId: "evt-2",
644
+ type: "agent_state_changed",
645
+ timestamp: 2000,
646
+ agentId: "agent-1" as AgentId,
647
+ data: { agentId: "agent-1", current: "stopped", previous: "running" },
648
+ });
649
+
650
+ // Emit agent_unregistered
651
+ impl.emitEvent({
652
+ eventId: "evt-3",
653
+ type: "agent_unregistered",
654
+ timestamp: 3000,
655
+ agentId: "agent-1" as AgentId,
656
+ data: { agentId: "agent-1", reason: "cancelled" },
657
+ });
658
+
659
+ // Query the event log - all three events should be stored
660
+ const eventLog = (impl as unknown as { eventLog: { query: (p: unknown) => { events: unknown[]; hasMore: boolean } } }).eventLog;
661
+ const result = eventLog.query({ limit: 100 });
662
+ expect(result.events.length).toBeGreaterThanOrEqual(3);
663
+ });
565
664
  });
566
665
 
567
666
  describe("messaging", () => {