@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,281 @@
1
+ /**
2
+ * ArchivalManager — on-demand archival primitive for sub-sessions. Pattern
3
+ * doc §12.3 (Retention and Archival).
4
+ *
5
+ * Convention #9 (Registry + Manager + Store): Manager-shape with explicit
6
+ * deps for the {@link SessionStore}, {@link WorkspaceBackendRegistry}, and a
7
+ * pluggable {@link ArchiveBackend}. Convention #5 deny-by-default: absent
8
+ * backend → {@link ArchiveNotConfiguredError} on every `archive()` call.
9
+ *
10
+ * Atomic invariant (pattern doc §12.3):
11
+ *
12
+ * 1. Read sub-session + owning session + messages + optional summary
13
+ * 2. backend.store(bundle) — archive durability confirmed
14
+ * 3. Flip sub-session to `status: 'archived'` + attach archiveRef/archivedAt
15
+ * 4. Workspace driver dispose (idempotent)
16
+ *
17
+ * Step 2 is the durability boundary: if the process crashes between step 2
18
+ * and step 3, the archive exists but the live record is still non-archived
19
+ * — recovery is to re-invoke `archive()`, which sees a non-terminal status
20
+ * and replays. Step 3 is the single point of no return.
21
+ *
22
+ * A completed archive leaves the sub-session in-place with `status:
23
+ * 'archived'` + an attached `archiveRef`. Pattern doc §12.3 calls this the
24
+ * tombstone: `SessionStore.drill` still finds it through the normal linkage
25
+ * path, so the archive is navigable without a parallel index.
26
+ */
27
+
28
+ import type { SessionId, SubSessionId, TenantId } from '../../types/ids/index.js'
29
+ import type { WorkspaceId } from '../../types/session/ids.js'
30
+ import type { SessionStore } from '../../types/session/store.js'
31
+ import type { SubSession, SubSessionStatus } from '../hierarchy/sub-session.js'
32
+ import type { WorkspaceRef } from '../workspace/ref.js'
33
+ import type { WorkspaceBackendRegistry } from '../workspace/registry.js'
34
+ import type { ArchiveBackend, SubSessionTombstone } from './backend.js'
35
+
36
+ /**
37
+ * Raised when {@link ArchivalManager.archive} or {@link ArchivalManager.restore}
38
+ * is invoked against a project whose retention policy does not supply an
39
+ * {@link ArchiveBackend}. Convention #5 — explicit error rather than silent
40
+ * no-op.
41
+ */
42
+ export class ArchiveNotConfiguredError extends Error {
43
+ constructor() {
44
+ super('Retention archival not configured for this project (Convention #5: deny-by-default)')
45
+ this.name = 'ArchiveNotConfiguredError'
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Raised when {@link ArchivalManager.archive} targets a sub-session that is
51
+ * not eligible for archival. The three reasons map to pattern doc §12.3
52
+ * (archival only applies to idle / merged / rejected / failed sub-sessions).
53
+ */
54
+ export class SubSessionNotArchivableError extends Error {
55
+ readonly details: {
56
+ readonly subSessionId: SubSessionId
57
+ readonly reason: 'not_idle' | 'already_archived' | 'missing'
58
+ }
59
+
60
+ constructor(details: {
61
+ subSessionId: SubSessionId
62
+ reason: 'not_idle' | 'already_archived' | 'missing'
63
+ }) {
64
+ super(`Sub-session ${details.subSessionId} not archivable: ${details.reason}`)
65
+ this.name = 'SubSessionNotArchivableError'
66
+ this.details = details
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Raised when {@link ArchivalManager.restore} is called against a
72
+ * sub-session that is not currently archived. Distinct from
73
+ * {@link SubSessionNotArchivableError} because the semantics are inverted:
74
+ * restore requires an archived record, archive rejects one.
75
+ */
76
+ export class SubSessionNotArchivedError extends Error {
77
+ readonly details: {
78
+ readonly subSessionId: SubSessionId
79
+ readonly reason: 'not_archived' | 'missing' | 'missing_archive_ref'
80
+ }
81
+
82
+ constructor(details: {
83
+ subSessionId: SubSessionId
84
+ reason: 'not_archived' | 'missing' | 'missing_archive_ref'
85
+ }) {
86
+ super(`Sub-session ${details.subSessionId} cannot be restored: ${details.reason}`)
87
+ this.name = 'SubSessionNotArchivedError'
88
+ this.details = details
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Lookup callback resolving a live {@link WorkspaceRef} from the id stored
94
+ * on a {@link SubSession}. Injected by the caller because Phase 8 does not
95
+ * ship a dedicated workspace store — the ref typically lives in a handoff
96
+ * assignment or is held by the agent lifecycle manager. Return `null` when
97
+ * the ref is unknown or already disposed; the manager archives without
98
+ * workspace data in that case (the disk backend allows it).
99
+ */
100
+ export type WorkspaceResolver = (
101
+ workspaceId: WorkspaceId,
102
+ tenantId: TenantId,
103
+ ) => Promise<WorkspaceRef | null>
104
+
105
+ /**
106
+ * Sub-session statuses eligible for archival. Pattern doc §12.3 speaks of
107
+ * "idle" broadly; we honor the enumerated terminal-like states. Anything
108
+ * else (active / pending / in-flight merge) rejects with
109
+ * `'not_idle'`.
110
+ */
111
+ const ARCHIVABLE_STATUSES: ReadonlySet<SubSessionStatus> = new Set([
112
+ 'idle',
113
+ 'merged',
114
+ 'merge_rejected',
115
+ 'failed',
116
+ ])
117
+
118
+ export interface ArchivalManagerDeps {
119
+ readonly sessionStore: SessionStore
120
+ readonly workspaceRegistry: WorkspaceBackendRegistry
121
+ /**
122
+ * Archive backend. Absent = archival disabled for this manager
123
+ * (`archive()`/`restore()` throw {@link ArchiveNotConfiguredError}).
124
+ */
125
+ readonly archiveBackend?: ArchiveBackend
126
+ /**
127
+ * Optional workspace resolver. When absent, `archive()` skips workspace
128
+ * snapshotting (only the ref would be captured) and workspace disposal
129
+ * (nothing to dispose). This is the conservative default and matches
130
+ * pattern doc §7.1 (lazy workspace provisioning).
131
+ */
132
+ readonly workspaceResolver?: WorkspaceResolver
133
+ /**
134
+ * Optional logger hook for `sub_session.archived` emission. Pattern doc
135
+ * §12.3 requires the event; full event-bus wiring is a platform concern
136
+ * (a later phase of the roadmap). Phase 8 ships the log seam so tests
137
+ * can observe without the bus.
138
+ */
139
+ readonly onArchived?: (tombstone: SubSessionTombstone) => void
140
+ readonly onRestored?: (subSessionId: SubSessionId, tenantId: TenantId) => void
141
+ }
142
+
143
+ export class ArchivalManager {
144
+ private readonly deps: ArchivalManagerDeps
145
+
146
+ constructor(deps: ArchivalManagerDeps) {
147
+ this.deps = deps
148
+ }
149
+
150
+ /**
151
+ * Archive an eligible sub-session. See module header for the atomic
152
+ * invariant and recovery semantics.
153
+ *
154
+ * Returns the {@link SubSessionTombstone} shape — the same identity +
155
+ * archive fields the store now carries on the live record.
156
+ */
157
+ async archive(subSessionId: SubSessionId, tenantId: TenantId): Promise<SubSessionTombstone> {
158
+ const backend = this.requireBackend()
159
+
160
+ // 1. Resolve + validate sub-session.
161
+ const sub = await this.deps.sessionStore.getSubSession(subSessionId, tenantId)
162
+ if (!sub) {
163
+ throw new SubSessionNotArchivableError({ subSessionId, reason: 'missing' })
164
+ }
165
+ if (sub.status === 'archived') {
166
+ throw new SubSessionNotArchivableError({ subSessionId, reason: 'already_archived' })
167
+ }
168
+ if (!ARCHIVABLE_STATUSES.has(sub.status)) {
169
+ throw new SubSessionNotArchivableError({ subSessionId, reason: 'not_idle' })
170
+ }
171
+
172
+ // 2. Load owning child session bundle (messages + optional summary).
173
+ // Phase 9 Known Delta #7: uses `loadSessionMessages` for full-fidelity
174
+ // round-trip (original MessageId + timestamp preserved). Previously
175
+ // the Phase 8 archivalmanager synthesized `msg_restored_N` IDs from the
176
+ // payload-only `loadMessages` return — that lossy reshape is gone.
177
+ const childSessionId: SessionId = sub.childSessionId
178
+ const messages = await this.deps.sessionStore.loadSessionMessages(childSessionId, tenantId)
179
+
180
+ const summaryRefOrNull = await this.deps.sessionStore.getSummary(childSessionId, tenantId)
181
+ const summaryRef = summaryRefOrNull ?? undefined
182
+
183
+ // 3. Resolve optional live workspace ref.
184
+ let workspace: WorkspaceRef | undefined
185
+ if (sub.workspaceId && this.deps.workspaceResolver) {
186
+ const resolved = await this.deps.workspaceResolver(sub.workspaceId, tenantId)
187
+ if (resolved) workspace = resolved
188
+ }
189
+
190
+ // 4. Durability boundary: persist the archive bundle.
191
+ const bundleOut = await backend.store({
192
+ subSessionId: sub.id,
193
+ sessionId: childSessionId,
194
+ tenantId,
195
+ ...(workspace !== undefined && { workspace }),
196
+ ...(summaryRef !== undefined && { summaryRef }),
197
+ messages,
198
+ })
199
+
200
+ // 5. Point-of-no-return: flip sub-session to archived + attach ref.
201
+ const archived: SubSession = {
202
+ ...sub,
203
+ status: 'archived',
204
+ archiveRef: bundleOut.archiveRef,
205
+ archivedAt: bundleOut.archivedAt,
206
+ }
207
+ await this.deps.sessionStore.updateSubSession(archived, tenantId)
208
+
209
+ // 6. Dispose the workspace (idempotent — driver contract tolerates
210
+ // already-disposed refs; a missing ref is a no-op).
211
+ if (workspace) {
212
+ try {
213
+ const driver = this.deps.workspaceRegistry.get(workspace.meta.backend)
214
+ await driver.dispose(workspace)
215
+ } catch {
216
+ // Idempotent — a secondary failure here must not unwind the
217
+ // already-committed archive. Pattern doc §12.3: workspace
218
+ // disposal is a cleanup operation, not part of the atomic
219
+ // archive envelope.
220
+ }
221
+ }
222
+
223
+ const tombstone: SubSessionTombstone = {
224
+ subSessionId: sub.id,
225
+ sessionId: childSessionId,
226
+ tenantId,
227
+ ...(sub.summaryRef !== undefined && { summaryRef: sub.summaryRef }),
228
+ archiveRef: bundleOut.archiveRef,
229
+ archivedAt: bundleOut.archivedAt,
230
+ }
231
+
232
+ this.deps.onArchived?.(tombstone)
233
+ return tombstone
234
+ }
235
+
236
+ /**
237
+ * Reverse of {@link archive}. Reads the tombstone, invokes
238
+ * `backend.restore`, then flips the sub-session back to `idle`. Does NOT
239
+ * re-materialize the workspace — the caller decides whether to
240
+ * re-provision via a {@link WorkspaceBackendDriver}.
241
+ *
242
+ * The restored `ArchiveInput` bundle is NOT returned here because the
243
+ * concrete pattern in Phase 8 is "flip status and make navigable again";
244
+ * consumers that need the bundle itself can call the backend directly.
245
+ */
246
+ async restore(subSessionId: SubSessionId, tenantId: TenantId): Promise<void> {
247
+ const backend = this.requireBackend()
248
+
249
+ const sub = await this.deps.sessionStore.getSubSession(subSessionId, tenantId)
250
+ if (!sub) {
251
+ throw new SubSessionNotArchivedError({ subSessionId, reason: 'missing' })
252
+ }
253
+ if (sub.status !== 'archived') {
254
+ throw new SubSessionNotArchivedError({ subSessionId, reason: 'not_archived' })
255
+ }
256
+ if (!sub.archiveRef) {
257
+ throw new SubSessionNotArchivedError({ subSessionId, reason: 'missing_archive_ref' })
258
+ }
259
+
260
+ // Validate the archive ref by invoking the backend — this surfaces
261
+ // ArchiveNotFoundError up the stack if the bundle is missing or
262
+ // corrupt, rather than silently un-archiving an orphaned record.
263
+ await backend.restore(sub.archiveRef)
264
+
265
+ const restored: SubSession = {
266
+ ...sub,
267
+ status: 'idle',
268
+ archiveRef: undefined,
269
+ archivedAt: undefined,
270
+ }
271
+ await this.deps.sessionStore.updateSubSession(restored, tenantId)
272
+
273
+ this.deps.onRestored?.(subSessionId, tenantId)
274
+ }
275
+
276
+ private requireBackend(): ArchiveBackend {
277
+ const backend = this.deps.archiveBackend
278
+ if (!backend) throw new ArchiveNotConfiguredError()
279
+ return backend
280
+ }
281
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * ArchiveBackend — pluggable archival contract. See session-hierarchy.md
3
+ * §12.3 Retention and Archival.
4
+ *
5
+ * Convention #10 (Provider abstraction): interface lives here; concrete
6
+ * implementations (disk, s3, glacier, …) live in sibling files. Phase 8 ships
7
+ * the reference disk impl (`disk-backend.ts`); production deployments plug
8
+ * their own over the same surface.
9
+ *
10
+ * Convention #9 (Registry + Manager + Store): {@link ArchivalManager} is the
11
+ * Manager; this `ArchiveBackend` is the Provider slot it drives; the live
12
+ * `SessionStore` is the Store it mutates.
13
+ */
14
+
15
+ import type { SessionMessage } from '../../store/session/messages.js'
16
+ import type { SessionId, SubSessionId, TenantId } from '../../types/ids/index.js'
17
+ import type { SummaryId } from '../../types/session/ids.js'
18
+ import type { SessionSummaryRef } from '../summary/ref.js'
19
+ import type { WorkspaceRef } from '../workspace/ref.js'
20
+ import type { ArchiveBackendRef } from './archive-backend-ref.js'
21
+
22
+ /**
23
+ * Output of a successful {@link ArchiveBackend.store} call. `archiveRef` is
24
+ * the opaque lookup key used by {@link ArchiveBackend.restore} to rehydrate
25
+ * the bundle.
26
+ */
27
+ export interface ArchiveOutput {
28
+ readonly archiveRef: ArchiveBackendRef
29
+ readonly archivedAt: Date
30
+ }
31
+
32
+ /**
33
+ * Bundle handed to {@link ArchiveBackend.store} (and returned by
34
+ * {@link ArchiveBackend.restore}). Captures the minimum surface needed to
35
+ * re-hydrate a sub-session in the future — sub-session metadata plus the
36
+ * owning session's messages and optional summary.
37
+ */
38
+ export interface ArchiveInput {
39
+ readonly subSessionId: SubSessionId
40
+ /**
41
+ * The session the sub-session owns. Each sub-session wraps exactly one
42
+ * child {@link Session} (pattern doc §4.4); the archived bundle captures
43
+ * that session's messages and summary.
44
+ */
45
+ readonly sessionId: SessionId
46
+ readonly tenantId: TenantId
47
+ /**
48
+ * Present when the sub-session had a provisioned workspace at archive
49
+ * time. Absent for sub-sessions that never materialized one (pattern doc
50
+ * §7.1 allows lazy workspace provisioning).
51
+ */
52
+ readonly workspace?: WorkspaceRef
53
+ readonly summaryRef?: SessionSummaryRef
54
+ /**
55
+ * Full message log for the owning session. Captured at archive time;
56
+ * append-only discipline (pattern doc §13.4) means this is a complete
57
+ * snapshot, not a partial view.
58
+ */
59
+ readonly messages: readonly SessionMessage[]
60
+ }
61
+
62
+ /**
63
+ * Pluggable archival backend. Implementations MUST write atomically
64
+ * (Convention #8 — write-tmp-rename per file) and MUST produce a unique
65
+ * {@link ArchiveBackendRef} per call. Concurrent `store` calls with
66
+ * overlapping input are a caller error — the Manager serializes per
67
+ * sub-session.
68
+ */
69
+ export interface ArchiveBackend {
70
+ /** Discriminator. Free-form; reference impl uses `'disk'`. */
71
+ readonly kind: string
72
+
73
+ /**
74
+ * Persist the bundle. Returns the lookup ref consumers embed in the
75
+ * sub-session tombstone (§12.3). Must be atomic at the bundle level —
76
+ * post-success, a restore sees the full bundle or throws.
77
+ */
78
+ store(input: ArchiveInput): Promise<ArchiveOutput>
79
+
80
+ /**
81
+ * Reverse of {@link store}. Throws when the ref does not resolve or when
82
+ * the bundle is corrupt. Does NOT re-materialize the workspace on disk —
83
+ * callers decide whether to re-provision via a
84
+ * {@link WorkspaceBackendDriver}.
85
+ */
86
+ restore(archiveRef: ArchiveBackendRef): Promise<ArchiveInput>
87
+ }
88
+
89
+ /**
90
+ * The in-store marker a sub-session becomes after archival. Replaces the
91
+ * live record in-slot (see pattern doc §12.3): the sub-session's status
92
+ * flips to `'archived'` and `archiveRef` + `archivedAt` are attached. This
93
+ * way `SessionStore.drill` still finds it via the normal linkage path — the
94
+ * tombstone is navigable without a parallel index.
95
+ *
96
+ * Fields are a subset of {@link SubSession} — the identity columns plus the
97
+ * archive pointer — extracted here so consumers can destructure a tombstone
98
+ * view without carrying the full live-record shape.
99
+ */
100
+ export interface SubSessionTombstone {
101
+ readonly subSessionId: SubSessionId
102
+ readonly sessionId: SessionId
103
+ readonly tenantId: TenantId
104
+ readonly summaryRef?: SummaryId
105
+ readonly archiveRef: ArchiveBackendRef
106
+ readonly archivedAt: Date
107
+ }
@@ -0,0 +1,304 @@
1
+ /**
2
+ * DiskArchiveBackend — reference filesystem-backed {@link ArchiveBackend}.
3
+ *
4
+ * Convention #8 (atomic writes): every file lands via write-tmp-rename; the
5
+ * final `archive.json` marker is written LAST so a crash mid-bundle leaves
6
+ * the directory visible but UN-marked, and `restore` treats such a bundle
7
+ * as missing. This mirrors the Phase 5 materializer's "marker-last"
8
+ * invariant.
9
+ *
10
+ * Layout:
11
+ *
12
+ * {rootDir}/archive/{arc_<opaque>}/
13
+ * subsession.json # Identity + metadata
14
+ * summary.json # SessionSummaryRef (optional — present iff input.summaryRef)
15
+ * messages.jsonl # One SessionMessage per line (append-style, serialized once)
16
+ * workspace.json # WorkspaceRef (optional — present iff input.workspace)
17
+ * archive.json # Marker — final write; presence = bundle committed
18
+ *
19
+ * Workspace directory contents are NOT archived — we persist the
20
+ * {@link WorkspaceRef} only. The pattern doc §12.3 explicitly allows this:
21
+ * the ref is the re-hydration handle; the worktree itself is disposed at
22
+ * archive time via the caller's {@link WorkspaceBackendDriver}, not copied
23
+ * into the archive bundle. This is a Phase 8 interpretation — see the
24
+ * roadmap deliverable report for rationale (tar bundling deferred).
25
+ *
26
+ * See session-hierarchy.md §12.3.
27
+ */
28
+
29
+ import { randomBytes } from 'node:crypto'
30
+ import { mkdir, readFile, readdir, rename, unlink, writeFile } from 'node:fs/promises'
31
+ import { join } from 'node:path'
32
+ import type { SessionMessage } from '../../store/session/messages.js'
33
+ import type { SessionId, SubSessionId, TenantId } from '../../types/ids/index.js'
34
+ import type { SessionSummaryRef } from '../summary/ref.js'
35
+ import type { WorkspaceRef } from '../workspace/ref.js'
36
+ import type { ArchiveBackendRef } from './archive-backend-ref.js'
37
+ import type { ArchiveBackend, ArchiveInput, ArchiveOutput } from './backend.js'
38
+
39
+ /**
40
+ * Raised when {@link DiskArchiveBackend.restore} cannot resolve the supplied
41
+ * ref — either the directory is missing, or the `archive.json` marker is
42
+ * absent (crash-mid-write signal).
43
+ */
44
+ export class ArchiveNotFoundError extends Error {
45
+ readonly details: { archiveRef: ArchiveBackendRef; reason: 'missing' | 'incomplete' }
46
+
47
+ constructor(details: { archiveRef: ArchiveBackendRef; reason: 'missing' | 'incomplete' }) {
48
+ super(`Archive ${details.archiveRef} could not be resolved: ${details.reason}`)
49
+ this.name = 'ArchiveNotFoundError'
50
+ this.details = details
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Config for {@link DiskArchiveBackend}. `rootDir` is absolute — bundles land
56
+ * under `{rootDir}/archive/`.
57
+ */
58
+ export interface DiskArchiveBackendConfig {
59
+ readonly rootDir: string
60
+ }
61
+
62
+ interface PersistedSubSessionEntry {
63
+ readonly subSessionId: SubSessionId
64
+ readonly sessionId: SessionId
65
+ readonly tenantId: TenantId
66
+ }
67
+
68
+ interface PersistedWorkspaceEntry {
69
+ readonly workspace: WorkspaceRef
70
+ }
71
+
72
+ interface PersistedSummaryEntry {
73
+ readonly summary: SessionSummaryRef
74
+ }
75
+
76
+ interface PersistedMessageLine {
77
+ readonly id: SessionMessage['id']
78
+ readonly sessionId: SessionId
79
+ readonly tenantId: TenantId
80
+ readonly message: SessionMessage['message']
81
+ readonly at: string
82
+ }
83
+
84
+ interface PersistedArchiveMarker {
85
+ readonly archiveRef: ArchiveBackendRef
86
+ readonly archivedAt: string
87
+ }
88
+
89
+ export class DiskArchiveBackend implements ArchiveBackend {
90
+ readonly kind = 'disk'
91
+ private readonly rootDir: string
92
+
93
+ constructor(config: DiskArchiveBackendConfig) {
94
+ this.rootDir = config.rootDir
95
+ }
96
+
97
+ async store(input: ArchiveInput): Promise<ArchiveOutput> {
98
+ const archiveRef = generateArchiveBackendRef()
99
+ const archivedAt = new Date()
100
+ const dir = join(this.rootDir, 'archive', archiveRef)
101
+ await mkdir(dir, { recursive: true })
102
+
103
+ // 1. Sub-session identity.
104
+ const subEntry: PersistedSubSessionEntry = {
105
+ subSessionId: input.subSessionId,
106
+ sessionId: input.sessionId,
107
+ tenantId: input.tenantId,
108
+ }
109
+ await atomicWriteJson(join(dir, 'subsession.json'), subEntry)
110
+
111
+ // 2. Summary (optional).
112
+ if (input.summaryRef) {
113
+ const entry: PersistedSummaryEntry = { summary: serializeSummaryFields(input.summaryRef) }
114
+ await atomicWriteJson(join(dir, 'summary.json'), entry)
115
+ }
116
+
117
+ // 3. Workspace ref (optional).
118
+ if (input.workspace) {
119
+ const entry: PersistedWorkspaceEntry = {
120
+ workspace: serializeWorkspaceFields(input.workspace),
121
+ }
122
+ await atomicWriteJson(join(dir, 'workspace.json'), entry)
123
+ }
124
+
125
+ // 4. Messages — one JSON per line, serialized once with an atomic
126
+ // tmp-rename. No append I/O: we have the full bundle upfront, and
127
+ // single-write is atomic at the file level.
128
+ const lines = input.messages.map((m) => {
129
+ const line: PersistedMessageLine = {
130
+ id: m.id,
131
+ sessionId: m.sessionId,
132
+ tenantId: m.tenantId,
133
+ message: m.message,
134
+ at: m.at.toISOString(),
135
+ }
136
+ return JSON.stringify(line)
137
+ })
138
+ const body = lines.length > 0 ? `${lines.join('\n')}\n` : ''
139
+ await atomicWriteText(join(dir, 'messages.jsonl'), body)
140
+
141
+ // 5. Marker — ALWAYS last. Presence = bundle committed.
142
+ const marker: PersistedArchiveMarker = {
143
+ archiveRef,
144
+ archivedAt: archivedAt.toISOString(),
145
+ }
146
+ await atomicWriteJson(join(dir, 'archive.json'), marker)
147
+
148
+ return { archiveRef, archivedAt }
149
+ }
150
+
151
+ async restore(archiveRef: ArchiveBackendRef): Promise<ArchiveInput> {
152
+ const dir = join(this.rootDir, 'archive', archiveRef)
153
+
154
+ // Directory must exist.
155
+ try {
156
+ await readdir(dir)
157
+ } catch (err) {
158
+ const code = (err as NodeJS.ErrnoException).code
159
+ if (code === 'ENOENT') {
160
+ throw new ArchiveNotFoundError({ archiveRef, reason: 'missing' })
161
+ }
162
+ throw err
163
+ }
164
+
165
+ // Marker must exist — absence = crash-mid-write.
166
+ const marker = await readJson<PersistedArchiveMarker>(join(dir, 'archive.json'))
167
+ if (!marker) {
168
+ throw new ArchiveNotFoundError({ archiveRef, reason: 'incomplete' })
169
+ }
170
+
171
+ const subEntry = await readJson<PersistedSubSessionEntry>(join(dir, 'subsession.json'))
172
+ if (!subEntry) {
173
+ throw new ArchiveNotFoundError({ archiveRef, reason: 'incomplete' })
174
+ }
175
+
176
+ const summaryEntry = await readJson<PersistedSummaryEntry>(join(dir, 'summary.json'))
177
+ const summaryRef = summaryEntry ? deserializeSummaryFields(summaryEntry.summary) : undefined
178
+
179
+ const workspaceEntry = await readJson<PersistedWorkspaceEntry>(join(dir, 'workspace.json'))
180
+ const workspace = workspaceEntry
181
+ ? deserializeWorkspaceFields(workspaceEntry.workspace)
182
+ : undefined
183
+
184
+ const messagesRaw = await readText(join(dir, 'messages.jsonl'))
185
+ const messages: SessionMessage[] =
186
+ messagesRaw === null
187
+ ? []
188
+ : messagesRaw
189
+ .split('\n')
190
+ .filter((l) => l.length > 0)
191
+ .map((l) => {
192
+ const raw = JSON.parse(l) as PersistedMessageLine
193
+ return {
194
+ id: raw.id,
195
+ sessionId: raw.sessionId,
196
+ tenantId: raw.tenantId,
197
+ message: raw.message,
198
+ at: new Date(raw.at),
199
+ }
200
+ })
201
+
202
+ return {
203
+ subSessionId: subEntry.subSessionId,
204
+ sessionId: subEntry.sessionId,
205
+ tenantId: subEntry.tenantId,
206
+ ...(workspace !== undefined && { workspace }),
207
+ ...(summaryRef !== undefined && { summaryRef }),
208
+ messages,
209
+ }
210
+ }
211
+ }
212
+
213
+ // Serialization helpers ------------------------------------------------------
214
+
215
+ function serializeSummaryFields(s: SessionSummaryRef): SessionSummaryRef {
216
+ // Dates survive JSON round-trip as strings; we let JSON.stringify handle
217
+ // the normal `toJSON` path but store them as ISO strings on the wire.
218
+ // On deserialize we coerce back. The in-memory record stays immutable.
219
+ return s
220
+ }
221
+
222
+ function deserializeSummaryFields(s: SessionSummaryRef): SessionSummaryRef {
223
+ // JSON revives Dates as strings — resurrect them.
224
+ const at = s.at instanceof Date ? s.at : new Date(s.at as unknown as string)
225
+ const keyDecisions = s.keyDecisions.map((k) => ({
226
+ at: k.at instanceof Date ? k.at : new Date(k.at as unknown as string),
227
+ summary: k.summary,
228
+ }))
229
+ return { ...s, at, keyDecisions }
230
+ }
231
+
232
+ function serializeWorkspaceFields(w: WorkspaceRef): WorkspaceRef {
233
+ return w
234
+ }
235
+
236
+ function deserializeWorkspaceFields(w: WorkspaceRef): WorkspaceRef {
237
+ const createdAt =
238
+ w.createdAt instanceof Date ? w.createdAt : new Date(w.createdAt as unknown as string)
239
+ return { ...w, createdAt }
240
+ }
241
+
242
+ // ID generation --------------------------------------------------------------
243
+
244
+ const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
245
+ const MAX_UNIFORM_BYTE = Math.floor(256 / ALPHABET.length) * ALPHABET.length
246
+
247
+ /**
248
+ * Mints an {@link ArchiveBackendRef}. Local helper rather than a `utils/id`
249
+ * export because the ref's uniqueness + prefix is an archive-backend concern
250
+ * — other backends may mint refs very differently (e.g. S3 keys).
251
+ */
252
+ function generateArchiveBackendRef(length = 12): ArchiveBackendRef {
253
+ let suffix = ''
254
+ let remaining = length
255
+ while (remaining > 0) {
256
+ const bytes = randomBytes(remaining + 8)
257
+ for (const byte of bytes) {
258
+ if (remaining <= 0) break
259
+ if (byte < MAX_UNIFORM_BYTE) {
260
+ suffix += ALPHABET[byte % ALPHABET.length]
261
+ remaining--
262
+ }
263
+ }
264
+ }
265
+ return `arc_${suffix}` as ArchiveBackendRef
266
+ }
267
+
268
+ // FS helpers -----------------------------------------------------------------
269
+
270
+ async function atomicWriteJson(filePath: string, value: unknown): Promise<void> {
271
+ await atomicWriteText(filePath, JSON.stringify(value, null, 2))
272
+ }
273
+
274
+ async function atomicWriteText(filePath: string, body: string): Promise<void> {
275
+ const tempPath = `${filePath}.tmp`
276
+ try {
277
+ await writeFile(tempPath, body, 'utf-8')
278
+ await rename(tempPath, filePath)
279
+ } catch (err) {
280
+ await unlink(tempPath).catch(() => undefined)
281
+ throw err
282
+ }
283
+ }
284
+
285
+ async function readJson<T>(path: string): Promise<T | null> {
286
+ try {
287
+ const raw = await readFile(path, 'utf-8')
288
+ return JSON.parse(raw) as T
289
+ } catch (err) {
290
+ const code = (err as NodeJS.ErrnoException).code
291
+ if (code === 'ENOENT') return null
292
+ throw err
293
+ }
294
+ }
295
+
296
+ async function readText(path: string): Promise<string | null> {
297
+ try {
298
+ return await readFile(path, 'utf-8')
299
+ } catch (err) {
300
+ const code = (err as NodeJS.ErrnoException).code
301
+ if (code === 'ENOENT') return null
302
+ throw err
303
+ }
304
+ }