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
@@ -0,0 +1,527 @@
1
+ /**
2
+ * Tests for EventLog — in-memory ring buffer for MAP event replay.
3
+ */
4
+
5
+ import { describe, it, expect } from "vitest";
6
+ import {
7
+ EventLog,
8
+ underscoreToDot,
9
+ dotToUnderscore,
10
+ type LoggedEvent,
11
+ } from "../event-log.js";
12
+
13
+ // =============================================================================
14
+ // Helpers
15
+ // =============================================================================
16
+
17
+ function makeEvent(
18
+ overrides: Partial<LoggedEvent> & { eventId: string },
19
+ ): LoggedEvent {
20
+ return {
21
+ timestamp: Date.now(),
22
+ type: "agent.registered",
23
+ data: {},
24
+ ...overrides,
25
+ };
26
+ }
27
+
28
+ function makeEvents(count: number, prefix = "evt"): LoggedEvent[] {
29
+ return Array.from({ length: count }, (_, i) =>
30
+ makeEvent({
31
+ eventId: `${prefix}-${String(i).padStart(4, "0")}`,
32
+ timestamp: 1000 + i,
33
+ type: i % 2 === 0 ? "agent.registered" : "message.sent",
34
+ data: { index: i },
35
+ agentId: `agent-${i % 3}`,
36
+ }),
37
+ );
38
+ }
39
+
40
+ // =============================================================================
41
+ // Format Normalization
42
+ // =============================================================================
43
+
44
+ describe("underscoreToDot", () => {
45
+ it("converts underscore format to dot format", () => {
46
+ expect(underscoreToDot("agent_registered")).toBe("agent.registered");
47
+ expect(underscoreToDot("message_sent")).toBe("message.sent");
48
+ expect(underscoreToDot("agent_state_changed")).toBe("agent.state.changed");
49
+ });
50
+
51
+ it("passes through dot format unchanged", () => {
52
+ expect(underscoreToDot("agent.registered")).toBe("agent.registered");
53
+ });
54
+
55
+ it("handles strings with no separators", () => {
56
+ expect(underscoreToDot("test")).toBe("test");
57
+ });
58
+ });
59
+
60
+ describe("dotToUnderscore", () => {
61
+ it("converts dot format to underscore format", () => {
62
+ expect(dotToUnderscore("agent.registered")).toBe("agent_registered");
63
+ expect(dotToUnderscore("message.sent")).toBe("message_sent");
64
+ expect(dotToUnderscore("agent.state.changed")).toBe("agent_state_changed");
65
+ });
66
+
67
+ it("passes through underscore format unchanged", () => {
68
+ expect(dotToUnderscore("agent_registered")).toBe("agent_registered");
69
+ });
70
+ });
71
+
72
+ // =============================================================================
73
+ // EventLog — Basic Operations
74
+ // =============================================================================
75
+
76
+ describe("EventLog", () => {
77
+ describe("append and query", () => {
78
+ it("appends events and queries all in chronological order", () => {
79
+ const log = new EventLog();
80
+ const events = makeEvents(5);
81
+ for (const e of events) log.append(e);
82
+
83
+ const result = log.query({ limit: 100 });
84
+
85
+ expect(result.events).toHaveLength(5);
86
+ expect(result.events.map((e) => e.eventId)).toEqual(
87
+ events.map((e) => e.eventId),
88
+ );
89
+ expect(result.hasMore).toBe(false);
90
+ });
91
+
92
+ it("returns empty result for empty buffer", () => {
93
+ const log = new EventLog();
94
+ const result = log.query();
95
+
96
+ expect(result.events).toEqual([]);
97
+ expect(result.hasMore).toBe(false);
98
+ });
99
+
100
+ it("reports correct size", () => {
101
+ const log = new EventLog();
102
+ expect(log.size).toBe(0);
103
+
104
+ log.append(makeEvent({ eventId: "e1" }));
105
+ expect(log.size).toBe(1);
106
+
107
+ log.append(makeEvent({ eventId: "e2" }));
108
+ expect(log.size).toBe(2);
109
+ });
110
+ });
111
+
112
+ // ===========================================================================
113
+ // Ring Buffer Eviction
114
+ // ===========================================================================
115
+
116
+ describe("ring buffer eviction", () => {
117
+ it("evicts oldest events when exceeding maxSize", () => {
118
+ const log = new EventLog({ maxSize: 5 });
119
+ const events = makeEvents(8);
120
+ for (const e of events) log.append(e);
121
+
122
+ expect(log.size).toBe(5);
123
+
124
+ const result = log.query({ limit: 100 });
125
+ // Should have events 3-7 (oldest 0-2 evicted)
126
+ expect(result.events).toHaveLength(5);
127
+ expect(result.events[0].eventId).toBe("evt-0003");
128
+ expect(result.events[4].eventId).toBe("evt-0007");
129
+ });
130
+ });
131
+
132
+ // ===========================================================================
133
+ // Keyset Pagination (afterEventId)
134
+ // ===========================================================================
135
+
136
+ describe("afterEventId pagination", () => {
137
+ it("returns events after specified eventId", () => {
138
+ const log = new EventLog();
139
+ const events = makeEvents(10);
140
+ for (const e of events) log.append(e);
141
+
142
+ const result = log.query({ afterEventId: "evt-0004", limit: 100 });
143
+
144
+ expect(result.events).toHaveLength(5);
145
+ expect(result.events[0].eventId).toBe("evt-0005");
146
+ expect(result.events[4].eventId).toBe("evt-0009");
147
+ });
148
+
149
+ it("returns empty when afterEventId is the last event", () => {
150
+ const log = new EventLog();
151
+ const events = makeEvents(5);
152
+ for (const e of events) log.append(e);
153
+
154
+ const result = log.query({ afterEventId: "evt-0004" });
155
+ expect(result.events).toEqual([]);
156
+ expect(result.hasMore).toBe(false);
157
+ });
158
+
159
+ it("starts from beginning when afterEventId is not found (evicted)", () => {
160
+ const log = new EventLog({ maxSize: 5 });
161
+ const events = makeEvents(10);
162
+ for (const e of events) log.append(e);
163
+
164
+ // evt-0002 has been evicted (buffer has evt-0005 through evt-0009)
165
+ const result = log.query({ afterEventId: "evt-0002", limit: 100 });
166
+
167
+ // Should start from beginning of buffer
168
+ expect(result.events).toHaveLength(5);
169
+ expect(result.events[0].eventId).toBe("evt-0005");
170
+ });
171
+
172
+ it("supports multi-page pagination", () => {
173
+ const log = new EventLog();
174
+ const events = makeEvents(10);
175
+ for (const e of events) log.append(e);
176
+
177
+ // Page 1
178
+ const page1 = log.query({ limit: 3 });
179
+ expect(page1.events).toHaveLength(3);
180
+ expect(page1.hasMore).toBe(true);
181
+ expect(page1.events[0].eventId).toBe("evt-0000");
182
+
183
+ // Page 2
184
+ const page2 = log.query({
185
+ afterEventId: page1.events[2].eventId,
186
+ limit: 3,
187
+ });
188
+ expect(page2.events).toHaveLength(3);
189
+ expect(page2.hasMore).toBe(true);
190
+ expect(page2.events[0].eventId).toBe("evt-0003");
191
+
192
+ // Page 3
193
+ const page3 = log.query({
194
+ afterEventId: page2.events[2].eventId,
195
+ limit: 3,
196
+ });
197
+ expect(page3.events).toHaveLength(3);
198
+ expect(page3.hasMore).toBe(true);
199
+ expect(page3.events[0].eventId).toBe("evt-0006");
200
+
201
+ // Page 4 (last)
202
+ const page4 = log.query({
203
+ afterEventId: page3.events[2].eventId,
204
+ limit: 3,
205
+ });
206
+ expect(page4.events).toHaveLength(1);
207
+ expect(page4.hasMore).toBe(false);
208
+ expect(page4.events[0].eventId).toBe("evt-0009");
209
+ });
210
+ });
211
+
212
+ // ===========================================================================
213
+ // Timestamp Filters
214
+ // ===========================================================================
215
+
216
+ describe("timestamp filtering", () => {
217
+ it("filters events from fromTimestamp", () => {
218
+ const log = new EventLog();
219
+ const events = makeEvents(5);
220
+ for (const e of events) log.append(e);
221
+
222
+ const result = log.query({ fromTimestamp: 1003, limit: 100 });
223
+
224
+ expect(result.events).toHaveLength(2);
225
+ expect(result.events[0].eventId).toBe("evt-0003");
226
+ expect(result.events[1].eventId).toBe("evt-0004");
227
+ });
228
+
229
+ it("filters events up to toTimestamp", () => {
230
+ const log = new EventLog();
231
+ const events = makeEvents(5);
232
+ for (const e of events) log.append(e);
233
+
234
+ const result = log.query({ toTimestamp: 1002, limit: 100 });
235
+
236
+ expect(result.events).toHaveLength(3);
237
+ expect(result.events[2].eventId).toBe("evt-0002");
238
+ });
239
+
240
+ it("combines fromTimestamp and toTimestamp", () => {
241
+ const log = new EventLog();
242
+ const events = makeEvents(10);
243
+ for (const e of events) log.append(e);
244
+
245
+ const result = log.query({
246
+ fromTimestamp: 1003,
247
+ toTimestamp: 1006,
248
+ limit: 100,
249
+ });
250
+
251
+ expect(result.events).toHaveLength(4);
252
+ expect(result.events[0].eventId).toBe("evt-0003");
253
+ expect(result.events[3].eventId).toBe("evt-0006");
254
+ });
255
+
256
+ it("returns empty when fromTimestamp is beyond all events", () => {
257
+ const log = new EventLog();
258
+ const events = makeEvents(5);
259
+ for (const e of events) log.append(e);
260
+
261
+ const result = log.query({ fromTimestamp: 9999 });
262
+ expect(result.events).toEqual([]);
263
+ });
264
+ });
265
+
266
+ // ===========================================================================
267
+ // Limit and hasMore
268
+ // ===========================================================================
269
+
270
+ describe("limit and hasMore", () => {
271
+ it("respects limit parameter", () => {
272
+ const log = new EventLog();
273
+ const events = makeEvents(10);
274
+ for (const e of events) log.append(e);
275
+
276
+ const result = log.query({ limit: 3 });
277
+
278
+ expect(result.events).toHaveLength(3);
279
+ expect(result.hasMore).toBe(true);
280
+ });
281
+
282
+ it("defaults to 100 when limit not specified", () => {
283
+ const log = new EventLog();
284
+ const events = makeEvents(150);
285
+ for (const e of events) log.append(e);
286
+
287
+ const result = log.query();
288
+
289
+ expect(result.events).toHaveLength(100);
290
+ expect(result.hasMore).toBe(true);
291
+ });
292
+
293
+ it("caps limit at 1000", () => {
294
+ const log = new EventLog();
295
+ const events = makeEvents(1500);
296
+ for (const e of events) log.append(e);
297
+
298
+ const result = log.query({ limit: 5000 });
299
+
300
+ expect(result.events).toHaveLength(1000);
301
+ expect(result.hasMore).toBe(true);
302
+ });
303
+
304
+ it("hasMore is false when all events fit within limit", () => {
305
+ const log = new EventLog();
306
+ const events = makeEvents(3);
307
+ for (const e of events) log.append(e);
308
+
309
+ const result = log.query({ limit: 10 });
310
+
311
+ expect(result.events).toHaveLength(3);
312
+ expect(result.hasMore).toBe(false);
313
+ });
314
+ });
315
+
316
+ // ===========================================================================
317
+ // Event Type Filters
318
+ // ===========================================================================
319
+
320
+ describe("event type filter", () => {
321
+ it("filters by underscore format event types", () => {
322
+ const log = new EventLog();
323
+ // Even indices: agent.registered, odd indices: message.sent
324
+ const events = makeEvents(6);
325
+ for (const e of events) log.append(e);
326
+
327
+ const result = log.query({
328
+ filter: { eventTypes: ["agent_registered"] },
329
+ limit: 100,
330
+ });
331
+
332
+ expect(result.events).toHaveLength(3);
333
+ expect(result.events.every((e) => e.type === "agent.registered")).toBe(
334
+ true,
335
+ );
336
+ });
337
+
338
+ it("filters by dot format event types", () => {
339
+ const log = new EventLog();
340
+ const events = makeEvents(6);
341
+ for (const e of events) log.append(e);
342
+
343
+ const result = log.query({
344
+ filter: { eventTypes: ["agent.registered"] },
345
+ limit: 100,
346
+ });
347
+
348
+ expect(result.events).toHaveLength(3);
349
+ });
350
+
351
+ it("handles mixed stored formats (dot and underscore)", () => {
352
+ const log = new EventLog();
353
+ // Event stored in dot format
354
+ log.append(
355
+ makeEvent({ eventId: "e1", type: "message.delivered", timestamp: 1 }),
356
+ );
357
+ // Event stored in underscore format (as ACP-over-MAP does)
358
+ log.append(
359
+ makeEvent({ eventId: "e2", type: "message_delivered", timestamp: 2 }),
360
+ );
361
+ // Different type
362
+ log.append(
363
+ makeEvent({ eventId: "e3", type: "agent.registered", timestamp: 3 }),
364
+ );
365
+
366
+ // Filter using underscore format — should match both message.delivered entries
367
+ const result = log.query({
368
+ filter: { eventTypes: ["message_delivered"] },
369
+ limit: 100,
370
+ });
371
+
372
+ expect(result.events).toHaveLength(2);
373
+ expect(result.events.map((e) => e.eventId)).toEqual(["e1", "e2"]);
374
+ });
375
+
376
+ it("supports multiple event types (OR)", () => {
377
+ const log = new EventLog();
378
+ const events = makeEvents(6);
379
+ for (const e of events) log.append(e);
380
+
381
+ const result = log.query({
382
+ filter: { eventTypes: ["agent_registered", "message_sent"] },
383
+ limit: 100,
384
+ });
385
+
386
+ // All 6 events match (alternating between the two types)
387
+ expect(result.events).toHaveLength(6);
388
+ });
389
+
390
+ it("empty eventTypes array matches all events", () => {
391
+ const log = new EventLog();
392
+ const events = makeEvents(5);
393
+ for (const e of events) log.append(e);
394
+
395
+ const result = log.query({
396
+ filter: { eventTypes: [] },
397
+ limit: 100,
398
+ });
399
+
400
+ // Empty eventTypes should not filter (matches all)
401
+ expect(result.events).toHaveLength(5);
402
+ });
403
+ });
404
+
405
+ // ===========================================================================
406
+ // Agent Filter
407
+ // ===========================================================================
408
+
409
+ describe("agent filter", () => {
410
+ it("filters by agent ID", () => {
411
+ const log = new EventLog();
412
+ // makeEvents assigns agentId: agent-${i % 3}
413
+ const events = makeEvents(9);
414
+ for (const e of events) log.append(e);
415
+
416
+ const result = log.query({
417
+ filter: { agents: ["agent-0"] },
418
+ limit: 100,
419
+ });
420
+
421
+ expect(result.events).toHaveLength(3);
422
+ expect(result.events.every((e) => e.agentId === "agent-0")).toBe(true);
423
+ });
424
+
425
+ it("excludes events without agentId", () => {
426
+ const log = new EventLog();
427
+ log.append(makeEvent({ eventId: "e1", agentId: "agent-1" }));
428
+ log.append(makeEvent({ eventId: "e2" })); // no agentId
429
+ log.append(makeEvent({ eventId: "e3", agentId: "agent-1" }));
430
+
431
+ const result = log.query({
432
+ filter: { agents: ["agent-1"] },
433
+ limit: 100,
434
+ });
435
+
436
+ expect(result.events).toHaveLength(2);
437
+ expect(result.events.map((e) => e.eventId)).toEqual(["e1", "e3"]);
438
+ });
439
+
440
+ it("supports multiple agent IDs (OR)", () => {
441
+ const log = new EventLog();
442
+ const events = makeEvents(9);
443
+ for (const e of events) log.append(e);
444
+
445
+ const result = log.query({
446
+ filter: { agents: ["agent-0", "agent-1"] },
447
+ limit: 100,
448
+ });
449
+
450
+ expect(result.events).toHaveLength(6);
451
+ });
452
+ });
453
+
454
+ // ===========================================================================
455
+ // Scope Filter
456
+ // ===========================================================================
457
+
458
+ describe("scope filter", () => {
459
+ it("filters by scope ID", () => {
460
+ const log = new EventLog();
461
+ log.append(makeEvent({ eventId: "e1", scopeId: "scope-a" }));
462
+ log.append(makeEvent({ eventId: "e2", scopeId: "scope-b" }));
463
+ log.append(makeEvent({ eventId: "e3", scopeId: "scope-a" }));
464
+ log.append(makeEvent({ eventId: "e4" })); // no scopeId
465
+
466
+ const result = log.query({
467
+ filter: { scopes: ["scope-a"] },
468
+ limit: 100,
469
+ });
470
+
471
+ expect(result.events).toHaveLength(2);
472
+ expect(result.events.map((e) => e.eventId)).toEqual(["e1", "e3"]);
473
+ });
474
+ });
475
+
476
+ // ===========================================================================
477
+ // Combined Filters
478
+ // ===========================================================================
479
+
480
+ describe("combined filters (AND)", () => {
481
+ it("combines eventType and agent filters", () => {
482
+ const log = new EventLog();
483
+ // makeEvents: even=agent.registered, odd=message.sent, agentId=agent-{i%3}
484
+ const events = makeEvents(9);
485
+ for (const e of events) log.append(e);
486
+
487
+ const result = log.query({
488
+ filter: {
489
+ eventTypes: ["agent_registered"],
490
+ agents: ["agent-0"],
491
+ },
492
+ limit: 100,
493
+ });
494
+
495
+ // agent.registered at indices 0,2,4,6,8
496
+ // agent-0 at indices 0,3,6
497
+ // Both: indices 0,6
498
+ expect(result.events).toHaveLength(2);
499
+ expect(result.events[0].eventId).toBe("evt-0000");
500
+ expect(result.events[1].eventId).toBe("evt-0006");
501
+ });
502
+ });
503
+
504
+ // ===========================================================================
505
+ // Empty / No Filter
506
+ // ===========================================================================
507
+
508
+ describe("empty filter matches all", () => {
509
+ it("returns all events with empty filter object", () => {
510
+ const log = new EventLog();
511
+ const events = makeEvents(5);
512
+ for (const e of events) log.append(e);
513
+
514
+ const result = log.query({ filter: {}, limit: 100 });
515
+ expect(result.events).toHaveLength(5);
516
+ });
517
+
518
+ it("returns all events with no filter", () => {
519
+ const log = new EventLog();
520
+ const events = makeEvents(5);
521
+ for (const e of events) log.append(e);
522
+
523
+ const result = log.query({ limit: 100 });
524
+ expect(result.events).toHaveLength(5);
525
+ });
526
+ });
527
+ });
@@ -77,9 +77,9 @@ describe("translateEvent", () => {
77
77
  });
78
78
  });
79
79
 
80
- describe("terminate event", () => {
80
+ describe("stop event", () => {
81
81
  it("translates to agent.unregistered", () => {
82
- const event = createTestEvent("terminate", {
82
+ const event = createTestEvent("stop", {
83
83
  payload: {
84
84
  reason: "completed",
85
85
  exit_code: 0,
@@ -380,7 +380,7 @@ describe("translateEvents", () => {
380
380
  const events = [
381
381
  createTestEvent("spawn"),
382
382
  createTestEvent("subscription"), // Not exposed
383
- createTestEvent("terminate"),
383
+ createTestEvent("stop"),
384
384
  ];
385
385
 
386
386
  const results = translateEvents(events);