macro-agent 0.0.17 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/.sudocode/specs.jsonl +4 -0
  3. package/CLAUDE.md +16 -14
  4. package/README.md +11 -29
  5. package/dist/acp/macro-agent.d.ts +17 -0
  6. package/dist/acp/macro-agent.d.ts.map +1 -1
  7. package/dist/acp/macro-agent.js +183 -55
  8. package/dist/acp/macro-agent.js.map +1 -1
  9. package/dist/acp/types.d.ts +32 -1
  10. package/dist/acp/types.d.ts.map +1 -1
  11. package/dist/acp/types.js.map +1 -1
  12. package/dist/agent/agent-manager.d.ts +65 -1
  13. package/dist/agent/agent-manager.d.ts.map +1 -1
  14. package/dist/agent/agent-manager.js +464 -183
  15. package/dist/agent/agent-manager.js.map +1 -1
  16. package/dist/agent/types.d.ts +1 -1
  17. package/dist/agent/types.d.ts.map +1 -1
  18. package/dist/api/server.d.ts +3 -0
  19. package/dist/api/server.d.ts.map +1 -1
  20. package/dist/api/server.js +37 -6
  21. package/dist/api/server.js.map +1 -1
  22. package/dist/auth/index.d.ts +2 -0
  23. package/dist/auth/index.d.ts.map +1 -0
  24. package/dist/auth/index.js +2 -0
  25. package/dist/auth/index.js.map +1 -0
  26. package/dist/auth/token.d.ts +41 -0
  27. package/dist/auth/token.d.ts.map +1 -0
  28. package/dist/auth/token.js +73 -0
  29. package/dist/auth/token.js.map +1 -0
  30. package/dist/cli/acp.d.ts +2 -23
  31. package/dist/cli/acp.d.ts.map +1 -1
  32. package/dist/cli/acp.js +127 -61
  33. package/dist/cli/acp.js.map +1 -1
  34. package/dist/cli/index.js +147 -15
  35. package/dist/cli/index.js.map +1 -1
  36. package/dist/cli/mcp.d.ts +6 -0
  37. package/dist/cli/mcp.d.ts.map +1 -1
  38. package/dist/cli/mcp.js +268 -181
  39. package/dist/cli/mcp.js.map +1 -1
  40. package/dist/cli/parse-args.d.ts +20 -0
  41. package/dist/cli/parse-args.d.ts.map +1 -0
  42. package/dist/cli/parse-args.js +43 -0
  43. package/dist/cli/parse-args.js.map +1 -0
  44. package/dist/cli/stable-instance-id.d.ts +8 -0
  45. package/dist/cli/stable-instance-id.d.ts.map +1 -0
  46. package/dist/cli/stable-instance-id.js +14 -0
  47. package/dist/cli/stable-instance-id.js.map +1 -0
  48. package/dist/config/project-config.d.ts +74 -7
  49. package/dist/config/project-config.d.ts.map +1 -1
  50. package/dist/config/project-config.js +123 -20
  51. package/dist/config/project-config.js.map +1 -1
  52. package/dist/map/adapter/acp-over-map.d.ts +23 -0
  53. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  54. package/dist/map/adapter/acp-over-map.js +482 -55
  55. package/dist/map/adapter/acp-over-map.js.map +1 -1
  56. package/dist/map/adapter/connection-manager.d.ts.map +1 -1
  57. package/dist/map/adapter/connection-manager.js +3 -0
  58. package/dist/map/adapter/connection-manager.js.map +1 -1
  59. package/dist/map/adapter/event-log.d.ts +87 -0
  60. package/dist/map/adapter/event-log.d.ts.map +1 -0
  61. package/dist/map/adapter/event-log.js +122 -0
  62. package/dist/map/adapter/event-log.js.map +1 -0
  63. package/dist/map/adapter/event-translator.js +6 -6
  64. package/dist/map/adapter/event-translator.js.map +1 -1
  65. package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
  66. package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
  67. package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
  68. package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
  69. package/dist/map/adapter/extensions/index.d.ts +10 -1
  70. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  71. package/dist/map/adapter/extensions/index.js +34 -0
  72. package/dist/map/adapter/extensions/index.js.map +1 -1
  73. package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
  74. package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
  75. package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
  76. package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
  77. package/dist/map/adapter/extensions/rename.d.ts +29 -0
  78. package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
  79. package/dist/map/adapter/extensions/rename.js +49 -0
  80. package/dist/map/adapter/extensions/rename.js.map +1 -0
  81. package/dist/map/adapter/extensions/task.d.ts.map +1 -1
  82. package/dist/map/adapter/extensions/task.js +10 -0
  83. package/dist/map/adapter/extensions/task.js.map +1 -1
  84. package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
  85. package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
  86. package/dist/map/adapter/extensions/update-metadata.js +67 -0
  87. package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
  88. package/dist/map/adapter/index.d.ts +2 -1
  89. package/dist/map/adapter/index.d.ts.map +1 -1
  90. package/dist/map/adapter/index.js +8 -2
  91. package/dist/map/adapter/index.js.map +1 -1
  92. package/dist/map/adapter/interface.d.ts +2 -0
  93. package/dist/map/adapter/interface.d.ts.map +1 -1
  94. package/dist/map/adapter/map-adapter.d.ts +4 -0
  95. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  96. package/dist/map/adapter/map-adapter.js +302 -30
  97. package/dist/map/adapter/map-adapter.js.map +1 -1
  98. package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
  99. package/dist/map/adapter/subscription-manager.js +5 -1
  100. package/dist/map/adapter/subscription-manager.js.map +1 -1
  101. package/dist/map/adapter/types.d.ts +2 -0
  102. package/dist/map/adapter/types.d.ts.map +1 -1
  103. package/dist/mcp/map-client.d.ts +39 -0
  104. package/dist/mcp/map-client.d.ts.map +1 -0
  105. package/dist/mcp/map-client.js +129 -0
  106. package/dist/mcp/map-client.js.map +1 -0
  107. package/dist/mcp/mcp-server.d.ts +14 -0
  108. package/dist/mcp/mcp-server.d.ts.map +1 -1
  109. package/dist/mcp/mcp-server.js +113 -85
  110. package/dist/mcp/mcp-server.js.map +1 -1
  111. package/dist/mcp/types.d.ts +9 -1
  112. package/dist/mcp/types.d.ts.map +1 -1
  113. package/dist/mcp/types.js.map +1 -1
  114. package/dist/metrics/metrics.js +1 -1
  115. package/dist/metrics/metrics.js.map +1 -1
  116. package/dist/roles/capabilities.d.ts +3 -1
  117. package/dist/roles/capabilities.d.ts.map +1 -1
  118. package/dist/roles/capabilities.js +17 -7
  119. package/dist/roles/capabilities.js.map +1 -1
  120. package/dist/roles/config-loader.d.ts +6 -6
  121. package/dist/roles/config-loader.d.ts.map +1 -1
  122. package/dist/roles/config-loader.js +6 -6
  123. package/dist/roles/config-loader.js.map +1 -1
  124. package/dist/roles/registry.d.ts +2 -2
  125. package/dist/roles/registry.js +2 -2
  126. package/dist/server/combined-server.d.ts +20 -0
  127. package/dist/server/combined-server.d.ts.map +1 -1
  128. package/dist/server/combined-server.js +107 -8
  129. package/dist/server/combined-server.js.map +1 -1
  130. package/dist/store/event-store.d.ts +7 -1
  131. package/dist/store/event-store.d.ts.map +1 -1
  132. package/dist/store/event-store.js +91 -8
  133. package/dist/store/event-store.js.map +1 -1
  134. package/dist/store/types/agents.d.ts +23 -0
  135. package/dist/store/types/agents.d.ts.map +1 -1
  136. package/dist/store/types/events.d.ts +1 -1
  137. package/dist/store/types/events.d.ts.map +1 -1
  138. package/dist/task/backend/index.d.ts +47 -29
  139. package/dist/task/backend/index.d.ts.map +1 -1
  140. package/dist/task/backend/index.js +109 -71
  141. package/dist/task/backend/index.js.map +1 -1
  142. package/dist/task/backend/memory.d.ts +1 -0
  143. package/dist/task/backend/memory.d.ts.map +1 -1
  144. package/dist/task/backend/memory.js +3 -0
  145. package/dist/task/backend/memory.js.map +1 -1
  146. package/dist/task/backend/opentasks/backend.d.ts +140 -0
  147. package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
  148. package/dist/task/backend/opentasks/backend.js +1023 -0
  149. package/dist/task/backend/opentasks/backend.js.map +1 -0
  150. package/dist/task/backend/opentasks/client.d.ts +337 -0
  151. package/dist/task/backend/opentasks/client.d.ts.map +1 -0
  152. package/dist/task/backend/opentasks/client.js +225 -0
  153. package/dist/task/backend/opentasks/client.js.map +1 -0
  154. package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
  155. package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
  156. package/dist/task/backend/opentasks/daemon-manager.js +195 -0
  157. package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
  158. package/dist/task/backend/opentasks/index.d.ts +21 -0
  159. package/dist/task/backend/opentasks/index.d.ts.map +1 -0
  160. package/dist/task/backend/opentasks/index.js +21 -0
  161. package/dist/task/backend/opentasks/index.js.map +1 -0
  162. package/dist/task/backend/opentasks/mapping.d.ts +48 -0
  163. package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
  164. package/dist/task/backend/opentasks/mapping.js +77 -0
  165. package/dist/task/backend/opentasks/mapping.js.map +1 -0
  166. package/dist/task/backend/types.d.ts +33 -53
  167. package/dist/task/backend/types.d.ts.map +1 -1
  168. package/dist/task/backend/types.js +7 -11
  169. package/dist/task/backend/types.js.map +1 -1
  170. package/dist/task/backend/unified-tool-provider.d.ts +57 -0
  171. package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
  172. package/dist/task/backend/unified-tool-provider.js +623 -0
  173. package/dist/task/backend/unified-tool-provider.js.map +1 -0
  174. package/dist/teams/team-loader.d.ts +2 -2
  175. package/dist/teams/team-loader.js +3 -3
  176. package/dist/teams/team-loader.js.map +1 -1
  177. package/dist/teams/team-runtime.d.ts.map +1 -1
  178. package/dist/teams/team-runtime.js +2 -0
  179. package/dist/teams/team-runtime.js.map +1 -1
  180. package/docs/architecture.md +7 -6
  181. package/docs/configuration.md +26 -62
  182. package/docs/implementation-details.md +5 -5
  183. package/docs/implementation-summary.md +17 -17
  184. package/docs/plan-self-driving-support.md +4 -4
  185. package/docs/spec-self-driving-support.md +10 -10
  186. package/docs/team-templates.md +2 -2
  187. package/docs/teams.md +3 -3
  188. package/docs/troubleshooting.md +10 -11
  189. package/package.json +6 -4
  190. package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
  191. package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
  192. package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
  193. package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
  194. package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
  195. package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
  196. package/src/acp/__tests__/history.test.ts +8 -4
  197. package/src/acp/__tests__/integration.test.ts +56 -31
  198. package/src/acp/__tests__/macro-agent.test.ts +16 -7
  199. package/src/acp/macro-agent.ts +230 -62
  200. package/src/acp/types.ts +46 -1
  201. package/src/agent/__tests__/agent-manager.test.ts +228 -2
  202. package/src/agent/agent-manager.ts +714 -261
  203. package/src/agent/types.ts +3 -1
  204. package/src/api/server.ts +41 -7
  205. package/src/auth/__tests__/token.test.ts +100 -0
  206. package/src/auth/index.ts +1 -0
  207. package/src/auth/token.ts +82 -0
  208. package/src/cli/__tests__/acp.test.ts +1 -1
  209. package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
  210. package/src/cli/acp.ts +130 -72
  211. package/src/cli/index.ts +120 -14
  212. package/src/cli/mcp.ts +311 -207
  213. package/src/cli/parse-args.ts +54 -0
  214. package/src/cli/stable-instance-id.ts +14 -0
  215. package/src/config/project-config.ts +190 -27
  216. package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
  217. package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +820 -0
  218. package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
  219. package/src/map/adapter/__tests__/acp-over-map-history.test.ts +724 -2
  220. package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
  221. package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
  222. package/src/map/adapter/__tests__/event-log.test.ts +527 -0
  223. package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
  224. package/src/map/adapter/__tests__/extensions.test.ts +408 -0
  225. package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
  226. package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
  227. package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
  228. package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
  229. package/src/map/adapter/acp-over-map.ts +777 -92
  230. package/src/map/adapter/connection-manager.ts +3 -0
  231. package/src/map/adapter/event-log.ts +208 -0
  232. package/src/map/adapter/event-translator.ts +6 -6
  233. package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
  234. package/src/map/adapter/extensions/index.ts +60 -0
  235. package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
  236. package/src/map/adapter/extensions/task.ts +11 -0
  237. package/src/map/adapter/extensions/update-metadata.ts +126 -0
  238. package/src/map/adapter/index.ts +28 -0
  239. package/src/map/adapter/interface.ts +2 -0
  240. package/src/map/adapter/map-adapter.ts +373 -38
  241. package/src/map/adapter/subscription-manager.ts +5 -1
  242. package/src/map/adapter/types.ts +2 -0
  243. package/src/mcp/__tests__/map-client.test.ts +386 -0
  244. package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
  245. package/src/mcp/__tests__/mcp-server.test.ts +100 -1
  246. package/src/mcp/map-client.ts +177 -0
  247. package/src/mcp/mcp-server.ts +191 -100
  248. package/src/mcp/types.ts +6 -1
  249. package/src/metrics/metrics.ts +1 -1
  250. package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
  251. package/src/roles/__tests__/config-loader.test.ts +7 -7
  252. package/src/roles/capabilities.ts +17 -7
  253. package/src/roles/config-loader.ts +6 -6
  254. package/src/roles/registry.ts +2 -2
  255. package/src/server/__tests__/combined-server.test.ts +94 -21
  256. package/src/server/combined-server.ts +189 -33
  257. package/src/steering/__tests__/steering-integration.test.ts +1 -1
  258. package/src/store/__tests__/event-store.test.ts +236 -1
  259. package/src/store/__tests__/instance.test.ts +3 -3
  260. package/src/store/event-store.ts +109 -8
  261. package/src/store/types/agents.ts +16 -0
  262. package/src/store/types/events.ts +1 -1
  263. package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
  264. package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
  265. package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
  266. package/src/task/backend/index.ts +156 -106
  267. package/src/task/backend/memory.ts +4 -0
  268. package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
  269. package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
  270. package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
  271. package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
  272. package/src/task/backend/opentasks/backend.ts +1323 -0
  273. package/src/task/backend/opentasks/client.ts +652 -0
  274. package/src/task/backend/opentasks/daemon-manager.ts +253 -0
  275. package/src/task/backend/opentasks/index.ts +69 -0
  276. package/src/task/backend/opentasks/mapping.ts +94 -0
  277. package/src/task/backend/types.ts +42 -66
  278. package/src/task/backend/unified-tool-provider.ts +779 -0
  279. package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
  280. package/src/teams/team-loader.ts +3 -3
  281. package/src/teams/team-runtime.ts +2 -0
  282. package/test_fixtures/README.md +2 -3
  283. package/test_fixtures/fixtures/index.ts +0 -3
  284. package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
  285. package/test_fixtures/fixtures/repos/index.ts +1 -3
  286. package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
  287. package/test_fixtures/fixtures/repos/types.ts +0 -11
  288. package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
  289. package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
  290. package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
  291. package/vitest.config.ts +1 -1
  292. package/vitest.e2e.config.ts +1 -1
  293. package/vitest.setup.ts +1 -30
  294. package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
  295. package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
  296. package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
  297. package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
  298. package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
  299. package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
  300. package/.macro-agent/teams/self-driving/team.yaml +0 -103
  301. package/.macro-agent/teams/structured/prompts/developer.md +0 -26
  302. package/.macro-agent/teams/structured/prompts/lead.md +0 -25
  303. package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
  304. package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
  305. package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
  306. package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
  307. package/.macro-agent/teams/structured/team.yaml +0 -89
  308. package/docs/sudocode-integration.md +0 -383
  309. package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
  310. package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
  311. package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
  312. package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
  313. package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
  314. package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
  315. package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
  316. package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
  317. package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
  318. package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
  319. package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
  320. package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
  321. package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
  322. package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
  323. package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
  324. package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
  325. package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
  326. package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
  327. package/src/task/backend/sudocode/backend.ts +0 -1237
  328. package/src/task/backend/sudocode/client.ts +0 -515
  329. package/src/task/backend/sudocode/index.ts +0 -120
  330. package/src/task/backend/sudocode/mapping.ts +0 -93
  331. package/src/task/backend/sudocode/server-client.ts +0 -522
  332. package/src/task/backend/sudocode/standalone-client.ts +0 -623
  333. package/src/task/backend/sudocode/sync-policy.ts +0 -387
  334. package/src/task/backend/sudocode/tools.ts +0 -896
  335. package/src/task/backend/tool-provider.ts +0 -506
  336. package/test_fixtures/fixtures/sudocode/index.ts +0 -29
  337. package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
  338. package/test_fixtures/fixtures/sudocode/specs.ts +0 -159
@@ -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", () => {