@namzu/sdk 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (531) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  3. package/dist/agents/ReactiveAgent.js +5 -3
  4. package/dist/agents/ReactiveAgent.js.map +1 -1
  5. package/dist/agents/RouterAgent.d.ts.map +1 -1
  6. package/dist/agents/RouterAgent.js +3 -0
  7. package/dist/agents/RouterAgent.js.map +1 -1
  8. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  9. package/dist/agents/SupervisorAgent.js +18 -5
  10. package/dist/agents/SupervisorAgent.js.map +1 -1
  11. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  12. package/dist/bridge/a2a/mapper.js +6 -0
  13. package/dist/bridge/a2a/mapper.js.map +1 -1
  14. package/dist/bridge/a2a/task.d.ts +2 -2
  15. package/dist/bridge/a2a/task.d.ts.map +1 -1
  16. package/dist/bridge/a2a/task.js.map +1 -1
  17. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  18. package/dist/bridge/sse/mapper.js +6 -0
  19. package/dist/bridge/sse/mapper.js.map +1 -1
  20. package/dist/constants/a2a/index.d.ts +2 -2
  21. package/dist/constants/a2a/index.d.ts.map +1 -1
  22. package/dist/constants/a2a/index.js.map +1 -1
  23. package/dist/contracts/api.d.ts +22 -3
  24. package/dist/contracts/api.d.ts.map +1 -1
  25. package/dist/contracts/index.d.ts +3 -1
  26. package/dist/contracts/index.d.ts.map +1 -1
  27. package/dist/contracts/index.js.map +1 -1
  28. package/dist/gateway/local.d.ts.map +1 -1
  29. package/dist/gateway/local.js +6 -0
  30. package/dist/gateway/local.js.map +1 -1
  31. package/dist/index.d.ts +4 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +4 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/manager/agent/__tests__/lifecycle.test.d.ts +2 -0
  36. package/dist/manager/agent/__tests__/lifecycle.test.d.ts.map +1 -0
  37. package/dist/manager/agent/__tests__/lifecycle.test.js +302 -0
  38. package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -0
  39. package/dist/manager/agent/lifecycle.d.ts +58 -3
  40. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  41. package/dist/manager/agent/lifecycle.js +311 -12
  42. package/dist/manager/agent/lifecycle.js.map +1 -1
  43. package/dist/manager/run/persistence.d.ts +8 -1
  44. package/dist/manager/run/persistence.d.ts.map +1 -1
  45. package/dist/manager/run/persistence.js +15 -0
  46. package/dist/manager/run/persistence.js.map +1 -1
  47. package/dist/run/reporter.d.ts.map +1 -1
  48. package/dist/run/reporter.js +25 -0
  49. package/dist/run/reporter.js.map +1 -1
  50. package/dist/runtime/query/__tests__/context.test.d.ts +2 -0
  51. package/dist/runtime/query/__tests__/context.test.d.ts.map +1 -0
  52. package/dist/runtime/query/__tests__/context.test.js +84 -0
  53. package/dist/runtime/query/__tests__/context.test.js.map +1 -0
  54. package/dist/runtime/query/context.d.ts +55 -2
  55. package/dist/runtime/query/context.d.ts.map +1 -1
  56. package/dist/runtime/query/context.js +48 -8
  57. package/dist/runtime/query/context.js.map +1 -1
  58. package/dist/runtime/query/events.d.ts.map +1 -1
  59. package/dist/runtime/query/events.js +8 -0
  60. package/dist/runtime/query/events.js.map +1 -1
  61. package/dist/runtime/query/index.d.ts +25 -2
  62. package/dist/runtime/query/index.d.ts.map +1 -1
  63. package/dist/runtime/query/index.js +11 -1
  64. package/dist/runtime/query/index.js.map +1 -1
  65. package/dist/session/__tests__/integration/_fixtures.d.ts +115 -0
  66. package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -0
  67. package/dist/session/__tests__/integration/_fixtures.js +198 -0
  68. package/dist/session/__tests__/integration/_fixtures.js.map +1 -0
  69. package/dist/session/__tests__/integration/capacity-caps.test.d.ts +13 -0
  70. package/dist/session/__tests__/integration/capacity-caps.test.d.ts.map +1 -0
  71. package/dist/session/__tests__/integration/capacity-caps.test.js +116 -0
  72. package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -0
  73. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts +18 -0
  74. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts.map +1 -0
  75. package/dist/session/__tests__/integration/e2e-spawn.test.js +226 -0
  76. package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -0
  77. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts +15 -0
  78. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts.map +1 -0
  79. package/dist/session/__tests__/integration/event-stream-ordering.test.js +323 -0
  80. package/dist/session/__tests__/integration/event-stream-ordering.test.js.map +1 -0
  81. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts +12 -0
  82. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts.map +1 -0
  83. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js +170 -0
  84. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -0
  85. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts +18 -0
  86. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts.map +1 -0
  87. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js +146 -0
  88. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js.map +1 -0
  89. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts +15 -0
  90. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts.map +1 -0
  91. package/dist/session/__tests__/integration/handoff-single-e2e.test.js +163 -0
  92. package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -0
  93. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts +12 -0
  94. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts.map +1 -0
  95. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js +157 -0
  96. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js.map +1 -0
  97. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts +11 -0
  98. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts.map +1 -0
  99. package/dist/session/__tests__/integration/migration-filesystem.test.js +140 -0
  100. package/dist/session/__tests__/integration/migration-filesystem.test.js.map +1 -0
  101. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts +13 -0
  102. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts.map +1 -0
  103. package/dist/session/__tests__/integration/migration-id-prefix.test.js +84 -0
  104. package/dist/session/__tests__/integration/migration-id-prefix.test.js.map +1 -0
  105. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts +14 -0
  106. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts.map +1 -0
  107. package/dist/session/__tests__/integration/prev-artifact-dag.test.js +241 -0
  108. package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -0
  109. package/dist/session/__tests__/integration/retention-archive.test.d.ts +12 -0
  110. package/dist/session/__tests__/integration/retention-archive.test.d.ts.map +1 -0
  111. package/dist/session/__tests__/integration/retention-archive.test.js +186 -0
  112. package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -0
  113. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts +18 -0
  114. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts.map +1 -0
  115. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +200 -0
  116. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -0
  117. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts +14 -0
  118. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts.map +1 -0
  119. package/dist/session/__tests__/integration/tenant-isolation.test.js +180 -0
  120. package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -0
  121. package/dist/session/errors.d.ts +60 -0
  122. package/dist/session/errors.d.ts.map +1 -0
  123. package/dist/session/errors.js +50 -0
  124. package/dist/session/errors.js.map +1 -0
  125. package/dist/session/events/index.d.ts +4 -0
  126. package/dist/session/events/index.d.ts.map +1 -0
  127. package/dist/session/events/index.js +8 -0
  128. package/dist/session/events/index.js.map +1 -0
  129. package/dist/session/events/schema-version.d.ts +13 -0
  130. package/dist/session/events/schema-version.d.ts.map +1 -0
  131. package/dist/session/events/schema-version.js +12 -0
  132. package/dist/session/events/schema-version.js.map +1 -0
  133. package/dist/session/events/types.d.ts +64 -0
  134. package/dist/session/events/types.d.ts.map +1 -0
  135. package/dist/session/events/types.js +2 -0
  136. package/dist/session/events/types.js.map +1 -0
  137. package/dist/session/handoff/__tests__/broadcast.test.d.ts +2 -0
  138. package/dist/session/handoff/__tests__/broadcast.test.d.ts.map +1 -0
  139. package/dist/session/handoff/__tests__/broadcast.test.js +243 -0
  140. package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -0
  141. package/dist/session/handoff/__tests__/capacity.test.d.ts +2 -0
  142. package/dist/session/handoff/__tests__/capacity.test.d.ts.map +1 -0
  143. package/dist/session/handoff/__tests__/capacity.test.js +100 -0
  144. package/dist/session/handoff/__tests__/capacity.test.js.map +1 -0
  145. package/dist/session/handoff/__tests__/single.test.d.ts +2 -0
  146. package/dist/session/handoff/__tests__/single.test.d.ts.map +1 -0
  147. package/dist/session/handoff/__tests__/single.test.js +230 -0
  148. package/dist/session/handoff/__tests__/single.test.js.map +1 -0
  149. package/dist/session/handoff/assignment.d.ts +59 -0
  150. package/dist/session/handoff/assignment.d.ts.map +1 -0
  151. package/dist/session/handoff/assignment.js +11 -0
  152. package/dist/session/handoff/assignment.js.map +1 -0
  153. package/dist/session/handoff/broadcast.d.ts +47 -0
  154. package/dist/session/handoff/broadcast.d.ts.map +1 -0
  155. package/dist/session/handoff/broadcast.js +296 -0
  156. package/dist/session/handoff/broadcast.js.map +1 -0
  157. package/dist/session/handoff/capacity.d.ts +66 -0
  158. package/dist/session/handoff/capacity.d.ts.map +1 -0
  159. package/dist/session/handoff/capacity.js +60 -0
  160. package/dist/session/handoff/capacity.js.map +1 -0
  161. package/dist/session/handoff/events.d.ts +66 -0
  162. package/dist/session/handoff/events.d.ts.map +1 -0
  163. package/dist/session/handoff/events.js +13 -0
  164. package/dist/session/handoff/events.js.map +1 -0
  165. package/dist/session/handoff/index.d.ts +12 -0
  166. package/dist/session/handoff/index.d.ts.map +1 -0
  167. package/dist/session/handoff/index.js +9 -0
  168. package/dist/session/handoff/index.js.map +1 -0
  169. package/dist/session/handoff/single.d.ts +62 -0
  170. package/dist/session/handoff/single.d.ts.map +1 -0
  171. package/dist/session/handoff/single.js +217 -0
  172. package/dist/session/handoff/single.js.map +1 -0
  173. package/dist/session/handoff/version.d.ts +52 -0
  174. package/dist/session/handoff/version.d.ts.map +1 -0
  175. package/dist/session/handoff/version.js +36 -0
  176. package/dist/session/handoff/version.js.map +1 -0
  177. package/dist/session/hierarchy/__tests__/session.test.d.ts +2 -0
  178. package/dist/session/hierarchy/__tests__/session.test.d.ts.map +1 -0
  179. package/dist/session/hierarchy/__tests__/session.test.js +67 -0
  180. package/dist/session/hierarchy/__tests__/session.test.js.map +1 -0
  181. package/dist/session/hierarchy/actor.d.ts +26 -0
  182. package/dist/session/hierarchy/actor.d.ts.map +1 -0
  183. package/dist/session/hierarchy/actor.js +2 -0
  184. package/dist/session/hierarchy/actor.js.map +1 -0
  185. package/dist/session/hierarchy/index.d.ts +8 -0
  186. package/dist/session/hierarchy/index.d.ts.map +1 -0
  187. package/dist/session/hierarchy/index.js +4 -0
  188. package/dist/session/hierarchy/index.js.map +1 -0
  189. package/dist/session/hierarchy/lineage.d.ts +15 -0
  190. package/dist/session/hierarchy/lineage.d.ts.map +1 -0
  191. package/dist/session/hierarchy/lineage.js +2 -0
  192. package/dist/session/hierarchy/lineage.js.map +1 -0
  193. package/dist/session/hierarchy/project.d.ts +40 -0
  194. package/dist/session/hierarchy/project.d.ts.map +1 -0
  195. package/dist/session/hierarchy/project.js +2 -0
  196. package/dist/session/hierarchy/project.js.map +1 -0
  197. package/dist/session/hierarchy/session.d.ts +59 -0
  198. package/dist/session/hierarchy/session.d.ts.map +1 -0
  199. package/dist/session/hierarchy/session.js +51 -0
  200. package/dist/session/hierarchy/session.js.map +1 -0
  201. package/dist/session/hierarchy/sub-session.d.ts +76 -0
  202. package/dist/session/hierarchy/sub-session.d.ts.map +1 -0
  203. package/dist/session/hierarchy/sub-session.js +2 -0
  204. package/dist/session/hierarchy/sub-session.js.map +1 -0
  205. package/dist/session/hierarchy/tenant.d.ts +13 -0
  206. package/dist/session/hierarchy/tenant.d.ts.map +1 -0
  207. package/dist/session/hierarchy/tenant.js +2 -0
  208. package/dist/session/hierarchy/tenant.js.map +1 -0
  209. package/dist/session/index.d.ts +10 -0
  210. package/dist/session/index.d.ts.map +1 -0
  211. package/dist/session/index.js +15 -0
  212. package/dist/session/index.js.map +1 -0
  213. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts +2 -0
  214. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts.map +1 -0
  215. package/dist/session/intervention/__tests__/prev-artifact.test.js +179 -0
  216. package/dist/session/intervention/__tests__/prev-artifact.test.js.map +1 -0
  217. package/dist/session/intervention/index.d.ts +3 -0
  218. package/dist/session/intervention/index.d.ts.map +1 -0
  219. package/dist/session/intervention/index.js +8 -0
  220. package/dist/session/intervention/index.js.map +1 -0
  221. package/dist/session/intervention/prev-artifact.d.ts +103 -0
  222. package/dist/session/intervention/prev-artifact.d.ts.map +1 -0
  223. package/dist/session/intervention/prev-artifact.js +112 -0
  224. package/dist/session/intervention/prev-artifact.js.map +1 -0
  225. package/dist/session/migration/__tests__/filesystem.test.d.ts +2 -0
  226. package/dist/session/migration/__tests__/filesystem.test.d.ts.map +1 -0
  227. package/dist/session/migration/__tests__/filesystem.test.js +188 -0
  228. package/dist/session/migration/__tests__/filesystem.test.js.map +1 -0
  229. package/dist/session/migration/__tests__/id-prefix.test.d.ts +2 -0
  230. package/dist/session/migration/__tests__/id-prefix.test.d.ts.map +1 -0
  231. package/dist/session/migration/__tests__/id-prefix.test.js +83 -0
  232. package/dist/session/migration/__tests__/id-prefix.test.js.map +1 -0
  233. package/dist/session/migration/__tests__/marker.test.d.ts +2 -0
  234. package/dist/session/migration/__tests__/marker.test.d.ts.map +1 -0
  235. package/dist/session/migration/__tests__/marker.test.js +75 -0
  236. package/dist/session/migration/__tests__/marker.test.js.map +1 -0
  237. package/dist/session/migration/errors.d.ts +26 -0
  238. package/dist/session/migration/errors.d.ts.map +1 -0
  239. package/dist/session/migration/errors.js +22 -0
  240. package/dist/session/migration/errors.js.map +1 -0
  241. package/dist/session/migration/filesystem.d.ts +94 -0
  242. package/dist/session/migration/filesystem.d.ts.map +1 -0
  243. package/dist/session/migration/filesystem.js +319 -0
  244. package/dist/session/migration/filesystem.js.map +1 -0
  245. package/dist/session/migration/id-prefix.d.ts +98 -0
  246. package/dist/session/migration/id-prefix.d.ts.map +1 -0
  247. package/dist/session/migration/id-prefix.js +116 -0
  248. package/dist/session/migration/id-prefix.js.map +1 -0
  249. package/dist/session/migration/index.d.ts +8 -0
  250. package/dist/session/migration/index.d.ts.map +1 -0
  251. package/dist/session/migration/index.js +8 -0
  252. package/dist/session/migration/index.js.map +1 -0
  253. package/dist/session/migration/marker.d.ts +57 -0
  254. package/dist/session/migration/marker.d.ts.map +1 -0
  255. package/dist/session/migration/marker.js +111 -0
  256. package/dist/session/migration/marker.js.map +1 -0
  257. package/dist/session/retention/__tests__/archive.test.d.ts +2 -0
  258. package/dist/session/retention/__tests__/archive.test.d.ts.map +1 -0
  259. package/dist/session/retention/__tests__/archive.test.js +252 -0
  260. package/dist/session/retention/__tests__/archive.test.js.map +1 -0
  261. package/dist/session/retention/__tests__/disk-backend.test.d.ts +2 -0
  262. package/dist/session/retention/__tests__/disk-backend.test.d.ts.map +1 -0
  263. package/dist/session/retention/__tests__/disk-backend.test.js +154 -0
  264. package/dist/session/retention/__tests__/disk-backend.test.js.map +1 -0
  265. package/dist/session/retention/archive-backend-ref.d.ts +18 -0
  266. package/dist/session/retention/archive-backend-ref.d.ts.map +1 -0
  267. package/dist/session/retention/archive-backend-ref.js +2 -0
  268. package/dist/session/retention/archive-backend-ref.js.map +1 -0
  269. package/dist/session/retention/archive.d.ts +130 -0
  270. package/dist/session/retention/archive.d.ts.map +1 -0
  271. package/dist/session/retention/archive.js +203 -0
  272. package/dist/session/retention/archive.js.map +1 -0
  273. package/dist/session/retention/backend.d.ts +101 -0
  274. package/dist/session/retention/backend.d.ts.map +1 -0
  275. package/dist/session/retention/backend.js +15 -0
  276. package/dist/session/retention/backend.js.map +1 -0
  277. package/dist/session/retention/disk-backend.d.ts +59 -0
  278. package/dist/session/retention/disk-backend.d.ts.map +1 -0
  279. package/dist/session/retention/disk-backend.js +236 -0
  280. package/dist/session/retention/disk-backend.js.map +1 -0
  281. package/dist/session/retention/index.d.ts +9 -0
  282. package/dist/session/retention/index.d.ts.map +1 -0
  283. package/dist/session/retention/index.js +6 -0
  284. package/dist/session/retention/index.js.map +1 -0
  285. package/dist/session/retention/policy.d.ts +49 -0
  286. package/dist/session/retention/policy.d.ts.map +1 -0
  287. package/dist/session/retention/policy.js +21 -0
  288. package/dist/session/retention/policy.js.map +1 -0
  289. package/dist/session/summary/__tests__/materialize.test.d.ts +2 -0
  290. package/dist/session/summary/__tests__/materialize.test.d.ts.map +1 -0
  291. package/dist/session/summary/__tests__/materialize.test.js +269 -0
  292. package/dist/session/summary/__tests__/materialize.test.js.map +1 -0
  293. package/dist/session/summary/deliverable.d.ts +74 -0
  294. package/dist/session/summary/deliverable.d.ts.map +1 -0
  295. package/dist/session/summary/deliverable.js +20 -0
  296. package/dist/session/summary/deliverable.js.map +1 -0
  297. package/dist/session/summary/index.d.ts +6 -0
  298. package/dist/session/summary/index.d.ts.map +1 -0
  299. package/dist/session/summary/index.js +9 -0
  300. package/dist/session/summary/index.js.map +1 -0
  301. package/dist/session/summary/materialize.d.ts +82 -0
  302. package/dist/session/summary/materialize.d.ts.map +1 -0
  303. package/dist/session/summary/materialize.js +117 -0
  304. package/dist/session/summary/materialize.js.map +1 -0
  305. package/dist/session/summary/ref.d.ts +91 -0
  306. package/dist/session/summary/ref.d.ts.map +1 -0
  307. package/dist/session/summary/ref.js +51 -0
  308. package/dist/session/summary/ref.js.map +1 -0
  309. package/dist/session/workspace/__tests__/git-worktree.test.d.ts +2 -0
  310. package/dist/session/workspace/__tests__/git-worktree.test.d.ts.map +1 -0
  311. package/dist/session/workspace/__tests__/git-worktree.test.js +244 -0
  312. package/dist/session/workspace/__tests__/git-worktree.test.js.map +1 -0
  313. package/dist/session/workspace/__tests__/path-builder.test.d.ts +2 -0
  314. package/dist/session/workspace/__tests__/path-builder.test.d.ts.map +1 -0
  315. package/dist/session/workspace/__tests__/path-builder.test.js +37 -0
  316. package/dist/session/workspace/__tests__/path-builder.test.js.map +1 -0
  317. package/dist/session/workspace/driver.d.ts +55 -0
  318. package/dist/session/workspace/driver.d.ts.map +1 -0
  319. package/dist/session/workspace/driver.js +12 -0
  320. package/dist/session/workspace/driver.js.map +1 -0
  321. package/dist/session/workspace/git-worktree.d.ts +65 -0
  322. package/dist/session/workspace/git-worktree.d.ts.map +1 -0
  323. package/dist/session/workspace/git-worktree.js +156 -0
  324. package/dist/session/workspace/git-worktree.js.map +1 -0
  325. package/dist/session/workspace/index.d.ts +8 -0
  326. package/dist/session/workspace/index.d.ts.map +1 -0
  327. package/dist/session/workspace/index.js +7 -0
  328. package/dist/session/workspace/index.js.map +1 -0
  329. package/dist/session/workspace/path-builder.d.ts +50 -0
  330. package/dist/session/workspace/path-builder.d.ts.map +1 -0
  331. package/dist/session/workspace/path-builder.js +50 -0
  332. package/dist/session/workspace/path-builder.js.map +1 -0
  333. package/dist/session/workspace/ref.d.ts +46 -0
  334. package/dist/session/workspace/ref.d.ts.map +1 -0
  335. package/dist/session/workspace/ref.js +11 -0
  336. package/dist/session/workspace/ref.js.map +1 -0
  337. package/dist/session/workspace/registry.d.ts +26 -0
  338. package/dist/session/workspace/registry.d.ts.map +1 -0
  339. package/dist/session/workspace/registry.js +35 -0
  340. package/dist/session/workspace/registry.js.map +1 -0
  341. package/dist/store/conversation/memory.d.ts +22 -0
  342. package/dist/store/conversation/memory.d.ts.map +1 -1
  343. package/dist/store/conversation/memory.js +22 -0
  344. package/dist/store/conversation/memory.js.map +1 -1
  345. package/dist/store/session/__tests__/disk.test.d.ts +2 -0
  346. package/dist/store/session/__tests__/disk.test.d.ts.map +1 -0
  347. package/dist/store/session/__tests__/disk.test.js +240 -0
  348. package/dist/store/session/__tests__/disk.test.js.map +1 -0
  349. package/dist/store/session/__tests__/memory.test.d.ts +2 -0
  350. package/dist/store/session/__tests__/memory.test.d.ts.map +1 -0
  351. package/dist/store/session/__tests__/memory.test.js +217 -0
  352. package/dist/store/session/__tests__/memory.test.js.map +1 -0
  353. package/dist/store/session/disk.d.ts +85 -0
  354. package/dist/store/session/disk.d.ts.map +1 -0
  355. package/dist/store/session/disk.js +757 -0
  356. package/dist/store/session/disk.js.map +1 -0
  357. package/dist/store/session/index.d.ts +7 -0
  358. package/dist/store/session/index.d.ts.map +1 -0
  359. package/dist/store/session/index.js +11 -0
  360. package/dist/store/session/index.js.map +1 -0
  361. package/dist/store/session/linkage.d.ts +38 -0
  362. package/dist/store/session/linkage.d.ts.map +1 -0
  363. package/dist/store/session/linkage.js +64 -0
  364. package/dist/store/session/linkage.js.map +1 -0
  365. package/dist/store/session/memory.d.ts +48 -0
  366. package/dist/store/session/memory.d.ts.map +1 -0
  367. package/dist/store/session/memory.js +322 -0
  368. package/dist/store/session/memory.js.map +1 -0
  369. package/dist/store/session/messages.d.ts +20 -0
  370. package/dist/store/session/messages.d.ts.map +1 -0
  371. package/dist/store/session/messages.js +12 -0
  372. package/dist/store/session/messages.js.map +1 -0
  373. package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts +1 -1
  374. package/dist/types/agent/base.d.ts +28 -1
  375. package/dist/types/agent/base.d.ts.map +1 -1
  376. package/dist/types/agent/task.d.ts +50 -2
  377. package/dist/types/agent/task.d.ts.map +1 -1
  378. package/dist/types/agent/task.js.map +1 -1
  379. package/dist/types/conversation/index.d.ts +7 -0
  380. package/dist/types/conversation/index.d.ts.map +1 -1
  381. package/dist/types/ids/index.d.ts +26 -3
  382. package/dist/types/ids/index.d.ts.map +1 -1
  383. package/dist/types/ids/index.js +8 -1
  384. package/dist/types/ids/index.js.map +1 -1
  385. package/dist/types/invocation/__tests__/state.test.js +36 -29
  386. package/dist/types/invocation/__tests__/state.test.js.map +1 -1
  387. package/dist/types/invocation/index.d.ts +20 -4
  388. package/dist/types/invocation/index.d.ts.map +1 -1
  389. package/dist/types/invocation/index.js +10 -7
  390. package/dist/types/invocation/index.js.map +1 -1
  391. package/dist/types/run/config.d.ts +11 -1
  392. package/dist/types/run/config.d.ts.map +1 -1
  393. package/dist/types/run/events.d.ts +26 -1
  394. package/dist/types/run/events.d.ts.map +1 -1
  395. package/dist/types/run/index.d.ts.map +1 -1
  396. package/dist/types/run/index.js +8 -0
  397. package/dist/types/run/index.js.map +1 -1
  398. package/dist/types/run/metadata.d.ts +24 -1
  399. package/dist/types/run/metadata.d.ts.map +1 -1
  400. package/dist/types/run/status.d.ts +26 -0
  401. package/dist/types/run/status.d.ts.map +1 -0
  402. package/dist/types/run/status.js +2 -0
  403. package/dist/types/run/status.js.map +1 -0
  404. package/dist/types/session/ids.d.ts +18 -0
  405. package/dist/types/session/ids.d.ts.map +1 -0
  406. package/dist/types/session/ids.js +12 -0
  407. package/dist/types/session/ids.js.map +1 -0
  408. package/dist/types/session/index.d.ts +3 -0
  409. package/dist/types/session/index.d.ts.map +1 -0
  410. package/dist/types/session/index.js +5 -0
  411. package/dist/types/session/index.js.map +1 -0
  412. package/dist/types/session/store.d.ts +188 -0
  413. package/dist/types/session/store.d.ts.map +1 -0
  414. package/dist/types/session/store.js +14 -0
  415. package/dist/types/session/store.js.map +1 -0
  416. package/dist/utils/id.d.ts +18 -1
  417. package/dist/utils/id.d.ts.map +1 -1
  418. package/dist/utils/id.js +42 -4
  419. package/dist/utils/id.js.map +1 -1
  420. package/package.json +1 -1
  421. package/src/agents/ReactiveAgent.ts +7 -3
  422. package/src/agents/RouterAgent.ts +5 -0
  423. package/src/agents/SupervisorAgent.ts +26 -6
  424. package/src/bridge/a2a/mapper.ts +7 -0
  425. package/src/bridge/a2a/task.ts +2 -2
  426. package/src/bridge/sse/mapper.ts +8 -1
  427. package/src/constants/a2a/index.ts +2 -2
  428. package/src/contracts/api.ts +23 -3
  429. package/src/contracts/index.ts +2 -0
  430. package/src/gateway/local.ts +6 -0
  431. package/src/index.ts +14 -0
  432. package/src/manager/agent/__tests__/lifecycle.test.ts +452 -0
  433. package/src/manager/agent/lifecycle.ts +434 -19
  434. package/src/manager/run/persistence.ts +20 -1
  435. package/src/run/reporter.ts +28 -0
  436. package/src/runtime/query/__tests__/context.test.ts +101 -0
  437. package/src/runtime/query/context.ts +106 -10
  438. package/src/runtime/query/events.ts +8 -0
  439. package/src/runtime/query/index.ts +41 -3
  440. package/src/session/__tests__/integration/_fixtures.ts +282 -0
  441. package/src/session/__tests__/integration/capacity-caps.test.ts +164 -0
  442. package/src/session/__tests__/integration/e2e-spawn.test.ts +278 -0
  443. package/src/session/__tests__/integration/event-stream-ordering.test.ts +403 -0
  444. package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +245 -0
  445. package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +179 -0
  446. package/src/session/__tests__/integration/handoff-single-e2e.test.ts +220 -0
  447. package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +237 -0
  448. package/src/session/__tests__/integration/migration-filesystem.test.ts +209 -0
  449. package/src/session/__tests__/integration/migration-id-prefix.test.ts +101 -0
  450. package/src/session/__tests__/integration/prev-artifact-dag.test.ts +318 -0
  451. package/src/session/__tests__/integration/retention-archive.test.ts +231 -0
  452. package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +237 -0
  453. package/src/session/__tests__/integration/tenant-isolation.test.ts +282 -0
  454. package/src/session/errors.ts +70 -0
  455. package/src/session/events/index.ts +16 -0
  456. package/src/session/events/schema-version.ts +13 -0
  457. package/src/session/events/types.ts +71 -0
  458. package/src/session/handoff/__tests__/broadcast.test.ts +350 -0
  459. package/src/session/handoff/__tests__/capacity.test.ts +123 -0
  460. package/src/session/handoff/__tests__/single.test.ts +316 -0
  461. package/src/session/handoff/assignment.ts +62 -0
  462. package/src/session/handoff/broadcast.ts +381 -0
  463. package/src/session/handoff/capacity.ts +121 -0
  464. package/src/session/handoff/events.ts +72 -0
  465. package/src/session/handoff/index.ts +29 -0
  466. package/src/session/handoff/single.ts +288 -0
  467. package/src/session/handoff/version.ts +59 -0
  468. package/src/session/hierarchy/__tests__/session.test.ts +92 -0
  469. package/src/session/hierarchy/actor.ts +17 -0
  470. package/src/session/hierarchy/index.ts +17 -0
  471. package/src/session/hierarchy/lineage.ts +15 -0
  472. package/src/session/hierarchy/project.ts +41 -0
  473. package/src/session/hierarchy/session.ts +97 -0
  474. package/src/session/hierarchy/sub-session.ts +92 -0
  475. package/src/session/hierarchy/tenant.ts +13 -0
  476. package/src/session/index.ts +15 -0
  477. package/src/session/intervention/__tests__/prev-artifact.test.ts +234 -0
  478. package/src/session/intervention/index.ts +16 -0
  479. package/src/session/intervention/prev-artifact.ts +180 -0
  480. package/src/session/migration/__tests__/filesystem.test.ts +263 -0
  481. package/src/session/migration/__tests__/id-prefix.test.ts +101 -0
  482. package/src/session/migration/__tests__/marker.test.ts +84 -0
  483. package/src/session/migration/errors.ts +23 -0
  484. package/src/session/migration/filesystem.ts +401 -0
  485. package/src/session/migration/id-prefix.ts +146 -0
  486. package/src/session/migration/index.ts +38 -0
  487. package/src/session/migration/marker.ts +131 -0
  488. package/src/session/retention/__tests__/archive.test.ts +316 -0
  489. package/src/session/retention/__tests__/disk-backend.test.ts +180 -0
  490. package/src/session/retention/archive-backend-ref.ts +17 -0
  491. package/src/session/retention/archive.ts +281 -0
  492. package/src/session/retention/backend.ts +107 -0
  493. package/src/session/retention/disk-backend.ts +304 -0
  494. package/src/session/retention/index.ts +16 -0
  495. package/src/session/retention/policy.ts +53 -0
  496. package/src/session/summary/__tests__/materialize.test.ts +341 -0
  497. package/src/session/summary/deliverable.ts +84 -0
  498. package/src/session/summary/index.ts +31 -0
  499. package/src/session/summary/materialize.ts +169 -0
  500. package/src/session/summary/ref.ts +104 -0
  501. package/src/session/workspace/__tests__/git-worktree.test.ts +258 -0
  502. package/src/session/workspace/__tests__/path-builder.test.ts +51 -0
  503. package/src/session/workspace/driver.ts +60 -0
  504. package/src/session/workspace/git-worktree.ts +209 -0
  505. package/src/session/workspace/index.ts +25 -0
  506. package/src/session/workspace/path-builder.ts +71 -0
  507. package/src/session/workspace/ref.ts +50 -0
  508. package/src/session/workspace/registry.ts +42 -0
  509. package/src/store/conversation/memory.ts +23 -0
  510. package/src/store/session/__tests__/disk.test.ts +346 -0
  511. package/src/store/session/__tests__/memory.test.ts +327 -0
  512. package/src/store/session/disk.ts +920 -0
  513. package/src/store/session/index.ts +14 -0
  514. package/src/store/session/linkage.ts +80 -0
  515. package/src/store/session/memory.ts +400 -0
  516. package/src/store/session/messages.ts +21 -0
  517. package/src/types/agent/base.ts +31 -1
  518. package/src/types/agent/task.ts +58 -2
  519. package/src/types/conversation/index.ts +7 -0
  520. package/src/types/ids/index.ts +41 -3
  521. package/src/types/invocation/__tests__/state.test.ts +37 -29
  522. package/src/types/invocation/index.ts +26 -10
  523. package/src/types/run/config.ts +12 -1
  524. package/src/types/run/events.ts +36 -1
  525. package/src/types/run/index.ts +8 -0
  526. package/src/types/run/metadata.ts +24 -1
  527. package/src/types/run/status.ts +33 -0
  528. package/src/types/session/ids.ts +34 -0
  529. package/src/types/session/index.ts +28 -0
  530. package/src/types/session/store.ts +229 -0
  531. package/src/utils/id.ts +55 -4
@@ -0,0 +1,401 @@
1
+ /**
2
+ * Boot-time filesystem re-layout — `.namzu/threads/{thd_X}/` →
3
+ * `.namzu/projects/{prj_legacy_<X>}/sessions/ses_legacy_default/runs/...`.
4
+ *
5
+ * Trigger: first {@link RunContextFactory.build} call per process. The
6
+ * factory invokes {@link DefaultFilesystemMigrator.migrate} before resolving
7
+ * any path so legacy runs are never orphaned by the new layout.
8
+ *
9
+ * See session-hierarchy.md §13.4.1 for the detection / trigger / atomicity
10
+ * contract. Concurrency model:
11
+ *
12
+ * 1. Main marker present → short-circuit `already_migrated`. Idempotent.
13
+ * 2. Legacy `.namzu/threads/` absent → write the main marker and return
14
+ * `noop_no_legacy`. This plants the marker on fresh installs so the
15
+ * `threads/` detection branch is only ever entered once.
16
+ * 3. Legacy layout detected → acquire the `.tmp` lock via `wx`; on
17
+ * EEXIST another boot is mid-migration. The loser waits 100ms and
18
+ * re-checks the main marker — cooperating, not competing. Roadmap
19
+ * Risk #4 mitigation.
20
+ * 4. Per-legacy-thread: rename the whole `runs/` subtree in a single
21
+ * `fs.rename` call (cross-OS atomic on the same filesystem; different
22
+ * filesystems fall back to copy-then-unlink via Node's default — a
23
+ * known limitation documented below).
24
+ * 5. Synthesize `project.json` + `session.json` via write-tmp-rename
25
+ * (Convention #8) so partial crashes leave no half-serialised state.
26
+ * 6. Write main marker last — presence of the marker is the canonical
27
+ * "migration done" signal.
28
+ *
29
+ * Known limitations:
30
+ * - Cross-filesystem moves: Node's `fs.rename` rejects with `EXDEV` when
31
+ * source and target live on different filesystems. This migrator does
32
+ * NOT fall back to copy-then-unlink; the error surfaces as
33
+ * {@link FilesystemMigrationError} with op `'rename_runs'`. Consumers
34
+ * running `.namzu/threads` and `.namzu/projects` on different mounts
35
+ * must migrate manually (documented INTERP flag).
36
+ * - `UNKNOWN_TENANT_ID`: legacy threads have no tenant denormalisation on
37
+ * disk. The synthesised project.json carries the sentinel so consumers
38
+ * know these are legacy-rehomed and can either tag-then-retain or
39
+ * reject until a real tenant is assigned (policy is consumer-owned).
40
+ */
41
+
42
+ import { mkdir, readdir, rename, stat } from 'node:fs/promises'
43
+ import { join } from 'node:path'
44
+ import type { TenantId } from '../../types/ids/index.js'
45
+ import { UNKNOWN_TENANT_ID } from '../../types/ids/index.js'
46
+ import type { ProjectId, SessionId } from '../../types/session/ids.js'
47
+ import { FilesystemMigrationError } from './errors.js'
48
+ import { acquireMigrationLock, readMarker, releaseMigrationLock, writeMarker } from './marker.js'
49
+
50
+ /**
51
+ * Sentinel SessionId used for legacy pre-0.2.0 runs that pre-date the
52
+ * Session entity. Every migrated thread collapses into this single session
53
+ * so consumers can still address the runs through the new layout.
54
+ */
55
+ export const LEGACY_DEFAULT_SESSION_ID = 'ses_legacy_default' as SessionId
56
+
57
+ /** Prefix for projects synthesised from legacy `thd_*` folders. */
58
+ export const LEGACY_DEFAULT_PROJECT_PREFIX = 'prj_legacy_'
59
+
60
+ /** Marker version string persisted at `.migration/v0.2.0`. */
61
+ export const MIGRATION_VERSION = '0.2.0'
62
+
63
+ /** Marker file path relative to rootDir. */
64
+ export const MARKER_REL_PATH = join('.migration', 'v0.2.0')
65
+
66
+ /** In-flight lock file path relative to rootDir. */
67
+ export const LOCK_REL_PATH = join('.migration', 'v0.2.0.tmp')
68
+
69
+ /** Delay before the loser re-checks the main marker on lock contention. */
70
+ const LOCK_WAIT_MS = 100
71
+
72
+ /**
73
+ * Result of a migration attempt. `kind` discriminates the three outcomes;
74
+ * `migratedThreads` is only non-empty for `kind: 'migrated'`. Sinks and
75
+ * callers can switch on `kind` without string parsing.
76
+ */
77
+ export interface FilesystemMigrationResult {
78
+ kind: 'migrated' | 'already_migrated' | 'noop_no_legacy'
79
+ migratedThreads: readonly { legacyThreadId: string; newProjectId: ProjectId }[]
80
+ markerPath: string
81
+ at: Date
82
+ }
83
+
84
+ /** Event emitted on successful migration (`kind === 'migrated'` only). */
85
+ export interface FilesystemMigrationEvent {
86
+ type: 'filesystem.migrated'
87
+ result: FilesystemMigrationResult
88
+ }
89
+
90
+ /** Sink contract — one `emit` method. */
91
+ export interface FilesystemMigrationSink {
92
+ emit(event: FilesystemMigrationEvent): void
93
+ }
94
+
95
+ export const NOOP_FILESYSTEM_MIGRATION_SINK: FilesystemMigrationSink = {
96
+ emit() {},
97
+ }
98
+
99
+ /** Interface so consumers can inject a stub migrator in tests. */
100
+ export interface FilesystemMigrator {
101
+ migrate(rootDir: string): Promise<FilesystemMigrationResult>
102
+ }
103
+
104
+ /**
105
+ * Persisted synthetic `project.json` shape. Matches
106
+ * `store/session/disk.ts:PersistedProject` plus a `_legacy: true` flag so
107
+ * readers can distinguish auto-synthesised records from real ones.
108
+ */
109
+ interface SyntheticProject {
110
+ id: ProjectId
111
+ tenantId: TenantId
112
+ name: string
113
+ config: {
114
+ maxDelegationDepth: number
115
+ maxDelegationWidth: number
116
+ maxInterventionDepth: number
117
+ }
118
+ createdAt: string
119
+ updatedAt: string
120
+ _legacy: true
121
+ }
122
+
123
+ /**
124
+ * Persisted synthetic `session.json` shape. Matches
125
+ * `store/session/disk.ts:PersistedSession` minimally. Status is `idle` so
126
+ * any read path that drills into these sessions does not mistake them for
127
+ * active work. `_legacy: true` flags them as auto-synthesised.
128
+ */
129
+ interface SyntheticSession {
130
+ id: SessionId
131
+ projectId: ProjectId
132
+ tenantId: TenantId
133
+ status: 'idle'
134
+ currentActor: null
135
+ previousActors: readonly []
136
+ workspaceId: null
137
+ ownerVersion: 0
138
+ createdAt: string
139
+ updatedAt: string
140
+ _legacy: true
141
+ }
142
+
143
+ /**
144
+ * Default implementation. Migration is driven by the contract documented in
145
+ * the module header — readers should trace concerns to this comment rather
146
+ * than re-deriving from code.
147
+ */
148
+ export class DefaultFilesystemMigrator implements FilesystemMigrator {
149
+ constructor(private readonly sink: FilesystemMigrationSink = NOOP_FILESYSTEM_MIGRATION_SINK) {}
150
+
151
+ async migrate(rootDir: string): Promise<FilesystemMigrationResult> {
152
+ const markerPath = join(rootDir, MARKER_REL_PATH)
153
+ const lockPath = join(rootDir, LOCK_REL_PATH)
154
+ const threadsDir = join(rootDir, 'threads')
155
+ const projectsDir = join(rootDir, 'projects')
156
+
157
+ // Step 1: completed-marker short-circuit (cheapest idempotency check).
158
+ const existing = await readMarker(markerPath)
159
+ if (existing) {
160
+ return {
161
+ kind: 'already_migrated',
162
+ migratedThreads: [],
163
+ markerPath,
164
+ at: existing.at,
165
+ }
166
+ }
167
+
168
+ // Step 2: legacy absent → no-op. Plant the marker so subsequent boots
169
+ // do not re-enter this branch. Fresh installs fall through here.
170
+ const threadsExists = await directoryExists(threadsDir)
171
+ if (!threadsExists) {
172
+ const at = new Date()
173
+ try {
174
+ await writeMarker(markerPath, {
175
+ version: MIGRATION_VERSION,
176
+ at,
177
+ migratedThreads: [],
178
+ })
179
+ } catch (cause) {
180
+ throw new FilesystemMigrationError({
181
+ op: 'write_marker',
182
+ path: markerPath,
183
+ cause,
184
+ })
185
+ }
186
+ return {
187
+ kind: 'noop_no_legacy',
188
+ migratedThreads: [],
189
+ markerPath,
190
+ at,
191
+ }
192
+ }
193
+
194
+ // Step 3: cooperate on the tmp lock.
195
+ try {
196
+ await acquireMigrationLock(lockPath)
197
+ } catch (err) {
198
+ const code = (err as NodeJS.ErrnoException).code
199
+ if (code === 'EEXIST') {
200
+ // Another boot is mid-migration — wait and re-read the main marker.
201
+ await sleep(LOCK_WAIT_MS)
202
+ const follow = await readMarker(markerPath)
203
+ if (follow) {
204
+ return {
205
+ kind: 'already_migrated',
206
+ migratedThreads: [],
207
+ markerPath,
208
+ at: follow.at,
209
+ }
210
+ }
211
+ // Main marker still absent — the winning boot is still going OR
212
+ // crashed. We re-throw so the caller sees a contention surface
213
+ // rather than silently assuming success.
214
+ throw new FilesystemMigrationError({
215
+ op: 'acquire_lock',
216
+ path: lockPath,
217
+ cause: err,
218
+ })
219
+ }
220
+ throw new FilesystemMigrationError({
221
+ op: 'acquire_lock',
222
+ path: lockPath,
223
+ cause: err,
224
+ })
225
+ }
226
+
227
+ try {
228
+ // Step 4a: enumerate legacy thread dirs.
229
+ let entries: string[]
230
+ try {
231
+ entries = await readdir(threadsDir)
232
+ } catch (cause) {
233
+ throw new FilesystemMigrationError({
234
+ op: 'enumerate_threads',
235
+ path: threadsDir,
236
+ cause,
237
+ })
238
+ }
239
+
240
+ const migrated: { legacyThreadId: string; newProjectId: ProjectId }[] = []
241
+ const now = new Date()
242
+
243
+ for (const entry of entries) {
244
+ // Accept only `thd_*` (and tolerate `prj_*` legacy in case of
245
+ // rerun after a partial-crash-with-renamed-but-no-marker).
246
+ if (!entry.startsWith('thd_')) continue
247
+
248
+ const legacyThreadId = entry
249
+ const suffix = legacyThreadId.slice('thd_'.length)
250
+ const newProjectId = `${LEGACY_DEFAULT_PROJECT_PREFIX}${suffix}` as ProjectId
251
+
252
+ const legacyRunsDir = join(threadsDir, legacyThreadId, 'runs')
253
+ const newProjectDir = join(projectsDir, newProjectId)
254
+ const newSessionDir = join(newProjectDir, 'sessions', LEGACY_DEFAULT_SESSION_ID)
255
+ const newRunsDir = join(newSessionDir, 'runs')
256
+
257
+ // Ensure parent path exists for the atomic rename of `runs/`.
258
+ try {
259
+ await mkdir(newSessionDir, { recursive: true })
260
+ } catch (cause) {
261
+ throw new FilesystemMigrationError({
262
+ op: 'mkdir_session',
263
+ path: newSessionDir,
264
+ cause,
265
+ })
266
+ }
267
+
268
+ // Move the whole `runs/` subtree in a single rename — atomic on
269
+ // same-filesystem, EXDEV on cross-mount (documented limitation).
270
+ const legacyRunsExists = await directoryExists(legacyRunsDir)
271
+ if (legacyRunsExists) {
272
+ try {
273
+ await rename(legacyRunsDir, newRunsDir)
274
+ } catch (cause) {
275
+ throw new FilesystemMigrationError({
276
+ op: 'rename_runs',
277
+ path: legacyRunsDir,
278
+ cause,
279
+ })
280
+ }
281
+ }
282
+
283
+ // Step 4b: synthesize project.json via write-tmp-rename.
284
+ const projectJson: SyntheticProject = {
285
+ id: newProjectId,
286
+ tenantId: UNKNOWN_TENANT_ID,
287
+ name: `legacy ${legacyThreadId}`,
288
+ config: {
289
+ maxDelegationDepth: 4,
290
+ maxDelegationWidth: 8,
291
+ maxInterventionDepth: 10,
292
+ },
293
+ createdAt: now.toISOString(),
294
+ updatedAt: now.toISOString(),
295
+ _legacy: true,
296
+ }
297
+ const projectJsonPath = join(newProjectDir, 'project.json')
298
+ try {
299
+ await atomicWriteJson(projectJsonPath, projectJson)
300
+ } catch (cause) {
301
+ throw new FilesystemMigrationError({
302
+ op: 'write_project_json',
303
+ path: projectJsonPath,
304
+ cause,
305
+ })
306
+ }
307
+
308
+ // Step 4c: synthesize session.json for the legacy-default session.
309
+ const sessionJson: SyntheticSession = {
310
+ id: LEGACY_DEFAULT_SESSION_ID,
311
+ projectId: newProjectId,
312
+ tenantId: UNKNOWN_TENANT_ID,
313
+ status: 'idle',
314
+ currentActor: null,
315
+ previousActors: [],
316
+ workspaceId: null,
317
+ ownerVersion: 0,
318
+ createdAt: now.toISOString(),
319
+ updatedAt: now.toISOString(),
320
+ _legacy: true,
321
+ }
322
+ const sessionJsonPath = join(newSessionDir, 'session.json')
323
+ try {
324
+ await atomicWriteJson(sessionJsonPath, sessionJson)
325
+ } catch (cause) {
326
+ throw new FilesystemMigrationError({
327
+ op: 'write_session_json',
328
+ path: sessionJsonPath,
329
+ cause,
330
+ })
331
+ }
332
+
333
+ migrated.push({ legacyThreadId, newProjectId })
334
+ }
335
+
336
+ // Step 5: write the completion marker last. Presence = done.
337
+ try {
338
+ await writeMarker(markerPath, {
339
+ version: MIGRATION_VERSION,
340
+ at: now,
341
+ migratedThreads: migrated,
342
+ })
343
+ } catch (cause) {
344
+ throw new FilesystemMigrationError({
345
+ op: 'write_marker',
346
+ path: markerPath,
347
+ cause,
348
+ })
349
+ }
350
+
351
+ const result: FilesystemMigrationResult = {
352
+ kind: 'migrated',
353
+ migratedThreads: migrated,
354
+ markerPath,
355
+ at: now,
356
+ }
357
+
358
+ // Step 6: emit event.
359
+ this.sink.emit({ type: 'filesystem.migrated', result })
360
+
361
+ return result
362
+ } finally {
363
+ // Always release the lock — even on failure, a crashed run with the
364
+ // main marker absent will retry on the next boot; the stale `.tmp`
365
+ // would otherwise wedge that retry.
366
+ await releaseMigrationLock(lockPath).catch(() => undefined)
367
+ }
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Shared atomic-write helper. Mirrors `store/session/disk.ts:atomicWriteJson`
373
+ * — intentionally duplicated so `session/migration/` has no inbound
374
+ * dependency on the store layer (Convention #4 dependency direction).
375
+ */
376
+ async function atomicWriteJson(filePath: string, value: unknown): Promise<void> {
377
+ const { writeFile, rename: renameFile, unlink } = await import('node:fs/promises')
378
+ const tmp = `${filePath}.tmp`
379
+ try {
380
+ await writeFile(tmp, JSON.stringify(value, null, 2), 'utf-8')
381
+ await renameFile(tmp, filePath)
382
+ } catch (err) {
383
+ await unlink(tmp).catch(() => undefined)
384
+ throw err
385
+ }
386
+ }
387
+
388
+ async function directoryExists(path: string): Promise<boolean> {
389
+ try {
390
+ const s = await stat(path)
391
+ return s.isDirectory()
392
+ } catch (err) {
393
+ const code = (err as NodeJS.ErrnoException).code
394
+ if (code === 'ENOENT') return false
395
+ throw err
396
+ }
397
+ }
398
+
399
+ function sleep(ms: number): Promise<void> {
400
+ return new Promise((resolve) => setTimeout(resolve, ms))
401
+ }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * ID-prefix migration window — read-side compat for legacy `thd_*` IDs.
3
+ *
4
+ * Phase 1 already ships {@link parseThreadId} in `utils/id.ts` that accepts
5
+ * either `thd_*` or `prj_*` silently. This module formalises the warning
6
+ * emission path called out in session-hierarchy.md §13.3.1:
7
+ *
8
+ * | Version | Reader accepts | Writer emits | Legacy read behaviour |
9
+ * |---------|---------------------|--------------|-------------------------------|
10
+ * | 0.2.x | `thd_*` AND `prj_*` | `prj_*` only | emits `MigrationWarning` once |
11
+ * | 0.3.x | `prj_*` only | `prj_*` only | rejects `StalePrefixError` |
12
+ *
13
+ * Consumers that touch raw legacy IDs (filesystem migrator, wire decoders,
14
+ * CLI imports) route through {@link acceptLegacyThreadId} so the warning
15
+ * signal is structured rather than ad-hoc console output (Convention #18).
16
+ *
17
+ * The `WINDOW_OPEN` constant is the single switch that flips this module
18
+ * from soft-accept to hard-reject when 0.3.0 cuts. Convention #0: no silent
19
+ * long-lived compat — the window is explicit, dated, and fails closed when
20
+ * the clock runs out.
21
+ */
22
+
23
+ import type { ProjectId } from '../../types/session/ids.js'
24
+
25
+ /**
26
+ * Structured event emitted when the reader accepts a legacy `thd_*` ID.
27
+ *
28
+ * Shape is stable across the 0.2.x window — platform consumers can wire
29
+ * this into their observability pipeline (metrics, audit log) without
30
+ * string parsing (Convention #18).
31
+ */
32
+ export interface MigrationWarning {
33
+ kind: 'id_prefix_legacy_read'
34
+ legacyId: string
35
+ normalizedId: ProjectId
36
+ at: Date
37
+ emittedOncePerProcess: true
38
+ }
39
+
40
+ /** Sink contract — one `emit` method so callers can swap implementations. */
41
+ export interface MigrationWarningSink {
42
+ emit(warning: MigrationWarning): void
43
+ }
44
+
45
+ /**
46
+ * Default sink used when consumers do not inject one. Drops warnings on the
47
+ * floor — migration still runs; observers just lose the signal. Convention
48
+ * #5 deny-by-default applies to behaviour, not telemetry; missing a warning
49
+ * sink is not a failure mode.
50
+ */
51
+ export const NOOP_MIGRATION_WARNING_SINK: MigrationWarningSink = {
52
+ emit() {},
53
+ }
54
+
55
+ /**
56
+ * Raised when the reader encounters a string that is neither a valid
57
+ * `prj_*` nor `thd_*` prefix. In the 0.3.x window the legacy branch will
58
+ * also throw this error — flip {@link WINDOW_OPEN} to `false` to cut over.
59
+ */
60
+ export class StalePrefixError extends Error {
61
+ readonly details: { rawId: string; kind: 'thd_rejected' | 'unknown_prefix' }
62
+
63
+ constructor(details: { rawId: string; kind: 'thd_rejected' | 'unknown_prefix' }) {
64
+ const reason =
65
+ details.kind === 'thd_rejected'
66
+ ? `Stale ThreadId prefix '${details.rawId.slice(0, 4)}…' — run 'namzu sdk migrate-ids' before 0.3.0`
67
+ : `Unknown ID prefix '${details.rawId.slice(0, 4)}…' — expected 'prj_' or 'thd_'`
68
+ super(reason)
69
+ this.name = 'StalePrefixError'
70
+ this.details = details
71
+ }
72
+ }
73
+
74
+ /**
75
+ * 0.2.x: compat window OPEN — `thd_*` coerces to `prj_*` with a warning.
76
+ * 0.3.x: flip to `false` — legacy branch becomes throw-only.
77
+ */
78
+ export const WINDOW_OPEN = true
79
+
80
+ /**
81
+ * Process-lifetime dedup map. Keyed by raw legacy ID so each distinct legacy
82
+ * string emits exactly one warning — spamming observability on a hot loop
83
+ * of reads is the anti-goal.
84
+ */
85
+ const seenLegacy = new Set<string>()
86
+
87
+ /**
88
+ * Accept-on-read for legacy `thd_*` IDs during the 0.2.x window.
89
+ *
90
+ * Contract:
91
+ * - `prj_*` inputs return as-is; no warning emitted.
92
+ * - `thd_*` inputs normalize to `prj_<suffix>` and emit a single
93
+ * {@link MigrationWarning} per distinct input string per process.
94
+ * - Everything else throws {@link StalePrefixError}.
95
+ * - When {@link WINDOW_OPEN} flips to `false`, the `thd_*` branch throws
96
+ * too — single knob, single commit.
97
+ *
98
+ * Testing hook: {@link __resetSeenLegacyForTests} clears the dedup Set so
99
+ * each test starts with a clean emission history.
100
+ */
101
+ export function acceptLegacyThreadId(raw: string, sink: MigrationWarningSink): ProjectId {
102
+ if (raw.startsWith('prj_')) {
103
+ return raw as ProjectId
104
+ }
105
+ if (raw.startsWith('thd_')) {
106
+ if (!WINDOW_OPEN) {
107
+ throw new StalePrefixError({ rawId: raw, kind: 'thd_rejected' })
108
+ }
109
+ const normalized = `prj_${raw.slice('thd_'.length)}` as ProjectId
110
+ if (!seenLegacy.has(raw)) {
111
+ seenLegacy.add(raw)
112
+ sink.emit({
113
+ kind: 'id_prefix_legacy_read',
114
+ legacyId: raw,
115
+ normalizedId: normalized,
116
+ at: new Date(),
117
+ emittedOncePerProcess: true,
118
+ })
119
+ }
120
+ return normalized
121
+ }
122
+ throw new StalePrefixError({ rawId: raw, kind: 'unknown_prefix' })
123
+ }
124
+
125
+ /**
126
+ * Writer guard: reject emission of `thd_*` at encode time. Phase 1's
127
+ * {@link generateProjectId} already emits `prj_*` only; this helper exists
128
+ * so write paths that handle raw strings (e.g. synthesis during filesystem
129
+ * migration) can fail fast on accidental legacy re-emission. Convention #0:
130
+ * no silent back-sliding to the old prefix.
131
+ */
132
+ export function rejectLegacyPrefix(id: string): void {
133
+ if (id.startsWith('thd_')) {
134
+ throw new StalePrefixError({ rawId: id, kind: 'thd_rejected' })
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Test-only: clear the process-level dedup Set so subsequent
140
+ * {@link acceptLegacyThreadId} calls emit warnings again. Production code
141
+ * must never call this — the whole point is one warning per distinct
142
+ * legacy id per process.
143
+ */
144
+ export function __resetSeenLegacyForTests(): void {
145
+ seenLegacy.clear()
146
+ }
@@ -0,0 +1,38 @@
1
+ // Sub-barrel for the migration module (Convention #4).
2
+ // Public surface for boot-time FS re-layout + ID-prefix read-accept.
3
+ // See session-hierarchy.md §13.3.1 (ID prefix) + §13.4.1 (filesystem).
4
+
5
+ export {
6
+ acceptLegacyThreadId,
7
+ rejectLegacyPrefix,
8
+ NOOP_MIGRATION_WARNING_SINK,
9
+ StalePrefixError,
10
+ WINDOW_OPEN,
11
+ } from './id-prefix.js'
12
+ export type { MigrationWarning, MigrationWarningSink } from './id-prefix.js'
13
+
14
+ export {
15
+ DefaultFilesystemMigrator,
16
+ NOOP_FILESYSTEM_MIGRATION_SINK,
17
+ LEGACY_DEFAULT_SESSION_ID,
18
+ LEGACY_DEFAULT_PROJECT_PREFIX,
19
+ MIGRATION_VERSION,
20
+ MARKER_REL_PATH,
21
+ LOCK_REL_PATH,
22
+ } from './filesystem.js'
23
+ export type {
24
+ FilesystemMigrator,
25
+ FilesystemMigrationResult,
26
+ FilesystemMigrationEvent,
27
+ FilesystemMigrationSink,
28
+ } from './filesystem.js'
29
+
30
+ export {
31
+ readMarker,
32
+ writeMarker,
33
+ acquireMigrationLock,
34
+ releaseMigrationLock,
35
+ } from './marker.js'
36
+ export type { MigrationMarker } from './marker.js'
37
+
38
+ export { FilesystemMigrationError } from './errors.js'