@namzu/sdk 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/CHANGELOG.md +23 -5
  2. package/README.md +14 -9
  3. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  4. package/dist/agents/ReactiveAgent.js +5 -3
  5. package/dist/agents/ReactiveAgent.js.map +1 -1
  6. package/dist/agents/RouterAgent.d.ts.map +1 -1
  7. package/dist/agents/RouterAgent.js +3 -0
  8. package/dist/agents/RouterAgent.js.map +1 -1
  9. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  10. package/dist/agents/SupervisorAgent.js +18 -5
  11. package/dist/agents/SupervisorAgent.js.map +1 -1
  12. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  13. package/dist/bridge/a2a/mapper.js +6 -0
  14. package/dist/bridge/a2a/mapper.js.map +1 -1
  15. package/dist/bridge/a2a/task.d.ts +2 -2
  16. package/dist/bridge/a2a/task.d.ts.map +1 -1
  17. package/dist/bridge/a2a/task.js.map +1 -1
  18. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  19. package/dist/bridge/sse/mapper.js +6 -0
  20. package/dist/bridge/sse/mapper.js.map +1 -1
  21. package/dist/constants/a2a/index.d.ts +2 -2
  22. package/dist/constants/a2a/index.d.ts.map +1 -1
  23. package/dist/constants/a2a/index.js.map +1 -1
  24. package/dist/contracts/api.d.ts +22 -3
  25. package/dist/contracts/api.d.ts.map +1 -1
  26. package/dist/contracts/index.d.ts +3 -1
  27. package/dist/contracts/index.d.ts.map +1 -1
  28. package/dist/contracts/index.js.map +1 -1
  29. package/dist/gateway/local.d.ts.map +1 -1
  30. package/dist/gateway/local.js +6 -0
  31. package/dist/gateway/local.js.map +1 -1
  32. package/dist/index.d.ts +4 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +4 -0
  35. package/dist/index.js.map +1 -1
  36. package/dist/manager/agent/__tests__/lifecycle.test.d.ts +2 -0
  37. package/dist/manager/agent/__tests__/lifecycle.test.d.ts.map +1 -0
  38. package/dist/manager/agent/__tests__/lifecycle.test.js +302 -0
  39. package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -0
  40. package/dist/manager/agent/lifecycle.d.ts +58 -3
  41. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  42. package/dist/manager/agent/lifecycle.js +311 -12
  43. package/dist/manager/agent/lifecycle.js.map +1 -1
  44. package/dist/manager/run/persistence.d.ts +8 -1
  45. package/dist/manager/run/persistence.d.ts.map +1 -1
  46. package/dist/manager/run/persistence.js +15 -0
  47. package/dist/manager/run/persistence.js.map +1 -1
  48. package/dist/run/reporter.d.ts.map +1 -1
  49. package/dist/run/reporter.js +25 -0
  50. package/dist/run/reporter.js.map +1 -1
  51. package/dist/runtime/query/__tests__/context.test.d.ts +2 -0
  52. package/dist/runtime/query/__tests__/context.test.d.ts.map +1 -0
  53. package/dist/runtime/query/__tests__/context.test.js +84 -0
  54. package/dist/runtime/query/__tests__/context.test.js.map +1 -0
  55. package/dist/runtime/query/context.d.ts +55 -2
  56. package/dist/runtime/query/context.d.ts.map +1 -1
  57. package/dist/runtime/query/context.js +48 -8
  58. package/dist/runtime/query/context.js.map +1 -1
  59. package/dist/runtime/query/events.d.ts.map +1 -1
  60. package/dist/runtime/query/events.js +8 -0
  61. package/dist/runtime/query/events.js.map +1 -1
  62. package/dist/runtime/query/index.d.ts +25 -2
  63. package/dist/runtime/query/index.d.ts.map +1 -1
  64. package/dist/runtime/query/index.js +11 -1
  65. package/dist/runtime/query/index.js.map +1 -1
  66. package/dist/session/__tests__/integration/_fixtures.d.ts +115 -0
  67. package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -0
  68. package/dist/session/__tests__/integration/_fixtures.js +198 -0
  69. package/dist/session/__tests__/integration/_fixtures.js.map +1 -0
  70. package/dist/session/__tests__/integration/capacity-caps.test.d.ts +13 -0
  71. package/dist/session/__tests__/integration/capacity-caps.test.d.ts.map +1 -0
  72. package/dist/session/__tests__/integration/capacity-caps.test.js +116 -0
  73. package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -0
  74. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts +18 -0
  75. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts.map +1 -0
  76. package/dist/session/__tests__/integration/e2e-spawn.test.js +226 -0
  77. package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -0
  78. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts +15 -0
  79. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts.map +1 -0
  80. package/dist/session/__tests__/integration/event-stream-ordering.test.js +323 -0
  81. package/dist/session/__tests__/integration/event-stream-ordering.test.js.map +1 -0
  82. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts +12 -0
  83. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts.map +1 -0
  84. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js +170 -0
  85. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -0
  86. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts +18 -0
  87. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts.map +1 -0
  88. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js +146 -0
  89. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js.map +1 -0
  90. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts +15 -0
  91. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts.map +1 -0
  92. package/dist/session/__tests__/integration/handoff-single-e2e.test.js +163 -0
  93. package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -0
  94. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts +12 -0
  95. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts.map +1 -0
  96. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js +157 -0
  97. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js.map +1 -0
  98. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts +11 -0
  99. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts.map +1 -0
  100. package/dist/session/__tests__/integration/migration-filesystem.test.js +140 -0
  101. package/dist/session/__tests__/integration/migration-filesystem.test.js.map +1 -0
  102. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts +13 -0
  103. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts.map +1 -0
  104. package/dist/session/__tests__/integration/migration-id-prefix.test.js +84 -0
  105. package/dist/session/__tests__/integration/migration-id-prefix.test.js.map +1 -0
  106. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts +14 -0
  107. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts.map +1 -0
  108. package/dist/session/__tests__/integration/prev-artifact-dag.test.js +241 -0
  109. package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -0
  110. package/dist/session/__tests__/integration/retention-archive.test.d.ts +12 -0
  111. package/dist/session/__tests__/integration/retention-archive.test.d.ts.map +1 -0
  112. package/dist/session/__tests__/integration/retention-archive.test.js +186 -0
  113. package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -0
  114. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts +18 -0
  115. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts.map +1 -0
  116. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +200 -0
  117. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -0
  118. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts +14 -0
  119. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts.map +1 -0
  120. package/dist/session/__tests__/integration/tenant-isolation.test.js +180 -0
  121. package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -0
  122. package/dist/session/errors.d.ts +60 -0
  123. package/dist/session/errors.d.ts.map +1 -0
  124. package/dist/session/errors.js +50 -0
  125. package/dist/session/errors.js.map +1 -0
  126. package/dist/session/events/index.d.ts +4 -0
  127. package/dist/session/events/index.d.ts.map +1 -0
  128. package/dist/session/events/index.js +8 -0
  129. package/dist/session/events/index.js.map +1 -0
  130. package/dist/session/events/schema-version.d.ts +13 -0
  131. package/dist/session/events/schema-version.d.ts.map +1 -0
  132. package/dist/session/events/schema-version.js +12 -0
  133. package/dist/session/events/schema-version.js.map +1 -0
  134. package/dist/session/events/types.d.ts +64 -0
  135. package/dist/session/events/types.d.ts.map +1 -0
  136. package/dist/session/events/types.js +2 -0
  137. package/dist/session/events/types.js.map +1 -0
  138. package/dist/session/handoff/__tests__/broadcast.test.d.ts +2 -0
  139. package/dist/session/handoff/__tests__/broadcast.test.d.ts.map +1 -0
  140. package/dist/session/handoff/__tests__/broadcast.test.js +243 -0
  141. package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -0
  142. package/dist/session/handoff/__tests__/capacity.test.d.ts +2 -0
  143. package/dist/session/handoff/__tests__/capacity.test.d.ts.map +1 -0
  144. package/dist/session/handoff/__tests__/capacity.test.js +100 -0
  145. package/dist/session/handoff/__tests__/capacity.test.js.map +1 -0
  146. package/dist/session/handoff/__tests__/single.test.d.ts +2 -0
  147. package/dist/session/handoff/__tests__/single.test.d.ts.map +1 -0
  148. package/dist/session/handoff/__tests__/single.test.js +230 -0
  149. package/dist/session/handoff/__tests__/single.test.js.map +1 -0
  150. package/dist/session/handoff/assignment.d.ts +59 -0
  151. package/dist/session/handoff/assignment.d.ts.map +1 -0
  152. package/dist/session/handoff/assignment.js +11 -0
  153. package/dist/session/handoff/assignment.js.map +1 -0
  154. package/dist/session/handoff/broadcast.d.ts +47 -0
  155. package/dist/session/handoff/broadcast.d.ts.map +1 -0
  156. package/dist/session/handoff/broadcast.js +296 -0
  157. package/dist/session/handoff/broadcast.js.map +1 -0
  158. package/dist/session/handoff/capacity.d.ts +66 -0
  159. package/dist/session/handoff/capacity.d.ts.map +1 -0
  160. package/dist/session/handoff/capacity.js +60 -0
  161. package/dist/session/handoff/capacity.js.map +1 -0
  162. package/dist/session/handoff/events.d.ts +66 -0
  163. package/dist/session/handoff/events.d.ts.map +1 -0
  164. package/dist/session/handoff/events.js +13 -0
  165. package/dist/session/handoff/events.js.map +1 -0
  166. package/dist/session/handoff/index.d.ts +12 -0
  167. package/dist/session/handoff/index.d.ts.map +1 -0
  168. package/dist/session/handoff/index.js +9 -0
  169. package/dist/session/handoff/index.js.map +1 -0
  170. package/dist/session/handoff/single.d.ts +62 -0
  171. package/dist/session/handoff/single.d.ts.map +1 -0
  172. package/dist/session/handoff/single.js +217 -0
  173. package/dist/session/handoff/single.js.map +1 -0
  174. package/dist/session/handoff/version.d.ts +52 -0
  175. package/dist/session/handoff/version.d.ts.map +1 -0
  176. package/dist/session/handoff/version.js +36 -0
  177. package/dist/session/handoff/version.js.map +1 -0
  178. package/dist/session/hierarchy/__tests__/session.test.d.ts +2 -0
  179. package/dist/session/hierarchy/__tests__/session.test.d.ts.map +1 -0
  180. package/dist/session/hierarchy/__tests__/session.test.js +67 -0
  181. package/dist/session/hierarchy/__tests__/session.test.js.map +1 -0
  182. package/dist/session/hierarchy/actor.d.ts +26 -0
  183. package/dist/session/hierarchy/actor.d.ts.map +1 -0
  184. package/dist/session/hierarchy/actor.js +2 -0
  185. package/dist/session/hierarchy/actor.js.map +1 -0
  186. package/dist/session/hierarchy/index.d.ts +8 -0
  187. package/dist/session/hierarchy/index.d.ts.map +1 -0
  188. package/dist/session/hierarchy/index.js +4 -0
  189. package/dist/session/hierarchy/index.js.map +1 -0
  190. package/dist/session/hierarchy/lineage.d.ts +15 -0
  191. package/dist/session/hierarchy/lineage.d.ts.map +1 -0
  192. package/dist/session/hierarchy/lineage.js +2 -0
  193. package/dist/session/hierarchy/lineage.js.map +1 -0
  194. package/dist/session/hierarchy/project.d.ts +40 -0
  195. package/dist/session/hierarchy/project.d.ts.map +1 -0
  196. package/dist/session/hierarchy/project.js +2 -0
  197. package/dist/session/hierarchy/project.js.map +1 -0
  198. package/dist/session/hierarchy/session.d.ts +59 -0
  199. package/dist/session/hierarchy/session.d.ts.map +1 -0
  200. package/dist/session/hierarchy/session.js +51 -0
  201. package/dist/session/hierarchy/session.js.map +1 -0
  202. package/dist/session/hierarchy/sub-session.d.ts +76 -0
  203. package/dist/session/hierarchy/sub-session.d.ts.map +1 -0
  204. package/dist/session/hierarchy/sub-session.js +2 -0
  205. package/dist/session/hierarchy/sub-session.js.map +1 -0
  206. package/dist/session/hierarchy/tenant.d.ts +13 -0
  207. package/dist/session/hierarchy/tenant.d.ts.map +1 -0
  208. package/dist/session/hierarchy/tenant.js +2 -0
  209. package/dist/session/hierarchy/tenant.js.map +1 -0
  210. package/dist/session/index.d.ts +10 -0
  211. package/dist/session/index.d.ts.map +1 -0
  212. package/dist/session/index.js +15 -0
  213. package/dist/session/index.js.map +1 -0
  214. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts +2 -0
  215. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts.map +1 -0
  216. package/dist/session/intervention/__tests__/prev-artifact.test.js +179 -0
  217. package/dist/session/intervention/__tests__/prev-artifact.test.js.map +1 -0
  218. package/dist/session/intervention/index.d.ts +3 -0
  219. package/dist/session/intervention/index.d.ts.map +1 -0
  220. package/dist/session/intervention/index.js +8 -0
  221. package/dist/session/intervention/index.js.map +1 -0
  222. package/dist/session/intervention/prev-artifact.d.ts +103 -0
  223. package/dist/session/intervention/prev-artifact.d.ts.map +1 -0
  224. package/dist/session/intervention/prev-artifact.js +112 -0
  225. package/dist/session/intervention/prev-artifact.js.map +1 -0
  226. package/dist/session/migration/__tests__/filesystem.test.d.ts +2 -0
  227. package/dist/session/migration/__tests__/filesystem.test.d.ts.map +1 -0
  228. package/dist/session/migration/__tests__/filesystem.test.js +188 -0
  229. package/dist/session/migration/__tests__/filesystem.test.js.map +1 -0
  230. package/dist/session/migration/__tests__/id-prefix.test.d.ts +2 -0
  231. package/dist/session/migration/__tests__/id-prefix.test.d.ts.map +1 -0
  232. package/dist/session/migration/__tests__/id-prefix.test.js +83 -0
  233. package/dist/session/migration/__tests__/id-prefix.test.js.map +1 -0
  234. package/dist/session/migration/__tests__/marker.test.d.ts +2 -0
  235. package/dist/session/migration/__tests__/marker.test.d.ts.map +1 -0
  236. package/dist/session/migration/__tests__/marker.test.js +75 -0
  237. package/dist/session/migration/__tests__/marker.test.js.map +1 -0
  238. package/dist/session/migration/errors.d.ts +26 -0
  239. package/dist/session/migration/errors.d.ts.map +1 -0
  240. package/dist/session/migration/errors.js +22 -0
  241. package/dist/session/migration/errors.js.map +1 -0
  242. package/dist/session/migration/filesystem.d.ts +94 -0
  243. package/dist/session/migration/filesystem.d.ts.map +1 -0
  244. package/dist/session/migration/filesystem.js +319 -0
  245. package/dist/session/migration/filesystem.js.map +1 -0
  246. package/dist/session/migration/id-prefix.d.ts +98 -0
  247. package/dist/session/migration/id-prefix.d.ts.map +1 -0
  248. package/dist/session/migration/id-prefix.js +116 -0
  249. package/dist/session/migration/id-prefix.js.map +1 -0
  250. package/dist/session/migration/index.d.ts +8 -0
  251. package/dist/session/migration/index.d.ts.map +1 -0
  252. package/dist/session/migration/index.js +8 -0
  253. package/dist/session/migration/index.js.map +1 -0
  254. package/dist/session/migration/marker.d.ts +57 -0
  255. package/dist/session/migration/marker.d.ts.map +1 -0
  256. package/dist/session/migration/marker.js +111 -0
  257. package/dist/session/migration/marker.js.map +1 -0
  258. package/dist/session/retention/__tests__/archive.test.d.ts +2 -0
  259. package/dist/session/retention/__tests__/archive.test.d.ts.map +1 -0
  260. package/dist/session/retention/__tests__/archive.test.js +252 -0
  261. package/dist/session/retention/__tests__/archive.test.js.map +1 -0
  262. package/dist/session/retention/__tests__/disk-backend.test.d.ts +2 -0
  263. package/dist/session/retention/__tests__/disk-backend.test.d.ts.map +1 -0
  264. package/dist/session/retention/__tests__/disk-backend.test.js +154 -0
  265. package/dist/session/retention/__tests__/disk-backend.test.js.map +1 -0
  266. package/dist/session/retention/archive-backend-ref.d.ts +18 -0
  267. package/dist/session/retention/archive-backend-ref.d.ts.map +1 -0
  268. package/dist/session/retention/archive-backend-ref.js +2 -0
  269. package/dist/session/retention/archive-backend-ref.js.map +1 -0
  270. package/dist/session/retention/archive.d.ts +130 -0
  271. package/dist/session/retention/archive.d.ts.map +1 -0
  272. package/dist/session/retention/archive.js +203 -0
  273. package/dist/session/retention/archive.js.map +1 -0
  274. package/dist/session/retention/backend.d.ts +101 -0
  275. package/dist/session/retention/backend.d.ts.map +1 -0
  276. package/dist/session/retention/backend.js +15 -0
  277. package/dist/session/retention/backend.js.map +1 -0
  278. package/dist/session/retention/disk-backend.d.ts +59 -0
  279. package/dist/session/retention/disk-backend.d.ts.map +1 -0
  280. package/dist/session/retention/disk-backend.js +236 -0
  281. package/dist/session/retention/disk-backend.js.map +1 -0
  282. package/dist/session/retention/index.d.ts +9 -0
  283. package/dist/session/retention/index.d.ts.map +1 -0
  284. package/dist/session/retention/index.js +6 -0
  285. package/dist/session/retention/index.js.map +1 -0
  286. package/dist/session/retention/policy.d.ts +49 -0
  287. package/dist/session/retention/policy.d.ts.map +1 -0
  288. package/dist/session/retention/policy.js +21 -0
  289. package/dist/session/retention/policy.js.map +1 -0
  290. package/dist/session/summary/__tests__/materialize.test.d.ts +2 -0
  291. package/dist/session/summary/__tests__/materialize.test.d.ts.map +1 -0
  292. package/dist/session/summary/__tests__/materialize.test.js +269 -0
  293. package/dist/session/summary/__tests__/materialize.test.js.map +1 -0
  294. package/dist/session/summary/deliverable.d.ts +74 -0
  295. package/dist/session/summary/deliverable.d.ts.map +1 -0
  296. package/dist/session/summary/deliverable.js +20 -0
  297. package/dist/session/summary/deliverable.js.map +1 -0
  298. package/dist/session/summary/index.d.ts +6 -0
  299. package/dist/session/summary/index.d.ts.map +1 -0
  300. package/dist/session/summary/index.js +9 -0
  301. package/dist/session/summary/index.js.map +1 -0
  302. package/dist/session/summary/materialize.d.ts +82 -0
  303. package/dist/session/summary/materialize.d.ts.map +1 -0
  304. package/dist/session/summary/materialize.js +117 -0
  305. package/dist/session/summary/materialize.js.map +1 -0
  306. package/dist/session/summary/ref.d.ts +91 -0
  307. package/dist/session/summary/ref.d.ts.map +1 -0
  308. package/dist/session/summary/ref.js +51 -0
  309. package/dist/session/summary/ref.js.map +1 -0
  310. package/dist/session/workspace/__tests__/git-worktree.test.d.ts +2 -0
  311. package/dist/session/workspace/__tests__/git-worktree.test.d.ts.map +1 -0
  312. package/dist/session/workspace/__tests__/git-worktree.test.js +244 -0
  313. package/dist/session/workspace/__tests__/git-worktree.test.js.map +1 -0
  314. package/dist/session/workspace/__tests__/path-builder.test.d.ts +2 -0
  315. package/dist/session/workspace/__tests__/path-builder.test.d.ts.map +1 -0
  316. package/dist/session/workspace/__tests__/path-builder.test.js +37 -0
  317. package/dist/session/workspace/__tests__/path-builder.test.js.map +1 -0
  318. package/dist/session/workspace/driver.d.ts +55 -0
  319. package/dist/session/workspace/driver.d.ts.map +1 -0
  320. package/dist/session/workspace/driver.js +12 -0
  321. package/dist/session/workspace/driver.js.map +1 -0
  322. package/dist/session/workspace/git-worktree.d.ts +65 -0
  323. package/dist/session/workspace/git-worktree.d.ts.map +1 -0
  324. package/dist/session/workspace/git-worktree.js +156 -0
  325. package/dist/session/workspace/git-worktree.js.map +1 -0
  326. package/dist/session/workspace/index.d.ts +8 -0
  327. package/dist/session/workspace/index.d.ts.map +1 -0
  328. package/dist/session/workspace/index.js +7 -0
  329. package/dist/session/workspace/index.js.map +1 -0
  330. package/dist/session/workspace/path-builder.d.ts +50 -0
  331. package/dist/session/workspace/path-builder.d.ts.map +1 -0
  332. package/dist/session/workspace/path-builder.js +50 -0
  333. package/dist/session/workspace/path-builder.js.map +1 -0
  334. package/dist/session/workspace/ref.d.ts +46 -0
  335. package/dist/session/workspace/ref.d.ts.map +1 -0
  336. package/dist/session/workspace/ref.js +11 -0
  337. package/dist/session/workspace/ref.js.map +1 -0
  338. package/dist/session/workspace/registry.d.ts +26 -0
  339. package/dist/session/workspace/registry.d.ts.map +1 -0
  340. package/dist/session/workspace/registry.js +35 -0
  341. package/dist/session/workspace/registry.js.map +1 -0
  342. package/dist/store/conversation/memory.d.ts +22 -0
  343. package/dist/store/conversation/memory.d.ts.map +1 -1
  344. package/dist/store/conversation/memory.js +22 -0
  345. package/dist/store/conversation/memory.js.map +1 -1
  346. package/dist/store/session/__tests__/disk.test.d.ts +2 -0
  347. package/dist/store/session/__tests__/disk.test.d.ts.map +1 -0
  348. package/dist/store/session/__tests__/disk.test.js +240 -0
  349. package/dist/store/session/__tests__/disk.test.js.map +1 -0
  350. package/dist/store/session/__tests__/memory.test.d.ts +2 -0
  351. package/dist/store/session/__tests__/memory.test.d.ts.map +1 -0
  352. package/dist/store/session/__tests__/memory.test.js +217 -0
  353. package/dist/store/session/__tests__/memory.test.js.map +1 -0
  354. package/dist/store/session/disk.d.ts +85 -0
  355. package/dist/store/session/disk.d.ts.map +1 -0
  356. package/dist/store/session/disk.js +757 -0
  357. package/dist/store/session/disk.js.map +1 -0
  358. package/dist/store/session/index.d.ts +7 -0
  359. package/dist/store/session/index.d.ts.map +1 -0
  360. package/dist/store/session/index.js +11 -0
  361. package/dist/store/session/index.js.map +1 -0
  362. package/dist/store/session/linkage.d.ts +38 -0
  363. package/dist/store/session/linkage.d.ts.map +1 -0
  364. package/dist/store/session/linkage.js +64 -0
  365. package/dist/store/session/linkage.js.map +1 -0
  366. package/dist/store/session/memory.d.ts +48 -0
  367. package/dist/store/session/memory.d.ts.map +1 -0
  368. package/dist/store/session/memory.js +322 -0
  369. package/dist/store/session/memory.js.map +1 -0
  370. package/dist/store/session/messages.d.ts +20 -0
  371. package/dist/store/session/messages.d.ts.map +1 -0
  372. package/dist/store/session/messages.js +12 -0
  373. package/dist/store/session/messages.js.map +1 -0
  374. package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts +1 -1
  375. package/dist/types/agent/base.d.ts +28 -1
  376. package/dist/types/agent/base.d.ts.map +1 -1
  377. package/dist/types/agent/task.d.ts +50 -2
  378. package/dist/types/agent/task.d.ts.map +1 -1
  379. package/dist/types/agent/task.js.map +1 -1
  380. package/dist/types/conversation/index.d.ts +7 -0
  381. package/dist/types/conversation/index.d.ts.map +1 -1
  382. package/dist/types/ids/index.d.ts +26 -3
  383. package/dist/types/ids/index.d.ts.map +1 -1
  384. package/dist/types/ids/index.js +8 -1
  385. package/dist/types/ids/index.js.map +1 -1
  386. package/dist/types/invocation/__tests__/state.test.js +36 -29
  387. package/dist/types/invocation/__tests__/state.test.js.map +1 -1
  388. package/dist/types/invocation/index.d.ts +20 -4
  389. package/dist/types/invocation/index.d.ts.map +1 -1
  390. package/dist/types/invocation/index.js +10 -7
  391. package/dist/types/invocation/index.js.map +1 -1
  392. package/dist/types/run/config.d.ts +11 -1
  393. package/dist/types/run/config.d.ts.map +1 -1
  394. package/dist/types/run/events.d.ts +26 -1
  395. package/dist/types/run/events.d.ts.map +1 -1
  396. package/dist/types/run/index.d.ts.map +1 -1
  397. package/dist/types/run/index.js +8 -0
  398. package/dist/types/run/index.js.map +1 -1
  399. package/dist/types/run/metadata.d.ts +24 -1
  400. package/dist/types/run/metadata.d.ts.map +1 -1
  401. package/dist/types/run/status.d.ts +26 -0
  402. package/dist/types/run/status.d.ts.map +1 -0
  403. package/dist/types/run/status.js +2 -0
  404. package/dist/types/run/status.js.map +1 -0
  405. package/dist/types/session/ids.d.ts +18 -0
  406. package/dist/types/session/ids.d.ts.map +1 -0
  407. package/dist/types/session/ids.js +12 -0
  408. package/dist/types/session/ids.js.map +1 -0
  409. package/dist/types/session/index.d.ts +3 -0
  410. package/dist/types/session/index.d.ts.map +1 -0
  411. package/dist/types/session/index.js +5 -0
  412. package/dist/types/session/index.js.map +1 -0
  413. package/dist/types/session/store.d.ts +188 -0
  414. package/dist/types/session/store.d.ts.map +1 -0
  415. package/dist/types/session/store.js +14 -0
  416. package/dist/types/session/store.js.map +1 -0
  417. package/dist/utils/id.d.ts +18 -1
  418. package/dist/utils/id.d.ts.map +1 -1
  419. package/dist/utils/id.js +42 -4
  420. package/dist/utils/id.js.map +1 -1
  421. package/package.json +1 -1
  422. package/src/agents/ReactiveAgent.ts +7 -3
  423. package/src/agents/RouterAgent.ts +5 -0
  424. package/src/agents/SupervisorAgent.ts +26 -6
  425. package/src/bridge/a2a/mapper.ts +7 -0
  426. package/src/bridge/a2a/task.ts +2 -2
  427. package/src/bridge/sse/mapper.ts +8 -1
  428. package/src/constants/a2a/index.ts +2 -2
  429. package/src/contracts/api.ts +23 -3
  430. package/src/contracts/index.ts +2 -0
  431. package/src/gateway/local.ts +6 -0
  432. package/src/index.ts +14 -0
  433. package/src/manager/agent/__tests__/lifecycle.test.ts +452 -0
  434. package/src/manager/agent/lifecycle.ts +434 -19
  435. package/src/manager/run/persistence.ts +20 -1
  436. package/src/run/reporter.ts +28 -0
  437. package/src/runtime/query/__tests__/context.test.ts +101 -0
  438. package/src/runtime/query/context.ts +106 -10
  439. package/src/runtime/query/events.ts +8 -0
  440. package/src/runtime/query/index.ts +41 -3
  441. package/src/session/__tests__/integration/_fixtures.ts +282 -0
  442. package/src/session/__tests__/integration/capacity-caps.test.ts +164 -0
  443. package/src/session/__tests__/integration/e2e-spawn.test.ts +278 -0
  444. package/src/session/__tests__/integration/event-stream-ordering.test.ts +403 -0
  445. package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +245 -0
  446. package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +179 -0
  447. package/src/session/__tests__/integration/handoff-single-e2e.test.ts +220 -0
  448. package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +237 -0
  449. package/src/session/__tests__/integration/migration-filesystem.test.ts +209 -0
  450. package/src/session/__tests__/integration/migration-id-prefix.test.ts +101 -0
  451. package/src/session/__tests__/integration/prev-artifact-dag.test.ts +318 -0
  452. package/src/session/__tests__/integration/retention-archive.test.ts +231 -0
  453. package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +237 -0
  454. package/src/session/__tests__/integration/tenant-isolation.test.ts +282 -0
  455. package/src/session/errors.ts +70 -0
  456. package/src/session/events/index.ts +16 -0
  457. package/src/session/events/schema-version.ts +13 -0
  458. package/src/session/events/types.ts +71 -0
  459. package/src/session/handoff/__tests__/broadcast.test.ts +350 -0
  460. package/src/session/handoff/__tests__/capacity.test.ts +123 -0
  461. package/src/session/handoff/__tests__/single.test.ts +316 -0
  462. package/src/session/handoff/assignment.ts +62 -0
  463. package/src/session/handoff/broadcast.ts +381 -0
  464. package/src/session/handoff/capacity.ts +121 -0
  465. package/src/session/handoff/events.ts +72 -0
  466. package/src/session/handoff/index.ts +29 -0
  467. package/src/session/handoff/single.ts +288 -0
  468. package/src/session/handoff/version.ts +59 -0
  469. package/src/session/hierarchy/__tests__/session.test.ts +92 -0
  470. package/src/session/hierarchy/actor.ts +17 -0
  471. package/src/session/hierarchy/index.ts +17 -0
  472. package/src/session/hierarchy/lineage.ts +15 -0
  473. package/src/session/hierarchy/project.ts +41 -0
  474. package/src/session/hierarchy/session.ts +97 -0
  475. package/src/session/hierarchy/sub-session.ts +92 -0
  476. package/src/session/hierarchy/tenant.ts +13 -0
  477. package/src/session/index.ts +15 -0
  478. package/src/session/intervention/__tests__/prev-artifact.test.ts +234 -0
  479. package/src/session/intervention/index.ts +16 -0
  480. package/src/session/intervention/prev-artifact.ts +180 -0
  481. package/src/session/migration/__tests__/filesystem.test.ts +263 -0
  482. package/src/session/migration/__tests__/id-prefix.test.ts +101 -0
  483. package/src/session/migration/__tests__/marker.test.ts +84 -0
  484. package/src/session/migration/errors.ts +23 -0
  485. package/src/session/migration/filesystem.ts +401 -0
  486. package/src/session/migration/id-prefix.ts +146 -0
  487. package/src/session/migration/index.ts +38 -0
  488. package/src/session/migration/marker.ts +131 -0
  489. package/src/session/retention/__tests__/archive.test.ts +316 -0
  490. package/src/session/retention/__tests__/disk-backend.test.ts +180 -0
  491. package/src/session/retention/archive-backend-ref.ts +17 -0
  492. package/src/session/retention/archive.ts +281 -0
  493. package/src/session/retention/backend.ts +107 -0
  494. package/src/session/retention/disk-backend.ts +304 -0
  495. package/src/session/retention/index.ts +16 -0
  496. package/src/session/retention/policy.ts +53 -0
  497. package/src/session/summary/__tests__/materialize.test.ts +341 -0
  498. package/src/session/summary/deliverable.ts +84 -0
  499. package/src/session/summary/index.ts +31 -0
  500. package/src/session/summary/materialize.ts +169 -0
  501. package/src/session/summary/ref.ts +104 -0
  502. package/src/session/workspace/__tests__/git-worktree.test.ts +258 -0
  503. package/src/session/workspace/__tests__/path-builder.test.ts +51 -0
  504. package/src/session/workspace/driver.ts +60 -0
  505. package/src/session/workspace/git-worktree.ts +209 -0
  506. package/src/session/workspace/index.ts +25 -0
  507. package/src/session/workspace/path-builder.ts +71 -0
  508. package/src/session/workspace/ref.ts +50 -0
  509. package/src/session/workspace/registry.ts +42 -0
  510. package/src/store/conversation/memory.ts +23 -0
  511. package/src/store/session/__tests__/disk.test.ts +346 -0
  512. package/src/store/session/__tests__/memory.test.ts +327 -0
  513. package/src/store/session/disk.ts +920 -0
  514. package/src/store/session/index.ts +14 -0
  515. package/src/store/session/linkage.ts +80 -0
  516. package/src/store/session/memory.ts +400 -0
  517. package/src/store/session/messages.ts +21 -0
  518. package/src/types/agent/base.ts +31 -1
  519. package/src/types/agent/task.ts +58 -2
  520. package/src/types/conversation/index.ts +7 -0
  521. package/src/types/ids/index.ts +41 -3
  522. package/src/types/invocation/__tests__/state.test.ts +37 -29
  523. package/src/types/invocation/index.ts +26 -10
  524. package/src/types/run/config.ts +12 -1
  525. package/src/types/run/events.ts +36 -1
  526. package/src/types/run/index.ts +8 -0
  527. package/src/types/run/metadata.ts +24 -1
  528. package/src/types/run/status.ts +33 -0
  529. package/src/types/session/ids.ts +34 -0
  530. package/src/types/session/index.ts +28 -0
  531. package/src/types/session/store.ts +229 -0
  532. package/src/utils/id.ts +55 -4
@@ -0,0 +1,263 @@
1
+ import { chmod, mkdir, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises'
2
+ import { tmpdir } from 'node:os'
3
+ import { join } from 'node:path'
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest'
5
+ import { UNKNOWN_TENANT_ID } from '../../../types/ids/index.js'
6
+ import { FilesystemMigrationError } from '../errors.js'
7
+ import {
8
+ DefaultFilesystemMigrator,
9
+ type FilesystemMigrationEvent,
10
+ type FilesystemMigrationSink,
11
+ LEGACY_DEFAULT_PROJECT_PREFIX,
12
+ LEGACY_DEFAULT_SESSION_ID,
13
+ MARKER_REL_PATH,
14
+ MIGRATION_VERSION,
15
+ } from '../filesystem.js'
16
+ import { acquireMigrationLock, writeMarker } from '../marker.js'
17
+
18
+ function collectingSink(): {
19
+ events: FilesystemMigrationEvent[]
20
+ sink: FilesystemMigrationSink
21
+ } {
22
+ const events: FilesystemMigrationEvent[] = []
23
+ return {
24
+ events,
25
+ sink: {
26
+ emit(ev) {
27
+ events.push(ev)
28
+ },
29
+ },
30
+ }
31
+ }
32
+
33
+ async function seedLegacyThread(root: string, thread: string, runs: string[]): Promise<void> {
34
+ for (const run of runs) {
35
+ const dir = join(root, 'threads', thread, 'runs', run)
36
+ await mkdir(dir, { recursive: true })
37
+ await writeFile(join(dir, 'run.json'), JSON.stringify({ id: run }), 'utf-8')
38
+ }
39
+ }
40
+
41
+ async function pathExists(p: string): Promise<boolean> {
42
+ try {
43
+ await stat(p)
44
+ return true
45
+ } catch {
46
+ return false
47
+ }
48
+ }
49
+
50
+ describe('DefaultFilesystemMigrator.migrate', () => {
51
+ let root: string
52
+
53
+ beforeEach(async () => {
54
+ root = await mkdtemp(join(tmpdir(), 'namzu-fsmig-'))
55
+ })
56
+
57
+ afterEach(async () => {
58
+ // chmod first in case a test left 000 perms on a directory.
59
+ await chmod(root, 0o755).catch(() => undefined)
60
+ await rm(root, { recursive: true, force: true })
61
+ })
62
+
63
+ it('cold boot with a single legacy thread: migrates, emits event, writes marker', async () => {
64
+ await seedLegacyThread(root, 'thd_abc', ['run_xyz'])
65
+
66
+ const { events, sink } = collectingSink()
67
+ const migrator = new DefaultFilesystemMigrator(sink)
68
+
69
+ const result = await migrator.migrate(root)
70
+
71
+ expect(result.kind).toBe('migrated')
72
+ expect(result.migratedThreads).toEqual([
73
+ { legacyThreadId: 'thd_abc', newProjectId: `${LEGACY_DEFAULT_PROJECT_PREFIX}abc` },
74
+ ])
75
+
76
+ // New layout exists.
77
+ const newRunDir = join(
78
+ root,
79
+ 'projects',
80
+ `${LEGACY_DEFAULT_PROJECT_PREFIX}abc`,
81
+ 'sessions',
82
+ LEGACY_DEFAULT_SESSION_ID,
83
+ 'runs',
84
+ 'run_xyz',
85
+ )
86
+ expect(await pathExists(newRunDir)).toBe(true)
87
+ expect(await pathExists(join(newRunDir, 'run.json'))).toBe(true)
88
+
89
+ // Legacy path moved (runs/ sub-tree renamed).
90
+ expect(await pathExists(join(root, 'threads', 'thd_abc', 'runs'))).toBe(false)
91
+
92
+ // Marker landed.
93
+ const markerRaw = await readFile(join(root, MARKER_REL_PATH), 'utf-8')
94
+ const markerParsed = JSON.parse(markerRaw)
95
+ expect(markerParsed.version).toBe(MIGRATION_VERSION)
96
+ expect(markerParsed.migratedThreads).toHaveLength(1)
97
+
98
+ // Event emitted with accurate result.
99
+ expect(events).toHaveLength(1)
100
+ expect(events[0]?.type).toBe('filesystem.migrated')
101
+ expect(events[0]?.result.kind).toBe('migrated')
102
+ })
103
+
104
+ it('warm boot with an existing marker short-circuits to already_migrated', async () => {
105
+ await writeMarker(join(root, MARKER_REL_PATH), {
106
+ version: MIGRATION_VERSION,
107
+ at: new Date(),
108
+ migratedThreads: [],
109
+ })
110
+ await seedLegacyThread(root, 'thd_stillhere', ['run_ignored'])
111
+
112
+ const { events, sink } = collectingSink()
113
+ const migrator = new DefaultFilesystemMigrator(sink)
114
+
115
+ const result = await migrator.migrate(root)
116
+
117
+ expect(result.kind).toBe('already_migrated')
118
+ expect(events).toHaveLength(0)
119
+ // No migration happened — legacy path untouched.
120
+ expect(await pathExists(join(root, 'threads', 'thd_stillhere', 'runs', 'run_ignored'))).toBe(
121
+ true,
122
+ )
123
+ })
124
+
125
+ it('cold boot with neither legacy nor marker writes a marker and returns noop_no_legacy', async () => {
126
+ const { events, sink } = collectingSink()
127
+ const migrator = new DefaultFilesystemMigrator(sink)
128
+
129
+ const result = await migrator.migrate(root)
130
+
131
+ expect(result.kind).toBe('noop_no_legacy')
132
+ expect(events).toHaveLength(0)
133
+ expect(await pathExists(join(root, MARKER_REL_PATH))).toBe(true)
134
+ })
135
+
136
+ it('cooperates with a concurrent migrator: main marker lands → already_migrated', async () => {
137
+ await seedLegacyThread(root, 'thd_abc', ['run_1'])
138
+
139
+ // Pre-seed the tmp lock to simulate another boot mid-migration.
140
+ await acquireMigrationLock(join(root, '.migration', 'v0.2.0.tmp'))
141
+
142
+ // Now write the main marker as the "winner" would. The loser must
143
+ // see this on the re-check after waiting and return already_migrated.
144
+ await writeMarker(join(root, MARKER_REL_PATH), {
145
+ version: MIGRATION_VERSION,
146
+ at: new Date(),
147
+ migratedThreads: [
148
+ { legacyThreadId: 'thd_abc', newProjectId: `${LEGACY_DEFAULT_PROJECT_PREFIX}abc` },
149
+ ],
150
+ })
151
+
152
+ // Because readMarker is checked FIRST (before lock contention), this
153
+ // actually returns already_migrated on step 1. That is the correct
154
+ // semantics: the main marker is the single source of truth.
155
+ const migrator = new DefaultFilesystemMigrator()
156
+ const result = await migrator.migrate(root)
157
+ expect(result.kind).toBe('already_migrated')
158
+ })
159
+
160
+ it('migrates multiple legacy threads in one pass with marker listing all', async () => {
161
+ await seedLegacyThread(root, 'thd_a', ['run_a1', 'run_a2'])
162
+ await seedLegacyThread(root, 'thd_b', ['run_b1'])
163
+ await seedLegacyThread(root, 'thd_c', ['run_c1'])
164
+
165
+ const migrator = new DefaultFilesystemMigrator()
166
+ const result = await migrator.migrate(root)
167
+
168
+ expect(result.kind).toBe('migrated')
169
+ expect(result.migratedThreads).toHaveLength(3)
170
+ const ids = result.migratedThreads.map((m) => m.legacyThreadId).sort()
171
+ expect(ids).toEqual(['thd_a', 'thd_b', 'thd_c'])
172
+
173
+ // Marker content mirrors result.
174
+ const markerRaw = await readFile(join(root, MARKER_REL_PATH), 'utf-8')
175
+ const markerParsed = JSON.parse(markerRaw)
176
+ expect(markerParsed.migratedThreads).toHaveLength(3)
177
+ })
178
+
179
+ it('synthesized project.json has _legacy: true and tenantId: UNKNOWN_TENANT_ID', async () => {
180
+ await seedLegacyThread(root, 'thd_tenantcheck', ['run_0'])
181
+ const migrator = new DefaultFilesystemMigrator()
182
+ await migrator.migrate(root)
183
+
184
+ const projectJsonPath = join(
185
+ root,
186
+ 'projects',
187
+ `${LEGACY_DEFAULT_PROJECT_PREFIX}tenantcheck`,
188
+ 'project.json',
189
+ )
190
+ const parsed = JSON.parse(await readFile(projectJsonPath, 'utf-8'))
191
+ expect(parsed._legacy).toBe(true)
192
+ expect(parsed.tenantId).toBe(UNKNOWN_TENANT_ID)
193
+ expect(parsed.id).toBe(`${LEGACY_DEFAULT_PROJECT_PREFIX}tenantcheck`)
194
+ expect(parsed.config).toMatchObject({
195
+ maxDelegationDepth: 4,
196
+ maxDelegationWidth: 8,
197
+ maxInterventionDepth: 10,
198
+ })
199
+ })
200
+
201
+ it('synthesized session.json is idle and flagged _legacy', async () => {
202
+ await seedLegacyThread(root, 'thd_sescheck', ['run_0'])
203
+ const migrator = new DefaultFilesystemMigrator()
204
+ await migrator.migrate(root)
205
+
206
+ const sessionJsonPath = join(
207
+ root,
208
+ 'projects',
209
+ `${LEGACY_DEFAULT_PROJECT_PREFIX}sescheck`,
210
+ 'sessions',
211
+ LEGACY_DEFAULT_SESSION_ID,
212
+ 'session.json',
213
+ )
214
+ const parsed = JSON.parse(await readFile(sessionJsonPath, 'utf-8'))
215
+ expect(parsed.id).toBe(LEGACY_DEFAULT_SESSION_ID)
216
+ expect(parsed.status).toBe('idle')
217
+ expect(parsed.tenantId).toBe(UNKNOWN_TENANT_ID)
218
+ expect(parsed._legacy).toBe(true)
219
+ })
220
+
221
+ it('idempotent: two successive migrate() calls produce the same end-state', async () => {
222
+ await seedLegacyThread(root, 'thd_idem', ['run_1'])
223
+
224
+ const migrator = new DefaultFilesystemMigrator()
225
+ const first = await migrator.migrate(root)
226
+ const second = await migrator.migrate(root)
227
+
228
+ expect(first.kind).toBe('migrated')
229
+ expect(second.kind).toBe('already_migrated')
230
+ expect(second.migratedThreads).toHaveLength(0)
231
+ // End state still valid.
232
+ const newRunDir = join(
233
+ root,
234
+ 'projects',
235
+ `${LEGACY_DEFAULT_PROJECT_PREFIX}idem`,
236
+ 'sessions',
237
+ LEGACY_DEFAULT_SESSION_ID,
238
+ 'runs',
239
+ 'run_1',
240
+ )
241
+ expect(await pathExists(newRunDir)).toBe(true)
242
+ })
243
+
244
+ it('error path: unwritable marker directory surfaces FilesystemMigrationError', async () => {
245
+ // Make the rootDir read-only so write_marker fails on the noop branch
246
+ // (simplest repro — no legacy threads needed).
247
+ await chmod(root, 0o555)
248
+
249
+ const migrator = new DefaultFilesystemMigrator()
250
+ try {
251
+ await migrator.migrate(root)
252
+ expect.fail('expected migrate() to throw')
253
+ } catch (err) {
254
+ expect(err).toBeInstanceOf(FilesystemMigrationError)
255
+ const details = (err as FilesystemMigrationError).details
256
+ expect(details.op).toBe('write_marker')
257
+ expect(details.path).toContain('v0.2.0')
258
+ } finally {
259
+ // restore perms so afterEach can clean up
260
+ await chmod(root, 0o755).catch(() => undefined)
261
+ }
262
+ })
263
+ })
@@ -0,0 +1,101 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest'
2
+ import type { ProjectId } from '../../../types/session/ids.js'
3
+ import {
4
+ NOOP_MIGRATION_WARNING_SINK,
5
+ StalePrefixError,
6
+ __resetSeenLegacyForTests,
7
+ acceptLegacyThreadId,
8
+ rejectLegacyPrefix,
9
+ } from '../id-prefix.js'
10
+ import type { MigrationWarning, MigrationWarningSink } from '../id-prefix.js'
11
+
12
+ function collectingSink(): { emitted: MigrationWarning[]; sink: MigrationWarningSink } {
13
+ const emitted: MigrationWarning[] = []
14
+ return {
15
+ emitted,
16
+ sink: {
17
+ emit(w) {
18
+ emitted.push(w)
19
+ },
20
+ },
21
+ }
22
+ }
23
+
24
+ describe('acceptLegacyThreadId', () => {
25
+ beforeEach(() => {
26
+ __resetSeenLegacyForTests()
27
+ })
28
+
29
+ it('coerces thd_* to prj_* and emits a warning on first encounter', () => {
30
+ const { emitted, sink } = collectingSink()
31
+ const result = acceptLegacyThreadId('thd_abc', sink)
32
+ expect(result).toBe('prj_abc' as ProjectId)
33
+ expect(emitted).toHaveLength(1)
34
+ expect(emitted[0]?.kind).toBe('id_prefix_legacy_read')
35
+ expect(emitted[0]?.legacyId).toBe('thd_abc')
36
+ expect(emitted[0]?.normalizedId).toBe('prj_abc')
37
+ expect(emitted[0]?.emittedOncePerProcess).toBe(true)
38
+ expect(emitted[0]?.at).toBeInstanceOf(Date)
39
+ })
40
+
41
+ it('does NOT re-emit a warning for the same legacy id on a second call', () => {
42
+ const { emitted, sink } = collectingSink()
43
+ acceptLegacyThreadId('thd_abc', sink)
44
+ acceptLegacyThreadId('thd_abc', sink)
45
+ acceptLegacyThreadId('thd_abc', sink)
46
+ expect(emitted).toHaveLength(1)
47
+ })
48
+
49
+ it('emits distinct warnings for distinct legacy ids', () => {
50
+ const { emitted, sink } = collectingSink()
51
+ acceptLegacyThreadId('thd_abc', sink)
52
+ acceptLegacyThreadId('thd_xyz', sink)
53
+ expect(emitted).toHaveLength(2)
54
+ expect(emitted.map((w) => w.legacyId).sort()).toEqual(['thd_abc', 'thd_xyz'])
55
+ })
56
+
57
+ it('returns prj_* ids unchanged and emits no warning', () => {
58
+ const { emitted, sink } = collectingSink()
59
+ const result = acceptLegacyThreadId('prj_keepme', sink)
60
+ expect(result).toBe('prj_keepme' as ProjectId)
61
+ expect(emitted).toHaveLength(0)
62
+ })
63
+
64
+ it('rejects unknown prefixes with StalePrefixError', () => {
65
+ const { sink } = collectingSink()
66
+ expect(() => acceptLegacyThreadId('xyz_nope', sink)).toThrowError(StalePrefixError)
67
+ })
68
+
69
+ it('StalePrefixError carries structured details for unknown prefixes', () => {
70
+ const { sink } = collectingSink()
71
+ try {
72
+ acceptLegacyThreadId('xyz_nope', sink)
73
+ expect.fail('expected throw')
74
+ } catch (err) {
75
+ expect(err).toBeInstanceOf(StalePrefixError)
76
+ expect((err as StalePrefixError).details.rawId).toBe('xyz_nope')
77
+ expect((err as StalePrefixError).details.kind).toBe('unknown_prefix')
78
+ }
79
+ })
80
+
81
+ it('NOOP_MIGRATION_WARNING_SINK swallows warnings without error', () => {
82
+ expect(() => acceptLegacyThreadId('thd_noop', NOOP_MIGRATION_WARNING_SINK)).not.toThrow()
83
+ })
84
+ })
85
+
86
+ describe('rejectLegacyPrefix', () => {
87
+ it('throws StalePrefixError for thd_* input', () => {
88
+ expect(() => rejectLegacyPrefix('thd_abc')).toThrowError(StalePrefixError)
89
+ })
90
+
91
+ it('accepts prj_* input without throwing', () => {
92
+ expect(() => rejectLegacyPrefix('prj_abc')).not.toThrow()
93
+ })
94
+
95
+ it('accepts non-thread prefixes without throwing (writer guard is scoped)', () => {
96
+ // The guard is specifically for thd_* re-emission; unrelated prefixes
97
+ // are a concern for their own parse functions.
98
+ expect(() => rejectLegacyPrefix('ses_abc')).not.toThrow()
99
+ expect(() => rejectLegacyPrefix('run_abc')).not.toThrow()
100
+ })
101
+ })
@@ -0,0 +1,84 @@
1
+ import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
2
+ import { tmpdir } from 'node:os'
3
+ import { join } from 'node:path'
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest'
5
+ import type { ProjectId } from '../../../types/session/ids.js'
6
+ import { acquireMigrationLock, readMarker, releaseMigrationLock, writeMarker } from '../marker.js'
7
+
8
+ describe('migration marker I/O', () => {
9
+ let root: string
10
+
11
+ beforeEach(async () => {
12
+ root = await mkdtemp(join(tmpdir(), 'namzu-marker-'))
13
+ })
14
+
15
+ afterEach(async () => {
16
+ await rm(root, { recursive: true, force: true })
17
+ })
18
+
19
+ it('readMarker returns null when the file is missing', async () => {
20
+ const result = await readMarker(join(root, 'missing.json'))
21
+ expect(result).toBeNull()
22
+ })
23
+
24
+ it('readMarker parses a valid JSON marker', async () => {
25
+ const path = join(root, 'v0.2.0')
26
+ const at = new Date('2026-04-17T00:00:00.000Z')
27
+ await writeMarker(path, {
28
+ version: '0.2.0',
29
+ at,
30
+ migratedThreads: [{ legacyThreadId: 'thd_abc', newProjectId: 'prj_legacy_abc' as ProjectId }],
31
+ })
32
+ const result = await readMarker(path)
33
+ expect(result).not.toBeNull()
34
+ expect(result?.version).toBe('0.2.0')
35
+ expect(result?.at.toISOString()).toBe('2026-04-17T00:00:00.000Z')
36
+ expect(result?.migratedThreads).toEqual([
37
+ { legacyThreadId: 'thd_abc', newProjectId: 'prj_legacy_abc' },
38
+ ])
39
+ })
40
+
41
+ it('readMarker returns null on corrupt JSON (retry-safe)', async () => {
42
+ const path = join(root, 'corrupt.json')
43
+ await writeFile(path, '{ not valid json', 'utf-8')
44
+ const result = await readMarker(path)
45
+ expect(result).toBeNull()
46
+ })
47
+
48
+ it('writeMarker atomically writes via tmp-rename (no partial content)', async () => {
49
+ const path = join(root, 'v0.2.0')
50
+ await writeMarker(path, {
51
+ version: '0.2.0',
52
+ at: new Date(),
53
+ migratedThreads: [],
54
+ })
55
+ const content = await readFile(path, 'utf-8')
56
+ const parsed = JSON.parse(content)
57
+ expect(parsed.version).toBe('0.2.0')
58
+ })
59
+
60
+ it('acquireMigrationLock succeeds on first call and throws EEXIST on the second', async () => {
61
+ const lockPath = join(root, 'v0.2.0.tmp')
62
+ await acquireMigrationLock(lockPath)
63
+ let caught: NodeJS.ErrnoException | null = null
64
+ try {
65
+ await acquireMigrationLock(lockPath)
66
+ } catch (err) {
67
+ caught = err as NodeJS.ErrnoException
68
+ }
69
+ expect(caught).not.toBeNull()
70
+ expect(caught?.code).toBe('EEXIST')
71
+ })
72
+
73
+ it('releaseMigrationLock tolerates a missing file (idempotent)', async () => {
74
+ const lockPath = join(root, 'never-existed.tmp')
75
+ await expect(releaseMigrationLock(lockPath)).resolves.toBeUndefined()
76
+ })
77
+
78
+ it('releaseMigrationLock clears the lock so re-acquire succeeds', async () => {
79
+ const lockPath = join(root, 'v0.2.0.tmp')
80
+ await acquireMigrationLock(lockPath)
81
+ await releaseMigrationLock(lockPath)
82
+ await expect(acquireMigrationLock(lockPath)).resolves.toBeUndefined()
83
+ })
84
+ })
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Typed errors for the migration module.
3
+ *
4
+ * See session-hierarchy.md §13.4.1. Structured `details` payload lets
5
+ * consumers route failures without string parsing (Convention #5: fail
6
+ * fast, surface cause, no silent swallowing).
7
+ */
8
+
9
+ /**
10
+ * Raised when any filesystem step during the boot-time v0.2.0 re-layout
11
+ * fails (enumerate, rename, synthesize project.json, write marker).
12
+ * `op` is a short stable tag so consumers can dashboard on failure mode;
13
+ * `cause` carries the underlying `Error` for stack preservation.
14
+ */
15
+ export class FilesystemMigrationError extends Error {
16
+ readonly details: { op: string; path: string; cause?: unknown }
17
+
18
+ constructor(details: { op: string; path: string; cause?: unknown }) {
19
+ super(`Filesystem migration failed at ${details.op} on ${details.path}`)
20
+ this.name = 'FilesystemMigrationError'
21
+ this.details = details
22
+ }
23
+ }