@namzu/sdk 0.1.8 → 0.3.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 (626) hide show
  1. package/CHANGELOG.md +69 -2
  2. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  3. package/dist/agents/ReactiveAgent.js +5 -2
  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 +21 -5
  10. package/dist/agents/SupervisorAgent.js.map +1 -1
  11. package/dist/bridge/a2a/index.d.ts +1 -1
  12. package/dist/bridge/a2a/index.d.ts.map +1 -1
  13. package/dist/bridge/a2a/index.js +1 -1
  14. package/dist/bridge/a2a/index.js.map +1 -1
  15. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  16. package/dist/bridge/a2a/mapper.js +6 -0
  17. package/dist/bridge/a2a/mapper.js.map +1 -1
  18. package/dist/bridge/a2a/message.d.ts +0 -2
  19. package/dist/bridge/a2a/message.d.ts.map +1 -1
  20. package/dist/bridge/a2a/message.js +0 -26
  21. package/dist/bridge/a2a/message.js.map +1 -1
  22. package/dist/bridge/a2a/task.d.ts +5 -4
  23. package/dist/bridge/a2a/task.d.ts.map +1 -1
  24. package/dist/bridge/a2a/task.js +4 -4
  25. package/dist/bridge/a2a/task.js.map +1 -1
  26. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  27. package/dist/bridge/sse/mapper.js +6 -0
  28. package/dist/bridge/sse/mapper.js.map +1 -1
  29. package/dist/constants/a2a/index.d.ts +2 -2
  30. package/dist/constants/a2a/index.d.ts.map +1 -1
  31. package/dist/constants/a2a/index.js.map +1 -1
  32. package/dist/contracts/api.d.ts +14 -27
  33. package/dist/contracts/api.d.ts.map +1 -1
  34. package/dist/contracts/ids.d.ts +1 -1
  35. package/dist/contracts/ids.d.ts.map +1 -1
  36. package/dist/contracts/index.d.ts +3 -3
  37. package/dist/contracts/index.d.ts.map +1 -1
  38. package/dist/contracts/index.js +1 -1
  39. package/dist/contracts/index.js.map +1 -1
  40. package/dist/contracts/schemas.d.ts +1 -31
  41. package/dist/contracts/schemas.d.ts.map +1 -1
  42. package/dist/contracts/schemas.js +1 -7
  43. package/dist/contracts/schemas.js.map +1 -1
  44. package/dist/gateway/local.d.ts.map +1 -1
  45. package/dist/gateway/local.js +6 -0
  46. package/dist/gateway/local.js.map +1 -1
  47. package/dist/index.d.ts +6 -3
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +6 -3
  50. package/dist/index.js.map +1 -1
  51. package/dist/manager/agent/__tests__/lifecycle.test.d.ts +2 -0
  52. package/dist/manager/agent/__tests__/lifecycle.test.d.ts.map +1 -0
  53. package/dist/manager/agent/__tests__/lifecycle.test.js +316 -0
  54. package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -0
  55. package/dist/manager/agent/lifecycle.d.ts +67 -3
  56. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  57. package/dist/manager/agent/lifecycle.js +375 -14
  58. package/dist/manager/agent/lifecycle.js.map +1 -1
  59. package/dist/manager/index.d.ts +2 -0
  60. package/dist/manager/index.d.ts.map +1 -1
  61. package/dist/manager/index.js +1 -0
  62. package/dist/manager/index.js.map +1 -1
  63. package/dist/manager/run/persistence.d.ts +10 -1
  64. package/dist/manager/run/persistence.d.ts.map +1 -1
  65. package/dist/manager/run/persistence.js +20 -0
  66. package/dist/manager/run/persistence.js.map +1 -1
  67. package/dist/manager/thread/__tests__/lifecycle.test.d.ts +2 -0
  68. package/dist/manager/thread/__tests__/lifecycle.test.d.ts.map +1 -0
  69. package/dist/manager/thread/__tests__/lifecycle.test.js +216 -0
  70. package/dist/manager/thread/__tests__/lifecycle.test.js.map +1 -0
  71. package/dist/manager/thread/lifecycle.d.ts +105 -0
  72. package/dist/manager/thread/lifecycle.d.ts.map +1 -0
  73. package/dist/manager/thread/lifecycle.js +186 -0
  74. package/dist/manager/thread/lifecycle.js.map +1 -0
  75. package/dist/rag/retriever.js +2 -2
  76. package/dist/run/reporter.d.ts.map +1 -1
  77. package/dist/run/reporter.js +25 -0
  78. package/dist/run/reporter.js.map +1 -1
  79. package/dist/runtime/query/__tests__/context.test.d.ts +2 -0
  80. package/dist/runtime/query/__tests__/context.test.d.ts.map +1 -0
  81. package/dist/runtime/query/__tests__/context.test.js +85 -0
  82. package/dist/runtime/query/__tests__/context.test.js.map +1 -0
  83. package/dist/runtime/query/context-cache.d.ts +3 -3
  84. package/dist/runtime/query/context-cache.d.ts.map +1 -1
  85. package/dist/runtime/query/context-cache.js +2 -2
  86. package/dist/runtime/query/context-cache.js.map +1 -1
  87. package/dist/runtime/query/context.d.ts +45 -1
  88. package/dist/runtime/query/context.d.ts.map +1 -1
  89. package/dist/runtime/query/context.js +50 -8
  90. package/dist/runtime/query/context.js.map +1 -1
  91. package/dist/runtime/query/events.d.ts.map +1 -1
  92. package/dist/runtime/query/events.js +8 -0
  93. package/dist/runtime/query/events.js.map +1 -1
  94. package/dist/runtime/query/index.d.ts +22 -1
  95. package/dist/runtime/query/index.d.ts.map +1 -1
  96. package/dist/runtime/query/index.js +11 -0
  97. package/dist/runtime/query/index.js.map +1 -1
  98. package/dist/session/__tests__/integration/_fixtures.d.ts +122 -0
  99. package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -0
  100. package/dist/session/__tests__/integration/_fixtures.js +215 -0
  101. package/dist/session/__tests__/integration/_fixtures.js.map +1 -0
  102. package/dist/session/__tests__/integration/archive-gate.test.d.ts +15 -0
  103. package/dist/session/__tests__/integration/archive-gate.test.d.ts.map +1 -0
  104. package/dist/session/__tests__/integration/archive-gate.test.js +214 -0
  105. package/dist/session/__tests__/integration/archive-gate.test.js.map +1 -0
  106. package/dist/session/__tests__/integration/capacity-caps.test.d.ts +13 -0
  107. package/dist/session/__tests__/integration/capacity-caps.test.d.ts.map +1 -0
  108. package/dist/session/__tests__/integration/capacity-caps.test.js +123 -0
  109. package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -0
  110. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts +18 -0
  111. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts.map +1 -0
  112. package/dist/session/__tests__/integration/e2e-spawn.test.js +238 -0
  113. package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -0
  114. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts +15 -0
  115. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts.map +1 -0
  116. package/dist/session/__tests__/integration/event-stream-ordering.test.js +330 -0
  117. package/dist/session/__tests__/integration/event-stream-ordering.test.js.map +1 -0
  118. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts +12 -0
  119. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts.map +1 -0
  120. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js +182 -0
  121. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -0
  122. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts +18 -0
  123. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts.map +1 -0
  124. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js +156 -0
  125. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js.map +1 -0
  126. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts +15 -0
  127. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts.map +1 -0
  128. package/dist/session/__tests__/integration/handoff-single-e2e.test.js +179 -0
  129. package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -0
  130. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts +12 -0
  131. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts.map +1 -0
  132. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js +158 -0
  133. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js.map +1 -0
  134. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts +11 -0
  135. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts.map +1 -0
  136. package/dist/session/__tests__/integration/migration-filesystem.test.js +140 -0
  137. package/dist/session/__tests__/integration/migration-filesystem.test.js.map +1 -0
  138. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts +13 -0
  139. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts.map +1 -0
  140. package/dist/session/__tests__/integration/migration-id-prefix.test.js +84 -0
  141. package/dist/session/__tests__/integration/migration-id-prefix.test.js.map +1 -0
  142. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts +14 -0
  143. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts.map +1 -0
  144. package/dist/session/__tests__/integration/prev-artifact-dag.test.js +242 -0
  145. package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -0
  146. package/dist/session/__tests__/integration/retention-archive.test.d.ts +12 -0
  147. package/dist/session/__tests__/integration/retention-archive.test.d.ts.map +1 -0
  148. package/dist/session/__tests__/integration/retention-archive.test.js +187 -0
  149. package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -0
  150. package/dist/session/__tests__/integration/spawn-rollback.test.d.ts +26 -0
  151. package/dist/session/__tests__/integration/spawn-rollback.test.d.ts.map +1 -0
  152. package/dist/session/__tests__/integration/spawn-rollback.test.js +236 -0
  153. package/dist/session/__tests__/integration/spawn-rollback.test.js.map +1 -0
  154. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts +18 -0
  155. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts.map +1 -0
  156. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +201 -0
  157. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -0
  158. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts +14 -0
  159. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts.map +1 -0
  160. package/dist/session/__tests__/integration/tenant-isolation.test.js +189 -0
  161. package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -0
  162. package/dist/session/errors.d.ts +139 -0
  163. package/dist/session/errors.d.ts.map +1 -0
  164. package/dist/session/errors.js +107 -0
  165. package/dist/session/errors.js.map +1 -0
  166. package/dist/session/events/index.d.ts +4 -0
  167. package/dist/session/events/index.d.ts.map +1 -0
  168. package/dist/session/events/index.js +8 -0
  169. package/dist/session/events/index.js.map +1 -0
  170. package/dist/session/events/schema-version.d.ts +13 -0
  171. package/dist/session/events/schema-version.d.ts.map +1 -0
  172. package/dist/session/events/schema-version.js +12 -0
  173. package/dist/session/events/schema-version.js.map +1 -0
  174. package/dist/session/events/types.d.ts +64 -0
  175. package/dist/session/events/types.d.ts.map +1 -0
  176. package/dist/session/events/types.js +2 -0
  177. package/dist/session/events/types.js.map +1 -0
  178. package/dist/session/handoff/__tests__/broadcast.test.d.ts +2 -0
  179. package/dist/session/handoff/__tests__/broadcast.test.d.ts.map +1 -0
  180. package/dist/session/handoff/__tests__/broadcast.test.js +261 -0
  181. package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -0
  182. package/dist/session/handoff/__tests__/capacity.test.d.ts +2 -0
  183. package/dist/session/handoff/__tests__/capacity.test.d.ts.map +1 -0
  184. package/dist/session/handoff/__tests__/capacity.test.js +103 -0
  185. package/dist/session/handoff/__tests__/capacity.test.js.map +1 -0
  186. package/dist/session/handoff/__tests__/single.test.d.ts +2 -0
  187. package/dist/session/handoff/__tests__/single.test.d.ts.map +1 -0
  188. package/dist/session/handoff/__tests__/single.test.js +239 -0
  189. package/dist/session/handoff/__tests__/single.test.js.map +1 -0
  190. package/dist/session/handoff/assignment.d.ts +71 -0
  191. package/dist/session/handoff/assignment.d.ts.map +1 -0
  192. package/dist/session/handoff/assignment.js +11 -0
  193. package/dist/session/handoff/assignment.js.map +1 -0
  194. package/dist/session/handoff/broadcast.d.ts +54 -0
  195. package/dist/session/handoff/broadcast.d.ts.map +1 -0
  196. package/dist/session/handoff/broadcast.js +311 -0
  197. package/dist/session/handoff/broadcast.js.map +1 -0
  198. package/dist/session/handoff/capacity.d.ts +66 -0
  199. package/dist/session/handoff/capacity.d.ts.map +1 -0
  200. package/dist/session/handoff/capacity.js +60 -0
  201. package/dist/session/handoff/capacity.js.map +1 -0
  202. package/dist/session/handoff/events.d.ts +66 -0
  203. package/dist/session/handoff/events.d.ts.map +1 -0
  204. package/dist/session/handoff/events.js +13 -0
  205. package/dist/session/handoff/events.js.map +1 -0
  206. package/dist/session/handoff/index.d.ts +12 -0
  207. package/dist/session/handoff/index.d.ts.map +1 -0
  208. package/dist/session/handoff/index.js +9 -0
  209. package/dist/session/handoff/index.js.map +1 -0
  210. package/dist/session/handoff/single.d.ts +69 -0
  211. package/dist/session/handoff/single.d.ts.map +1 -0
  212. package/dist/session/handoff/single.js +229 -0
  213. package/dist/session/handoff/single.js.map +1 -0
  214. package/dist/session/handoff/version.d.ts +52 -0
  215. package/dist/session/handoff/version.d.ts.map +1 -0
  216. package/dist/session/handoff/version.js +36 -0
  217. package/dist/session/handoff/version.js.map +1 -0
  218. package/dist/session/hierarchy/__tests__/session.test.d.ts +2 -0
  219. package/dist/session/hierarchy/__tests__/session.test.d.ts.map +1 -0
  220. package/dist/session/hierarchy/__tests__/session.test.js +69 -0
  221. package/dist/session/hierarchy/__tests__/session.test.js.map +1 -0
  222. package/dist/session/hierarchy/actor.d.ts +26 -0
  223. package/dist/session/hierarchy/actor.d.ts.map +1 -0
  224. package/dist/session/hierarchy/actor.js +2 -0
  225. package/dist/session/hierarchy/actor.js.map +1 -0
  226. package/dist/session/hierarchy/index.d.ts +9 -0
  227. package/dist/session/hierarchy/index.d.ts.map +1 -0
  228. package/dist/session/hierarchy/index.js +4 -0
  229. package/dist/session/hierarchy/index.js.map +1 -0
  230. package/dist/session/hierarchy/lineage.d.ts +15 -0
  231. package/dist/session/hierarchy/lineage.d.ts.map +1 -0
  232. package/dist/session/hierarchy/lineage.js +2 -0
  233. package/dist/session/hierarchy/lineage.js.map +1 -0
  234. package/dist/session/hierarchy/project.d.ts +40 -0
  235. package/dist/session/hierarchy/project.d.ts.map +1 -0
  236. package/dist/session/hierarchy/project.js +2 -0
  237. package/dist/session/hierarchy/project.js.map +1 -0
  238. package/dist/session/hierarchy/session.d.ts +71 -0
  239. package/dist/session/hierarchy/session.d.ts.map +1 -0
  240. package/dist/session/hierarchy/session.js +51 -0
  241. package/dist/session/hierarchy/session.js.map +1 -0
  242. package/dist/session/hierarchy/sub-session.d.ts +76 -0
  243. package/dist/session/hierarchy/sub-session.d.ts.map +1 -0
  244. package/dist/session/hierarchy/sub-session.js +2 -0
  245. package/dist/session/hierarchy/sub-session.js.map +1 -0
  246. package/dist/session/hierarchy/tenant.d.ts +13 -0
  247. package/dist/session/hierarchy/tenant.d.ts.map +1 -0
  248. package/dist/session/hierarchy/tenant.js +2 -0
  249. package/dist/session/hierarchy/tenant.js.map +1 -0
  250. package/dist/session/hierarchy/thread.d.ts +54 -0
  251. package/dist/session/hierarchy/thread.d.ts.map +1 -0
  252. package/dist/session/hierarchy/thread.js +2 -0
  253. package/dist/session/hierarchy/thread.js.map +1 -0
  254. package/dist/session/index.d.ts +10 -0
  255. package/dist/session/index.d.ts.map +1 -0
  256. package/dist/session/index.js +15 -0
  257. package/dist/session/index.js.map +1 -0
  258. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts +2 -0
  259. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts.map +1 -0
  260. package/dist/session/intervention/__tests__/prev-artifact.test.js +179 -0
  261. package/dist/session/intervention/__tests__/prev-artifact.test.js.map +1 -0
  262. package/dist/session/intervention/index.d.ts +3 -0
  263. package/dist/session/intervention/index.d.ts.map +1 -0
  264. package/dist/session/intervention/index.js +8 -0
  265. package/dist/session/intervention/index.js.map +1 -0
  266. package/dist/session/intervention/prev-artifact.d.ts +103 -0
  267. package/dist/session/intervention/prev-artifact.d.ts.map +1 -0
  268. package/dist/session/intervention/prev-artifact.js +112 -0
  269. package/dist/session/intervention/prev-artifact.js.map +1 -0
  270. package/dist/session/migration/__tests__/filesystem.test.d.ts +2 -0
  271. package/dist/session/migration/__tests__/filesystem.test.d.ts.map +1 -0
  272. package/dist/session/migration/__tests__/filesystem.test.js +188 -0
  273. package/dist/session/migration/__tests__/filesystem.test.js.map +1 -0
  274. package/dist/session/migration/__tests__/id-prefix.test.d.ts +2 -0
  275. package/dist/session/migration/__tests__/id-prefix.test.d.ts.map +1 -0
  276. package/dist/session/migration/__tests__/id-prefix.test.js +83 -0
  277. package/dist/session/migration/__tests__/id-prefix.test.js.map +1 -0
  278. package/dist/session/migration/__tests__/marker.test.d.ts +2 -0
  279. package/dist/session/migration/__tests__/marker.test.d.ts.map +1 -0
  280. package/dist/session/migration/__tests__/marker.test.js +75 -0
  281. package/dist/session/migration/__tests__/marker.test.js.map +1 -0
  282. package/dist/session/migration/errors.d.ts +26 -0
  283. package/dist/session/migration/errors.d.ts.map +1 -0
  284. package/dist/session/migration/errors.js +22 -0
  285. package/dist/session/migration/errors.js.map +1 -0
  286. package/dist/session/migration/filesystem.d.ts +94 -0
  287. package/dist/session/migration/filesystem.d.ts.map +1 -0
  288. package/dist/session/migration/filesystem.js +319 -0
  289. package/dist/session/migration/filesystem.js.map +1 -0
  290. package/dist/session/migration/id-prefix.d.ts +93 -0
  291. package/dist/session/migration/id-prefix.d.ts.map +1 -0
  292. package/dist/session/migration/id-prefix.js +111 -0
  293. package/dist/session/migration/id-prefix.js.map +1 -0
  294. package/dist/session/migration/index.d.ts +8 -0
  295. package/dist/session/migration/index.d.ts.map +1 -0
  296. package/dist/session/migration/index.js +8 -0
  297. package/dist/session/migration/index.js.map +1 -0
  298. package/dist/session/migration/marker.d.ts +57 -0
  299. package/dist/session/migration/marker.d.ts.map +1 -0
  300. package/dist/session/migration/marker.js +111 -0
  301. package/dist/session/migration/marker.js.map +1 -0
  302. package/dist/session/retention/__tests__/archive.test.d.ts +2 -0
  303. package/dist/session/retention/__tests__/archive.test.d.ts.map +1 -0
  304. package/dist/session/retention/__tests__/archive.test.js +253 -0
  305. package/dist/session/retention/__tests__/archive.test.js.map +1 -0
  306. package/dist/session/retention/__tests__/disk-backend.test.d.ts +2 -0
  307. package/dist/session/retention/__tests__/disk-backend.test.d.ts.map +1 -0
  308. package/dist/session/retention/__tests__/disk-backend.test.js +154 -0
  309. package/dist/session/retention/__tests__/disk-backend.test.js.map +1 -0
  310. package/dist/session/retention/archive-backend-ref.d.ts +18 -0
  311. package/dist/session/retention/archive-backend-ref.d.ts.map +1 -0
  312. package/dist/session/retention/archive-backend-ref.js +2 -0
  313. package/dist/session/retention/archive-backend-ref.js.map +1 -0
  314. package/dist/session/retention/archive.d.ts +130 -0
  315. package/dist/session/retention/archive.d.ts.map +1 -0
  316. package/dist/session/retention/archive.js +203 -0
  317. package/dist/session/retention/archive.js.map +1 -0
  318. package/dist/session/retention/backend.d.ts +101 -0
  319. package/dist/session/retention/backend.d.ts.map +1 -0
  320. package/dist/session/retention/backend.js +15 -0
  321. package/dist/session/retention/backend.js.map +1 -0
  322. package/dist/session/retention/disk-backend.d.ts +59 -0
  323. package/dist/session/retention/disk-backend.d.ts.map +1 -0
  324. package/dist/session/retention/disk-backend.js +236 -0
  325. package/dist/session/retention/disk-backend.js.map +1 -0
  326. package/dist/session/retention/index.d.ts +9 -0
  327. package/dist/session/retention/index.d.ts.map +1 -0
  328. package/dist/session/retention/index.js +6 -0
  329. package/dist/session/retention/index.js.map +1 -0
  330. package/dist/session/retention/policy.d.ts +49 -0
  331. package/dist/session/retention/policy.d.ts.map +1 -0
  332. package/dist/session/retention/policy.js +21 -0
  333. package/dist/session/retention/policy.js.map +1 -0
  334. package/dist/session/summary/__tests__/materialize.test.d.ts +2 -0
  335. package/dist/session/summary/__tests__/materialize.test.d.ts.map +1 -0
  336. package/dist/session/summary/__tests__/materialize.test.js +270 -0
  337. package/dist/session/summary/__tests__/materialize.test.js.map +1 -0
  338. package/dist/session/summary/deliverable.d.ts +74 -0
  339. package/dist/session/summary/deliverable.d.ts.map +1 -0
  340. package/dist/session/summary/deliverable.js +20 -0
  341. package/dist/session/summary/deliverable.js.map +1 -0
  342. package/dist/session/summary/index.d.ts +6 -0
  343. package/dist/session/summary/index.d.ts.map +1 -0
  344. package/dist/session/summary/index.js +9 -0
  345. package/dist/session/summary/index.js.map +1 -0
  346. package/dist/session/summary/materialize.d.ts +82 -0
  347. package/dist/session/summary/materialize.d.ts.map +1 -0
  348. package/dist/session/summary/materialize.js +117 -0
  349. package/dist/session/summary/materialize.js.map +1 -0
  350. package/dist/session/summary/ref.d.ts +91 -0
  351. package/dist/session/summary/ref.d.ts.map +1 -0
  352. package/dist/session/summary/ref.js +51 -0
  353. package/dist/session/summary/ref.js.map +1 -0
  354. package/dist/session/workspace/__tests__/git-worktree.test.d.ts +2 -0
  355. package/dist/session/workspace/__tests__/git-worktree.test.d.ts.map +1 -0
  356. package/dist/session/workspace/__tests__/git-worktree.test.js +244 -0
  357. package/dist/session/workspace/__tests__/git-worktree.test.js.map +1 -0
  358. package/dist/session/workspace/__tests__/path-builder.test.d.ts +2 -0
  359. package/dist/session/workspace/__tests__/path-builder.test.d.ts.map +1 -0
  360. package/dist/session/workspace/__tests__/path-builder.test.js +37 -0
  361. package/dist/session/workspace/__tests__/path-builder.test.js.map +1 -0
  362. package/dist/session/workspace/driver.d.ts +55 -0
  363. package/dist/session/workspace/driver.d.ts.map +1 -0
  364. package/dist/session/workspace/driver.js +12 -0
  365. package/dist/session/workspace/driver.js.map +1 -0
  366. package/dist/session/workspace/git-worktree.d.ts +65 -0
  367. package/dist/session/workspace/git-worktree.d.ts.map +1 -0
  368. package/dist/session/workspace/git-worktree.js +156 -0
  369. package/dist/session/workspace/git-worktree.js.map +1 -0
  370. package/dist/session/workspace/index.d.ts +8 -0
  371. package/dist/session/workspace/index.d.ts.map +1 -0
  372. package/dist/session/workspace/index.js +7 -0
  373. package/dist/session/workspace/index.js.map +1 -0
  374. package/dist/session/workspace/path-builder.d.ts +50 -0
  375. package/dist/session/workspace/path-builder.d.ts.map +1 -0
  376. package/dist/session/workspace/path-builder.js +50 -0
  377. package/dist/session/workspace/path-builder.js.map +1 -0
  378. package/dist/session/workspace/ref.d.ts +46 -0
  379. package/dist/session/workspace/ref.d.ts.map +1 -0
  380. package/dist/session/workspace/ref.js +11 -0
  381. package/dist/session/workspace/ref.js.map +1 -0
  382. package/dist/session/workspace/registry.d.ts +26 -0
  383. package/dist/session/workspace/registry.d.ts.map +1 -0
  384. package/dist/session/workspace/registry.js +35 -0
  385. package/dist/session/workspace/registry.js.map +1 -0
  386. package/dist/store/index.d.ts +0 -2
  387. package/dist/store/index.d.ts.map +1 -1
  388. package/dist/store/index.js +0 -1
  389. package/dist/store/index.js.map +1 -1
  390. package/dist/store/session/__tests__/disk.test.d.ts +2 -0
  391. package/dist/store/session/__tests__/disk.test.d.ts.map +1 -0
  392. package/dist/store/session/__tests__/disk.test.js +267 -0
  393. package/dist/store/session/__tests__/disk.test.js.map +1 -0
  394. package/dist/store/session/__tests__/memory.test.d.ts +2 -0
  395. package/dist/store/session/__tests__/memory.test.d.ts.map +1 -0
  396. package/dist/store/session/__tests__/memory.test.js +258 -0
  397. package/dist/store/session/__tests__/memory.test.js.map +1 -0
  398. package/dist/store/session/disk.d.ts +86 -0
  399. package/dist/store/session/disk.d.ts.map +1 -0
  400. package/dist/store/session/disk.js +818 -0
  401. package/dist/store/session/disk.js.map +1 -0
  402. package/dist/store/session/index.d.ts +7 -0
  403. package/dist/store/session/index.d.ts.map +1 -0
  404. package/dist/store/session/index.js +10 -0
  405. package/dist/store/session/index.js.map +1 -0
  406. package/dist/store/session/linkage.d.ts +38 -0
  407. package/dist/store/session/linkage.d.ts.map +1 -0
  408. package/dist/store/session/linkage.js +64 -0
  409. package/dist/store/session/linkage.js.map +1 -0
  410. package/dist/store/session/memory.d.ts +49 -0
  411. package/dist/store/session/memory.d.ts.map +1 -0
  412. package/dist/store/session/memory.js +335 -0
  413. package/dist/store/session/memory.js.map +1 -0
  414. package/dist/store/session/messages.d.ts +20 -0
  415. package/dist/store/session/messages.d.ts.map +1 -0
  416. package/dist/store/session/messages.js +12 -0
  417. package/dist/store/session/messages.js.map +1 -0
  418. package/dist/store/thread/disk.d.ts +41 -0
  419. package/dist/store/thread/disk.d.ts.map +1 -0
  420. package/dist/store/thread/disk.js +229 -0
  421. package/dist/store/thread/disk.js.map +1 -0
  422. package/dist/store/thread/index.d.ts +4 -0
  423. package/dist/store/thread/index.d.ts.map +1 -0
  424. package/dist/store/thread/index.js +6 -0
  425. package/dist/store/thread/index.js.map +1 -0
  426. package/dist/store/thread/memory.d.ts +23 -0
  427. package/dist/store/thread/memory.d.ts.map +1 -0
  428. package/dist/store/thread/memory.js +90 -0
  429. package/dist/store/thread/memory.js.map +1 -0
  430. package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts +1 -1
  431. package/dist/types/agent/base.d.ts +24 -1
  432. package/dist/types/agent/base.d.ts.map +1 -1
  433. package/dist/types/agent/factory.d.ts +8 -2
  434. package/dist/types/agent/factory.d.ts.map +1 -1
  435. package/dist/types/agent/task.d.ts +57 -2
  436. package/dist/types/agent/task.d.ts.map +1 -1
  437. package/dist/types/agent/task.js.map +1 -1
  438. package/dist/types/ids/index.d.ts +22 -3
  439. package/dist/types/ids/index.d.ts.map +1 -1
  440. package/dist/types/ids/index.js +8 -1
  441. package/dist/types/ids/index.js.map +1 -1
  442. package/dist/types/invocation/__tests__/state.test.js +36 -29
  443. package/dist/types/invocation/__tests__/state.test.js.map +1 -1
  444. package/dist/types/invocation/index.d.ts +20 -4
  445. package/dist/types/invocation/index.d.ts.map +1 -1
  446. package/dist/types/invocation/index.js +10 -7
  447. package/dist/types/invocation/index.js.map +1 -1
  448. package/dist/types/rag/retrieval.d.ts +4 -3
  449. package/dist/types/rag/retrieval.d.ts.map +1 -1
  450. package/dist/types/run/config.d.ts +12 -1
  451. package/dist/types/run/config.d.ts.map +1 -1
  452. package/dist/types/run/events.d.ts +26 -1
  453. package/dist/types/run/events.d.ts.map +1 -1
  454. package/dist/types/run/index.d.ts.map +1 -1
  455. package/dist/types/run/index.js +8 -0
  456. package/dist/types/run/index.js.map +1 -1
  457. package/dist/types/run/metadata.d.ts +12 -2
  458. package/dist/types/run/metadata.d.ts.map +1 -1
  459. package/dist/types/run/status.d.ts +26 -0
  460. package/dist/types/run/status.d.ts.map +1 -0
  461. package/dist/types/run/status.js +2 -0
  462. package/dist/types/run/status.js.map +1 -0
  463. package/dist/types/session/ids.d.ts +9 -0
  464. package/dist/types/session/ids.d.ts.map +1 -0
  465. package/dist/types/session/ids.js +9 -0
  466. package/dist/types/session/ids.js.map +1 -0
  467. package/dist/types/session/index.d.ts +3 -0
  468. package/dist/types/session/index.d.ts.map +1 -0
  469. package/dist/types/session/index.js +5 -0
  470. package/dist/types/session/index.js.map +1 -0
  471. package/dist/types/session/store.d.ts +210 -0
  472. package/dist/types/session/store.d.ts.map +1 -0
  473. package/dist/types/session/store.js +9 -0
  474. package/dist/types/session/store.js.map +1 -0
  475. package/dist/types/thread/index.d.ts +2 -0
  476. package/dist/types/thread/index.d.ts.map +1 -0
  477. package/dist/types/thread/index.js +5 -0
  478. package/dist/types/thread/index.js.map +1 -0
  479. package/dist/types/thread/store.d.ts +86 -0
  480. package/dist/types/thread/store.d.ts.map +1 -0
  481. package/dist/types/thread/store.js +22 -0
  482. package/dist/types/thread/store.js.map +1 -0
  483. package/dist/utils/id.d.ts +8 -2
  484. package/dist/utils/id.d.ts.map +1 -1
  485. package/dist/utils/id.js +22 -4
  486. package/dist/utils/id.js.map +1 -1
  487. package/package.json +6 -11
  488. package/src/agents/ReactiveAgent.ts +7 -2
  489. package/src/agents/RouterAgent.ts +5 -0
  490. package/src/agents/SupervisorAgent.ts +29 -6
  491. package/src/bridge/a2a/index.ts +0 -1
  492. package/src/bridge/a2a/mapper.ts +7 -0
  493. package/src/bridge/a2a/message.ts +0 -32
  494. package/src/bridge/a2a/task.ts +9 -8
  495. package/src/bridge/sse/mapper.ts +8 -1
  496. package/src/constants/a2a/index.ts +2 -2
  497. package/src/contracts/api.ts +14 -30
  498. package/src/contracts/ids.ts +1 -1
  499. package/src/contracts/index.ts +3 -7
  500. package/src/contracts/schemas.ts +1 -8
  501. package/src/gateway/local.ts +6 -0
  502. package/src/index.ts +14 -4
  503. package/src/manager/agent/__tests__/lifecycle.test.ts +473 -0
  504. package/src/manager/agent/lifecycle.ts +515 -21
  505. package/src/manager/index.ts +3 -0
  506. package/src/manager/run/persistence.ts +26 -1
  507. package/src/manager/thread/__tests__/lifecycle.test.ts +286 -0
  508. package/src/manager/thread/lifecycle.ts +217 -0
  509. package/src/rag/retriever.ts +2 -2
  510. package/src/run/reporter.ts +28 -0
  511. package/src/runtime/query/__tests__/context.test.ts +102 -0
  512. package/src/runtime/query/context-cache.ts +4 -4
  513. package/src/runtime/query/context.ts +98 -9
  514. package/src/runtime/query/events.ts +8 -0
  515. package/src/runtime/query/index.ts +38 -1
  516. package/src/session/__tests__/integration/_fixtures.ts +310 -0
  517. package/src/session/__tests__/integration/archive-gate.test.ts +288 -0
  518. package/src/session/__tests__/integration/capacity-caps.test.ts +171 -0
  519. package/src/session/__tests__/integration/e2e-spawn.test.ts +296 -0
  520. package/src/session/__tests__/integration/event-stream-ordering.test.ts +410 -0
  521. package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +271 -0
  522. package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +214 -0
  523. package/src/session/__tests__/integration/handoff-single-e2e.test.ts +251 -0
  524. package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +240 -0
  525. package/src/session/__tests__/integration/migration-filesystem.test.ts +209 -0
  526. package/src/session/__tests__/integration/migration-id-prefix.test.ts +101 -0
  527. package/src/session/__tests__/integration/prev-artifact-dag.test.ts +325 -0
  528. package/src/session/__tests__/integration/retention-archive.test.ts +233 -0
  529. package/src/session/__tests__/integration/spawn-rollback.test.ts +313 -0
  530. package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +239 -0
  531. package/src/session/__tests__/integration/tenant-isolation.test.ts +292 -0
  532. package/src/session/errors.ts +159 -0
  533. package/src/session/events/index.ts +16 -0
  534. package/src/session/events/schema-version.ts +13 -0
  535. package/src/session/events/types.ts +71 -0
  536. package/src/session/handoff/__tests__/broadcast.test.ts +378 -0
  537. package/src/session/handoff/__tests__/capacity.test.ts +129 -0
  538. package/src/session/handoff/__tests__/single.test.ts +333 -0
  539. package/src/session/handoff/assignment.ts +74 -0
  540. package/src/session/handoff/broadcast.ts +406 -0
  541. package/src/session/handoff/capacity.ts +121 -0
  542. package/src/session/handoff/events.ts +72 -0
  543. package/src/session/handoff/index.ts +29 -0
  544. package/src/session/handoff/single.ts +310 -0
  545. package/src/session/handoff/version.ts +59 -0
  546. package/src/session/hierarchy/__tests__/session.test.ts +100 -0
  547. package/src/session/hierarchy/actor.ts +17 -0
  548. package/src/session/hierarchy/index.ts +18 -0
  549. package/src/session/hierarchy/lineage.ts +15 -0
  550. package/src/session/hierarchy/project.ts +41 -0
  551. package/src/session/hierarchy/session.ts +109 -0
  552. package/src/session/hierarchy/sub-session.ts +92 -0
  553. package/src/session/hierarchy/tenant.ts +13 -0
  554. package/src/session/hierarchy/thread.ts +55 -0
  555. package/src/session/index.ts +15 -0
  556. package/src/session/intervention/__tests__/prev-artifact.test.ts +234 -0
  557. package/src/session/intervention/index.ts +16 -0
  558. package/src/session/intervention/prev-artifact.ts +180 -0
  559. package/src/session/migration/__tests__/filesystem.test.ts +263 -0
  560. package/src/session/migration/__tests__/id-prefix.test.ts +101 -0
  561. package/src/session/migration/__tests__/marker.test.ts +84 -0
  562. package/src/session/migration/errors.ts +23 -0
  563. package/src/session/migration/filesystem.ts +401 -0
  564. package/src/session/migration/id-prefix.ts +141 -0
  565. package/src/session/migration/index.ts +38 -0
  566. package/src/session/migration/marker.ts +131 -0
  567. package/src/session/retention/__tests__/archive.test.ts +318 -0
  568. package/src/session/retention/__tests__/disk-backend.test.ts +180 -0
  569. package/src/session/retention/archive-backend-ref.ts +17 -0
  570. package/src/session/retention/archive.ts +281 -0
  571. package/src/session/retention/backend.ts +107 -0
  572. package/src/session/retention/disk-backend.ts +304 -0
  573. package/src/session/retention/index.ts +16 -0
  574. package/src/session/retention/policy.ts +53 -0
  575. package/src/session/summary/__tests__/materialize.test.ts +343 -0
  576. package/src/session/summary/deliverable.ts +84 -0
  577. package/src/session/summary/index.ts +31 -0
  578. package/src/session/summary/materialize.ts +169 -0
  579. package/src/session/summary/ref.ts +104 -0
  580. package/src/session/workspace/__tests__/git-worktree.test.ts +258 -0
  581. package/src/session/workspace/__tests__/path-builder.test.ts +51 -0
  582. package/src/session/workspace/driver.ts +60 -0
  583. package/src/session/workspace/git-worktree.ts +209 -0
  584. package/src/session/workspace/index.ts +25 -0
  585. package/src/session/workspace/path-builder.ts +71 -0
  586. package/src/session/workspace/ref.ts +50 -0
  587. package/src/session/workspace/registry.ts +42 -0
  588. package/src/store/index.ts +0 -3
  589. package/src/store/session/__tests__/disk.test.ts +397 -0
  590. package/src/store/session/__tests__/memory.test.ts +402 -0
  591. package/src/store/session/disk.ts +976 -0
  592. package/src/store/session/index.ts +13 -0
  593. package/src/store/session/linkage.ts +80 -0
  594. package/src/store/session/memory.ts +412 -0
  595. package/src/store/session/messages.ts +21 -0
  596. package/src/store/thread/disk.ts +261 -0
  597. package/src/store/thread/index.ts +7 -0
  598. package/src/store/thread/memory.ts +104 -0
  599. package/src/types/agent/base.ts +27 -1
  600. package/src/types/agent/factory.ts +8 -3
  601. package/src/types/agent/task.ts +66 -2
  602. package/src/types/ids/index.ts +34 -3
  603. package/src/types/invocation/__tests__/state.test.ts +37 -29
  604. package/src/types/invocation/index.ts +26 -10
  605. package/src/types/rag/retrieval.ts +4 -3
  606. package/src/types/run/config.ts +13 -1
  607. package/src/types/run/events.ts +36 -1
  608. package/src/types/run/index.ts +8 -0
  609. package/src/types/run/metadata.ts +12 -2
  610. package/src/types/run/status.ts +33 -0
  611. package/src/types/session/ids.ts +23 -0
  612. package/src/types/session/index.ts +27 -0
  613. package/src/types/session/store.ts +252 -0
  614. package/src/types/thread/index.ts +5 -0
  615. package/src/types/thread/store.ts +92 -0
  616. package/src/utils/id.ts +34 -4
  617. package/dist/store/conversation/memory.d.ts +0 -21
  618. package/dist/store/conversation/memory.d.ts.map +0 -1
  619. package/dist/store/conversation/memory.js +0 -86
  620. package/dist/store/conversation/memory.js.map +0 -1
  621. package/dist/types/conversation/index.d.ts +0 -7
  622. package/dist/types/conversation/index.d.ts.map +0 -1
  623. package/dist/types/conversation/index.js +0 -2
  624. package/dist/types/conversation/index.js.map +0 -1
  625. package/src/store/conversation/memory.ts +0 -121
  626. package/src/types/conversation/index.ts +0 -8
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Integration — SessionSummaryMaterializer + SessionStore atomic transition,
3
+ * plus the crash-recovery path.
4
+ *
5
+ * Covers roadmap §5 invariants: §8.1 (summary kernel-owned, no agent-callable
6
+ * emission surface), §8.1 atomic with terminal transition, recovery path
7
+ * when the status-flip lost to a mid-flight crash. `SessionAlreadySummarizedError`
8
+ * on concurrent re-materialize.
9
+ *
10
+ * The kernel-ownership assertion is expressed both structurally (the
11
+ * `materializedBy: 'kernel'` brand on the persisted record) and by routing
12
+ * every successful materialize through the Materializer — no test below calls
13
+ * `store.recordSummary` directly, and the compile-time type narrows the
14
+ * argument to `& { materializedBy: 'kernel' }` so an agent-constructed payload
15
+ * would fail typecheck (not just runtime validation).
16
+ */
17
+
18
+ import { describe, expect, it } from 'vitest'
19
+ import { InMemorySessionStore } from '../../../store/session/memory.js'
20
+ import type { SessionId } from '../../../types/ids/index.js'
21
+ import type { SummaryId, ThreadId } from '../../../types/session/ids.js'
22
+ import { SessionSummaryMaterializer } from '../../summary/materialize.js'
23
+ import { SessionAlreadySummarizedError } from '../../summary/ref.js'
24
+ import { DEFAULT_TENANT, agentActor } from './_fixtures.js'
25
+
26
+ const TEST_THREAD_ID = 'thd_test' as ThreadId
27
+
28
+ async function seedActive(store: InMemorySessionStore) {
29
+ const project = await store.createProject(
30
+ { tenantId: DEFAULT_TENANT, name: 'summary' },
31
+ DEFAULT_TENANT,
32
+ )
33
+ const session = await store.createSession(
34
+ { threadId: TEST_THREAD_ID, projectId: project.id, currentActor: agentActor('agt_worker') },
35
+ DEFAULT_TENANT,
36
+ )
37
+ await store.updateSession({ ...session, status: 'active' }, DEFAULT_TENANT)
38
+ return { project, session: { ...session, status: 'active' as const } }
39
+ }
40
+
41
+ function makeGen(): () => SummaryId {
42
+ let n = 0
43
+ return () => `sum_materialize_${++n}` as SummaryId
44
+ }
45
+
46
+ describe('Integration — summary materialization E2E', () => {
47
+ it('Materializer writes summary + flips session active→idle atomically', async () => {
48
+ const store = new InMemorySessionStore()
49
+ const { session } = await seedActive(store)
50
+ const materializer = new SessionSummaryMaterializer({
51
+ store,
52
+ generateSummaryId: makeGen(),
53
+ })
54
+
55
+ const summary = await materializer.materialize({
56
+ sessionId: session.id,
57
+ tenantId: DEFAULT_TENANT,
58
+ finalOutcome: { status: 'succeeded' },
59
+ agentSummary: 'done',
60
+ declaredDeliverables: [],
61
+ keyDecisions: [],
62
+ })
63
+
64
+ // Persisted.
65
+ const stored = await store.getSummary(session.id, DEFAULT_TENANT)
66
+ expect(stored?.id).toBe(summary.id)
67
+ expect(stored?.materializedBy).toBe('kernel')
68
+
69
+ // Status atomically flipped.
70
+ const reloaded = await store.getSession(session.id, DEFAULT_TENANT)
71
+ expect(reloaded?.status).toBe('idle')
72
+ })
73
+
74
+ it('§8.1 atomicity invariant: no external observer sees terminal without summary', async () => {
75
+ // With InMemorySessionStore the two writes happen inside a single Map
76
+ // method call — there is no observable mid-state. We assert by reading
77
+ // both resources immediately after a single awaited materialize: the
78
+ // terminal status and the summary are visible together.
79
+ const store = new InMemorySessionStore()
80
+ const { session } = await seedActive(store)
81
+ const materializer = new SessionSummaryMaterializer({
82
+ store,
83
+ generateSummaryId: makeGen(),
84
+ })
85
+
86
+ await materializer.materialize({
87
+ sessionId: session.id,
88
+ tenantId: DEFAULT_TENANT,
89
+ finalOutcome: { status: 'succeeded' },
90
+ agentSummary: '',
91
+ declaredDeliverables: [],
92
+ keyDecisions: [],
93
+ })
94
+
95
+ const [finalSession, finalSummary] = await Promise.all([
96
+ store.getSession(session.id, DEFAULT_TENANT),
97
+ store.getSummary(session.id, DEFAULT_TENANT),
98
+ ])
99
+ // Atomic pairing: idle status AND persisted summary present together.
100
+ expect(finalSession?.status).toBe('idle')
101
+ expect(finalSummary).not.toBeNull()
102
+ })
103
+
104
+ it('concurrent re-materialize rejects with SessionAlreadySummarizedError', async () => {
105
+ const store = new InMemorySessionStore()
106
+ const { session } = await seedActive(store)
107
+ const materializer = new SessionSummaryMaterializer({
108
+ store,
109
+ generateSummaryId: makeGen(),
110
+ })
111
+
112
+ await materializer.materialize({
113
+ sessionId: session.id,
114
+ tenantId: DEFAULT_TENANT,
115
+ finalOutcome: { status: 'succeeded' },
116
+ agentSummary: 'first',
117
+ declaredDeliverables: [],
118
+ keyDecisions: [],
119
+ })
120
+
121
+ await expect(
122
+ materializer.materialize({
123
+ sessionId: session.id,
124
+ tenantId: DEFAULT_TENANT,
125
+ finalOutcome: { status: 'succeeded' },
126
+ agentSummary: 'second',
127
+ declaredDeliverables: [],
128
+ keyDecisions: [],
129
+ }),
130
+ ).rejects.toBeInstanceOf(SessionAlreadySummarizedError)
131
+ })
132
+
133
+ it('crash recovery: summary persisted + session still active → recover() replays idempotently', async () => {
134
+ const store = new InMemorySessionStore()
135
+ const { session } = await seedActive(store)
136
+ const materializer = new SessionSummaryMaterializer({
137
+ store,
138
+ generateSummaryId: makeGen(),
139
+ })
140
+
141
+ // Materialize once (happy path writes both). Then simulate a crash by
142
+ // forcing the session status back to `active` while the summary record
143
+ // stays intact — mimicking summary.json landing but session.json being
144
+ // lost to a mid-write power failure (see session/summary/materialize.ts
145
+ // `recover()` docs).
146
+ await materializer.materialize({
147
+ sessionId: session.id,
148
+ tenantId: DEFAULT_TENANT,
149
+ finalOutcome: { status: 'succeeded' },
150
+ agentSummary: '',
151
+ declaredDeliverables: [],
152
+ keyDecisions: [],
153
+ })
154
+ const mid = await store.getSession(session.id, DEFAULT_TENANT)
155
+ if (!mid) throw new Error('mid session missing')
156
+ await store.updateSession({ ...mid, status: 'active' }, DEFAULT_TENANT)
157
+
158
+ // Recovery call re-triggers the store's flip path without minting a
159
+ // new summary id.
160
+ const recovered = await materializer.recover(session.id, DEFAULT_TENANT)
161
+ expect(recovered).not.toBeNull()
162
+
163
+ const reloaded = await store.getSession(session.id, DEFAULT_TENANT)
164
+ expect(reloaded?.status).toBe('idle')
165
+
166
+ // Second recover call with session already idle: still idempotent.
167
+ const recovered2 = await materializer.recover(session.id, DEFAULT_TENANT)
168
+ expect(recovered2?.id).toBe(recovered?.id)
169
+ const reloaded2 = await store.getSession(session.id, DEFAULT_TENANT)
170
+ expect(reloaded2?.status).toBe('idle')
171
+ })
172
+
173
+ it('agent cannot construct SessionSummaryRef directly: recordSummary rejects non-kernel payload', async () => {
174
+ // The SessionStore contract narrows `recordSummary` to
175
+ // `SessionSummaryRef & { materializedBy: 'kernel' }`. Agents cannot
176
+ // type-construct a brand literal of `'kernel'` without going through
177
+ // the Materializer (see session/summary/ref.ts module header). Even
178
+ // attempting to cast into the shape and call directly would bypass
179
+ // the materialize ordering (status-check, length-check,
180
+ // already-exists guard). This test exercises the runtime guard: a
181
+ // second kernel-branded record for an already-summarized session
182
+ // rejects with SessionAlreadySummarizedError.
183
+ const store = new InMemorySessionStore()
184
+ const { session } = await seedActive(store)
185
+ const materializer = new SessionSummaryMaterializer({
186
+ store,
187
+ generateSummaryId: makeGen(),
188
+ })
189
+ await materializer.materialize({
190
+ sessionId: session.id,
191
+ tenantId: DEFAULT_TENANT,
192
+ finalOutcome: { status: 'succeeded' },
193
+ agentSummary: '',
194
+ declaredDeliverables: [],
195
+ keyDecisions: [],
196
+ })
197
+
198
+ // Direct call with a fabricated "kernel" ref payload — rejected
199
+ // because a summary already exists (store guard). The kernel-brand
200
+ // check at the type layer prevents naive agent-side construction; the
201
+ // runtime guard here catches store-level re-entry (materialize goes
202
+ // through the same path).
203
+ await expect(
204
+ store.recordSummary(
205
+ {
206
+ id: 'sum_fake' as SummaryId,
207
+ sessionRef: session.id,
208
+ tenantId: DEFAULT_TENANT,
209
+ outcome: { status: 'succeeded' },
210
+ deliverables: [],
211
+ agentSummary: 'forged',
212
+ keyDecisions: [],
213
+ at: new Date(),
214
+ materializedBy: 'kernel',
215
+ },
216
+ DEFAULT_TENANT,
217
+ ),
218
+ ).rejects.toBeInstanceOf(SessionAlreadySummarizedError)
219
+ })
220
+
221
+ it('missing session: materialize throws a not-found error', async () => {
222
+ const store = new InMemorySessionStore()
223
+ const materializer = new SessionSummaryMaterializer({
224
+ store,
225
+ generateSummaryId: makeGen(),
226
+ })
227
+
228
+ await expect(
229
+ materializer.materialize({
230
+ sessionId: 'ses_never' as SessionId,
231
+ tenantId: DEFAULT_TENANT,
232
+ finalOutcome: { status: 'succeeded' },
233
+ agentSummary: '',
234
+ declaredDeliverables: [],
235
+ keyDecisions: [],
236
+ }),
237
+ ).rejects.toThrow(/not found/)
238
+ })
239
+ })
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Integration — multi-tenant isolation enforcement at every store accessor
3
+ * and cross-store boundary.
4
+ *
5
+ * Covers roadmap §5 invariants: §12 `tenantId` denormalized on every
6
+ * persisted entity, §12.2 cross-tenant rejection (TenantIsolationError at
7
+ * every accessor), broadcast handoff rejecting when recipient tenant
8
+ * differs.
9
+ *
10
+ * Every assertion here crosses a kernel boundary with a mismatched tenantId
11
+ * and checks that the SDK rejects rather than silently re-scoping.
12
+ */
13
+
14
+ import { describe, expect, it } from 'vitest'
15
+ import { InMemorySessionStore } from '../../../store/session/memory.js'
16
+ import { createUserMessage } from '../../../types/message/index.js'
17
+ import type { ProjectId, SubSessionId, SummaryId, ThreadId } from '../../../types/session/ids.js'
18
+ import { TenantIsolationError } from '../../errors.js'
19
+ import { DEFAULT_TENANT, OTHER_TENANT, agentActor, userActor } from './_fixtures.js'
20
+
21
+ const TEST_THREAD_ID = 'thd_test' as ThreadId
22
+
23
+ async function seedTenantAResources() {
24
+ const store = new InMemorySessionStore()
25
+ const project = await store.createProject(
26
+ { tenantId: DEFAULT_TENANT, name: 'tenA' },
27
+ DEFAULT_TENANT,
28
+ )
29
+ const parent = await store.createSession(
30
+ { threadId: TEST_THREAD_ID, projectId: project.id, currentActor: userActor('usr_a') },
31
+ DEFAULT_TENANT,
32
+ )
33
+ const child = await store.createSession(
34
+ { threadId: TEST_THREAD_ID, projectId: project.id, currentActor: agentActor('agt_a') },
35
+ DEFAULT_TENANT,
36
+ )
37
+ const sub = await store.createSubSession(
38
+ {
39
+ parentSessionId: parent.id,
40
+ childSessionId: child.id,
41
+ kind: 'agent_spawn',
42
+ spawnedBy: userActor('usr_a'),
43
+ },
44
+ DEFAULT_TENANT,
45
+ )
46
+ return { store, project, parent, child, sub }
47
+ }
48
+
49
+ describe('Integration — tenant isolation', () => {
50
+ it('getProject with wrong tenantId → TenantIsolationError', async () => {
51
+ const { store, project } = await seedTenantAResources()
52
+ await expect(store.getProject(project.id, OTHER_TENANT)).rejects.toBeInstanceOf(
53
+ TenantIsolationError,
54
+ )
55
+ })
56
+
57
+ it('getSession with wrong tenantId → TenantIsolationError', async () => {
58
+ const { store, parent } = await seedTenantAResources()
59
+ await expect(store.getSession(parent.id, OTHER_TENANT)).rejects.toBeInstanceOf(
60
+ TenantIsolationError,
61
+ )
62
+ })
63
+
64
+ it('getSubSession with wrong tenantId → TenantIsolationError', async () => {
65
+ const { store, sub } = await seedTenantAResources()
66
+ await expect(store.getSubSession(sub.id, OTHER_TENANT)).rejects.toBeInstanceOf(
67
+ TenantIsolationError,
68
+ )
69
+ })
70
+
71
+ it('updateSession with wrong tenantId → TenantIsolationError', async () => {
72
+ const { store, parent } = await seedTenantAResources()
73
+ await expect(
74
+ store.updateSession({ ...parent, status: 'active' }, OTHER_TENANT),
75
+ ).rejects.toBeInstanceOf(TenantIsolationError)
76
+ })
77
+
78
+ it('createSubSession from a session owned by another tenant → TenantIsolationError', async () => {
79
+ const { store, parent, child } = await seedTenantAResources()
80
+ await expect(
81
+ store.createSubSession(
82
+ {
83
+ parentSessionId: parent.id,
84
+ childSessionId: child.id,
85
+ kind: 'agent_spawn',
86
+ spawnedBy: userActor('usr_intruder', OTHER_TENANT),
87
+ },
88
+ OTHER_TENANT,
89
+ ),
90
+ ).rejects.toBeInstanceOf(TenantIsolationError)
91
+ })
92
+
93
+ it('appendMessage with wrong tenantId → TenantIsolationError', async () => {
94
+ const { store, child } = await seedTenantAResources()
95
+ await expect(
96
+ store.appendMessage(child.id, createUserMessage('intruder'), OTHER_TENANT),
97
+ ).rejects.toBeInstanceOf(TenantIsolationError)
98
+ })
99
+
100
+ it('loadSessionMessages cross-tenant → TenantIsolationError', async () => {
101
+ const { store, child } = await seedTenantAResources()
102
+ await store.appendMessage(child.id, createUserMessage('legit'), DEFAULT_TENANT)
103
+ await expect(store.loadSessionMessages(child.id, OTHER_TENANT)).rejects.toBeInstanceOf(
104
+ TenantIsolationError,
105
+ )
106
+ })
107
+
108
+ it('loadMessages cross-tenant → TenantIsolationError', async () => {
109
+ const { store, child } = await seedTenantAResources()
110
+ await store.appendMessage(child.id, createUserMessage('legit'), DEFAULT_TENANT)
111
+ await expect(store.loadMessages(child.id, OTHER_TENANT)).rejects.toBeInstanceOf(
112
+ TenantIsolationError,
113
+ )
114
+ })
115
+
116
+ it('drill(sessionId, OTHER_TENANT) on an existing session → TenantIsolationError (pattern doc §12.2 hard reject)', async () => {
117
+ const { store, parent } = await seedTenantAResources()
118
+ // Existing session owned by DEFAULT_TENANT, caller supplies OTHER_TENANT.
119
+ // Pattern doc §12 specifies hard reject — no silent null masking.
120
+ await expect(store.drill(parent.id, OTHER_TENANT)).rejects.toBeInstanceOf(TenantIsolationError)
121
+ })
122
+
123
+ it('drill on a missing session returns null (deny-by-default surface without leaking tenant info)', async () => {
124
+ const { store } = await seedTenantAResources()
125
+ const view = await store.drill(
126
+ 'ses_never_existed' as Parameters<typeof store.drill>[0],
127
+ OTHER_TENANT,
128
+ )
129
+ // Missing session for the queried tenant returns null (Convention #5).
130
+ // The tenant check is conditional on the resource existing; absent
131
+ // resources don't leak tenant info via a thrown isolation error.
132
+ expect(view).toBeNull()
133
+ })
134
+
135
+ it('getChildren cross-tenant → TenantIsolationError', async () => {
136
+ const { store, parent } = await seedTenantAResources()
137
+ await expect(store.getChildren(parent.id, OTHER_TENANT)).rejects.toBeInstanceOf(
138
+ TenantIsolationError,
139
+ )
140
+ })
141
+
142
+ it('getAncestry cross-tenant → TenantIsolationError', async () => {
143
+ const { store, parent } = await seedTenantAResources()
144
+ await expect(store.getAncestry(parent.id, OTHER_TENANT)).rejects.toBeInstanceOf(
145
+ TenantIsolationError,
146
+ )
147
+ })
148
+
149
+ it('recordSummary with mismatched payload tenantId → TenantIsolationError', async () => {
150
+ const { store, parent } = await seedTenantAResources()
151
+ // Attempt to record a summary whose payload tenantId differs from the
152
+ // caller tenantId — runtime guard rejects.
153
+ await expect(
154
+ store.recordSummary(
155
+ {
156
+ id: 'sum_intruder' as SummaryId,
157
+ sessionRef: parent.id,
158
+ tenantId: OTHER_TENANT,
159
+ outcome: { status: 'succeeded' },
160
+ deliverables: [],
161
+ agentSummary: '',
162
+ keyDecisions: [],
163
+ at: new Date(),
164
+ materializedBy: 'kernel',
165
+ },
166
+ DEFAULT_TENANT,
167
+ ),
168
+ ).rejects.toBeInstanceOf(TenantIsolationError)
169
+ })
170
+
171
+ it('getSummary cross-tenant → TenantIsolationError when a summary exists', async () => {
172
+ const { store, parent } = await seedTenantAResources()
173
+ await store.updateSession({ ...parent, status: 'active' }, DEFAULT_TENANT)
174
+ await store.recordSummary(
175
+ {
176
+ id: 'sum_ok' as SummaryId,
177
+ sessionRef: parent.id,
178
+ tenantId: DEFAULT_TENANT,
179
+ outcome: { status: 'succeeded' },
180
+ deliverables: [],
181
+ agentSummary: '',
182
+ keyDecisions: [],
183
+ at: new Date(),
184
+ materializedBy: 'kernel',
185
+ },
186
+ DEFAULT_TENANT,
187
+ )
188
+
189
+ await expect(store.getSummary(parent.id, OTHER_TENANT)).rejects.toBeInstanceOf(
190
+ TenantIsolationError,
191
+ )
192
+ })
193
+
194
+ it('createProject with params.tenantId ≠ caller tenantId → TenantIsolationError (deep check)', async () => {
195
+ const store = new InMemorySessionStore()
196
+ await expect(
197
+ store.createProject({ tenantId: OTHER_TENANT, name: 'mismatch' }, DEFAULT_TENANT),
198
+ ).rejects.toBeInstanceOf(TenantIsolationError)
199
+ })
200
+
201
+ it('createSession with project owned by another tenant → TenantIsolationError', async () => {
202
+ const { store, project } = await seedTenantAResources()
203
+ await expect(
204
+ store.createSession(
205
+ {
206
+ threadId: TEST_THREAD_ID,
207
+ projectId: project.id,
208
+ currentActor: userActor('usr_intruder', OTHER_TENANT),
209
+ },
210
+ OTHER_TENANT,
211
+ ),
212
+ ).rejects.toBeInstanceOf(TenantIsolationError)
213
+ })
214
+
215
+ it('tenant denormalization: Session, SubSession records carry tenantId explicitly', async () => {
216
+ const { store, parent, sub } = await seedTenantAResources()
217
+ const parentReloaded = await store.getSession(parent.id, DEFAULT_TENANT)
218
+ expect(parentReloaded?.tenantId).toBe(DEFAULT_TENANT)
219
+
220
+ // SubSession record itself does not carry tenantId in its shape — the
221
+ // isolation is stored via the parent record tuple (subSessions map:
222
+ // { tenantId, subSession }). Getting it via the correct tenant succeeds;
223
+ // via the wrong tenant rejects — already covered above. This test just
224
+ // confirms the successful access path.
225
+ const reloaded = await store.getSubSession(sub.id, DEFAULT_TENANT)
226
+ expect(reloaded?.id).toBe(sub.id)
227
+ })
228
+
229
+ it('broadcast-style cross-tenant attempt: cannot createSubSession linking parents owned by another tenant', async () => {
230
+ // Pattern doc §12 requires recipient & source to share tenant. The
231
+ // store-level guard here catches the shape violation — createSubSession
232
+ // refuses to link parent/child across tenants.
233
+ const { store, parent } = await seedTenantAResources()
234
+
235
+ // Create a session in OTHER_TENANT with its own project.
236
+ const otherProject = await store.createProject(
237
+ { tenantId: OTHER_TENANT, name: 'other' },
238
+ OTHER_TENANT,
239
+ )
240
+ const otherChild = await store.createSession(
241
+ {
242
+ threadId: TEST_THREAD_ID,
243
+ projectId: otherProject.id,
244
+ currentActor: userActor('usr_other', OTHER_TENANT),
245
+ },
246
+ OTHER_TENANT,
247
+ )
248
+
249
+ await expect(
250
+ store.createSubSession(
251
+ {
252
+ parentSessionId: parent.id, // DEFAULT_TENANT
253
+ childSessionId: otherChild.id, // OTHER_TENANT
254
+ kind: 'agent_spawn',
255
+ spawnedBy: userActor('usr_a'),
256
+ },
257
+ DEFAULT_TENANT,
258
+ ),
259
+ ).rejects.toBeInstanceOf(TenantIsolationError)
260
+ })
261
+
262
+ it('deleteSubSession cross-tenant → TenantIsolationError', async () => {
263
+ const { store, sub } = await seedTenantAResources()
264
+ await expect(store.deleteSubSession(sub.id, OTHER_TENANT)).rejects.toBeInstanceOf(
265
+ TenantIsolationError,
266
+ )
267
+ })
268
+
269
+ it('deleteSession cross-tenant → TenantIsolationError', async () => {
270
+ const { store } = await seedTenantAResources()
271
+ // Parent has a sub-session attached → deleteSession would fail anyway,
272
+ // but the tenant guard fires first. Use a standalone session.
273
+ const project: ProjectId = (
274
+ await store.createProject({ tenantId: DEFAULT_TENANT, name: 'del' }, DEFAULT_TENANT)
275
+ ).id
276
+ const lonely = await store.createSession(
277
+ { threadId: TEST_THREAD_ID, projectId: project, currentActor: userActor('usr_lonely') },
278
+ DEFAULT_TENANT,
279
+ )
280
+ await expect(store.deleteSession(lonely.id, OTHER_TENANT)).rejects.toBeInstanceOf(
281
+ TenantIsolationError,
282
+ )
283
+ })
284
+
285
+ it('missing sub-session returns null for correct tenant (not a leak channel)', async () => {
286
+ const { store } = await seedTenantAResources()
287
+ // Missing id via correct tenant → null, not thrown. Confirms the
288
+ // missing-resource fast-path doesn't pre-empt the tenant check.
289
+ const missing = await store.getSubSession('sub_never_existed' as SubSessionId, DEFAULT_TENANT)
290
+ expect(missing).toBeNull()
291
+ })
292
+ })
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Typed errors for the session hierarchy module.
3
+ *
4
+ * See session-hierarchy.md §12.2 (cross-tenant rejection), §6.2 (workspace
5
+ * backend operation failures), §4.5 (intervention DAG). Each error carries a
6
+ * structured `details` payload so consumers can route without string parsing
7
+ * (Convention #5: deny-by-default, fail fast).
8
+ */
9
+
10
+ import type { SessionId, TenantId } from '../types/ids/index.js'
11
+ import type { ThreadId } from '../types/session/ids.js'
12
+ import type { SessionStatus } from './hierarchy/session.js'
13
+ import type { WorkspaceBackendKind } from './workspace/driver.js'
14
+
15
+ /**
16
+ * Raised by {@link SessionStore} accessors when the supplied {@link TenantId}
17
+ * does not match the tenant owning the target resource. Convention #17:
18
+ * cross-tenant access is a hard error at the kernel boundary — there is no
19
+ * escape hatch. See session-hierarchy.md §12.2.
20
+ */
21
+ export class TenantIsolationError extends Error {
22
+ readonly details: {
23
+ requested: TenantId
24
+ resource: string
25
+ }
26
+
27
+ constructor(details: { requested: TenantId; resource: string }) {
28
+ super(`Tenant isolation violation: ${details.requested} accessed ${details.resource}`)
29
+ this.name = 'TenantIsolationError'
30
+ this.details = details
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Raised by {@link SessionStore.getAncestry} / {@link SessionStore.drill}
36
+ * when walking parent sub-session links encounters a revisit. Indicates store
37
+ * corruption — the write path enforces acyclicity (session-hierarchy.md §4.5).
38
+ */
39
+ export class AncestryCycleError extends Error {
40
+ readonly details: {
41
+ sessionId: SessionId
42
+ cyclePath: readonly SessionId[]
43
+ }
44
+
45
+ constructor(details: { sessionId: SessionId; cyclePath: readonly SessionId[] }) {
46
+ super(
47
+ `Ancestry cycle detected starting at ${details.sessionId}: ${details.cyclePath.join(' -> ')}`,
48
+ )
49
+ this.name = 'AncestryCycleError'
50
+ this.details = details
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Raised by {@link WorkspaceBackendDriver} implementations on any I/O or
56
+ * invariant failure. Wraps the underlying cause; callers can match on
57
+ * `details.op` + `details.kind` for routing (Convention #0: no silent
58
+ * fallbacks — surface the failure). See session-hierarchy.md §6.2 / §7.
59
+ */
60
+ export class WorkspaceBackendError extends Error {
61
+ readonly details: {
62
+ op: string
63
+ kind: WorkspaceBackendKind
64
+ cause?: unknown
65
+ }
66
+
67
+ constructor(details: { op: string; kind: WorkspaceBackendKind; cause?: unknown }) {
68
+ super(`Workspace backend ${details.kind} failed on ${details.op}`)
69
+ this.name = 'WorkspaceBackendError'
70
+ this.details = details
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Raised by {@link import('../types/thread/store.js').ThreadStore.updateThread}
76
+ * when the supplied {@link Thread.ownerVersion} does not match the persisted
77
+ * record. The caller must re-read via `getThread`, re-apply its intended
78
+ * mutation on top of the fresh record, and retry. Mirrors the Session
79
+ * handoff CAS pattern (§6.1).
80
+ */
81
+ export class StaleThreadError extends Error {
82
+ readonly details: {
83
+ threadId: ThreadId
84
+ expectedVersion: number
85
+ actualVersion: number
86
+ }
87
+
88
+ constructor(details: { threadId: ThreadId; expectedVersion: number; actualVersion: number }) {
89
+ super(
90
+ `Stale Thread ${details.threadId}: expected ownerVersion=${details.expectedVersion}, actual=${details.actualVersion}`,
91
+ )
92
+ this.name = 'StaleThreadError'
93
+ this.details = details
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Raised by the spawn path (and any caller that enforces the open-thread
99
+ * precondition) when a Thread is in `'archived'` state and would-be mutations
100
+ * require it to be `'open'`. Convention #5: deny-by-default — archival is a
101
+ * hard read-only boundary.
102
+ */
103
+ export class ThreadClosedError extends Error {
104
+ readonly details: {
105
+ threadId: ThreadId
106
+ op: string
107
+ }
108
+
109
+ constructor(details: { threadId: ThreadId; op: string }) {
110
+ super(`Thread ${details.threadId} is archived; operation '${details.op}' rejected`)
111
+ this.name = 'ThreadClosedError'
112
+ this.details = details
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Raised by {@link import('../manager/thread/lifecycle.js').ThreadManager.archive}
118
+ * and `.delete` when the Thread's session-presence precondition is violated:
119
+ *
120
+ * - `op: 'archive'` — at least one Session under the Thread is in a
121
+ * non-terminal state (`active | locked | awaiting_hitl | awaiting_merge`).
122
+ * The caller must first quiesce those sessions (let them reach `idle`,
123
+ * `failed`, or `archived`) before flipping the Thread to archived.
124
+ * - `op: 'delete'` — the Thread still has at least one attached Session.
125
+ * Callers must either archive + tombstone those sessions (`deleteSession`)
126
+ * before calling `deleteThread`, or accept that deletion is not yet safe.
127
+ *
128
+ * `blockingSessions` carries the first {@link THREAD_NOT_EMPTY_SAMPLE_LIMIT}
129
+ * offenders with their current status so operator tooling can surface an
130
+ * actionable list without unbounded error payloads on large threads.
131
+ * `totalBlockingSessions` holds the full count even when the sample is
132
+ * truncated. Convention #5: deny-by-default — no implicit cascade, no silent
133
+ * no-op.
134
+ */
135
+ export const THREAD_NOT_EMPTY_SAMPLE_LIMIT = 50
136
+
137
+ export class ThreadNotEmptyError extends Error {
138
+ readonly details: {
139
+ threadId: ThreadId
140
+ tenantId: TenantId
141
+ op: 'archive' | 'delete'
142
+ blockingSessions: ReadonlyArray<{ sessionId: SessionId; status: SessionStatus }>
143
+ totalBlockingSessions: number
144
+ }
145
+
146
+ constructor(details: {
147
+ threadId: ThreadId
148
+ tenantId: TenantId
149
+ op: 'archive' | 'delete'
150
+ blockingSessions: ReadonlyArray<{ sessionId: SessionId; status: SessionStatus }>
151
+ totalBlockingSessions: number
152
+ }) {
153
+ super(
154
+ `Thread ${details.threadId} ${details.op} blocked: ${details.totalBlockingSessions} session(s) still attached`,
155
+ )
156
+ this.name = 'ThreadNotEmptyError'
157
+ this.details = details
158
+ }
159
+ }