@namzu/sdk 0.1.8 → 0.2.0

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 (531) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  3. package/dist/agents/ReactiveAgent.js +5 -3
  4. package/dist/agents/ReactiveAgent.js.map +1 -1
  5. package/dist/agents/RouterAgent.d.ts.map +1 -1
  6. package/dist/agents/RouterAgent.js +3 -0
  7. package/dist/agents/RouterAgent.js.map +1 -1
  8. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  9. package/dist/agents/SupervisorAgent.js +18 -5
  10. package/dist/agents/SupervisorAgent.js.map +1 -1
  11. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  12. package/dist/bridge/a2a/mapper.js +6 -0
  13. package/dist/bridge/a2a/mapper.js.map +1 -1
  14. package/dist/bridge/a2a/task.d.ts +2 -2
  15. package/dist/bridge/a2a/task.d.ts.map +1 -1
  16. package/dist/bridge/a2a/task.js.map +1 -1
  17. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  18. package/dist/bridge/sse/mapper.js +6 -0
  19. package/dist/bridge/sse/mapper.js.map +1 -1
  20. package/dist/constants/a2a/index.d.ts +2 -2
  21. package/dist/constants/a2a/index.d.ts.map +1 -1
  22. package/dist/constants/a2a/index.js.map +1 -1
  23. package/dist/contracts/api.d.ts +22 -3
  24. package/dist/contracts/api.d.ts.map +1 -1
  25. package/dist/contracts/index.d.ts +3 -1
  26. package/dist/contracts/index.d.ts.map +1 -1
  27. package/dist/contracts/index.js.map +1 -1
  28. package/dist/gateway/local.d.ts.map +1 -1
  29. package/dist/gateway/local.js +6 -0
  30. package/dist/gateway/local.js.map +1 -1
  31. package/dist/index.d.ts +4 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +4 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/manager/agent/__tests__/lifecycle.test.d.ts +2 -0
  36. package/dist/manager/agent/__tests__/lifecycle.test.d.ts.map +1 -0
  37. package/dist/manager/agent/__tests__/lifecycle.test.js +302 -0
  38. package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -0
  39. package/dist/manager/agent/lifecycle.d.ts +58 -3
  40. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  41. package/dist/manager/agent/lifecycle.js +311 -12
  42. package/dist/manager/agent/lifecycle.js.map +1 -1
  43. package/dist/manager/run/persistence.d.ts +8 -1
  44. package/dist/manager/run/persistence.d.ts.map +1 -1
  45. package/dist/manager/run/persistence.js +15 -0
  46. package/dist/manager/run/persistence.js.map +1 -1
  47. package/dist/run/reporter.d.ts.map +1 -1
  48. package/dist/run/reporter.js +25 -0
  49. package/dist/run/reporter.js.map +1 -1
  50. package/dist/runtime/query/__tests__/context.test.d.ts +2 -0
  51. package/dist/runtime/query/__tests__/context.test.d.ts.map +1 -0
  52. package/dist/runtime/query/__tests__/context.test.js +84 -0
  53. package/dist/runtime/query/__tests__/context.test.js.map +1 -0
  54. package/dist/runtime/query/context.d.ts +55 -2
  55. package/dist/runtime/query/context.d.ts.map +1 -1
  56. package/dist/runtime/query/context.js +48 -8
  57. package/dist/runtime/query/context.js.map +1 -1
  58. package/dist/runtime/query/events.d.ts.map +1 -1
  59. package/dist/runtime/query/events.js +8 -0
  60. package/dist/runtime/query/events.js.map +1 -1
  61. package/dist/runtime/query/index.d.ts +25 -2
  62. package/dist/runtime/query/index.d.ts.map +1 -1
  63. package/dist/runtime/query/index.js +11 -1
  64. package/dist/runtime/query/index.js.map +1 -1
  65. package/dist/session/__tests__/integration/_fixtures.d.ts +115 -0
  66. package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -0
  67. package/dist/session/__tests__/integration/_fixtures.js +198 -0
  68. package/dist/session/__tests__/integration/_fixtures.js.map +1 -0
  69. package/dist/session/__tests__/integration/capacity-caps.test.d.ts +13 -0
  70. package/dist/session/__tests__/integration/capacity-caps.test.d.ts.map +1 -0
  71. package/dist/session/__tests__/integration/capacity-caps.test.js +116 -0
  72. package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -0
  73. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts +18 -0
  74. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts.map +1 -0
  75. package/dist/session/__tests__/integration/e2e-spawn.test.js +226 -0
  76. package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -0
  77. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts +15 -0
  78. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts.map +1 -0
  79. package/dist/session/__tests__/integration/event-stream-ordering.test.js +323 -0
  80. package/dist/session/__tests__/integration/event-stream-ordering.test.js.map +1 -0
  81. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts +12 -0
  82. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts.map +1 -0
  83. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js +170 -0
  84. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -0
  85. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts +18 -0
  86. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts.map +1 -0
  87. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js +146 -0
  88. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js.map +1 -0
  89. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts +15 -0
  90. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts.map +1 -0
  91. package/dist/session/__tests__/integration/handoff-single-e2e.test.js +163 -0
  92. package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -0
  93. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts +12 -0
  94. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts.map +1 -0
  95. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js +157 -0
  96. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js.map +1 -0
  97. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts +11 -0
  98. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts.map +1 -0
  99. package/dist/session/__tests__/integration/migration-filesystem.test.js +140 -0
  100. package/dist/session/__tests__/integration/migration-filesystem.test.js.map +1 -0
  101. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts +13 -0
  102. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts.map +1 -0
  103. package/dist/session/__tests__/integration/migration-id-prefix.test.js +84 -0
  104. package/dist/session/__tests__/integration/migration-id-prefix.test.js.map +1 -0
  105. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts +14 -0
  106. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts.map +1 -0
  107. package/dist/session/__tests__/integration/prev-artifact-dag.test.js +241 -0
  108. package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -0
  109. package/dist/session/__tests__/integration/retention-archive.test.d.ts +12 -0
  110. package/dist/session/__tests__/integration/retention-archive.test.d.ts.map +1 -0
  111. package/dist/session/__tests__/integration/retention-archive.test.js +186 -0
  112. package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -0
  113. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts +18 -0
  114. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts.map +1 -0
  115. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +200 -0
  116. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -0
  117. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts +14 -0
  118. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts.map +1 -0
  119. package/dist/session/__tests__/integration/tenant-isolation.test.js +180 -0
  120. package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -0
  121. package/dist/session/errors.d.ts +60 -0
  122. package/dist/session/errors.d.ts.map +1 -0
  123. package/dist/session/errors.js +50 -0
  124. package/dist/session/errors.js.map +1 -0
  125. package/dist/session/events/index.d.ts +4 -0
  126. package/dist/session/events/index.d.ts.map +1 -0
  127. package/dist/session/events/index.js +8 -0
  128. package/dist/session/events/index.js.map +1 -0
  129. package/dist/session/events/schema-version.d.ts +13 -0
  130. package/dist/session/events/schema-version.d.ts.map +1 -0
  131. package/dist/session/events/schema-version.js +12 -0
  132. package/dist/session/events/schema-version.js.map +1 -0
  133. package/dist/session/events/types.d.ts +64 -0
  134. package/dist/session/events/types.d.ts.map +1 -0
  135. package/dist/session/events/types.js +2 -0
  136. package/dist/session/events/types.js.map +1 -0
  137. package/dist/session/handoff/__tests__/broadcast.test.d.ts +2 -0
  138. package/dist/session/handoff/__tests__/broadcast.test.d.ts.map +1 -0
  139. package/dist/session/handoff/__tests__/broadcast.test.js +243 -0
  140. package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -0
  141. package/dist/session/handoff/__tests__/capacity.test.d.ts +2 -0
  142. package/dist/session/handoff/__tests__/capacity.test.d.ts.map +1 -0
  143. package/dist/session/handoff/__tests__/capacity.test.js +100 -0
  144. package/dist/session/handoff/__tests__/capacity.test.js.map +1 -0
  145. package/dist/session/handoff/__tests__/single.test.d.ts +2 -0
  146. package/dist/session/handoff/__tests__/single.test.d.ts.map +1 -0
  147. package/dist/session/handoff/__tests__/single.test.js +230 -0
  148. package/dist/session/handoff/__tests__/single.test.js.map +1 -0
  149. package/dist/session/handoff/assignment.d.ts +59 -0
  150. package/dist/session/handoff/assignment.d.ts.map +1 -0
  151. package/dist/session/handoff/assignment.js +11 -0
  152. package/dist/session/handoff/assignment.js.map +1 -0
  153. package/dist/session/handoff/broadcast.d.ts +47 -0
  154. package/dist/session/handoff/broadcast.d.ts.map +1 -0
  155. package/dist/session/handoff/broadcast.js +296 -0
  156. package/dist/session/handoff/broadcast.js.map +1 -0
  157. package/dist/session/handoff/capacity.d.ts +66 -0
  158. package/dist/session/handoff/capacity.d.ts.map +1 -0
  159. package/dist/session/handoff/capacity.js +60 -0
  160. package/dist/session/handoff/capacity.js.map +1 -0
  161. package/dist/session/handoff/events.d.ts +66 -0
  162. package/dist/session/handoff/events.d.ts.map +1 -0
  163. package/dist/session/handoff/events.js +13 -0
  164. package/dist/session/handoff/events.js.map +1 -0
  165. package/dist/session/handoff/index.d.ts +12 -0
  166. package/dist/session/handoff/index.d.ts.map +1 -0
  167. package/dist/session/handoff/index.js +9 -0
  168. package/dist/session/handoff/index.js.map +1 -0
  169. package/dist/session/handoff/single.d.ts +62 -0
  170. package/dist/session/handoff/single.d.ts.map +1 -0
  171. package/dist/session/handoff/single.js +217 -0
  172. package/dist/session/handoff/single.js.map +1 -0
  173. package/dist/session/handoff/version.d.ts +52 -0
  174. package/dist/session/handoff/version.d.ts.map +1 -0
  175. package/dist/session/handoff/version.js +36 -0
  176. package/dist/session/handoff/version.js.map +1 -0
  177. package/dist/session/hierarchy/__tests__/session.test.d.ts +2 -0
  178. package/dist/session/hierarchy/__tests__/session.test.d.ts.map +1 -0
  179. package/dist/session/hierarchy/__tests__/session.test.js +67 -0
  180. package/dist/session/hierarchy/__tests__/session.test.js.map +1 -0
  181. package/dist/session/hierarchy/actor.d.ts +26 -0
  182. package/dist/session/hierarchy/actor.d.ts.map +1 -0
  183. package/dist/session/hierarchy/actor.js +2 -0
  184. package/dist/session/hierarchy/actor.js.map +1 -0
  185. package/dist/session/hierarchy/index.d.ts +8 -0
  186. package/dist/session/hierarchy/index.d.ts.map +1 -0
  187. package/dist/session/hierarchy/index.js +4 -0
  188. package/dist/session/hierarchy/index.js.map +1 -0
  189. package/dist/session/hierarchy/lineage.d.ts +15 -0
  190. package/dist/session/hierarchy/lineage.d.ts.map +1 -0
  191. package/dist/session/hierarchy/lineage.js +2 -0
  192. package/dist/session/hierarchy/lineage.js.map +1 -0
  193. package/dist/session/hierarchy/project.d.ts +40 -0
  194. package/dist/session/hierarchy/project.d.ts.map +1 -0
  195. package/dist/session/hierarchy/project.js +2 -0
  196. package/dist/session/hierarchy/project.js.map +1 -0
  197. package/dist/session/hierarchy/session.d.ts +59 -0
  198. package/dist/session/hierarchy/session.d.ts.map +1 -0
  199. package/dist/session/hierarchy/session.js +51 -0
  200. package/dist/session/hierarchy/session.js.map +1 -0
  201. package/dist/session/hierarchy/sub-session.d.ts +76 -0
  202. package/dist/session/hierarchy/sub-session.d.ts.map +1 -0
  203. package/dist/session/hierarchy/sub-session.js +2 -0
  204. package/dist/session/hierarchy/sub-session.js.map +1 -0
  205. package/dist/session/hierarchy/tenant.d.ts +13 -0
  206. package/dist/session/hierarchy/tenant.d.ts.map +1 -0
  207. package/dist/session/hierarchy/tenant.js +2 -0
  208. package/dist/session/hierarchy/tenant.js.map +1 -0
  209. package/dist/session/index.d.ts +10 -0
  210. package/dist/session/index.d.ts.map +1 -0
  211. package/dist/session/index.js +15 -0
  212. package/dist/session/index.js.map +1 -0
  213. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts +2 -0
  214. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts.map +1 -0
  215. package/dist/session/intervention/__tests__/prev-artifact.test.js +179 -0
  216. package/dist/session/intervention/__tests__/prev-artifact.test.js.map +1 -0
  217. package/dist/session/intervention/index.d.ts +3 -0
  218. package/dist/session/intervention/index.d.ts.map +1 -0
  219. package/dist/session/intervention/index.js +8 -0
  220. package/dist/session/intervention/index.js.map +1 -0
  221. package/dist/session/intervention/prev-artifact.d.ts +103 -0
  222. package/dist/session/intervention/prev-artifact.d.ts.map +1 -0
  223. package/dist/session/intervention/prev-artifact.js +112 -0
  224. package/dist/session/intervention/prev-artifact.js.map +1 -0
  225. package/dist/session/migration/__tests__/filesystem.test.d.ts +2 -0
  226. package/dist/session/migration/__tests__/filesystem.test.d.ts.map +1 -0
  227. package/dist/session/migration/__tests__/filesystem.test.js +188 -0
  228. package/dist/session/migration/__tests__/filesystem.test.js.map +1 -0
  229. package/dist/session/migration/__tests__/id-prefix.test.d.ts +2 -0
  230. package/dist/session/migration/__tests__/id-prefix.test.d.ts.map +1 -0
  231. package/dist/session/migration/__tests__/id-prefix.test.js +83 -0
  232. package/dist/session/migration/__tests__/id-prefix.test.js.map +1 -0
  233. package/dist/session/migration/__tests__/marker.test.d.ts +2 -0
  234. package/dist/session/migration/__tests__/marker.test.d.ts.map +1 -0
  235. package/dist/session/migration/__tests__/marker.test.js +75 -0
  236. package/dist/session/migration/__tests__/marker.test.js.map +1 -0
  237. package/dist/session/migration/errors.d.ts +26 -0
  238. package/dist/session/migration/errors.d.ts.map +1 -0
  239. package/dist/session/migration/errors.js +22 -0
  240. package/dist/session/migration/errors.js.map +1 -0
  241. package/dist/session/migration/filesystem.d.ts +94 -0
  242. package/dist/session/migration/filesystem.d.ts.map +1 -0
  243. package/dist/session/migration/filesystem.js +319 -0
  244. package/dist/session/migration/filesystem.js.map +1 -0
  245. package/dist/session/migration/id-prefix.d.ts +98 -0
  246. package/dist/session/migration/id-prefix.d.ts.map +1 -0
  247. package/dist/session/migration/id-prefix.js +116 -0
  248. package/dist/session/migration/id-prefix.js.map +1 -0
  249. package/dist/session/migration/index.d.ts +8 -0
  250. package/dist/session/migration/index.d.ts.map +1 -0
  251. package/dist/session/migration/index.js +8 -0
  252. package/dist/session/migration/index.js.map +1 -0
  253. package/dist/session/migration/marker.d.ts +57 -0
  254. package/dist/session/migration/marker.d.ts.map +1 -0
  255. package/dist/session/migration/marker.js +111 -0
  256. package/dist/session/migration/marker.js.map +1 -0
  257. package/dist/session/retention/__tests__/archive.test.d.ts +2 -0
  258. package/dist/session/retention/__tests__/archive.test.d.ts.map +1 -0
  259. package/dist/session/retention/__tests__/archive.test.js +252 -0
  260. package/dist/session/retention/__tests__/archive.test.js.map +1 -0
  261. package/dist/session/retention/__tests__/disk-backend.test.d.ts +2 -0
  262. package/dist/session/retention/__tests__/disk-backend.test.d.ts.map +1 -0
  263. package/dist/session/retention/__tests__/disk-backend.test.js +154 -0
  264. package/dist/session/retention/__tests__/disk-backend.test.js.map +1 -0
  265. package/dist/session/retention/archive-backend-ref.d.ts +18 -0
  266. package/dist/session/retention/archive-backend-ref.d.ts.map +1 -0
  267. package/dist/session/retention/archive-backend-ref.js +2 -0
  268. package/dist/session/retention/archive-backend-ref.js.map +1 -0
  269. package/dist/session/retention/archive.d.ts +130 -0
  270. package/dist/session/retention/archive.d.ts.map +1 -0
  271. package/dist/session/retention/archive.js +203 -0
  272. package/dist/session/retention/archive.js.map +1 -0
  273. package/dist/session/retention/backend.d.ts +101 -0
  274. package/dist/session/retention/backend.d.ts.map +1 -0
  275. package/dist/session/retention/backend.js +15 -0
  276. package/dist/session/retention/backend.js.map +1 -0
  277. package/dist/session/retention/disk-backend.d.ts +59 -0
  278. package/dist/session/retention/disk-backend.d.ts.map +1 -0
  279. package/dist/session/retention/disk-backend.js +236 -0
  280. package/dist/session/retention/disk-backend.js.map +1 -0
  281. package/dist/session/retention/index.d.ts +9 -0
  282. package/dist/session/retention/index.d.ts.map +1 -0
  283. package/dist/session/retention/index.js +6 -0
  284. package/dist/session/retention/index.js.map +1 -0
  285. package/dist/session/retention/policy.d.ts +49 -0
  286. package/dist/session/retention/policy.d.ts.map +1 -0
  287. package/dist/session/retention/policy.js +21 -0
  288. package/dist/session/retention/policy.js.map +1 -0
  289. package/dist/session/summary/__tests__/materialize.test.d.ts +2 -0
  290. package/dist/session/summary/__tests__/materialize.test.d.ts.map +1 -0
  291. package/dist/session/summary/__tests__/materialize.test.js +269 -0
  292. package/dist/session/summary/__tests__/materialize.test.js.map +1 -0
  293. package/dist/session/summary/deliverable.d.ts +74 -0
  294. package/dist/session/summary/deliverable.d.ts.map +1 -0
  295. package/dist/session/summary/deliverable.js +20 -0
  296. package/dist/session/summary/deliverable.js.map +1 -0
  297. package/dist/session/summary/index.d.ts +6 -0
  298. package/dist/session/summary/index.d.ts.map +1 -0
  299. package/dist/session/summary/index.js +9 -0
  300. package/dist/session/summary/index.js.map +1 -0
  301. package/dist/session/summary/materialize.d.ts +82 -0
  302. package/dist/session/summary/materialize.d.ts.map +1 -0
  303. package/dist/session/summary/materialize.js +117 -0
  304. package/dist/session/summary/materialize.js.map +1 -0
  305. package/dist/session/summary/ref.d.ts +91 -0
  306. package/dist/session/summary/ref.d.ts.map +1 -0
  307. package/dist/session/summary/ref.js +51 -0
  308. package/dist/session/summary/ref.js.map +1 -0
  309. package/dist/session/workspace/__tests__/git-worktree.test.d.ts +2 -0
  310. package/dist/session/workspace/__tests__/git-worktree.test.d.ts.map +1 -0
  311. package/dist/session/workspace/__tests__/git-worktree.test.js +244 -0
  312. package/dist/session/workspace/__tests__/git-worktree.test.js.map +1 -0
  313. package/dist/session/workspace/__tests__/path-builder.test.d.ts +2 -0
  314. package/dist/session/workspace/__tests__/path-builder.test.d.ts.map +1 -0
  315. package/dist/session/workspace/__tests__/path-builder.test.js +37 -0
  316. package/dist/session/workspace/__tests__/path-builder.test.js.map +1 -0
  317. package/dist/session/workspace/driver.d.ts +55 -0
  318. package/dist/session/workspace/driver.d.ts.map +1 -0
  319. package/dist/session/workspace/driver.js +12 -0
  320. package/dist/session/workspace/driver.js.map +1 -0
  321. package/dist/session/workspace/git-worktree.d.ts +65 -0
  322. package/dist/session/workspace/git-worktree.d.ts.map +1 -0
  323. package/dist/session/workspace/git-worktree.js +156 -0
  324. package/dist/session/workspace/git-worktree.js.map +1 -0
  325. package/dist/session/workspace/index.d.ts +8 -0
  326. package/dist/session/workspace/index.d.ts.map +1 -0
  327. package/dist/session/workspace/index.js +7 -0
  328. package/dist/session/workspace/index.js.map +1 -0
  329. package/dist/session/workspace/path-builder.d.ts +50 -0
  330. package/dist/session/workspace/path-builder.d.ts.map +1 -0
  331. package/dist/session/workspace/path-builder.js +50 -0
  332. package/dist/session/workspace/path-builder.js.map +1 -0
  333. package/dist/session/workspace/ref.d.ts +46 -0
  334. package/dist/session/workspace/ref.d.ts.map +1 -0
  335. package/dist/session/workspace/ref.js +11 -0
  336. package/dist/session/workspace/ref.js.map +1 -0
  337. package/dist/session/workspace/registry.d.ts +26 -0
  338. package/dist/session/workspace/registry.d.ts.map +1 -0
  339. package/dist/session/workspace/registry.js +35 -0
  340. package/dist/session/workspace/registry.js.map +1 -0
  341. package/dist/store/conversation/memory.d.ts +22 -0
  342. package/dist/store/conversation/memory.d.ts.map +1 -1
  343. package/dist/store/conversation/memory.js +22 -0
  344. package/dist/store/conversation/memory.js.map +1 -1
  345. package/dist/store/session/__tests__/disk.test.d.ts +2 -0
  346. package/dist/store/session/__tests__/disk.test.d.ts.map +1 -0
  347. package/dist/store/session/__tests__/disk.test.js +240 -0
  348. package/dist/store/session/__tests__/disk.test.js.map +1 -0
  349. package/dist/store/session/__tests__/memory.test.d.ts +2 -0
  350. package/dist/store/session/__tests__/memory.test.d.ts.map +1 -0
  351. package/dist/store/session/__tests__/memory.test.js +217 -0
  352. package/dist/store/session/__tests__/memory.test.js.map +1 -0
  353. package/dist/store/session/disk.d.ts +85 -0
  354. package/dist/store/session/disk.d.ts.map +1 -0
  355. package/dist/store/session/disk.js +757 -0
  356. package/dist/store/session/disk.js.map +1 -0
  357. package/dist/store/session/index.d.ts +7 -0
  358. package/dist/store/session/index.d.ts.map +1 -0
  359. package/dist/store/session/index.js +11 -0
  360. package/dist/store/session/index.js.map +1 -0
  361. package/dist/store/session/linkage.d.ts +38 -0
  362. package/dist/store/session/linkage.d.ts.map +1 -0
  363. package/dist/store/session/linkage.js +64 -0
  364. package/dist/store/session/linkage.js.map +1 -0
  365. package/dist/store/session/memory.d.ts +48 -0
  366. package/dist/store/session/memory.d.ts.map +1 -0
  367. package/dist/store/session/memory.js +322 -0
  368. package/dist/store/session/memory.js.map +1 -0
  369. package/dist/store/session/messages.d.ts +20 -0
  370. package/dist/store/session/messages.d.ts.map +1 -0
  371. package/dist/store/session/messages.js +12 -0
  372. package/dist/store/session/messages.js.map +1 -0
  373. package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts +1 -1
  374. package/dist/types/agent/base.d.ts +28 -1
  375. package/dist/types/agent/base.d.ts.map +1 -1
  376. package/dist/types/agent/task.d.ts +50 -2
  377. package/dist/types/agent/task.d.ts.map +1 -1
  378. package/dist/types/agent/task.js.map +1 -1
  379. package/dist/types/conversation/index.d.ts +7 -0
  380. package/dist/types/conversation/index.d.ts.map +1 -1
  381. package/dist/types/ids/index.d.ts +26 -3
  382. package/dist/types/ids/index.d.ts.map +1 -1
  383. package/dist/types/ids/index.js +8 -1
  384. package/dist/types/ids/index.js.map +1 -1
  385. package/dist/types/invocation/__tests__/state.test.js +36 -29
  386. package/dist/types/invocation/__tests__/state.test.js.map +1 -1
  387. package/dist/types/invocation/index.d.ts +20 -4
  388. package/dist/types/invocation/index.d.ts.map +1 -1
  389. package/dist/types/invocation/index.js +10 -7
  390. package/dist/types/invocation/index.js.map +1 -1
  391. package/dist/types/run/config.d.ts +11 -1
  392. package/dist/types/run/config.d.ts.map +1 -1
  393. package/dist/types/run/events.d.ts +26 -1
  394. package/dist/types/run/events.d.ts.map +1 -1
  395. package/dist/types/run/index.d.ts.map +1 -1
  396. package/dist/types/run/index.js +8 -0
  397. package/dist/types/run/index.js.map +1 -1
  398. package/dist/types/run/metadata.d.ts +24 -1
  399. package/dist/types/run/metadata.d.ts.map +1 -1
  400. package/dist/types/run/status.d.ts +26 -0
  401. package/dist/types/run/status.d.ts.map +1 -0
  402. package/dist/types/run/status.js +2 -0
  403. package/dist/types/run/status.js.map +1 -0
  404. package/dist/types/session/ids.d.ts +18 -0
  405. package/dist/types/session/ids.d.ts.map +1 -0
  406. package/dist/types/session/ids.js +12 -0
  407. package/dist/types/session/ids.js.map +1 -0
  408. package/dist/types/session/index.d.ts +3 -0
  409. package/dist/types/session/index.d.ts.map +1 -0
  410. package/dist/types/session/index.js +5 -0
  411. package/dist/types/session/index.js.map +1 -0
  412. package/dist/types/session/store.d.ts +188 -0
  413. package/dist/types/session/store.d.ts.map +1 -0
  414. package/dist/types/session/store.js +14 -0
  415. package/dist/types/session/store.js.map +1 -0
  416. package/dist/utils/id.d.ts +18 -1
  417. package/dist/utils/id.d.ts.map +1 -1
  418. package/dist/utils/id.js +42 -4
  419. package/dist/utils/id.js.map +1 -1
  420. package/package.json +1 -1
  421. package/src/agents/ReactiveAgent.ts +7 -3
  422. package/src/agents/RouterAgent.ts +5 -0
  423. package/src/agents/SupervisorAgent.ts +26 -6
  424. package/src/bridge/a2a/mapper.ts +7 -0
  425. package/src/bridge/a2a/task.ts +2 -2
  426. package/src/bridge/sse/mapper.ts +8 -1
  427. package/src/constants/a2a/index.ts +2 -2
  428. package/src/contracts/api.ts +23 -3
  429. package/src/contracts/index.ts +2 -0
  430. package/src/gateway/local.ts +6 -0
  431. package/src/index.ts +14 -0
  432. package/src/manager/agent/__tests__/lifecycle.test.ts +452 -0
  433. package/src/manager/agent/lifecycle.ts +434 -19
  434. package/src/manager/run/persistence.ts +20 -1
  435. package/src/run/reporter.ts +28 -0
  436. package/src/runtime/query/__tests__/context.test.ts +101 -0
  437. package/src/runtime/query/context.ts +106 -10
  438. package/src/runtime/query/events.ts +8 -0
  439. package/src/runtime/query/index.ts +41 -3
  440. package/src/session/__tests__/integration/_fixtures.ts +282 -0
  441. package/src/session/__tests__/integration/capacity-caps.test.ts +164 -0
  442. package/src/session/__tests__/integration/e2e-spawn.test.ts +278 -0
  443. package/src/session/__tests__/integration/event-stream-ordering.test.ts +403 -0
  444. package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +245 -0
  445. package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +179 -0
  446. package/src/session/__tests__/integration/handoff-single-e2e.test.ts +220 -0
  447. package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +237 -0
  448. package/src/session/__tests__/integration/migration-filesystem.test.ts +209 -0
  449. package/src/session/__tests__/integration/migration-id-prefix.test.ts +101 -0
  450. package/src/session/__tests__/integration/prev-artifact-dag.test.ts +318 -0
  451. package/src/session/__tests__/integration/retention-archive.test.ts +231 -0
  452. package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +237 -0
  453. package/src/session/__tests__/integration/tenant-isolation.test.ts +282 -0
  454. package/src/session/errors.ts +70 -0
  455. package/src/session/events/index.ts +16 -0
  456. package/src/session/events/schema-version.ts +13 -0
  457. package/src/session/events/types.ts +71 -0
  458. package/src/session/handoff/__tests__/broadcast.test.ts +350 -0
  459. package/src/session/handoff/__tests__/capacity.test.ts +123 -0
  460. package/src/session/handoff/__tests__/single.test.ts +316 -0
  461. package/src/session/handoff/assignment.ts +62 -0
  462. package/src/session/handoff/broadcast.ts +381 -0
  463. package/src/session/handoff/capacity.ts +121 -0
  464. package/src/session/handoff/events.ts +72 -0
  465. package/src/session/handoff/index.ts +29 -0
  466. package/src/session/handoff/single.ts +288 -0
  467. package/src/session/handoff/version.ts +59 -0
  468. package/src/session/hierarchy/__tests__/session.test.ts +92 -0
  469. package/src/session/hierarchy/actor.ts +17 -0
  470. package/src/session/hierarchy/index.ts +17 -0
  471. package/src/session/hierarchy/lineage.ts +15 -0
  472. package/src/session/hierarchy/project.ts +41 -0
  473. package/src/session/hierarchy/session.ts +97 -0
  474. package/src/session/hierarchy/sub-session.ts +92 -0
  475. package/src/session/hierarchy/tenant.ts +13 -0
  476. package/src/session/index.ts +15 -0
  477. package/src/session/intervention/__tests__/prev-artifact.test.ts +234 -0
  478. package/src/session/intervention/index.ts +16 -0
  479. package/src/session/intervention/prev-artifact.ts +180 -0
  480. package/src/session/migration/__tests__/filesystem.test.ts +263 -0
  481. package/src/session/migration/__tests__/id-prefix.test.ts +101 -0
  482. package/src/session/migration/__tests__/marker.test.ts +84 -0
  483. package/src/session/migration/errors.ts +23 -0
  484. package/src/session/migration/filesystem.ts +401 -0
  485. package/src/session/migration/id-prefix.ts +146 -0
  486. package/src/session/migration/index.ts +38 -0
  487. package/src/session/migration/marker.ts +131 -0
  488. package/src/session/retention/__tests__/archive.test.ts +316 -0
  489. package/src/session/retention/__tests__/disk-backend.test.ts +180 -0
  490. package/src/session/retention/archive-backend-ref.ts +17 -0
  491. package/src/session/retention/archive.ts +281 -0
  492. package/src/session/retention/backend.ts +107 -0
  493. package/src/session/retention/disk-backend.ts +304 -0
  494. package/src/session/retention/index.ts +16 -0
  495. package/src/session/retention/policy.ts +53 -0
  496. package/src/session/summary/__tests__/materialize.test.ts +341 -0
  497. package/src/session/summary/deliverable.ts +84 -0
  498. package/src/session/summary/index.ts +31 -0
  499. package/src/session/summary/materialize.ts +169 -0
  500. package/src/session/summary/ref.ts +104 -0
  501. package/src/session/workspace/__tests__/git-worktree.test.ts +258 -0
  502. package/src/session/workspace/__tests__/path-builder.test.ts +51 -0
  503. package/src/session/workspace/driver.ts +60 -0
  504. package/src/session/workspace/git-worktree.ts +209 -0
  505. package/src/session/workspace/index.ts +25 -0
  506. package/src/session/workspace/path-builder.ts +71 -0
  507. package/src/session/workspace/ref.ts +50 -0
  508. package/src/session/workspace/registry.ts +42 -0
  509. package/src/store/conversation/memory.ts +23 -0
  510. package/src/store/session/__tests__/disk.test.ts +346 -0
  511. package/src/store/session/__tests__/memory.test.ts +327 -0
  512. package/src/store/session/disk.ts +920 -0
  513. package/src/store/session/index.ts +14 -0
  514. package/src/store/session/linkage.ts +80 -0
  515. package/src/store/session/memory.ts +400 -0
  516. package/src/store/session/messages.ts +21 -0
  517. package/src/types/agent/base.ts +31 -1
  518. package/src/types/agent/task.ts +58 -2
  519. package/src/types/conversation/index.ts +7 -0
  520. package/src/types/ids/index.ts +41 -3
  521. package/src/types/invocation/__tests__/state.test.ts +37 -29
  522. package/src/types/invocation/index.ts +26 -10
  523. package/src/types/run/config.ts +12 -1
  524. package/src/types/run/events.ts +36 -1
  525. package/src/types/run/index.ts +8 -0
  526. package/src/types/run/metadata.ts +24 -1
  527. package/src/types/run/status.ts +33 -0
  528. package/src/types/session/ids.ts +34 -0
  529. package/src/types/session/index.ts +28 -0
  530. package/src/types/session/store.ts +229 -0
  531. package/src/utils/id.ts +55 -4
@@ -0,0 +1,403 @@
1
+ /**
2
+ * Integration — event stream ordering + lineage + schemaVersion envelope.
3
+ *
4
+ * Covers roadmap §5 invariants:
5
+ * - §10.1 schemaVersion: 2 on every sub-session RunEvent
6
+ * - §10.3 tree-scoped monotonic ordering by (rootSessionId, eventId)
7
+ * - §10.3 depth filter ('self' vs 'tree') at subscribe time
8
+ * - §10.4 lineage stamped on every sub-session event with parent + root + depth
9
+ *
10
+ * Orthogonal to `e2e-spawn.test.ts` (covers single-level spawn). This file
11
+ * drives a multi-level (3-deep) delegation tree so monotonic ordering across
12
+ * concurrent descendants is observable.
13
+ */
14
+
15
+ import { describe, expect, it } from 'vitest'
16
+ import { EMPTY_TOKEN_USAGE } from '../../../constants/limits.js'
17
+ import type { AgentManager } from '../../../manager/agent/lifecycle.js'
18
+ import type { AgentInput, BaseAgentConfig, BaseAgentResult } from '../../../types/agent/base.js'
19
+ import type { RunId } from '../../../types/ids/index.js'
20
+ import { createAssistantMessage } from '../../../types/message/index.js'
21
+ import type { RunEvent } from '../../../types/run/events.js'
22
+ import { ZERO_COST } from '../../../utils/cost.js'
23
+ import {
24
+ DEFAULT_TENANT,
25
+ buildAgent,
26
+ buildAgentCustom,
27
+ buildDefinition,
28
+ buildHarness,
29
+ buildSendMessageOptions,
30
+ buildTaskContext,
31
+ seedActiveParent,
32
+ } from './_fixtures.js'
33
+
34
+ describe('Integration — event stream ordering + lineage + schemaVersion', () => {
35
+ it('every sub-session RunEvent carries schemaVersion: 2', async () => {
36
+ const harness = buildHarness()
37
+ const { project, session, actor } = await seedActiveParent(harness)
38
+ harness.registry.register(buildDefinition(buildAgent('worker')))
39
+
40
+ const captured: RunEvent[] = []
41
+ const task = await harness.manager.sendMessage(
42
+ buildSendMessageOptions({
43
+ agentId: 'worker',
44
+ parentSessionId: session.id,
45
+ projectId: project.id,
46
+ tenantId: DEFAULT_TENANT,
47
+ parentActor: actor,
48
+ }),
49
+ buildTaskContext({
50
+ sessionId: session.id,
51
+ projectId: project.id,
52
+ tenantId: DEFAULT_TENANT,
53
+ parentActor: actor,
54
+ }),
55
+ (ev) => {
56
+ captured.push(ev)
57
+ },
58
+ )
59
+ await harness.manager.waitForCompletion(task.taskId)
60
+
61
+ // Every sub-session lifecycle event is stamped with schemaVersion: 2.
62
+ const subSessionEvents = captured.filter(
63
+ (e) =>
64
+ e.type === 'subsession_spawned' ||
65
+ e.type === 'subsession_messaged' ||
66
+ e.type === 'subsession_idled',
67
+ )
68
+ expect(subSessionEvents.length).toBeGreaterThan(0)
69
+ for (const ev of subSessionEvents) {
70
+ expect(ev.schemaVersion).toBe(2)
71
+ }
72
+ })
73
+
74
+ it('every sub-session event carries lineage { parentSessionId, rootSessionId, depth }', async () => {
75
+ const harness = buildHarness()
76
+ const { project, session, actor } = await seedActiveParent(harness)
77
+ harness.registry.register(buildDefinition(buildAgent('worker')))
78
+
79
+ const captured: RunEvent[] = []
80
+ const task = await harness.manager.sendMessage(
81
+ buildSendMessageOptions({
82
+ agentId: 'worker',
83
+ parentSessionId: session.id,
84
+ projectId: project.id,
85
+ tenantId: DEFAULT_TENANT,
86
+ parentActor: actor,
87
+ }),
88
+ buildTaskContext({
89
+ sessionId: session.id,
90
+ projectId: project.id,
91
+ tenantId: DEFAULT_TENANT,
92
+ parentActor: actor,
93
+ }),
94
+ (ev) => {
95
+ captured.push(ev)
96
+ },
97
+ )
98
+ await harness.manager.waitForCompletion(task.taskId)
99
+
100
+ const spawned = captured.find((e) => e.type === 'subsession_spawned')
101
+ const idled = captured.find((e) => e.type === 'subsession_idled')
102
+ expect(spawned).toBeDefined()
103
+ expect(idled).toBeDefined()
104
+
105
+ if (spawned && 'lineage' in spawned) {
106
+ expect(spawned.lineage.parentSessionId).toBe(session.id)
107
+ expect(spawned.lineage.rootSessionId).toBe(session.id)
108
+ expect(spawned.lineage.depth).toBe(1)
109
+ }
110
+ if (idled && 'lineage' in idled) {
111
+ expect(idled.lineage.parentSessionId).toBe(session.id)
112
+ expect(idled.lineage.rootSessionId).toBe(session.id)
113
+ expect(idled.lineage.depth).toBe(1)
114
+ }
115
+ })
116
+
117
+ it('3-deep delegation: rootSessionId identical across tree; depth ascends 1→2→3', async () => {
118
+ const harness = buildHarness()
119
+ const { project, session, actor } = await seedActiveParent(harness)
120
+
121
+ // Wire a cascading agent: level-1 child spawns level-2 via its own
122
+ // sendMessage. We hand a reference to the manager into the child agent
123
+ // via a closure so level-2 can spawn level-3.
124
+ const manager: AgentManager = harness.manager
125
+ const nestedEventsCaptured: RunEvent[] = []
126
+
127
+ const leafAgent = buildAgent('leaf', 'leaf result')
128
+ const midAgent = buildAgentCustom(
129
+ 'mid',
130
+ async (_input: AgentInput, config: BaseAgentConfig): Promise<BaseAgentResult> => {
131
+ // Spawn a level-2 child from inside the mid-agent's run.
132
+ if (!config.sessionId || !config.projectId || !config.tenantId) {
133
+ throw new Error('mid agent missing session scoping')
134
+ }
135
+ // Flip child session to active so it is a legal spawn parent.
136
+ const childSessionId = config.sessionId
137
+ const cs = await harness.store.getSession(childSessionId, config.tenantId)
138
+ if (cs && cs.status !== 'active') {
139
+ await harness.store.updateSession({ ...cs, status: 'active' }, config.tenantId)
140
+ }
141
+ const task2 = await manager.sendMessage(
142
+ {
143
+ agentId: 'leaf',
144
+ input: { messages: [], workingDirectory: '/tmp' },
145
+ parentSessionId: childSessionId,
146
+ tenantId: config.tenantId,
147
+ projectId: config.projectId,
148
+ parentActor: { kind: 'agent', agentId: 'mid' as never, tenantId: config.tenantId },
149
+ },
150
+ {
151
+ parentRunId: 'run_mid' as RunId,
152
+ parentAgentId: 'mid',
153
+ parentAbortController: new AbortController(),
154
+ depth: 1,
155
+ budgetTracker: { total: 10_000, remaining: 10_000 },
156
+ tenantId: config.tenantId,
157
+ sessionId: childSessionId,
158
+ projectId: config.projectId,
159
+ parentActor: { kind: 'agent', agentId: 'mid' as never, tenantId: config.tenantId },
160
+ },
161
+ (ev) => {
162
+ nestedEventsCaptured.push(ev)
163
+ },
164
+ )
165
+ await manager.waitForCompletion(task2.taskId)
166
+
167
+ return {
168
+ runId: 'run_mid_result' as RunId,
169
+ status: 'completed',
170
+ usage: { ...EMPTY_TOKEN_USAGE },
171
+ cost: { ...ZERO_COST },
172
+ iterations: 1,
173
+ durationMs: 1,
174
+ messages: [createAssistantMessage('mid done')],
175
+ result: 'mid done',
176
+ }
177
+ },
178
+ )
179
+
180
+ harness.registry.register(buildDefinition(leafAgent))
181
+ harness.registry.register(buildDefinition(midAgent))
182
+
183
+ const outerCaptured: RunEvent[] = []
184
+ const task = await harness.manager.sendMessage(
185
+ buildSendMessageOptions({
186
+ agentId: 'mid',
187
+ parentSessionId: session.id,
188
+ projectId: project.id,
189
+ tenantId: DEFAULT_TENANT,
190
+ parentActor: actor,
191
+ }),
192
+ buildTaskContext({
193
+ sessionId: session.id,
194
+ projectId: project.id,
195
+ tenantId: DEFAULT_TENANT,
196
+ parentActor: actor,
197
+ }),
198
+ (ev) => {
199
+ outerCaptured.push(ev)
200
+ },
201
+ )
202
+ await harness.manager.waitForCompletion(task.taskId)
203
+
204
+ // Outer capture has level-1 events with rootSessionId === session.id,
205
+ // depth 1. The nested capture has level-2 events with rootSessionId
206
+ // also === session.id (the whole tree shares a root) and depth 2.
207
+ const outerLineages = outerCaptured
208
+ .filter((e) => 'lineage' in e && e.lineage)
209
+ .map((e) => {
210
+ const l = (e as unknown as { lineage: { rootSessionId: string; depth: number } }).lineage
211
+ return { rootSessionId: l.rootSessionId, depth: l.depth }
212
+ })
213
+ expect(outerLineages.length).toBeGreaterThan(0)
214
+ for (const l of outerLineages) {
215
+ expect(l.rootSessionId).toBe(session.id)
216
+ expect(l.depth).toBe(1)
217
+ }
218
+
219
+ // Nested level-2 events: same rootSessionId, depth 2.
220
+ const nestedLineages = nestedEventsCaptured
221
+ .filter((e) => 'lineage' in e && e.lineage)
222
+ .map((e) => {
223
+ const l = (e as unknown as { lineage: { rootSessionId: string; depth: number } }).lineage
224
+ return { rootSessionId: l.rootSessionId, depth: l.depth }
225
+ })
226
+ expect(nestedLineages.length).toBeGreaterThan(0)
227
+ for (const l of nestedLineages) {
228
+ expect(l.rootSessionId).toBe(session.id)
229
+ expect(l.depth).toBe(2)
230
+ }
231
+ })
232
+
233
+ it('self vs tree depth filter: outer listener sees only its session events; nested listener sees its own tree', async () => {
234
+ // The subscribe-time depth filter is implemented at the listener
235
+ // injection seam — the parent passes a listener that captures events
236
+ // from its own sendMessage call. A nested child's sendMessage receives
237
+ // its own listener — the outer listener does NOT see the nested
238
+ // listener's events (no cross-contamination).
239
+ const harness = buildHarness()
240
+ const { project, session, actor } = await seedActiveParent(harness)
241
+
242
+ const outerCaptured: RunEvent[] = []
243
+ const nestedCaptured: RunEvent[] = []
244
+
245
+ const leafAgent = buildAgent('leaf', 'leaf')
246
+ const midAgent = buildAgentCustom(
247
+ 'mid',
248
+ async (_input: AgentInput, config: BaseAgentConfig): Promise<BaseAgentResult> => {
249
+ if (!config.sessionId || !config.projectId || !config.tenantId) {
250
+ throw new Error('mid missing scope')
251
+ }
252
+ const cs = await harness.store.getSession(config.sessionId, config.tenantId)
253
+ if (cs && cs.status !== 'active') {
254
+ await harness.store.updateSession({ ...cs, status: 'active' }, config.tenantId)
255
+ }
256
+ const inner = await harness.manager.sendMessage(
257
+ {
258
+ agentId: 'leaf',
259
+ input: { messages: [], workingDirectory: '/tmp' },
260
+ parentSessionId: config.sessionId,
261
+ tenantId: config.tenantId,
262
+ projectId: config.projectId,
263
+ parentActor: {
264
+ kind: 'agent',
265
+ agentId: 'mid' as never,
266
+ tenantId: config.tenantId,
267
+ },
268
+ },
269
+ {
270
+ parentRunId: 'run_mid_inner' as RunId,
271
+ parentAgentId: 'mid',
272
+ parentAbortController: new AbortController(),
273
+ depth: 1,
274
+ budgetTracker: { total: 10_000, remaining: 10_000 },
275
+ tenantId: config.tenantId,
276
+ sessionId: config.sessionId,
277
+ projectId: config.projectId,
278
+ parentActor: {
279
+ kind: 'agent',
280
+ agentId: 'mid' as never,
281
+ tenantId: config.tenantId,
282
+ },
283
+ },
284
+ (ev) => {
285
+ nestedCaptured.push(ev)
286
+ },
287
+ )
288
+ await harness.manager.waitForCompletion(inner.taskId)
289
+ return {
290
+ runId: 'run_mid_done' as RunId,
291
+ status: 'completed',
292
+ usage: { ...EMPTY_TOKEN_USAGE },
293
+ cost: { ...ZERO_COST },
294
+ iterations: 1,
295
+ durationMs: 1,
296
+ messages: [createAssistantMessage('mid')],
297
+ result: 'mid',
298
+ }
299
+ },
300
+ )
301
+
302
+ harness.registry.register(buildDefinition(leafAgent))
303
+ harness.registry.register(buildDefinition(midAgent))
304
+
305
+ const task = await harness.manager.sendMessage(
306
+ buildSendMessageOptions({
307
+ agentId: 'mid',
308
+ parentSessionId: session.id,
309
+ projectId: project.id,
310
+ tenantId: DEFAULT_TENANT,
311
+ parentActor: actor,
312
+ }),
313
+ buildTaskContext({
314
+ sessionId: session.id,
315
+ projectId: project.id,
316
+ tenantId: DEFAULT_TENANT,
317
+ parentActor: actor,
318
+ }),
319
+ (ev) => {
320
+ outerCaptured.push(ev)
321
+ },
322
+ )
323
+ await harness.manager.waitForCompletion(task.taskId)
324
+
325
+ // Outer only sees its own spawn events (depth 1).
326
+ const outerSpawnedDepths = outerCaptured
327
+ .filter((e) => e.type === 'subsession_spawned')
328
+ .map((e) => ('lineage' in e && e.lineage ? e.lineage.depth : -1))
329
+ expect(outerSpawnedDepths).toEqual([1])
330
+
331
+ // Nested listener only sees its own spawn events (depth 2).
332
+ const nestedSpawnedDepths = nestedCaptured
333
+ .filter((e) => e.type === 'subsession_spawned')
334
+ .map((e) => ('lineage' in e && e.lineage ? e.lineage.depth : -1))
335
+ expect(nestedSpawnedDepths).toEqual([2])
336
+
337
+ // Cross-contamination sentinel: outer listener MUST NOT contain any
338
+ // depth-2 events (those belong to the nested scope).
339
+ const outerDepths = outerCaptured
340
+ .filter((e) => 'lineage' in e && e.lineage)
341
+ .map((e) => ('lineage' in e && e.lineage ? e.lineage.depth : -1))
342
+ expect(outerDepths.every((d) => d === 1)).toBe(true)
343
+ })
344
+
345
+ it('run_started and other core RunEvents also carry schemaVersion: 2 when stamped by the child listener wrapper', async () => {
346
+ // The listener wrapper in `manager/agent/lifecycle.ts#wrapChildListener`
347
+ // stamps `schemaVersion: 2` + `lineage` on EVERY event emitted inside
348
+ // the child's run. Core events that pass through the wrapped listener
349
+ // therefore inherit the envelope even though they have no lineage in
350
+ // their own type definition.
351
+ const harness = buildHarness()
352
+ const { project, session, actor } = await seedActiveParent(harness)
353
+
354
+ const leafAgent = buildAgentCustom(
355
+ 'leaf-emit',
356
+ async (_i, _c, listener): Promise<BaseAgentResult> => {
357
+ // Emit a core event inside the child's run via the listener passed in.
358
+ await listener?.({
359
+ type: 'run_started',
360
+ runId: 'run_child_inner' as RunId,
361
+ })
362
+ return {
363
+ runId: 'run_child_inner' as RunId,
364
+ status: 'completed',
365
+ usage: { ...EMPTY_TOKEN_USAGE },
366
+ cost: { ...ZERO_COST },
367
+ iterations: 1,
368
+ durationMs: 1,
369
+ messages: [createAssistantMessage('done')],
370
+ result: 'done',
371
+ }
372
+ },
373
+ )
374
+ harness.registry.register(buildDefinition(leafAgent))
375
+
376
+ const captured: RunEvent[] = []
377
+ const task = await harness.manager.sendMessage(
378
+ buildSendMessageOptions({
379
+ agentId: 'leaf-emit',
380
+ parentSessionId: session.id,
381
+ projectId: project.id,
382
+ tenantId: DEFAULT_TENANT,
383
+ parentActor: actor,
384
+ }),
385
+ buildTaskContext({
386
+ sessionId: session.id,
387
+ projectId: project.id,
388
+ tenantId: DEFAULT_TENANT,
389
+ parentActor: actor,
390
+ }),
391
+ (ev) => {
392
+ captured.push(ev)
393
+ },
394
+ )
395
+ await harness.manager.waitForCompletion(task.taskId)
396
+
397
+ const runStarted = captured.find((e) => e.type === 'run_started')
398
+ expect(runStarted).toBeDefined()
399
+ if (runStarted && 'schemaVersion' in runStarted) {
400
+ expect(runStarted.schemaVersion).toBe(2)
401
+ }
402
+ })
403
+ })
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Integration — broadcast handoff atomic fan-out + rollback wired through
3
+ * the real stack.
4
+ *
5
+ * Covers roadmap §5 invariants: §5.4 (source → `awaiting_merge` after
6
+ * successful commit), §6.2 (broadcast atomic rollback — zero orphan
7
+ * sub-sessions/sessions after rollback via `deleteSubSession` +
8
+ * `deleteSession`), §10.2 (broadcast.rollback event carries accurate
9
+ * partialState counts).
10
+ */
11
+
12
+ import { describe, expect, it, vi } from 'vitest'
13
+ import { InMemorySessionStore } from '../../../store/session/memory.js'
14
+ import type { SessionId } from '../../../types/ids/index.js'
15
+ import type { ProjectId } from '../../../types/session/ids.js'
16
+ import { generateHandoffId } from '../../../utils/id.js'
17
+ import type { HandoffAssignment } from '../../handoff/assignment.js'
18
+ import { type BroadcastHandoffDeps, executeBroadcastHandoff } from '../../handoff/broadcast.js'
19
+ import { DefaultCapacityValidator } from '../../handoff/capacity.js'
20
+ import type { HandoffEventSink } from '../../handoff/events.js'
21
+ import type { ActorRef } from '../../hierarchy/actor.js'
22
+ import type { ExecFile } from '../../workspace/git-worktree.js'
23
+ import { GitWorktreeDriver } from '../../workspace/git-worktree.js'
24
+ import { WorkspaceBackendRegistry } from '../../workspace/registry.js'
25
+ import { DEFAULT_TENANT, okExec, stubLogger, userActor } from './_fixtures.js'
26
+
27
+ function buildDeps(
28
+ store: InMemorySessionStore,
29
+ execOverride?: ExecFile,
30
+ ): {
31
+ deps: BroadcastHandoffDeps
32
+ events: HandoffEventSink & { onBroadcastRollback: ReturnType<typeof vi.fn> }
33
+ } {
34
+ const exec: ExecFile = execOverride ?? (async () => okExec())
35
+ const driver = new GitWorktreeDriver({
36
+ repoRoot: '/repo',
37
+ logger: stubLogger(),
38
+ execFile: exec,
39
+ })
40
+ const workspaceRegistry = new WorkspaceBackendRegistry()
41
+ workspaceRegistry.register(driver)
42
+
43
+ const onBroadcastRollback = vi.fn()
44
+ const sink: HandoffEventSink = {
45
+ onLocked: vi.fn(),
46
+ onUnlocked: vi.fn(),
47
+ onCommitted: vi.fn(),
48
+ onBroadcastRollback,
49
+ }
50
+
51
+ return {
52
+ deps: {
53
+ store,
54
+ workspaceRegistry,
55
+ capacity: new DefaultCapacityValidator(store),
56
+ events: sink,
57
+ },
58
+ events: { ...sink, onBroadcastRollback },
59
+ }
60
+ }
61
+
62
+ function buildAssignments(
63
+ sourceSessionId: SessionId,
64
+ projectId: ProjectId,
65
+ recipients: ActorRef[],
66
+ broadcastId = 'bc_integration',
67
+ expectedOwnerVersion = 0,
68
+ ): HandoffAssignment[] {
69
+ return recipients.map((recipientActor) => ({
70
+ id: generateHandoffId(),
71
+ mode: 'broadcast' as const,
72
+ sourceSessionId,
73
+ tenantId: DEFAULT_TENANT,
74
+ projectId,
75
+ sourceActor: userActor('usr_source'),
76
+ recipientActor,
77
+ expectedOwnerVersion,
78
+ broadcastId,
79
+ createdAt: new Date('2026-04-17'),
80
+ }))
81
+ }
82
+
83
+ describe('Integration — broadcast handoff E2E', () => {
84
+ it('happy: 3-recipient fan-out → each recipient has isolated worktree + source reaches awaiting_merge', async () => {
85
+ const store = new InMemorySessionStore()
86
+ const project = await store.createProject(
87
+ { tenantId: DEFAULT_TENANT, name: 'bc-happy' },
88
+ DEFAULT_TENANT,
89
+ )
90
+ const source = await store.createSession(
91
+ { projectId: project.id, currentActor: userActor('usr_source') },
92
+ DEFAULT_TENANT,
93
+ )
94
+
95
+ // Track each `worktree add` call so we can assert each recipient got a
96
+ // distinct worktree path (isolation).
97
+ const addCalls: string[] = []
98
+ const exec: ExecFile = async (_file, args) => {
99
+ if (args.includes('add')) {
100
+ // args contains ['-C', ..., 'worktree', 'add', '-b', branch, path].
101
+ const path = args[args.length - 1]
102
+ if (typeof path === 'string') addCalls.push(path)
103
+ }
104
+ return okExec()
105
+ }
106
+ const { deps } = buildDeps(store, exec)
107
+
108
+ const recipients = [userActor('usr_bob'), userActor('usr_carol'), userActor('usr_dan')]
109
+ const assignments = buildAssignments(source.id, project.id, recipients)
110
+
111
+ const outcomes = await executeBroadcastHandoff(deps, assignments, DEFAULT_TENANT)
112
+ expect(outcomes).toHaveLength(3)
113
+ expect(new Set(outcomes.map((o) => o.newSessionId)).size).toBe(3)
114
+ expect(new Set(outcomes.map((o) => o.workspaceId)).size).toBe(3)
115
+
116
+ // Each recipient landed on a distinct worktree path — isolation holds.
117
+ expect(new Set(addCalls).size).toBe(3)
118
+
119
+ // §5.4: source transitions to awaiting_merge post-commit.
120
+ const reloaded = await store.getSession(source.id, DEFAULT_TENANT)
121
+ expect(reloaded?.status).toBe('awaiting_merge')
122
+
123
+ // Three children visible via getChildren.
124
+ const children = await store.getChildren(source.id, DEFAULT_TENANT)
125
+ expect(children).toHaveLength(3)
126
+ expect(children.every((c) => c.kind === 'user_handoff')).toBe(true)
127
+ })
128
+
129
+ it('rollback on 2nd-recipient provisioning failure: zero orphan records, partialState accurate', async () => {
130
+ const store = new InMemorySessionStore()
131
+ const project = await store.createProject(
132
+ { tenantId: DEFAULT_TENANT, name: 'bc-rb' },
133
+ DEFAULT_TENANT,
134
+ )
135
+ const source = await store.createSession(
136
+ { projectId: project.id, currentActor: userActor('usr_source') },
137
+ DEFAULT_TENANT,
138
+ )
139
+
140
+ let addCount = 0
141
+ const exec: ExecFile = async (_file, args) => {
142
+ if (args.includes('add')) {
143
+ addCount += 1
144
+ if (addCount === 2) throw new Error('simulated fault on 2nd recipient')
145
+ }
146
+ return okExec()
147
+ }
148
+ const { deps, events } = buildDeps(store, exec)
149
+
150
+ const assignments = buildAssignments(source.id, project.id, [
151
+ userActor('usr_b'),
152
+ userActor('usr_c'),
153
+ userActor('usr_d'),
154
+ ])
155
+
156
+ await expect(executeBroadcastHandoff(deps, assignments, DEFAULT_TENANT)).rejects.toThrow(
157
+ /Workspace backend git-worktree failed on create/,
158
+ )
159
+
160
+ // Phase 8 closed the Known Delta: rollback now calls deleteSubSession +
161
+ // deleteSession rather than flipping to 'archived'. Zero orphan
162
+ // sub-session records remain.
163
+ const children = await store.getChildren(source.id, DEFAULT_TENANT)
164
+ expect(children).toHaveLength(0)
165
+
166
+ // Source reverted to idle with original ownerVersion.
167
+ const reloaded = await store.getSession(source.id, DEFAULT_TENANT)
168
+ expect(reloaded?.status).toBe('idle')
169
+ expect(reloaded?.ownerVersion).toBe(0)
170
+
171
+ // onBroadcastRollback emitted with accurate counts.
172
+ expect(events.onBroadcastRollback).toHaveBeenCalledTimes(1)
173
+ const rollbackCall = events.onBroadcastRollback.mock.calls[0]?.[0] as
174
+ | {
175
+ partialState: {
176
+ worktreesProvisioned: number
177
+ subsessionsCreated: number
178
+ assignmentsWritten: number
179
+ }
180
+ }
181
+ | undefined
182
+ expect(rollbackCall?.partialState.worktreesProvisioned).toBe(1)
183
+ expect(rollbackCall?.partialState.subsessionsCreated).toBe(1)
184
+ expect(rollbackCall?.partialState.assignmentsWritten).toBe(1)
185
+ })
186
+
187
+ it('source transitions to awaiting_merge + retains currentActor as coordinator (§5.4)', async () => {
188
+ const store = new InMemorySessionStore()
189
+ const project = await store.createProject(
190
+ { tenantId: DEFAULT_TENANT, name: 'coord' },
191
+ DEFAULT_TENANT,
192
+ )
193
+ const coordinator = userActor('usr_source')
194
+ const source = await store.createSession(
195
+ { projectId: project.id, currentActor: coordinator },
196
+ DEFAULT_TENANT,
197
+ )
198
+
199
+ const { deps } = buildDeps(store)
200
+ const assignments = buildAssignments(source.id, project.id, [
201
+ userActor('usr_b'),
202
+ userActor('usr_c'),
203
+ ])
204
+
205
+ await executeBroadcastHandoff(deps, assignments, DEFAULT_TENANT)
206
+
207
+ const reloaded = await store.getSession(source.id, DEFAULT_TENANT)
208
+ expect(reloaded?.status).toBe('awaiting_merge')
209
+ // Coordinator retained as current actor (§5.4).
210
+ expect(reloaded?.currentActor).toEqual(coordinator)
211
+ expect(reloaded?.ownerVersion).toBe(1)
212
+ })
213
+
214
+ it('all recipients get isolated worktrees — zero path collisions even under N=8', async () => {
215
+ const store = new InMemorySessionStore()
216
+ const project = await store.createProject(
217
+ { tenantId: DEFAULT_TENANT, name: 'iso' },
218
+ DEFAULT_TENANT,
219
+ )
220
+ const source = await store.createSession(
221
+ { projectId: project.id, currentActor: userActor('usr_source') },
222
+ DEFAULT_TENANT,
223
+ )
224
+
225
+ const seenPaths = new Set<string>()
226
+ const exec: ExecFile = async (_file, args) => {
227
+ if (args.includes('add')) {
228
+ const path = args[args.length - 1]
229
+ if (typeof path === 'string') {
230
+ if (seenPaths.has(path)) throw new Error(`path collision: ${path}`)
231
+ seenPaths.add(path)
232
+ }
233
+ }
234
+ return okExec()
235
+ }
236
+ const { deps } = buildDeps(store, exec)
237
+
238
+ const recipients = Array.from({ length: 8 }, (_, i) => userActor(`usr_${i}`))
239
+ const assignments = buildAssignments(source.id, project.id, recipients)
240
+
241
+ const outcomes = await executeBroadcastHandoff(deps, assignments, DEFAULT_TENANT)
242
+ expect(outcomes).toHaveLength(8)
243
+ expect(seenPaths.size).toBe(8)
244
+ })
245
+ })