@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,288 @@
1
+ /**
2
+ * Single-recipient handoff flow — `idle → locked → CAS → commit | revert`.
3
+ *
4
+ * See session-hierarchy.md §6.1 (single-recipient flow) and §6.4 (concurrent
5
+ * CAS). Function-based per Convention #9 — dependencies arrive as an
6
+ * explicit `deps` envelope so tests can inject mocks and production code
7
+ * composes flows without a class hierarchy.
8
+ *
9
+ * Flow (pattern doc §5.1 + §6.1):
10
+ * 1. Load source session; verify tenant.
11
+ * 2. Check status (must be `idle`); no non-terminal Runs.
12
+ * 3. Validate capacity (depth + width).
13
+ * 4. Transition source `idle → locked` with CAS on `ownerVersion`.
14
+ * 5. Emit `onLocked`.
15
+ * 6. Spawn recipient sub-session + provision isolated workspace.
16
+ * 7. On any step 6 failure: compensating revert (`locked → idle`, version
17
+ * unchanged, dispose any partial worktree), emit `onUnlocked`, rethrow.
18
+ * 8. On success: commit `locked → idle` with updated `currentActor` +
19
+ * appended `previousActors` + bumped `ownerVersion`.
20
+ * 9. Emit `onCommitted` with the new version.
21
+ */
22
+
23
+ import type { SessionId, TenantId } from '../../types/ids/index.js'
24
+ import type { SessionStore } from '../../types/session/store.js'
25
+ import { TenantIsolationError } from '../errors.js'
26
+ import type { Session } from '../hierarchy/session.js'
27
+ import type { WorkspaceBackendDriver } from '../workspace/driver.js'
28
+ import type { WorkspaceRef } from '../workspace/ref.js'
29
+ import type { WorkspaceBackendRegistry } from '../workspace/registry.js'
30
+ import type { HandoffAssignment, HandoffOutcome } from './assignment.js'
31
+ import type { CapacityValidator } from './capacity.js'
32
+ import type { HandoffEventSink } from './events.js'
33
+ import { HandoffLockRejected, HandoffVersionConflict } from './version.js'
34
+
35
+ /**
36
+ * Minimal surface the handoff flow queries for Run fan-in status. A Run is
37
+ * considered "blocking" if it is in any non-terminal status that prevents the
38
+ * source session from transitioning to `locked` (session-hierarchy.md §5.1).
39
+ *
40
+ * The flow injects the resolver so Phase 4 stays decoupled from Phase 6's
41
+ * Run persistence refactor. Production wires the real Run store; tests stub.
42
+ */
43
+ export interface RunStatusResolver {
44
+ /**
45
+ * Returns the reason the session has a non-terminal Run, or `null` when
46
+ * all Runs are terminal and the lock is allowed.
47
+ */
48
+ blockingRun(
49
+ sessionId: SessionId,
50
+ tenantId: TenantId,
51
+ ): Promise<{ reason: 'active_run' | 'pending_hitl' | 'pending_subsession' } | null>
52
+ }
53
+
54
+ /** Null resolver — treats every session as unblocked. Used by tests that do not exercise Run fan-in. */
55
+ export const NOOP_RUN_STATUS_RESOLVER: RunStatusResolver = {
56
+ async blockingRun(): Promise<null> {
57
+ return null
58
+ },
59
+ }
60
+
61
+ export interface SingleHandoffDeps {
62
+ store: SessionStore
63
+ workspaceRegistry: WorkspaceBackendRegistry
64
+ capacity: CapacityValidator
65
+ events: HandoffEventSink
66
+ runStatus?: RunStatusResolver
67
+ }
68
+
69
+ /**
70
+ * Executes a single-recipient handoff against `deps.store`. Throws
71
+ * {@link HandoffLockRejected}, {@link HandoffVersionConflict},
72
+ * {@link TenantIsolationError}, or {@link DelegationCapacityExceeded} on
73
+ * invariant violations. Workspace provisioning failures surface as
74
+ * {@link WorkspaceBackendError} after the compensating revert.
75
+ */
76
+ export async function executeSingleHandoff(
77
+ deps: SingleHandoffDeps,
78
+ assignment: HandoffAssignment,
79
+ tenantId: TenantId,
80
+ ): Promise<HandoffOutcome> {
81
+ if (assignment.tenantId !== tenantId) {
82
+ throw new TenantIsolationError({
83
+ requested: tenantId,
84
+ resource: `handoff-assignment(${assignment.id})`,
85
+ })
86
+ }
87
+
88
+ // 1. Load source session + tenant check.
89
+ const source = await deps.store.getSession(assignment.sourceSessionId, tenantId)
90
+ if (!source) {
91
+ throw new Error(`Source session ${assignment.sourceSessionId} not found`)
92
+ }
93
+ if (source.tenantId !== tenantId) {
94
+ throw new TenantIsolationError({
95
+ requested: tenantId,
96
+ resource: `session(${source.id})`,
97
+ })
98
+ }
99
+ if (source.projectId !== assignment.projectId) {
100
+ throw new Error(
101
+ `Assignment projectId ${assignment.projectId} does not match source session projectId ${source.projectId}`,
102
+ )
103
+ }
104
+
105
+ // 2. Status check — only `idle` sessions may lock. `active`, `awaiting_hitl`,
106
+ // `awaiting_merge`, `locked`, `failed`, `archived` all reject.
107
+ if (source.status !== 'idle') {
108
+ throw new HandoffLockRejected({
109
+ sessionId: source.id,
110
+ reason: statusToLockReason(source.status),
111
+ })
112
+ }
113
+
114
+ // 3. Non-terminal Run fan-in (§5.1).
115
+ const runResolver = deps.runStatus ?? NOOP_RUN_STATUS_RESOLVER
116
+ const blocking = await runResolver.blockingRun(source.id, tenantId)
117
+ if (blocking) {
118
+ throw new HandoffLockRejected({
119
+ sessionId: source.id,
120
+ reason: blocking.reason,
121
+ })
122
+ }
123
+
124
+ // 4. Capacity — depth (new child depth = parent ancestry length + 1) and
125
+ // width (one new child under the source's *parent* would change — but
126
+ // single handoff does NOT create a child under the source; it transfers
127
+ // ownership of the same session. Width only applies to broadcast).
128
+ // For `single` we still validate depth to future-proof should the flow
129
+ // evolve into a branch variant.
130
+ const project = await deps.store.getProject(source.projectId, tenantId)
131
+ if (!project) {
132
+ throw new Error(`Project ${source.projectId} not found`)
133
+ }
134
+ await deps.capacity.validateDepth(source.id, project.config.maxDelegationDepth, tenantId)
135
+
136
+ // 5. CAS → `idle → locked`.
137
+ if (source.ownerVersion !== assignment.expectedOwnerVersion) {
138
+ throw new HandoffVersionConflict({
139
+ sessionId: source.id,
140
+ expected: assignment.expectedOwnerVersion,
141
+ actual: source.ownerVersion,
142
+ })
143
+ }
144
+
145
+ const locked: Session = {
146
+ ...source,
147
+ status: 'locked',
148
+ }
149
+ await deps.store.updateSession(locked, tenantId)
150
+ emit(deps.events.onLocked, { sessionId: source.id, at: new Date() })
151
+
152
+ // 6. Provision recipient resources. Track partial state for rollback.
153
+ let provisionedWorkspace: WorkspaceRef | null = null
154
+ let createdSessionId: SessionId | null = null
155
+ try {
156
+ const driver: WorkspaceBackendDriver = deps.workspaceRegistry.get('git-worktree')
157
+ provisionedWorkspace = await driver.create({ label: `handoff-${assignment.id}` })
158
+
159
+ const recipientSession = await deps.store.createSession(
160
+ { projectId: source.projectId, currentActor: assignment.recipientActor },
161
+ tenantId,
162
+ )
163
+ createdSessionId = recipientSession.id
164
+
165
+ await deps.store.createSubSession(
166
+ {
167
+ parentSessionId: source.id,
168
+ childSessionId: recipientSession.id,
169
+ kind: 'user_handoff',
170
+ spawnedBy: assignment.sourceActor,
171
+ },
172
+ tenantId,
173
+ )
174
+
175
+ // 7. Commit source: `locked → idle` with appended actor + bumped version.
176
+ // The source transitions ownership to the recipient — the previous
177
+ // owner is permanently read-only (§6.1).
178
+ const committed: Session = {
179
+ ...source,
180
+ status: 'idle',
181
+ currentActor: assignment.recipientActor,
182
+ previousActors: source.currentActor
183
+ ? [...source.previousActors, source.currentActor]
184
+ : [...source.previousActors],
185
+ ownerVersion: source.ownerVersion + 1,
186
+ }
187
+ await deps.store.updateSession(committed, tenantId)
188
+
189
+ emit(deps.events.onCommitted, {
190
+ sessionId: source.id,
191
+ newVersion: committed.ownerVersion,
192
+ handoffIds: [assignment.id],
193
+ at: new Date(),
194
+ })
195
+
196
+ return {
197
+ assignmentId: assignment.id,
198
+ newSessionId: recipientSession.id,
199
+ workspaceId: provisionedWorkspace.id,
200
+ committedOwnerVersion: committed.ownerVersion,
201
+ }
202
+ } catch (failure) {
203
+ // Compensating revert — idempotent. Every step tolerates prior success.
204
+ await revertLock(deps, source, provisionedWorkspace, createdSessionId, tenantId)
205
+ throw failure
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Reverts a source session from `locked` back to `idle` preserving
211
+ * `ownerVersion`, disposes any provisioned worktree, and emits `onUnlocked`.
212
+ *
213
+ * **Idempotent.** Every sub-op tolerates being called against already-released
214
+ * state:
215
+ * - `updateSession` replays the same payload — last-write-wins (Phase 3
216
+ * store uses write-tmp-rename).
217
+ * - `dispose` on a missing worktree is a no-op by contract
218
+ * (`driver.ts#dispose` + `git-worktree.ts` regex for "not a working tree").
219
+ */
220
+ async function revertLock(
221
+ deps: SingleHandoffDeps,
222
+ source: Session,
223
+ workspace: WorkspaceRef | null,
224
+ createdSessionId: SessionId | null,
225
+ tenantId: TenantId,
226
+ ): Promise<void> {
227
+ const reverted: Session = { ...source, status: 'idle' }
228
+ try {
229
+ await deps.store.updateSession(reverted, tenantId)
230
+ } catch {
231
+ // Swallow — the flow is already unwinding a primary failure; surfacing
232
+ // secondary errors would mask root cause. Idempotent per Risk #3.
233
+ }
234
+
235
+ if (workspace) {
236
+ try {
237
+ const driver = deps.workspaceRegistry.get('git-worktree')
238
+ await driver.dispose(workspace)
239
+ } catch {
240
+ // Idempotent rollback per Risk #3 — dispose is already tolerant of
241
+ // missing worktrees, but we still guard the registry lookup path.
242
+ }
243
+ }
244
+
245
+ if (createdSessionId) {
246
+ // No `deleteSession` in the Phase 3 store surface — mark the partially
247
+ // created recipient session as `archived` so it is inert. A later phase
248
+ // introduces explicit deletion; until then this is the cleanest
249
+ // compensator that does not add surface area.
250
+ try {
251
+ const recipient = await deps.store.getSession(createdSessionId, tenantId)
252
+ if (recipient) {
253
+ await deps.store.updateSession({ ...recipient, status: 'archived' }, tenantId)
254
+ }
255
+ } catch {
256
+ // Same rationale as above.
257
+ }
258
+ }
259
+
260
+ emit(deps.events.onUnlocked, { sessionId: source.id, at: new Date() })
261
+ }
262
+
263
+ function statusToLockReason(
264
+ status: Session['status'],
265
+ ): 'active_run' | 'pending_hitl' | 'pending_subsession' {
266
+ switch (status) {
267
+ case 'active':
268
+ return 'active_run'
269
+ case 'awaiting_hitl':
270
+ return 'pending_hitl'
271
+ case 'awaiting_merge':
272
+ return 'pending_subsession'
273
+ case 'locked':
274
+ return 'active_run'
275
+ case 'failed':
276
+ return 'active_run'
277
+ case 'archived':
278
+ return 'active_run'
279
+ case 'idle':
280
+ // Unreachable — caller guards. Keep a sentinel value so exhaustiveness
281
+ // does not force an `assert never` export from this module.
282
+ return 'active_run'
283
+ }
284
+ }
285
+
286
+ function emit<T>(handler: ((ev: T) => void) | undefined, event: T): void {
287
+ if (handler) handler(event)
288
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Typed errors for the handoff state machine.
3
+ *
4
+ * See session-hierarchy.md §5.1 (illegal `active → locked` transition) and
5
+ * §6.4 (concurrent CAS). Both classes carry structured `details` so consumers
6
+ * can route without string parsing (Convention #5: deny-by-default, fail
7
+ * fast).
8
+ */
9
+
10
+ import type { RunId, SessionId } from '../../types/ids/index.js'
11
+
12
+ /**
13
+ * Raised when a handoff's CAS write finds {@link Session.ownerVersion} has
14
+ * advanced since the assignment was constructed — another actor committed
15
+ * first (session-hierarchy.md §6.4 concurrent CAS). The caller re-reads and
16
+ * decides whether to retry.
17
+ */
18
+ export class HandoffVersionConflict extends Error {
19
+ readonly details: {
20
+ sessionId: SessionId
21
+ expected: number
22
+ actual: number
23
+ }
24
+
25
+ constructor(details: { sessionId: SessionId; expected: number; actual: number }) {
26
+ super(
27
+ `Handoff version conflict on ${details.sessionId}: expected ${details.expected}, actual ${details.actual}`,
28
+ )
29
+ this.name = 'HandoffVersionConflict'
30
+ this.details = details
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Reasons a session cannot transition `* → locked` for handoff. See
36
+ * session-hierarchy.md §5.1 — lock entry requires an `idle` session with all
37
+ * runs terminal. The three reasons are the non-terminal Run statuses that
38
+ * fan in to a non-idle Session.
39
+ */
40
+ export type HandoffLockRejectedReason = 'active_run' | 'pending_hitl' | 'pending_subsession'
41
+
42
+ /**
43
+ * Raised when a handoff targets a session whose current Run is non-terminal.
44
+ * Callers must wait for the active Run to terminalize (or cancel it) before
45
+ * re-attempting the handoff (session-hierarchy.md §5.1).
46
+ */
47
+ export class HandoffLockRejected extends Error {
48
+ readonly details: {
49
+ sessionId: SessionId
50
+ reason: HandoffLockRejectedReason
51
+ runId?: RunId
52
+ }
53
+
54
+ constructor(details: { sessionId: SessionId; reason: HandoffLockRejectedReason; runId?: RunId }) {
55
+ super(`Handoff lock rejected on ${details.sessionId}: ${details.reason}`)
56
+ this.name = 'HandoffLockRejected'
57
+ this.details = details
58
+ }
59
+ }
@@ -0,0 +1,92 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import type { RunStatus } from '../../../types/run/status.js'
3
+ import type { ProjectId, SessionId, TenantId, UserId } from '../../../types/session/ids.js'
4
+ import type { ActorRef } from '../actor.js'
5
+ import { type Session, type SessionStatus, deriveStatus } from '../session.js'
6
+
7
+ const tenant = 'tnt_a' as TenantId
8
+ const project = 'prj_a' as ProjectId
9
+
10
+ function user(): ActorRef {
11
+ return { kind: 'user', userId: 'usr_a' as UserId, tenantId: tenant }
12
+ }
13
+
14
+ function makeSession(status: SessionStatus): Session {
15
+ return {
16
+ id: 'ses_a' as SessionId,
17
+ projectId: project,
18
+ tenantId: tenant,
19
+ status,
20
+ currentActor: user(),
21
+ previousActors: [],
22
+ workspaceId: null,
23
+ ownerVersion: 0,
24
+ createdAt: new Date('2026-01-01'),
25
+ updatedAt: new Date('2026-01-01'),
26
+ }
27
+ }
28
+
29
+ function runs(...statuses: RunStatus[]): readonly { status: RunStatus }[] {
30
+ return statuses.map((status) => ({ status }))
31
+ }
32
+
33
+ describe('deriveStatus', () => {
34
+ it('empty run set → idle', () => {
35
+ expect(deriveStatus(makeSession('idle'), [])).toBe('idle')
36
+ })
37
+
38
+ it('all succeeded → idle', () => {
39
+ expect(deriveStatus(makeSession('idle'), runs('succeeded', 'succeeded'))).toBe('idle')
40
+ })
41
+
42
+ it('any running → active (overrides idle session status)', () => {
43
+ expect(deriveStatus(makeSession('idle'), runs('succeeded', 'running'))).toBe('active')
44
+ })
45
+
46
+ it('any awaiting_subsession → active (delegation-in-flight parent is active)', () => {
47
+ expect(deriveStatus(makeSession('idle'), runs('succeeded', 'awaiting_subsession'))).toBe(
48
+ 'active',
49
+ )
50
+ })
51
+
52
+ it('awaiting_subsession alone → active', () => {
53
+ expect(deriveStatus(makeSession('idle'), runs('awaiting_subsession'))).toBe('active')
54
+ })
55
+
56
+ it('any awaiting_hitl → awaiting_hitl', () => {
57
+ expect(deriveStatus(makeSession('idle'), runs('succeeded', 'awaiting_hitl'))).toBe(
58
+ 'awaiting_hitl',
59
+ )
60
+ })
61
+
62
+ it('any awaiting_hitl_resolution → awaiting_hitl (persisted HITL wait)', () => {
63
+ expect(deriveStatus(makeSession('idle'), runs('awaiting_hitl_resolution'))).toBe(
64
+ 'awaiting_hitl',
65
+ )
66
+ })
67
+
68
+ it('all failed → failed', () => {
69
+ expect(deriveStatus(makeSession('idle'), runs('failed', 'failed'))).toBe('failed')
70
+ })
71
+
72
+ it('cancelled + failed + succeeded mix → idle (cancellation is not terminal Session state)', () => {
73
+ expect(deriveStatus(makeSession('idle'), runs('succeeded', 'cancelled', 'failed'))).toBe('idle')
74
+ })
75
+
76
+ it('locked session-level state wins over derived (even with succeeded runs)', () => {
77
+ expect(deriveStatus(makeSession('locked'), runs('succeeded'))).toBe('locked')
78
+ })
79
+
80
+ it('awaiting_merge session-level state wins over derived', () => {
81
+ expect(deriveStatus(makeSession('awaiting_merge'), runs('succeeded'))).toBe('awaiting_merge')
82
+ })
83
+
84
+ it('archived session-level state wins over derived (retention tombstone)', () => {
85
+ expect(deriveStatus(makeSession('archived'), runs('succeeded'))).toBe('archived')
86
+ })
87
+
88
+ it('running takes precedence over HITL', () => {
89
+ // Two runs — one running, one HITL. Active is higher priority (§5.1).
90
+ expect(deriveStatus(makeSession('idle'), runs('running', 'awaiting_hitl'))).toBe('active')
91
+ })
92
+ })
@@ -0,0 +1,17 @@
1
+ import type { AgentId, TenantId, UserId } from '../../types/ids/index.js'
2
+
3
+ /**
4
+ * Discriminated union of actors that can own a {@link Session}.
5
+ *
6
+ * See session-hierarchy.md §4.3. The `parentActor` field on the agent variant
7
+ * pairs with {@link Lineage} (§10.4) — permission audit events walk this
8
+ * chain to attribute subagent actions back to the originating user. Renamed
9
+ * from `spawnedBy` during the 0.2.0 design phase (no shim kept).
10
+ */
11
+ export type ActorRef =
12
+ | { kind: 'user'; userId: UserId; tenantId: TenantId }
13
+ | { kind: 'agent'; agentId: AgentId; tenantId: TenantId; parentActor?: ActorRef }
14
+ | { kind: 'system'; role: SystemRoleId; tenantId: TenantId }
15
+
16
+ /** Branded id for the {@link ActorRef} `system` variant. */
17
+ export type SystemRoleId = `sys_${string}`
@@ -0,0 +1,17 @@
1
+ // Sub-barrel for the session-hierarchy entity model.
2
+ // Convention #4: concrete types live in sibling files; re-export them here.
3
+
4
+ export type { ActorRef, SystemRoleId } from './actor.js'
5
+ export type { Lineage } from './lineage.js'
6
+ export type { Tenant } from './tenant.js'
7
+ export type { Project, ProjectConfig } from './project.js'
8
+ export type { Session, SessionStatus } from './session.js'
9
+ export { deriveStatus } from './session.js'
10
+ export type {
11
+ SubSession,
12
+ SubSessionStatus,
13
+ SubSessionKind,
14
+ FailureMode,
15
+ CompletionMode,
16
+ DeliverableRef,
17
+ } from './sub-session.js'
@@ -0,0 +1,15 @@
1
+ import type { SessionId } from '../../types/ids/index.js'
2
+
3
+ /**
4
+ * Parent/root linkage carried on every sub-session event.
5
+ *
6
+ * Per session-hierarchy.md §10.4 every `RunEvent` emitted from a sub-session
7
+ * carries a {@link Lineage} so consumers can reconstruct the delegation tree
8
+ * without walking the store. `depth` is 0 at the root session and grows by 1
9
+ * per delegation level.
10
+ */
11
+ export interface Lineage {
12
+ parentSessionId: SessionId
13
+ rootSessionId: SessionId
14
+ depth: number
15
+ }
@@ -0,0 +1,41 @@
1
+ import type { KnowledgeBaseRef, MemoryStoreRef, TenantId, VaultRef } from '../../types/ids/index.js'
2
+ import type { ProjectId } from '../../types/session/ids.js'
3
+ import type { RetentionPolicy } from '../retention/policy.js'
4
+
5
+ /**
6
+ * Per-project configuration. Defaults per session-hierarchy.md §3 / §4.2 /
7
+ * §8.2 are applied at instantiation time (not encoded here) so the type
8
+ * stays declarative:
9
+ * - maxDelegationDepth: 4
10
+ * - maxDelegationWidth: 8
11
+ * - maxInterventionDepth: 10
12
+ * - sharedDeliverables: false
13
+ *
14
+ * `retentionPolicy` replaces the Phase 1 `RetentionPolicyRef = unknown`
15
+ * placeholder with the real {@link RetentionPolicy} shape (§12.3). Absent
16
+ * (deny-by-default per Convention #5) means archival is fully disabled for
17
+ * the project; explicit configuration is required.
18
+ */
19
+ export interface ProjectConfig {
20
+ maxDelegationDepth: number
21
+ maxDelegationWidth: number
22
+ maxInterventionDepth: number
23
+ sharedMemoryStores?: readonly MemoryStoreRef[]
24
+ sharedVaults?: readonly VaultRef[]
25
+ sharedKnowledgeBases?: readonly KnowledgeBaseRef[]
26
+ sharedDeliverables?: boolean
27
+ retentionPolicy?: RetentionPolicy
28
+ }
29
+
30
+ /**
31
+ * Long-lived goal scope that owns shared memory, vaults, knowledge bases,
32
+ * and deliverables across sessions. See session-hierarchy.md §4.2.
33
+ */
34
+ export interface Project {
35
+ id: ProjectId
36
+ tenantId: TenantId
37
+ name: string
38
+ config: ProjectConfig
39
+ createdAt: Date
40
+ updatedAt: Date
41
+ }
@@ -0,0 +1,97 @@
1
+ import type { SessionId, TenantId } from '../../types/ids/index.js'
2
+ import type { RunStatus } from '../../types/run/status.js'
3
+ import type { ProjectId, WorkspaceId } from '../../types/session/ids.js'
4
+ import type { ActorRef } from './actor.js'
5
+
6
+ /**
7
+ * Session lifecycle states. See session-hierarchy.md §4.3 and the state
8
+ * machine in §5.1. `awaiting_merge` is a sub-state of idle used on the
9
+ * broadcast source session (§5.4) between fan-out and all recipients
10
+ * terminalizing.
11
+ */
12
+ export type SessionStatus =
13
+ | 'active'
14
+ | 'idle'
15
+ | 'locked'
16
+ | 'awaiting_hitl'
17
+ | 'awaiting_merge'
18
+ | 'failed'
19
+ | 'archived'
20
+
21
+ /**
22
+ * Multi-turn work unit owned by exactly one {@link ActorRef} at a time.
23
+ *
24
+ * Fields derived from session-hierarchy.md §4.3:
25
+ * - `previousActors` is append-only and publicly read-only; previous
26
+ * owners cannot write to the session again (Decision #3).
27
+ * - `ownerVersion` is the CAS counter for handoff (§6.1 / §6.2 / §6.4).
28
+ * - `workspaceId` is nullable for sessions whose workspace has not yet
29
+ * been provisioned (or has been torn down during archival).
30
+ */
31
+ export interface Session {
32
+ id: SessionId
33
+ projectId: ProjectId
34
+ tenantId: TenantId
35
+ status: SessionStatus
36
+ currentActor: ActorRef | null
37
+ previousActors: readonly ActorRef[]
38
+ workspaceId: WorkspaceId | null
39
+ ownerVersion: number
40
+ createdAt: Date
41
+ updatedAt: Date
42
+ }
43
+
44
+ /**
45
+ * Pure Run→Session fan-in helper per session-hierarchy.md §5.1.
46
+ *
47
+ * The precedence (highest first) matches the pattern-doc table:
48
+ * 1. Session-level states that do not fan in from Run status:
49
+ * - `locked` (handoff CAS window) — preserved verbatim
50
+ * - `awaiting_merge` (broadcast source post-fan-out, §5.4) — preserved
51
+ * - `archived` (retention tombstone, §12.3) — preserved
52
+ * 2. Any Run `running` or `awaiting_subsession` → Session `active`.
53
+ * Delegation-in-flight is an active state of the parent — the parent
54
+ * Run is suspended waiting on the child's SessionSummaryMaterializer,
55
+ * and the session is NOT idle while that is pending.
56
+ * 3. Any Run `awaiting_hitl` or `awaiting_hitl_resolution` → Session
57
+ * `awaiting_hitl`.
58
+ * 4. All Runs `failed` and at least one Run present → Session `failed`.
59
+ * 5. Otherwise (all runs terminal — succeeded/cancelled/failed mix, or no
60
+ * runs at all) → Session `idle`.
61
+ *
62
+ * `cancelled` does NOT surface a `failed` Session (§5.1 — "Cancellation is
63
+ * not a terminal Session state"). Only `failed` runs drive the Session to
64
+ * `failed` when every Run ended that way.
65
+ */
66
+ export function deriveStatus(
67
+ session: Session,
68
+ runs: readonly { status: RunStatus }[],
69
+ ): SessionStatus {
70
+ // Session-level overrides — these states do not fan in from Run status.
71
+ if (session.status === 'locked') return 'locked'
72
+ if (session.status === 'awaiting_merge') return 'awaiting_merge'
73
+ if (session.status === 'archived') return 'archived'
74
+
75
+ // Any active Run (in-flight iteration or awaiting a child sub-session) →
76
+ // `active`. Delegation is an active state: the parent Run is suspended
77
+ // waiting on the child's Materializer, not idle.
78
+ const hasActive = runs.some((r) => r.status === 'running' || r.status === 'awaiting_subsession')
79
+ if (hasActive) return 'active'
80
+
81
+ // Any HITL block (synchronous or persisted) → `awaiting_hitl`.
82
+ const hasHitl = runs.some(
83
+ (r) => r.status === 'awaiting_hitl' || r.status === 'awaiting_hitl_resolution',
84
+ )
85
+ if (hasHitl) return 'awaiting_hitl'
86
+
87
+ // All failed (with at least one Run) → `failed`. Note that a `cancelled`
88
+ // Run does NOT drive the Session to `failed`; §5.1 is explicit that
89
+ // cancellation leaves the Session `idle`.
90
+ if (runs.length > 0 && runs.every((r) => r.status === 'failed')) {
91
+ return 'failed'
92
+ }
93
+
94
+ // Otherwise — empty run set, or all runs terminated (succeeded / cancelled
95
+ // / mixed with failed) — the Session is `idle`.
96
+ return 'idle'
97
+ }