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
@@ -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);