@earendil-works/pi-agent-core 0.84.4 → 0.85.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 (343) hide show
  1. package/README.md +4 -0
  2. package/dist/agent-loop.d.ts.map +1 -1
  3. package/dist/agent-loop.js +9 -0
  4. package/dist/agent-loop.js.map +1 -1
  5. package/dist/harness/agent-harness.d.ts +639 -384
  6. package/dist/harness/agent-harness.d.ts.map +1 -1
  7. package/dist/harness/agent-harness.js +5 -251
  8. package/dist/harness/agent-harness.js.map +1 -1
  9. package/dist/harness/compaction/branch-summarization.d.ts +12 -6
  10. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  11. package/dist/harness/compaction/branch-summarization.js +33 -26
  12. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  13. package/dist/harness/compaction/compaction.d.ts +30 -8
  14. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  15. package/dist/harness/compaction/compaction.js +53 -63
  16. package/dist/harness/compaction/compaction.js.map +1 -1
  17. package/dist/harness/config.d.ts +9 -0
  18. package/dist/harness/config.d.ts.map +1 -0
  19. package/dist/harness/config.js +27 -0
  20. package/dist/harness/config.js.map +1 -0
  21. package/dist/harness/context.d.ts +9 -0
  22. package/dist/harness/context.d.ts.map +1 -0
  23. package/dist/harness/context.js +13 -0
  24. package/dist/harness/context.js.map +1 -0
  25. package/dist/harness/env/nodejs.d.ts +24 -28
  26. package/dist/harness/env/nodejs.d.ts.map +1 -1
  27. package/dist/harness/env/nodejs.js +239 -86
  28. package/dist/harness/env/nodejs.js.map +1 -1
  29. package/dist/harness/events.d.ts +20 -38
  30. package/dist/harness/events.d.ts.map +1 -1
  31. package/dist/harness/events.js +240 -55
  32. package/dist/harness/events.js.map +1 -1
  33. package/dist/harness/execution/assistant.d.ts +42 -0
  34. package/dist/harness/execution/assistant.d.ts.map +1 -0
  35. package/dist/harness/execution/assistant.js +82 -0
  36. package/dist/harness/execution/assistant.js.map +1 -0
  37. package/dist/harness/execution/effect-gate.d.ts +22 -0
  38. package/dist/harness/execution/effect-gate.d.ts.map +1 -0
  39. package/dist/harness/execution/effect-gate.js +49 -0
  40. package/dist/harness/execution/effect-gate.js.map +1 -0
  41. package/dist/harness/execution/tools.d.ts +67 -0
  42. package/dist/harness/execution/tools.d.ts.map +1 -0
  43. package/dist/harness/execution/tools.js +121 -0
  44. package/dist/harness/execution/tools.js.map +1 -0
  45. package/dist/harness/hooks.d.ts +38 -0
  46. package/dist/harness/hooks.d.ts.map +1 -0
  47. package/dist/harness/hooks.js +406 -0
  48. package/dist/harness/hooks.js.map +1 -0
  49. package/dist/harness/messages.d.ts +2 -2
  50. package/dist/harness/messages.d.ts.map +1 -1
  51. package/dist/harness/messages.js.map +1 -1
  52. package/dist/harness/prompt-templates.d.ts +3 -2
  53. package/dist/harness/prompt-templates.d.ts.map +1 -1
  54. package/dist/harness/prompt-templates.js +17 -17
  55. package/dist/harness/prompt-templates.js.map +1 -1
  56. package/dist/harness/result.d.ts +93 -0
  57. package/dist/harness/result.d.ts.map +1 -1
  58. package/dist/harness/result.js +40 -0
  59. package/dist/harness/result.js.map +1 -1
  60. package/dist/harness/runtime/drive/boundary.d.ts +28 -0
  61. package/dist/harness/runtime/drive/boundary.d.ts.map +1 -0
  62. package/dist/harness/runtime/drive/boundary.js +170 -0
  63. package/dist/harness/runtime/drive/boundary.js.map +1 -0
  64. package/dist/harness/runtime/drive/checkpoint.d.ts +8 -0
  65. package/dist/harness/runtime/drive/checkpoint.d.ts.map +1 -0
  66. package/dist/harness/runtime/drive/checkpoint.js +133 -0
  67. package/dist/harness/runtime/drive/checkpoint.js.map +1 -0
  68. package/dist/harness/runtime/drive/deferred.d.ts +15 -0
  69. package/dist/harness/runtime/drive/deferred.d.ts.map +1 -0
  70. package/dist/harness/runtime/drive/deferred.js +179 -0
  71. package/dist/harness/runtime/drive/deferred.js.map +1 -0
  72. package/dist/harness/runtime/drive/generation.d.ts +8 -0
  73. package/dist/harness/runtime/drive/generation.d.ts.map +1 -0
  74. package/dist/harness/runtime/drive/generation.js +205 -0
  75. package/dist/harness/runtime/drive/generation.js.map +1 -0
  76. package/dist/harness/runtime/drive/reconcile.d.ts +5 -0
  77. package/dist/harness/runtime/drive/reconcile.d.ts.map +1 -0
  78. package/dist/harness/runtime/drive/reconcile.js +140 -0
  79. package/dist/harness/runtime/drive/reconcile.js.map +1 -0
  80. package/dist/harness/runtime/drive/recovery.d.ts +8 -0
  81. package/dist/harness/runtime/drive/recovery.d.ts.map +1 -0
  82. package/dist/harness/runtime/drive/recovery.js +85 -0
  83. package/dist/harness/runtime/drive/recovery.js.map +1 -0
  84. package/dist/harness/runtime/drive/response.d.ts +23 -0
  85. package/dist/harness/runtime/drive/response.d.ts.map +1 -0
  86. package/dist/harness/runtime/drive/response.js +394 -0
  87. package/dist/harness/runtime/drive/response.js.map +1 -0
  88. package/dist/harness/runtime/drive/retry.d.ts +4 -0
  89. package/dist/harness/runtime/drive/retry.d.ts.map +1 -0
  90. package/dist/harness/runtime/drive/retry.js +37 -0
  91. package/dist/harness/runtime/drive/retry.js.map +1 -0
  92. package/dist/harness/runtime/drive/structural.d.ts +32 -0
  93. package/dist/harness/runtime/drive/structural.d.ts.map +1 -0
  94. package/dist/harness/runtime/drive/structural.js +929 -0
  95. package/dist/harness/runtime/drive/structural.js.map +1 -0
  96. package/dist/harness/runtime/drive/terminal.d.ts +7 -0
  97. package/dist/harness/runtime/drive/terminal.d.ts.map +1 -0
  98. package/dist/harness/runtime/drive/terminal.js +49 -0
  99. package/dist/harness/runtime/drive/terminal.js.map +1 -0
  100. package/dist/harness/runtime/drive/tool-placement.d.ts +14 -0
  101. package/dist/harness/runtime/drive/tool-placement.d.ts.map +1 -0
  102. package/dist/harness/runtime/drive/tool-placement.js +244 -0
  103. package/dist/harness/runtime/drive/tool-placement.js.map +1 -0
  104. package/dist/harness/runtime/drive/tools.d.ts +6 -0
  105. package/dist/harness/runtime/drive/tools.d.ts.map +1 -0
  106. package/dist/harness/runtime/drive/tools.js +449 -0
  107. package/dist/harness/runtime/drive/tools.js.map +1 -0
  108. package/dist/harness/runtime/drive.d.ts +6 -0
  109. package/dist/harness/runtime/drive.d.ts.map +1 -0
  110. package/dist/harness/runtime/drive.js +93 -0
  111. package/dist/harness/runtime/drive.js.map +1 -0
  112. package/dist/harness/runtime/harness.d.ts +59 -0
  113. package/dist/harness/runtime/harness.d.ts.map +1 -0
  114. package/dist/harness/runtime/harness.js +311 -0
  115. package/dist/harness/runtime/harness.js.map +1 -0
  116. package/dist/harness/runtime/index.d.ts +2 -0
  117. package/dist/harness/runtime/index.d.ts.map +1 -0
  118. package/dist/harness/runtime/index.js +2 -0
  119. package/dist/harness/runtime/index.js.map +1 -0
  120. package/dist/harness/runtime/lane.d.ts +101 -0
  121. package/dist/harness/runtime/lane.d.ts.map +1 -0
  122. package/dist/harness/runtime/lane.js +1575 -0
  123. package/dist/harness/runtime/lane.js.map +1 -0
  124. package/dist/harness/runtime/progress.d.ts +15 -0
  125. package/dist/harness/runtime/progress.d.ts.map +1 -0
  126. package/dist/harness/runtime/progress.js +66 -0
  127. package/dist/harness/runtime/progress.js.map +1 -0
  128. package/dist/harness/runtime/reducer.d.ts +5 -0
  129. package/dist/harness/runtime/reducer.d.ts.map +1 -0
  130. package/dist/harness/runtime/reducer.js +240 -0
  131. package/dist/harness/runtime/reducer.js.map +1 -0
  132. package/dist/harness/runtime/restore.d.ts +24 -0
  133. package/dist/harness/runtime/restore.d.ts.map +1 -0
  134. package/dist/harness/runtime/restore.js +117 -0
  135. package/dist/harness/runtime/restore.js.map +1 -0
  136. package/dist/harness/runtime/transcript.d.ts +21 -0
  137. package/dist/harness/runtime/transcript.d.ts.map +1 -0
  138. package/dist/harness/runtime/transcript.js +72 -0
  139. package/dist/harness/runtime/transcript.js.map +1 -0
  140. package/dist/harness/runtime/types.d.ts +105 -0
  141. package/dist/harness/runtime/types.d.ts.map +1 -0
  142. package/dist/harness/runtime/types.js +61 -0
  143. package/dist/harness/runtime/types.js.map +1 -0
  144. package/dist/harness/session/commit.d.ts +53 -0
  145. package/dist/harness/session/commit.d.ts.map +1 -0
  146. package/dist/harness/session/commit.js +57 -0
  147. package/dist/harness/session/commit.js.map +1 -0
  148. package/dist/harness/session/context.d.ts +6 -18
  149. package/dist/harness/session/context.d.ts.map +1 -1
  150. package/dist/harness/session/context.js +31 -49
  151. package/dist/harness/session/context.js.map +1 -1
  152. package/dist/harness/session/fork-policy.d.ts +13 -0
  153. package/dist/harness/session/fork-policy.d.ts.map +1 -0
  154. package/dist/harness/session/fork-policy.js +22 -0
  155. package/dist/harness/session/fork-policy.js.map +1 -0
  156. package/dist/harness/session/fork.d.ts +18 -0
  157. package/dist/harness/session/fork.d.ts.map +1 -0
  158. package/dist/harness/session/fork.js +127 -0
  159. package/dist/harness/session/fork.js.map +1 -0
  160. package/dist/harness/session/in-memory-storage-state.d.ts +39 -0
  161. package/dist/harness/session/in-memory-storage-state.d.ts.map +1 -0
  162. package/dist/harness/session/in-memory-storage-state.js +216 -0
  163. package/dist/harness/session/in-memory-storage-state.js.map +1 -0
  164. package/dist/harness/session/index.d.ts +9 -5
  165. package/dist/harness/session/index.d.ts.map +1 -1
  166. package/dist/harness/session/index.js +7 -4
  167. package/dist/harness/session/index.js.map +1 -1
  168. package/dist/harness/session/jsonl/codec.d.ts +19 -8
  169. package/dist/harness/session/jsonl/codec.d.ts.map +1 -1
  170. package/dist/harness/session/jsonl/codec.js +34 -218
  171. package/dist/harness/session/jsonl/codec.js.map +1 -1
  172. package/dist/harness/session/jsonl/index.d.ts +4 -0
  173. package/dist/harness/session/jsonl/index.d.ts.map +1 -0
  174. package/dist/harness/session/jsonl/index.js +4 -0
  175. package/dist/harness/session/jsonl/index.js.map +1 -0
  176. package/dist/harness/session/jsonl/legacy-v3.d.ts +18 -0
  177. package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -0
  178. package/dist/harness/session/jsonl/legacy-v3.js +383 -0
  179. package/dist/harness/session/jsonl/legacy-v3.js.map +1 -0
  180. package/dist/harness/session/jsonl/repo.d.ts +26 -19
  181. package/dist/harness/session/jsonl/repo.d.ts.map +1 -1
  182. package/dist/harness/session/jsonl/repo.js +266 -156
  183. package/dist/harness/session/jsonl/repo.js.map +1 -1
  184. package/dist/harness/session/jsonl/storage.d.ts +39 -41
  185. package/dist/harness/session/jsonl/storage.d.ts.map +1 -1
  186. package/dist/harness/session/jsonl/storage.js +238 -181
  187. package/dist/harness/session/jsonl/storage.js.map +1 -1
  188. package/dist/harness/session/jsonl/types.d.ts +23 -22
  189. package/dist/harness/session/jsonl/types.d.ts.map +1 -1
  190. package/dist/harness/session/jsonl/types.js +2 -1
  191. package/dist/harness/session/jsonl/types.js.map +1 -1
  192. package/dist/harness/session/memory.d.ts +46 -40
  193. package/dist/harness/session/memory.d.ts.map +1 -1
  194. package/dist/harness/session/memory.js +346 -113
  195. package/dist/harness/session/memory.js.map +1 -1
  196. package/dist/harness/session/mutation-line.d.ts +8 -0
  197. package/dist/harness/session/mutation-line.d.ts.map +1 -0
  198. package/dist/harness/session/mutation-line.js +21 -0
  199. package/dist/harness/session/mutation-line.js.map +1 -0
  200. package/dist/harness/session/session.d.ts +78 -46
  201. package/dist/harness/session/session.d.ts.map +1 -1
  202. package/dist/harness/session/session.js +343 -209
  203. package/dist/harness/session/session.js.map +1 -1
  204. package/dist/harness/session/testing/benchmark/datasets.d.ts +12 -0
  205. package/dist/harness/session/testing/benchmark/datasets.d.ts.map +1 -0
  206. package/dist/harness/session/testing/benchmark/datasets.js +24 -0
  207. package/dist/harness/session/testing/benchmark/datasets.js.map +1 -0
  208. package/dist/harness/session/testing/benchmark/session-repo.d.ts +42 -0
  209. package/dist/harness/session/testing/benchmark/session-repo.d.ts.map +1 -0
  210. package/dist/harness/session/testing/benchmark/session-repo.js +127 -0
  211. package/dist/harness/session/testing/benchmark/session-repo.js.map +1 -0
  212. package/dist/harness/session/testing/benchmark/storage.d.ts +25 -0
  213. package/dist/harness/session/testing/benchmark/storage.d.ts.map +1 -0
  214. package/dist/harness/session/testing/benchmark/storage.js +114 -0
  215. package/dist/harness/session/testing/benchmark/storage.js.map +1 -0
  216. package/dist/harness/session/testing/conformance/session-repo.d.ts +21 -0
  217. package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -0
  218. package/dist/harness/session/testing/conformance/session-repo.js +590 -0
  219. package/dist/harness/session/testing/conformance/session-repo.js.map +1 -0
  220. package/dist/harness/session/testing/conformance/storage.d.ts +4 -0
  221. package/dist/harness/session/testing/conformance/storage.d.ts.map +1 -0
  222. package/dist/harness/session/testing/conformance/storage.js +600 -0
  223. package/dist/harness/session/testing/conformance/storage.js.map +1 -0
  224. package/dist/harness/session/testing/gating-storage.d.ts +26 -0
  225. package/dist/harness/session/testing/gating-storage.d.ts.map +1 -0
  226. package/dist/harness/session/testing/gating-storage.js +100 -0
  227. package/dist/harness/session/testing/gating-storage.js.map +1 -0
  228. package/dist/harness/session/testing/index.d.ts +9 -2
  229. package/dist/harness/session/testing/index.d.ts.map +1 -1
  230. package/dist/harness/session/testing/index.js +8 -1
  231. package/dist/harness/session/testing/index.js.map +1 -1
  232. package/dist/harness/session/testing/instrumented-storage.d.ts +11 -0
  233. package/dist/harness/session/testing/instrumented-storage.d.ts.map +1 -0
  234. package/dist/harness/session/testing/instrumented-storage.js +16 -0
  235. package/dist/harness/session/testing/instrumented-storage.js.map +1 -0
  236. package/dist/harness/session/testing/storage-decorator.d.ts +20 -0
  237. package/dist/harness/session/testing/storage-decorator.d.ts.map +1 -0
  238. package/dist/harness/session/testing/storage-decorator.js +41 -0
  239. package/dist/harness/session/testing/storage-decorator.js.map +1 -0
  240. package/dist/harness/session/testing/types.d.ts +5 -7
  241. package/dist/harness/session/testing/types.d.ts.map +1 -1
  242. package/dist/harness/session/testing/types.js.map +1 -1
  243. package/dist/harness/session/types.d.ts +424 -259
  244. package/dist/harness/session/types.d.ts.map +1 -1
  245. package/dist/harness/session/types.js +7 -8
  246. package/dist/harness/session/types.js.map +1 -1
  247. package/dist/harness/session/values.d.ts +95 -0
  248. package/dist/harness/session/values.d.ts.map +1 -0
  249. package/dist/harness/session/values.js +81 -0
  250. package/dist/harness/session/values.js.map +1 -0
  251. package/dist/harness/skills.d.ts +3 -2
  252. package/dist/harness/skills.d.ts.map +1 -1
  253. package/dist/harness/skills.js +29 -26
  254. package/dist/harness/skills.js.map +1 -1
  255. package/dist/harness/telemetry.d.ts +64 -43
  256. package/dist/harness/telemetry.d.ts.map +1 -1
  257. package/dist/harness/telemetry.js +45 -26
  258. package/dist/harness/telemetry.js.map +1 -1
  259. package/dist/harness/tools/bash.d.ts +4 -4
  260. package/dist/harness/tools/bash.d.ts.map +1 -1
  261. package/dist/harness/tools/bash.js +66 -93
  262. package/dist/harness/tools/bash.js.map +1 -1
  263. package/dist/harness/tools/edit.d.ts.map +1 -1
  264. package/dist/harness/tools/edit.js +10 -10
  265. package/dist/harness/tools/edit.js.map +1 -1
  266. package/dist/harness/tools/file-mutation-queue.d.ts +2 -1
  267. package/dist/harness/tools/file-mutation-queue.d.ts.map +1 -1
  268. package/dist/harness/tools/file-mutation-queue.js +5 -5
  269. package/dist/harness/tools/file-mutation-queue.js.map +1 -1
  270. package/dist/harness/tools/path-utils.d.ts +3 -2
  271. package/dist/harness/tools/path-utils.d.ts.map +1 -1
  272. package/dist/harness/tools/path-utils.js +5 -5
  273. package/dist/harness/tools/path-utils.js.map +1 -1
  274. package/dist/harness/tools/read.d.ts +2 -1
  275. package/dist/harness/tools/read.d.ts.map +1 -1
  276. package/dist/harness/tools/read.js +4 -6
  277. package/dist/harness/tools/read.js.map +1 -1
  278. package/dist/harness/tools/write.d.ts.map +1 -1
  279. package/dist/harness/tools/write.js +7 -7
  280. package/dist/harness/tools/write.js.map +1 -1
  281. package/dist/harness/types.d.ts +108 -45
  282. package/dist/harness/types.d.ts.map +1 -1
  283. package/dist/harness/types.js.map +1 -1
  284. package/dist/harness/utils/adaptive-publisher.d.ts +24 -0
  285. package/dist/harness/utils/adaptive-publisher.d.ts.map +1 -0
  286. package/dist/harness/utils/adaptive-publisher.js +79 -0
  287. package/dist/harness/utils/adaptive-publisher.js.map +1 -0
  288. package/dist/harness/utils/output-capture.d.ts +31 -0
  289. package/dist/harness/utils/output-capture.d.ts.map +1 -0
  290. package/dist/harness/utils/output-capture.js +217 -0
  291. package/dist/harness/utils/output-capture.js.map +1 -0
  292. package/dist/harness/utils/shell-output.d.ts +12 -5
  293. package/dist/harness/utils/shell-output.d.ts.map +1 -1
  294. package/dist/harness/utils/shell-output.js +64 -174
  295. package/dist/harness/utils/shell-output.js.map +1 -1
  296. package/dist/harness/utils/truncate.d.ts +1 -0
  297. package/dist/harness/utils/truncate.d.ts.map +1 -1
  298. package/dist/harness/utils/truncate.js +1 -1
  299. package/dist/harness/utils/truncate.js.map +1 -1
  300. package/dist/harness/utils/usage.d.ts +4 -0
  301. package/dist/harness/utils/usage.d.ts.map +1 -0
  302. package/dist/harness/utils/usage.js +33 -0
  303. package/dist/harness/utils/usage.js.map +1 -0
  304. package/dist/index.d.ts +4 -1
  305. package/dist/index.d.ts.map +1 -1
  306. package/dist/index.js +3 -6
  307. package/dist/index.js.map +1 -1
  308. package/dist/proxy.d.ts +2 -0
  309. package/dist/proxy.d.ts.map +1 -1
  310. package/dist/proxy.js +40 -10
  311. package/dist/proxy.js.map +1 -1
  312. package/dist/search/index.d.ts +24 -16
  313. package/dist/search/index.d.ts.map +1 -1
  314. package/dist/search/index.js +1 -1
  315. package/dist/search/index.js.map +1 -1
  316. package/dist/types.d.ts +2 -0
  317. package/dist/types.d.ts.map +1 -1
  318. package/dist/types.js.map +1 -1
  319. package/package.json +25 -4
  320. package/dist/harness/reducer.d.ts +0 -100
  321. package/dist/harness/reducer.d.ts.map +0 -1
  322. package/dist/harness/reducer.js +0 -415
  323. package/dist/harness/reducer.js.map +0 -1
  324. package/dist/harness/session/jsonl/errors.d.ts +0 -9
  325. package/dist/harness/session/jsonl/errors.d.ts.map +0 -1
  326. package/dist/harness/session/jsonl/errors.js +0 -19
  327. package/dist/harness/session/jsonl/errors.js.map +0 -1
  328. package/dist/harness/session/jsonl.d.ts +0 -3
  329. package/dist/harness/session/jsonl.d.ts.map +0 -1
  330. package/dist/harness/session/jsonl.js +0 -2
  331. package/dist/harness/session/jsonl.js.map +0 -1
  332. package/dist/harness/session/state.d.ts +0 -65
  333. package/dist/harness/session/state.d.ts.map +0 -1
  334. package/dist/harness/session/state.js +0 -319
  335. package/dist/harness/session/state.js.map +0 -1
  336. package/dist/harness/session/testing/conformance.d.ts +0 -4
  337. package/dist/harness/session/testing/conformance.d.ts.map +0 -1
  338. package/dist/harness/session/testing/conformance.js +0 -762
  339. package/dist/harness/session/testing/conformance.js.map +0 -1
  340. package/dist/search/scanning.d.ts +0 -29
  341. package/dist/search/scanning.d.ts.map +0 -1
  342. package/dist/search/scanning.js +0 -103
  343. package/dist/search/scanning.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/storage.ts"],"names":[],"mappings":"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","sourcesContent":["import { type SessionMutation, SessionState } from \"../state.ts\";\nimport {\n\ttype BranchBounds,\n\ttype Entry,\n\ttype EntryQuery,\n\ttype ForkOptions,\n\ttype LanePointer,\n\ttype LaneRecord,\n\ttype LogItem,\n\ttype LogOptions,\n\ttype NewRecord,\n\ttype OperationStartedRecord,\n\ttype ProvisionedEntry,\n\ttype RecordQuery,\n\tSessionError,\n\ttype SessionStats,\n\ttype SessionStorage,\n} from \"../types.ts\";\nimport { encodeHeader, encodeMutation, metadataFromHeader, parseHeader, parseMutation } from \"./codec.ts\";\nimport { fileResult, invalidFile, JsonlDecodeError } from \"./errors.ts\";\nimport type { JsonlSessionMetadata, JsonlSessionRepoFileSystem, JsonlV4Header } from \"./types.ts\";\n\n/**\n * Build a complete sibling temporary file, then atomically rename it over the destination.\n * The populate callback must create or overwrite `tempPath` with the complete file. The\n * destination is untouched until the rename commits, so a process crash while populating\n * can leave only the ignored `.tmp` file behind.\n *\n * Rejects when population or rename fails. On rejection, temporary-file removal is\n * best-effort and the original error is preserved. Callers must serialize publications to\n * the same destination because they share its deterministic `.tmp` path.\n */\nasync function publishFileAtomically(\n\tfs: JsonlSessionRepoFileSystem,\n\tdestinationPath: string,\n\tpopulate: (tempPath: string) => Promise<void>,\n): Promise<void> {\n\tconst tempPath = `${destinationPath}.tmp`;\n\ttry {\n\t\tawait populate(tempPath);\n\t\tfileResult(await fs.renameFile(tempPath, destinationPath), `Failed to publish staged file ${destinationPath}`);\n\t} catch (error) {\n\t\tawait fs.remove(tempPath, { force: true });\n\t\tthrow error;\n\t}\n}\n\nexport class JsonlSessionStorage implements SessionStorage<JsonlSessionMetadata> {\n\tprivate readonly fs: JsonlSessionRepoFileSystem;\n\tprivate readonly metadata: JsonlSessionMetadata;\n\tprivate readonly state = new SessionState();\n\tprivate tail: Promise<void> = Promise.resolve();\n\n\tconstructor(fs: JsonlSessionRepoFileSystem, metadata: JsonlSessionMetadata) {\n\t\tthis.fs = fs;\n\t\tthis.metadata = structuredClone(metadata);\n\t}\n\n\tstatic async create(\n\t\tfs: JsonlSessionRepoFileSystem,\n\t\tpath: string,\n\t\theader: JsonlV4Header,\n\t): Promise<JsonlSessionStorage> {\n\t\tfileResult(await fs.writeFile(path, encodeHeader(header)), `Failed to initialize session ${path}`);\n\t\tconst fileInfo = fileResult(await fs.fileInfo(path), `Failed to read session metadata ${path}`);\n\t\treturn new JsonlSessionStorage(fs, metadataFromHeader(header, path, fileInfo.mtimeMs));\n\t}\n\n\tstatic async load(fs: JsonlSessionRepoFileSystem, path: string): Promise<JsonlSessionStorage> {\n\t\tconst content = fileResult(await fs.readTextFile(path), `Failed to read session ${path}`);\n\t\tconst physicalLines = content.split(\"\\n\");\n\t\tif (physicalLines.at(-1) === \"\") physicalLines.pop();\n\t\tif (physicalLines.length === 0 || !physicalLines[0]) {\n\t\t\tthrow invalidFile(path, 1, new JsonlDecodeError(\"schema\", \"is missing a header\"));\n\t\t}\n\t\tconst headerResult = parseHeader(physicalLines[0]);\n\t\tif (!headerResult.ok) throw invalidFile(path, 1, headerResult.error);\n\t\tconst fileInfo = fileResult(await fs.fileInfo(path), `Failed to read session metadata ${path}`);\n\t\tconst storage = new JsonlSessionStorage(fs, metadataFromHeader(headerResult.value, path, fileInfo.mtimeMs));\n\t\tfor (let index = 1; index < physicalLines.length; index++) {\n\t\t\tconst line = physicalLines[index]!;\n\t\t\tconst mutationResult = parseMutation(line);\n\t\t\tif (!mutationResult.ok) {\n\t\t\t\tconst isTornTail = index === physicalLines.length - 1 && mutationResult.error.kind === \"syntax\";\n\t\t\t\tif (isTornTail) {\n\t\t\t\t\t// Drop the unacknowledged partial append by atomically publishing the valid prefix.\n\t\t\t\t\tconst validPrefix = `${physicalLines.slice(0, index).join(\"\\n\")}\\n`;\n\t\t\t\t\tawait publishFileAtomically(fs, path, async (tempPath) => {\n\t\t\t\t\t\tfileResult(await fs.writeFile(tempPath, validPrefix), `Failed to stage torn-tail repair ${path}`);\n\t\t\t\t\t});\n\t\t\t\t\treturn storage;\n\t\t\t\t}\n\t\t\t\tthrow invalidFile(path, index + 1, mutationResult.error);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tstorage.applyMutation(mutationResult.value);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof SessionError && error.code === \"invalid_entry\") {\n\t\t\t\t\tthrow invalidFile(path, index + 1, error);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\tif (!content.endsWith(\"\\n\")) {\n\t\t\tfileResult(await fs.appendFile(path, \"\\n\"), `Failed to repair unterminated session tail ${path}`);\n\t\t}\n\t\treturn storage;\n\t}\n\n\tasync fork(path: string, header: JsonlV4Header, options: ForkOptions): Promise<JsonlSessionStorage> {\n\t\tconst mutations = this.state.createForkMutations(options);\n\t\tawait publishFileAtomically(this.fs, path, async (tempPath) => {\n\t\t\tconst targetStorage = await JsonlSessionStorage.create(this.fs, tempPath, header);\n\t\t\tfor (const mutation of mutations) {\n\t\t\t\tawait targetStorage.appendMutation(mutation);\n\t\t\t\ttargetStorage.applyMutation(mutation);\n\t\t\t}\n\t\t});\n\t\treturn JsonlSessionStorage.load(this.fs, path);\n\t}\n\n\tasync drain(): Promise<void> {\n\t\tawait this.tail;\n\t}\n\n\tasync getMetadata(): Promise<JsonlSessionMetadata> {\n\t\treturn structuredClone(this.metadata);\n\t}\n\n\tasync getLanes(): Promise<LanePointer[]> {\n\t\treturn this.state.getLanes();\n\t}\n\n\tcreateLane(lane: string, at: string | null): Promise<void> {\n\t\treturn this.enqueue(async () => {\n\t\t\tthis.state.validateNewLane(lane);\n\t\t\tthis.state.validateTarget(at);\n\t\t\tconst mutation: SessionMutation = { kind: \"lane\", seq: this.state.nextSequence, lane, leafId: at };\n\t\t\tawait this.appendMutation(mutation);\n\t\t\tthis.applyMutation(mutation);\n\t\t});\n\t}\n\n\tmoveLane(lane: string, to: string | null): Promise<void> {\n\t\treturn this.enqueue(async () => {\n\t\t\tthis.state.requireLane(lane);\n\t\t\tthis.state.validateTarget(to);\n\t\t\tconst mutation: SessionMutation = { kind: \"lane\", seq: this.state.nextSequence, lane, leafId: to };\n\t\t\tawait this.appendMutation(mutation);\n\t\t\tthis.applyMutation(mutation);\n\t\t});\n\t}\n\n\tappendEntry<TEntry extends Entry>(newEntry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\treturn this.enqueue(async () => {\n\t\t\tconst parentId = this.state.requireLane(lane);\n\t\t\tthis.state.validateUnusedId(newEntry.id);\n\t\t\tconst entry = {\n\t\t\t\t...structuredClone(newEntry),\n\t\t\t\tparentId,\n\t\t\t\tseq: this.state.nextSequence,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t} as unknown as TEntry;\n\t\t\tconst mutation: SessionMutation = { kind: \"entry\", lane, entry };\n\t\t\tawait this.appendMutation(mutation);\n\t\t\tthis.applyMutation(mutation);\n\t\t\treturn structuredClone(entry);\n\t\t});\n\t}\n\n\tappendRecord<TRecord extends LaneRecord>(newRecord: NewRecord<TRecord>): Promise<TRecord> {\n\t\treturn this.enqueue(async () => {\n\t\t\tthis.state.requireLane(newRecord.lane);\n\t\t\tthis.state.validateUnusedId(newRecord.id);\n\t\t\tconst currentOpenOperationId = this.state.findOpenOperations(newRecord.lane, { limit: 1 })[0]?.id;\n\t\t\tif (newRecord.type === \"operation_started\" && currentOpenOperationId !== undefined) {\n\t\t\t\tthrow new SessionError(\n\t\t\t\t\t\"storage\",\n\t\t\t\t\t`Lane ${newRecord.lane} already has an open operation ${currentOpenOperationId}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst record = {\n\t\t\t\t...structuredClone(newRecord),\n\t\t\t\tseq: this.state.nextSequence,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t} as unknown as TRecord;\n\t\t\tconst mutation: SessionMutation = { kind: \"record\", record };\n\t\t\tawait this.appendMutation(mutation);\n\t\t\tthis.applyMutation(mutation);\n\t\t\treturn structuredClone(record);\n\t\t});\n\t}\n\n\tasync getEntry(id: string): Promise<Entry | undefined> {\n\t\tconst entry = this.state.getEntry(id);\n\t\treturn entry === undefined ? undefined : structuredClone(entry);\n\t}\n\n\tasync findEntries(query: EntryQuery = {}): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntries(query));\n\t}\n\n\tasync findEntriesOnBranch(query: EntryQuery & BranchBounds & { start: string }): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntriesOnBranch(query));\n\t}\n\n\tasync findRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\tasync findRecords(query: RecordQuery = {}): Promise<LaneRecord[]> {\n\t\treturn structuredClone(this.state.findRecords(query));\n\t}\n\n\tasync findOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]> {\n\t\treturn structuredClone(this.state.findOpenOperations(lane, options));\n\t}\n\n\tasync getLog(options: LogOptions = {}): Promise<LogItem[]> {\n\t\treturn structuredClone(this.state.getLog(options));\n\t}\n\n\tasync getName(): Promise<string | undefined> {\n\t\treturn this.state.getName();\n\t}\n\n\tsetName(name: string | undefined): Promise<void> {\n\t\treturn this.enqueue(async () => {\n\t\t\tconst mutation: SessionMutation = { kind: \"fact\", seq: this.state.nextSequence, fact: \"name\", name };\n\t\t\tawait this.appendMutation(mutation);\n\t\t\tthis.applyMutation(mutation);\n\t\t});\n\t}\n\n\tasync getLabel(id: string): Promise<string | undefined> {\n\t\treturn this.state.getLabel(id);\n\t}\n\n\tsetLabel(id: string, label: string | undefined): Promise<void> {\n\t\treturn this.enqueue(async () => {\n\t\t\tthis.state.validateTarget(id);\n\t\t\tconst mutation: SessionMutation = {\n\t\t\t\tkind: \"fact\",\n\t\t\t\tseq: this.state.nextSequence,\n\t\t\t\tfact: \"label\",\n\t\t\t\ttargetId: id,\n\t\t\t\tlabel,\n\t\t\t};\n\t\t\tawait this.appendMutation(mutation);\n\t\t\tthis.applyMutation(mutation);\n\t\t});\n\t}\n\n\tasync getStats(): Promise<SessionStats> {\n\t\treturn structuredClone(this.state.getStats());\n\t}\n\n\tprivate enqueue<T>(operation: () => Promise<T>): Promise<T> {\n\t\tconst result = this.tail.then(operation);\n\t\tthis.tail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n\n\tprivate async appendMutation(mutation: SessionMutation): Promise<void> {\n\t\tfileResult(\n\t\t\tawait this.fs.appendFile(this.metadata.path, encodeMutation(mutation)),\n\t\t\t`Failed to append session ${this.metadata.path}`,\n\t\t);\n\t}\n\n\tprivate applyMutation(mutation: SessionMutation): void {\n\t\tthis.state.applyMutation(mutation);\n\t}\n}\n"]}
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/storage.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Usage } from \"@earendil-works/pi-ai\";\nimport { uuidv7 } from \"@earendil-works/pi-ai/utils/uuid\";\nimport type { Context } from \"../../context.ts\";\nimport type { FileError, FileSystem, Result } from \"../../types.ts\";\nimport { insertUsage } from \"../commit.ts\";\nimport { type ForkDestinationSnapshot, type ForkSourceSnapshot, forkSnapshotWrites } from \"../fork.ts\";\nimport {\n\ttype CommittedEntryWrite,\n\ttype CommittedListAppendWrite,\n\ttype CommittedListDeleteWrite,\n\ttype CommittedUsageWrite,\n\ttype CommittedValueDeleteWrite,\n\ttype CommittedValueSetWrite,\n\ttype CommittedWrite,\n\tInMemoryStorageState,\n} from \"../in-memory-storage-state.ts\";\nimport type {\n\tCommitResult,\n\tEntry,\n\tEntryScan,\n\tEntryStructure,\n\tSessionStats,\n\tStorage,\n\tStorageBranchScan,\n\tUsageRow,\n\tUsageScan,\n\tWrite,\n} from \"../types.ts\";\nimport type { ListElement, ListReadOptions, StoredValue, Value, ValueList } from \"../values.ts\";\nimport { type LegacyV3SessionHeader, parseJsonlSessionHeader } from \"./codec.ts\";\nimport { normalizeLegacyV3Header, normalizeLegacyV3Records } from \"./legacy-v3.ts\";\nimport { JSONL_STORAGE_VERSION, type JsonlStorageHeader, type JsonlStorageOptions } from \"./types.ts\";\n\nfunction fileValue<T>(result: Result<T, FileError>, action: string): T {\n\tif (!result.ok) throw new Error(`${action}: ${result.error.message}`, { cause: result.error });\n\treturn result.value;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction requireSafeInteger(value: unknown, field: string, minimum: number): void {\n\tif (!Number.isSafeInteger(value) || (value as number) < minimum) throw new Error(`Invalid JSONL ${field}`);\n}\n\nfunction parseCommittedWrite(value: unknown): CommittedWrite {\n\tif (!isRecord(value)) throw new Error(\"Invalid JSONL transaction write\");\n\trequireSafeInteger(value.seq, \"write seq\", 1);\n\tswitch (value.kind) {\n\t\tcase \"entry\":\n\t\t\trequireSafeInteger(value.timestamp, \"entry timestamp\", 0);\n\t\t\treturn value as unknown as CommittedEntryWrite;\n\t\tcase \"usage\":\n\t\t\treturn value as unknown as CommittedUsageWrite;\n\t\tcase \"value\":\n\t\t\tif (value.op === \"set\") return value as unknown as CommittedValueSetWrite;\n\t\t\tif (value.op === \"delete\") return value as unknown as CommittedValueDeleteWrite;\n\t\t\tthrow new Error(`Invalid JSONL value operation: ${String(value.op)}`);\n\t\tcase \"list\":\n\t\t\tif (value.op === \"append\") return value as unknown as CommittedListAppendWrite;\n\t\t\tif (value.op === \"delete\") return value as unknown as CommittedListDeleteWrite;\n\t\t\tthrow new Error(`Invalid JSONL list operation: ${String(value.op)}`);\n\t\tdefault:\n\t\t\tthrow new Error(`Invalid JSONL write kind: ${String(value.kind)}`);\n\t}\n}\n\nfunction parseTransaction(line: string): CommittedWrite[] {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(line);\n\t} catch (error) {\n\t\tthrow new Error(\"Invalid JSONL transaction: not valid JSON\", { cause: error });\n\t}\n\treturn (Array.isArray(value) ? value : [value]).map(parseCommittedWrite);\n}\n\nfunction serializeTransaction(writes: CommittedWrite[]): string {\n\treturn JSON.stringify(writes.length === 1 ? writes[0] : writes);\n}\n\nfunction serializeStorage(header: JsonlStorageHeader, transactions: CommittedWrite[][]): string {\n\treturn `${[JSON.stringify(header), ...transactions.map(serializeTransaction)].join(\"\\n\")}\\n`;\n}\n\nfunction splitCompleteLines(content: string): { lines: string[]; torn: boolean } {\n\tif (content.endsWith(\"\\n\")) return { lines: content.slice(0, -1).split(\"\\n\"), torn: false };\n\tconst lastNewline = content.lastIndexOf(\"\\n\");\n\tif (lastNewline === -1) return { lines: [], torn: true };\n\treturn { lines: content.slice(0, lastNewline).split(\"\\n\"), torn: true };\n}\n\nasync function publishFileAtomically(\n\tfileSystem: FileSystem,\n\tdestinationPath: string,\n\tcontent: string,\n\tcontext: Context,\n): Promise<void> {\n\tconst tempPath = `${destinationPath}.tmp`;\n\ttry {\n\t\tfileValue(\n\t\t\tawait fileSystem.writeFile(tempPath, content, context),\n\t\t\t`Failed to stage JSONL storage ${destinationPath}`,\n\t\t);\n\t\tfileValue(\n\t\t\tawait fileSystem.renameFile(tempPath, destinationPath, context),\n\t\t\t`Failed to publish JSONL storage ${destinationPath}`,\n\t\t);\n\t} catch (error) {\n\t\tawait fileSystem.remove(tempPath, { force: true }, context);\n\t\tthrow error;\n\t}\n}\n\ntype LegacyV3Backing = {\n\tkind: \"v3\";\n\timportedUsage: Usage;\n\tbaselineWrites: readonly CommittedWrite[];\n};\n\ntype JsonlBacking = { kind: \"v4\" } | LegacyV3Backing;\n\n/** JSONL storage backed by an injected filesystem capability. */\nexport class JsonlStorage implements Storage {\n\tprivate readonly fileSystem: FileSystem;\n\tprivate readonly path: string;\n\tprivate readonly now: () => number;\n\treadonly header: JsonlStorageHeader;\n\tprivate backing: JsonlBacking;\n\tprivate readonly storageState = new InMemoryStorageState();\n\tprivate commitQueue: Promise<void> = Promise.resolve();\n\tprivate state: \"open\" | \"closing\" | \"closed\" = \"open\";\n\tprivate closePromise: Promise<void> | undefined;\n\n\tprivate constructor(options: JsonlStorageOptions, header: JsonlStorageHeader, backing: JsonlBacking) {\n\t\tthis.fileSystem = options.fileSystem;\n\t\tthis.path = options.path;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.header = header;\n\t\tthis.backing = backing;\n\t}\n\n\tstatic async create(\n\t\toptions: JsonlStorageOptions,\n\t\theader: JsonlStorageHeader,\n\t\tinitialWrites: Write[],\n\t\tcontext: Context,\n\t): Promise<JsonlStorage> {\n\t\tconst storage = new JsonlStorage(options, header, { kind: \"v4\" });\n\t\tconst prepared = storage.storageState.prepareCommit(initialWrites, storage.now());\n\t\tconst transactions = prepared.writes.length === 0 ? [] : [prepared.writes];\n\t\tawait publishFileAtomically(options.fileSystem, options.path, serializeStorage(header, transactions), context);\n\t\tstorage.storageState.applyValidated(prepared.writes);\n\t\treturn storage;\n\t}\n\n\t/** Atomically create storage from a complete prepared snapshot. */\n\tstatic async createFromForkSnapshot(\n\t\toptions: JsonlStorageOptions,\n\t\theader: JsonlStorageHeader,\n\t\tsnapshot: ForkDestinationSnapshot,\n\t\tcontext: Context,\n\t): Promise<JsonlStorage> {\n\t\tconst writes = forkSnapshotWrites(snapshot);\n\t\tconst snapshotHeader = { ...header, nextSeq: snapshot.nextSeq };\n\t\tawait publishFileAtomically(\n\t\t\toptions.fileSystem,\n\t\t\toptions.path,\n\t\t\tserializeStorage(\n\t\t\t\tsnapshotHeader,\n\t\t\t\twrites.map((write) => [write]),\n\t\t\t),\n\t\t\tcontext,\n\t\t);\n\t\treturn JsonlStorage.open(options, context);\n\t}\n\n\tstatic async open(options: JsonlStorageOptions, context: Context): Promise<JsonlStorage> {\n\t\tconst content = fileValue(\n\t\t\tawait options.fileSystem.readTextFile(options.path, context),\n\t\t\t`Failed to read JSONL storage ${options.path}`,\n\t\t);\n\t\tconst { lines, torn } = splitCompleteLines(content);\n\t\tif (lines[0] === undefined || lines[0] === \"\") {\n\t\t\tthrow new Error(`Invalid JSONL storage ${options.path}: missing header`);\n\t\t}\n\t\tconst parsedHeader = parseJsonlSessionHeader(lines[0]);\n\t\tif (!parsedHeader.ok) {\n\t\t\tthrow new Error(`Invalid JSONL storage ${options.path}: invalid header`, { cause: parsedHeader.error });\n\t\t}\n\t\tif (parsedHeader.value.format === \"v3-legacy\") {\n\t\t\treturn JsonlStorage.openLegacyV3(options, parsedHeader.value.header, lines.slice(1), context);\n\t\t}\n\n\t\tconst header = parsedHeader.value.header;\n\t\tif (header.storageVersion !== JSONL_STORAGE_VERSION) {\n\t\t\tthrow new Error(`Session ${header.id} uses unsupported storage version ${header.storageVersion}`);\n\t\t}\n\t\tconst storage = new JsonlStorage(options, header, { kind: \"v4\" });\n\t\tfor (let index = 1; index < lines.length; index++) {\n\t\t\tconst line = lines[index]!;\n\t\t\ttry {\n\t\t\t\tstorage.replayCommitted(parseTransaction(line));\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(`Invalid JSONL storage ${options.path}: line ${index + 1}`, { cause: error });\n\t\t\t}\n\t\t}\n\t\tif (header.nextSeq !== undefined) storage.storageState.advanceNextSeq(header.nextSeq);\n\t\tif (torn) await publishFileAtomically(options.fileSystem, options.path, `${lines.join(\"\\n\")}\\n`, context);\n\t\treturn storage;\n\t}\n\n\tprivate static async openLegacyV3(\n\t\toptions: JsonlStorageOptions,\n\t\theader: LegacyV3SessionHeader,\n\t\trecordLines: readonly string[],\n\t\tcontext: Context,\n\t): Promise<JsonlStorage> {\n\t\tconst { writes, importedUsage, nextSeq } = normalizeLegacyV3Records(recordLines);\n\t\tconst targetHeader = {\n\t\t\t...(await normalizeLegacyV3Header(options.fileSystem, header, context)),\n\t\t\tnextSeq,\n\t\t};\n\t\tconst storage = new JsonlStorage(options, targetHeader, {\n\t\t\tkind: \"v3\",\n\t\t\timportedUsage,\n\t\t\tbaselineWrites: writes,\n\t\t});\n\t\tstorage.replayCommitted(writes);\n\t\treturn storage;\n\t}\n\n\tprivate replayCommitted(writes: readonly CommittedWrite[]): void {\n\t\tthis.storageState.validateCommitted(writes);\n\t\tthis.storageState.applyValidated(writes);\n\t}\n\n\tasync commit(writes: Write[], context: Context): Promise<CommitResult> {\n\t\tif (this.state !== \"open\") throw new Error(\"JsonlStorage is closed\");\n\t\tconst result = this.commitQueue.then(() => this.applyCommit(writes, context));\n\t\tthis.commitQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n\n\tprivate async applyCommit(writes: Write[], context: Context): Promise<CommitResult> {\n\t\tif (this.backing.kind === \"v3\" && writes.length !== 0) {\n\t\t\treturn this.upgradeLegacyV3ToV4(this.backing, writes, context);\n\t\t}\n\t\tconst prepared = this.storageState.prepareCommit(writes, this.now());\n\t\tif (prepared.writes.length !== 0) {\n\t\t\tfileValue(\n\t\t\t\tawait this.fileSystem.appendFile(this.path, `${serializeTransaction(prepared.writes)}\\n`, context),\n\t\t\t\t`Failed to append JSONL storage ${this.path}`,\n\t\t\t);\n\t\t}\n\t\tconst stats = this.storageState.applyValidated(prepared.writes);\n\t\treturn { ...prepared.result, stats: this.withImportedUsage(stats) };\n\t}\n\n\t/** Atomically upgrade legacy v3 backing and preserve the first caller write as a v4 transaction. */\n\tprivate async upgradeLegacyV3ToV4(\n\t\tbacking: LegacyV3Backing,\n\t\tcallerWrites: Write[],\n\t\tcontext: Context,\n\t): Promise<CommitResult> {\n\t\tconst timestamp = this.now();\n\t\tconst prepared = this.storageState.prepareCommit(\n\t\t\t[\n\t\t\t\tinsertUsage({\n\t\t\t\t\tid: uuidv7(timestamp),\n\t\t\t\t\tusage: backing.importedUsage,\n\t\t\t\t\tadjustment: true,\n\t\t\t\t\tdetails: { source: \"v3-import\" },\n\t\t\t\t}),\n\t\t\t\t...callerWrites,\n\t\t\t],\n\t\t\ttimestamp,\n\t\t);\n\n\t\tconst nextSeq = prepared.result.firstSeq + prepared.writes.length;\n\t\tconst upgradedHeader = { ...this.header, nextSeq };\n\t\tawait publishFileAtomically(\n\t\t\tthis.fileSystem,\n\t\t\tthis.path,\n\t\t\tserializeStorage(upgradedHeader, [...backing.baselineWrites.map((write) => [write]), prepared.writes]),\n\t\t\tcontext,\n\t\t);\n\n\t\tconst stats = this.storageState.applyValidated(prepared.writes);\n\t\tthis.backing = { kind: \"v4\" };\n\t\t// The first sequence belongs to the internal usage adjustment; return only caller-write sequences.\n\t\treturn {\n\t\t\t...prepared.result,\n\t\t\tfirstSeq: prepared.result.firstSeq + 1,\n\t\t\tseqs: prepared.result.seqs.slice(1),\n\t\t\tstats,\n\t\t};\n\t}\n\n\tgetEntries(ids: string[], _context: Context): Promise<Map<string, Entry>> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"JsonlStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.getEntries(ids));\n\t}\n\n\tgetValue<T>(address: Value<T>, _context: Context): Promise<StoredValue<T> | undefined> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"JsonlStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.getValue(address));\n\t}\n\n\tscanValues<T>(prefix: Value<T>, _context: Context): Promise<StoredValue<T>[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"JsonlStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.scanValues(prefix));\n\t}\n\n\tasync readList<T>(\n\t\taddress: ValueList<T>,\n\t\toptions: ListReadOptions | undefined,\n\t\t_context: Context,\n\t): Promise<ListElement<T>[]> {\n\t\tif (this.state !== \"open\") throw new Error(\"JsonlStorage is closed\");\n\t\treturn this.storageState.readList(address, options);\n\t}\n\n\tasync scanBranch(query: StorageBranchScan, _context: Context): Promise<Entry[]> {\n\t\tif (this.state !== \"open\") throw new Error(\"JsonlStorage is closed\");\n\t\treturn this.storageState.scanBranch(query);\n\t}\n\n\tasync scanBranchStructure(query: StorageBranchScan, _context: Context): Promise<EntryStructure[]> {\n\t\tif (this.state !== \"open\") throw new Error(\"JsonlStorage is closed\");\n\t\treturn this.storageState.scanBranchStructure(query);\n\t}\n\n\tscanEntries(query: EntryScan, _context: Context): Promise<Entry[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"JsonlStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.scanEntries(query));\n\t}\n\n\tscanUsage(query: UsageScan, _context: Context): Promise<UsageRow[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"JsonlStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.scanUsage(query));\n\t}\n\n\tgetStats(_context: Context): Promise<SessionStats> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"JsonlStorage is closed\"));\n\t\treturn Promise.resolve(this.withImportedUsage(this.storageState.getStats()));\n\t}\n\n\tprivate withImportedUsage(stats: SessionStats): SessionStats {\n\t\treturn this.backing.kind === \"v4\" ? stats : { ...stats, usage: this.backing.importedUsage };\n\t}\n\n\t/** Capture the state needed to fork at one serialized boundary between commits. */\n\tcaptureForkSource(_context: Context): Promise<ForkSourceSnapshot> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"JsonlStorage is closed\"));\n\t\tconst result = this.commitQueue.then(() => this.storageState.snapshotEntriesAndValues());\n\t\tthis.commitQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n\n\tclose(_context: Context): Promise<void> {\n\t\tif (this.closePromise !== undefined) return this.closePromise;\n\t\tthis.state = \"closing\";\n\t\tthis.closePromise = this.commitQueue.then(() => {\n\t\t\tthis.state = \"closed\";\n\t\t});\n\t\treturn this.closePromise;\n\t}\n}\n"]}
@@ -1,38 +1,39 @@
1
1
  import type { FileSystem } from "../../types.ts";
2
- import type { JsonValue, SessionCreateOptions, SessionMetadata } from "../types.ts";
3
- export type JsonlSessionRepoFileSystem = Pick<FileSystem, "absolutePath" | "joinPath" | "readTextFile" | "readTextLines" | "writeFile" | "appendFile" | "renameFile" | "fileInfo" | "listDir" | "exists" | "createDir" | "remove">;
4
- export interface JsonlSessionRepoOptions {
5
- fs: JsonlSessionRepoFileSystem;
6
- /** Root containing coding-agent-compatible cwd-encoded session directories. */
7
- sessionsRoot: string;
2
+ import type { SessionCreateOptions, SessionMetadata } from "../types.ts";
3
+ export declare const JSONL_FORMAT_VERSION = 4;
4
+ export declare const JSONL_STORAGE_VERSION = 1;
5
+ export interface JsonlStorageHeader {
6
+ v: typeof JSONL_FORMAT_VERSION;
7
+ kind: "header";
8
+ id: string;
9
+ storageVersion: number;
10
+ createdAt: number;
11
+ cwd: string;
12
+ parentSessionId?: string;
13
+ legacyParentSessionPath?: string;
14
+ /** Sequence high-water mark written by snapshot rewrites. */
15
+ nextSeq?: number;
16
+ }
17
+ export interface JsonlStorageOptions {
18
+ fileSystem: FileSystem;
19
+ path: string;
20
+ now?: () => number;
8
21
  }
9
22
  export interface JsonlSessionMetadata extends SessionMetadata {
10
23
  cwd: string;
11
24
  path: string;
12
25
  /** Filesystem modification time as milliseconds since Unix epoch. */
13
26
  modifiedAt: number;
14
- sourceFormat: 3 | 4;
15
- /** Present only when a v3 parent path could not be resolved to a session id. */
16
- legacyParentSessionPath?: string;
17
- /** Opaque application-owned metadata. */
18
- metadata?: Record<string, JsonValue>;
19
27
  }
20
28
  export interface JsonlSessionCreateOptions extends SessionCreateOptions {
21
29
  cwd: string;
22
- metadata?: Record<string, JsonValue>;
23
30
  }
24
31
  export interface JsonlSessionListOptions {
25
32
  cwd?: string;
26
33
  }
27
- export interface JsonlV4Header {
28
- kind: "header";
29
- version: 4;
30
- id: string;
31
- createdAt: number;
32
- cwd: string;
33
- parentSessionId?: string;
34
- /** Preserved only when a v3 parent path could not be resolved to a session id. */
35
- legacyParentSessionPath?: string;
36
- metadata?: Record<string, JsonValue>;
34
+ export interface JsonlSessionRepoOptions {
35
+ fileSystem: FileSystem;
36
+ sessionsRoot: string;
37
+ now?: () => number;
37
38
  }
38
39
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEpF,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC5C,UAAU,EACR,cAAc,GACd,UAAU,GACV,cAAc,GACd,eAAe,GACf,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,UAAU,GACV,SAAS,GACT,QAAQ,GACR,WAAW,GACX,QAAQ,CACV,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,0BAA0B,CAAC;IAC/B,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC;IACpB,gFAAgF;IAChF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,uBAAuB;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,CAAC,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kFAAkF;IAClF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC","sourcesContent":["import type { FileSystem } from \"../../types.ts\";\nimport type { JsonValue, SessionCreateOptions, SessionMetadata } from \"../types.ts\";\n\nexport type JsonlSessionRepoFileSystem = Pick<\n\tFileSystem,\n\t| \"absolutePath\"\n\t| \"joinPath\"\n\t| \"readTextFile\"\n\t| \"readTextLines\"\n\t| \"writeFile\"\n\t| \"appendFile\"\n\t| \"renameFile\"\n\t| \"fileInfo\"\n\t| \"listDir\"\n\t| \"exists\"\n\t| \"createDir\"\n\t| \"remove\"\n>;\n\nexport interface JsonlSessionRepoOptions {\n\tfs: JsonlSessionRepoFileSystem;\n\t/** Root containing coding-agent-compatible cwd-encoded session directories. */\n\tsessionsRoot: string;\n}\n\nexport interface JsonlSessionMetadata extends SessionMetadata {\n\tcwd: string;\n\tpath: string;\n\t/** Filesystem modification time as milliseconds since Unix epoch. */\n\tmodifiedAt: number;\n\tsourceFormat: 3 | 4;\n\t/** Present only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\t/** Opaque application-owned metadata. */\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionCreateOptions extends SessionCreateOptions {\n\tcwd: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionListOptions {\n\tcwd?: string;\n}\n\nexport interface JsonlV4Header {\n\tkind: \"header\";\n\tversion: 4;\n\tid: string;\n\tcreatedAt: number;\n\tcwd: string;\n\tparentSessionId?: string;\n\t/** Preserved only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n"]}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEzE,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IAClC,CAAC,EAAE,OAAO,oBAAoB,CAAC;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IACnC,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACtE,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,uBAAuB;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,uBAAuB;IACvC,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB","sourcesContent":["import type { FileSystem } from \"../../types.ts\";\nimport type { SessionCreateOptions, SessionMetadata } from \"../types.ts\";\n\nexport const JSONL_FORMAT_VERSION = 4;\nexport const JSONL_STORAGE_VERSION = 1;\n\nexport interface JsonlStorageHeader {\n\tv: typeof JSONL_FORMAT_VERSION;\n\tkind: \"header\";\n\tid: string;\n\tstorageVersion: number;\n\tcreatedAt: number;\n\tcwd: string;\n\tparentSessionId?: string;\n\tlegacyParentSessionPath?: string;\n\t/** Sequence high-water mark written by snapshot rewrites. */\n\tnextSeq?: number;\n}\n\nexport interface JsonlStorageOptions {\n\tfileSystem: FileSystem;\n\tpath: string;\n\tnow?: () => number;\n}\n\nexport interface JsonlSessionMetadata extends SessionMetadata {\n\tcwd: string;\n\tpath: string;\n\t/** Filesystem modification time as milliseconds since Unix epoch. */\n\tmodifiedAt: number;\n}\n\nexport interface JsonlSessionCreateOptions extends SessionCreateOptions {\n\tcwd: string;\n}\n\nexport interface JsonlSessionListOptions {\n\tcwd?: string;\n}\n\nexport interface JsonlSessionRepoOptions {\n\tfileSystem: FileSystem;\n\tsessionsRoot: string;\n\tnow?: () => number;\n}\n"]}
@@ -1,2 +1,3 @@
1
- export {};
1
+ export const JSONL_FORMAT_VERSION = 4;
2
+ export const JSONL_STORAGE_VERSION = 1;
2
3
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { FileSystem } from \"../../types.ts\";\nimport type { JsonValue, SessionCreateOptions, SessionMetadata } from \"../types.ts\";\n\nexport type JsonlSessionRepoFileSystem = Pick<\n\tFileSystem,\n\t| \"absolutePath\"\n\t| \"joinPath\"\n\t| \"readTextFile\"\n\t| \"readTextLines\"\n\t| \"writeFile\"\n\t| \"appendFile\"\n\t| \"renameFile\"\n\t| \"fileInfo\"\n\t| \"listDir\"\n\t| \"exists\"\n\t| \"createDir\"\n\t| \"remove\"\n>;\n\nexport interface JsonlSessionRepoOptions {\n\tfs: JsonlSessionRepoFileSystem;\n\t/** Root containing coding-agent-compatible cwd-encoded session directories. */\n\tsessionsRoot: string;\n}\n\nexport interface JsonlSessionMetadata extends SessionMetadata {\n\tcwd: string;\n\tpath: string;\n\t/** Filesystem modification time as milliseconds since Unix epoch. */\n\tmodifiedAt: number;\n\tsourceFormat: 3 | 4;\n\t/** Present only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\t/** Opaque application-owned metadata. */\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionCreateOptions extends SessionCreateOptions {\n\tcwd: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionListOptions {\n\tcwd?: string;\n}\n\nexport interface JsonlV4Header {\n\tkind: \"header\";\n\tversion: 4;\n\tid: string;\n\tcreatedAt: number;\n\tcwd: string;\n\tparentSessionId?: string;\n\t/** Preserved only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/types.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AACtC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC","sourcesContent":["import type { FileSystem } from \"../../types.ts\";\nimport type { SessionCreateOptions, SessionMetadata } from \"../types.ts\";\n\nexport const JSONL_FORMAT_VERSION = 4;\nexport const JSONL_STORAGE_VERSION = 1;\n\nexport interface JsonlStorageHeader {\n\tv: typeof JSONL_FORMAT_VERSION;\n\tkind: \"header\";\n\tid: string;\n\tstorageVersion: number;\n\tcreatedAt: number;\n\tcwd: string;\n\tparentSessionId?: string;\n\tlegacyParentSessionPath?: string;\n\t/** Sequence high-water mark written by snapshot rewrites. */\n\tnextSeq?: number;\n}\n\nexport interface JsonlStorageOptions {\n\tfileSystem: FileSystem;\n\tpath: string;\n\tnow?: () => number;\n}\n\nexport interface JsonlSessionMetadata extends SessionMetadata {\n\tcwd: string;\n\tpath: string;\n\t/** Filesystem modification time as milliseconds since Unix epoch. */\n\tmodifiedAt: number;\n}\n\nexport interface JsonlSessionCreateOptions extends SessionCreateOptions {\n\tcwd: string;\n}\n\nexport interface JsonlSessionListOptions {\n\tcwd?: string;\n}\n\nexport interface JsonlSessionRepoOptions {\n\tfileSystem: FileSystem;\n\tsessionsRoot: string;\n\tnow?: () => number;\n}\n"]}
@@ -1,44 +1,50 @@
1
- import { Session } from "./session.ts";
2
- import { type BranchBounds, type Entry, type EntryQuery, type ForkOptions, type LanePointer, type LaneRecord, type LogItem, type LogOptions, type NewRecord, type OperationStartedRecord, type ProvisionedEntry, type RecordQuery, type SessionCreateOptions, type SessionMetadata, type SessionRepo, type SessionStats, type SessionStorage } from "./types.ts";
3
- export declare class InMemorySessionStorage implements SessionStorage {
4
- private readonly metadata;
5
- private readonly state;
6
- constructor(metadata: SessionMetadata);
7
- fork(metadata: SessionMetadata, options: ForkOptions & SessionCreateOptions): InMemorySessionStorage;
8
- getMetadata(): Promise<SessionMetadata>;
9
- getLanes(): Promise<LanePointer[]>;
10
- createLane(lane: string, at: string | null): Promise<void>;
11
- moveLane(lane: string, to: string | null): Promise<void>;
12
- appendEntry<TEntry extends Entry>(newEntry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry>;
13
- appendRecord<TRecord extends LaneRecord>(newRecord: NewRecord<TRecord>): Promise<TRecord>;
14
- getEntry(id: string): Promise<Entry | undefined>;
15
- findEntries(query?: EntryQuery): Promise<Entry[]>;
16
- findEntriesOnBranch(query: EntryQuery & BranchBounds & {
17
- start: string;
18
- }): Promise<Entry[]>;
19
- findRecords<K extends LaneRecord["type"]>(query: RecordQuery & {
20
- type: K;
21
- }): Promise<Extract<LaneRecord, {
22
- type: K;
23
- }>[]>;
24
- findRecords(query?: RecordQuery): Promise<LaneRecord[]>;
25
- findOpenOperations(lane: string, options?: {
26
- limit?: number;
27
- }): Promise<OperationStartedRecord[]>;
28
- getLog(options?: LogOptions): Promise<LogItem[]>;
29
- getName(): Promise<string | undefined>;
30
- setName(name: string | undefined): Promise<void>;
31
- getLabel(id: string): Promise<string | undefined>;
32
- setLabel(id: string, label: string | undefined): Promise<void>;
33
- getStats(): Promise<SessionStats>;
1
+ import type { Context } from "../context.ts";
2
+ import { type ForkDestinationSnapshot, type ForkSourceSnapshot } from "./fork.ts";
3
+ import type { CommitResult, Entry, EntryScan, EntryStructure, ForkOptions, Session, SessionCreateOptions, SessionMetadata, SessionRepo, SessionStats, Storage, StorageBranchScan, UsageRow, UsageScan, Write } from "./types.ts";
4
+ import type { ListElement, ListReadOptions, StoredValue, Value, ValueList } from "./values.ts";
5
+ export interface MemoryStorageOptions {
6
+ now?: () => number;
34
7
  }
35
- export declare class InMemorySessionRepo implements SessionRepo {
8
+ export interface MemorySessionRepoOptions {
9
+ now?: () => number;
10
+ }
11
+ export declare class MemoryStorage implements Storage {
12
+ private readonly now;
13
+ private storageState;
14
+ private commitQueue;
15
+ private state;
16
+ private closePromise;
17
+ constructor(options?: MemoryStorageOptions);
18
+ commit(writes: Write[], _context: Context): Promise<CommitResult>;
19
+ getEntries(ids: string[], _context: Context): Promise<Map<string, Entry>>;
20
+ getValue<T>(address: Value<T>, _context: Context): Promise<StoredValue<T> | undefined>;
21
+ scanValues<T>(prefix: Value<T>, _context: Context): Promise<StoredValue<T>[]>;
22
+ readList<T>(address: ValueList<T>, options: ListReadOptions | undefined, _context: Context): Promise<ListElement<T>[]>;
23
+ scanBranch(query: StorageBranchScan, _context: Context): Promise<Entry[]>;
24
+ scanBranchStructure(query: StorageBranchScan, _context: Context): Promise<EntryStructure[]>;
25
+ scanEntries(query: EntryScan, _context: Context): Promise<Entry[]>;
26
+ scanUsage(query: UsageScan, _context: Context): Promise<UsageRow[]>;
27
+ getStats(_context: Context): Promise<SessionStats>;
28
+ /** Capture the state needed to fork at one serialized boundary between commits. */
29
+ captureForkSource(_context: Context): Promise<ForkSourceSnapshot>;
30
+ close(_context: Context): Promise<void>;
31
+ static fromSnapshot(options: MemoryStorageOptions, snapshot: ForkDestinationSnapshot): MemoryStorage;
32
+ }
33
+ export declare class MemorySessionRepo implements SessionRepo {
34
+ private readonly now;
36
35
  private readonly sessions;
37
- create(options?: SessionCreateOptions): Promise<Session>;
38
- open(metadata: SessionMetadata): Promise<Session>;
39
- list(): Promise<SessionMetadata[]>;
40
- delete(metadata: SessionMetadata): Promise<void>;
41
- fork(source: SessionMetadata, options?: ForkOptions & SessionCreateOptions): Promise<Session>;
42
- private requireStorage;
36
+ private readonly pendingIds;
37
+ private closed;
38
+ private closePromise;
39
+ constructor(options?: MemorySessionRepoOptions);
40
+ create(options: SessionCreateOptions, context: Context): Promise<Session>;
41
+ open(metadata: SessionMetadata, _context: Context): Promise<Session>;
42
+ list(_options: undefined, _context: Context): Promise<SessionMetadata[]>;
43
+ delete(metadata: SessionMetadata, context: Context): Promise<void>;
44
+ fork(source: SessionMetadata, options: ForkOptions, context: Context): Promise<Session>;
45
+ close(context: Context): Promise<void>;
46
+ private openRecord;
47
+ private reserveId;
48
+ private assertOpen;
43
49
  }
44
50
  //# sourceMappingURL=memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/harness/session/memory.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai\";\nimport { Session } from \"./session.ts\";\nimport { SessionState } from \"./state.ts\";\nimport {\n\ttype BranchBounds,\n\ttype Entry,\n\ttype EntryQuery,\n\ttype ForkOptions,\n\ttype LanePointer,\n\ttype LaneRecord,\n\ttype LogItem,\n\ttype LogOptions,\n\ttype NewRecord,\n\ttype OperationStartedRecord,\n\ttype ProvisionedEntry,\n\ttype RecordQuery,\n\ttype SessionCreateOptions,\n\tSessionError,\n\ttype SessionMetadata,\n\ttype SessionRepo,\n\ttype SessionStats,\n\ttype SessionStorage,\n} from \"./types.ts\";\n\nexport class InMemorySessionStorage implements SessionStorage {\n\tprivate readonly metadata: SessionMetadata;\n\tprivate readonly state = new SessionState();\n\n\tconstructor(metadata: SessionMetadata) {\n\t\tthis.metadata = structuredClone(metadata);\n\t}\n\n\tfork(metadata: SessionMetadata, options: ForkOptions & SessionCreateOptions): InMemorySessionStorage {\n\t\tconst storage = new InMemorySessionStorage(metadata);\n\t\tfor (const mutation of this.state.createForkMutations(options)) storage.state.applyMutation(mutation);\n\t\treturn storage;\n\t}\n\n\tasync getMetadata(): Promise<SessionMetadata> {\n\t\treturn structuredClone(this.metadata);\n\t}\n\n\tasync getLanes(): Promise<LanePointer[]> {\n\t\treturn this.state.getLanes();\n\t}\n\n\tasync createLane(lane: string, at: string | null): Promise<void> {\n\t\tthis.state.validateNewLane(lane);\n\t\tthis.state.validateTarget(at);\n\t\tthis.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: at });\n\t}\n\n\tasync moveLane(lane: string, to: string | null): Promise<void> {\n\t\tthis.state.requireLane(lane);\n\t\tthis.state.validateTarget(to);\n\t\tthis.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: to });\n\t}\n\n\tasync appendEntry<TEntry extends Entry>(newEntry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\tconst parentId = this.state.requireLane(lane);\n\t\tthis.state.validateUnusedId(newEntry.id);\n\t\tconst entry = {\n\t\t\t...structuredClone(newEntry),\n\t\t\tparentId,\n\t\t\tseq: this.state.nextSequence,\n\t\t\ttimestamp: Date.now(),\n\t\t} as unknown as TEntry;\n\t\tthis.state.applyMutation({ kind: \"entry\", lane, entry });\n\t\treturn structuredClone(entry);\n\t}\n\n\tasync appendRecord<TRecord extends LaneRecord>(newRecord: NewRecord<TRecord>): Promise<TRecord> {\n\t\tthis.state.requireLane(newRecord.lane);\n\t\tthis.state.validateUnusedId(newRecord.id);\n\t\tconst currentOpenOperationId = this.state.findOpenOperations(newRecord.lane, { limit: 1 })[0]?.id;\n\t\tif (newRecord.type === \"operation_started\" && currentOpenOperationId !== undefined) {\n\t\t\tthrow new SessionError(\n\t\t\t\t\"storage\",\n\t\t\t\t`Lane ${newRecord.lane} already has an open operation ${currentOpenOperationId}`,\n\t\t\t);\n\t\t}\n\t\tconst record = {\n\t\t\t...structuredClone(newRecord),\n\t\t\tseq: this.state.nextSequence,\n\t\t\ttimestamp: Date.now(),\n\t\t} as unknown as TRecord;\n\t\tthis.state.applyMutation({ kind: \"record\", record });\n\t\treturn structuredClone(record);\n\t}\n\n\tasync getEntry(id: string): Promise<Entry | undefined> {\n\t\tconst entry = this.state.getEntry(id);\n\t\treturn entry === undefined ? undefined : structuredClone(entry);\n\t}\n\n\tasync findEntries(query: EntryQuery = {}): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntries(query));\n\t}\n\n\tasync findEntriesOnBranch(query: EntryQuery & BranchBounds & { start: string }): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntriesOnBranch(query));\n\t}\n\n\tasync findRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\tasync findRecords(query: RecordQuery = {}): Promise<LaneRecord[]> {\n\t\treturn structuredClone(this.state.findRecords(query));\n\t}\n\n\tasync findOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]> {\n\t\treturn structuredClone(this.state.findOpenOperations(lane, options));\n\t}\n\n\tasync getLog(options: LogOptions = {}): Promise<LogItem[]> {\n\t\treturn structuredClone(this.state.getLog(options));\n\t}\n\n\tasync getName(): Promise<string | undefined> {\n\t\treturn this.state.getName();\n\t}\n\n\tasync setName(name: string | undefined): Promise<void> {\n\t\tthis.state.applyMutation({ kind: \"fact\", seq: this.state.nextSequence, fact: \"name\", name });\n\t}\n\n\tasync getLabel(id: string): Promise<string | undefined> {\n\t\treturn this.state.getLabel(id);\n\t}\n\n\tasync setLabel(id: string, label: string | undefined): Promise<void> {\n\t\tthis.state.validateTarget(id);\n\t\tthis.state.applyMutation({\n\t\t\tkind: \"fact\",\n\t\t\tseq: this.state.nextSequence,\n\t\t\tfact: \"label\",\n\t\t\ttargetId: id,\n\t\t\tlabel,\n\t\t});\n\t}\n\n\tasync getStats(): Promise<SessionStats> {\n\t\treturn structuredClone(this.state.getStats());\n\t}\n}\n\nexport class InMemorySessionRepo implements SessionRepo {\n\tprivate readonly sessions = new Map<string, InMemorySessionStorage>();\n\n\tasync create(options: SessionCreateOptions = {}): Promise<Session> {\n\t\tconst id = options.id ?? uuidv7();\n\t\tif (this.sessions.has(id)) throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\tconst storage = new InMemorySessionStorage({\n\t\t\tid,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tparentSessionId: options.parentSessionId,\n\t\t});\n\t\tthis.sessions.set(id, storage);\n\t\treturn new Session(storage);\n\t}\n\n\tasync open(metadata: SessionMetadata): Promise<Session> {\n\t\treturn new Session(this.requireStorage(metadata.id));\n\t}\n\n\tasync list(): Promise<SessionMetadata[]> {\n\t\treturn Promise.all([...this.sessions.values()].map((storage) => storage.getMetadata()));\n\t}\n\n\tasync delete(metadata: SessionMetadata): Promise<void> {\n\t\tthis.sessions.delete(metadata.id);\n\t}\n\n\tasync fork(source: SessionMetadata, options: ForkOptions & SessionCreateOptions = {}): Promise<Session> {\n\t\tconst sourceStorage = this.requireStorage(source.id);\n\t\tconst id = options.id ?? uuidv7();\n\t\tif (this.sessions.has(id)) throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\tconst storage = sourceStorage.fork(\n\t\t\t{ id, createdAt: Date.now(), parentSessionId: options.parentSessionId ?? source.id },\n\t\t\toptions,\n\t\t);\n\t\tthis.sessions.set(id, storage);\n\t\treturn new Session(storage);\n\t}\n\n\tprivate requireStorage(id: string): InMemorySessionStorage {\n\t\tconst storage = this.sessions.get(id);\n\t\tif (!storage) throw new SessionError(\"not_found\", `Session not found: ${id}`);\n\t\treturn storage;\n\t}\n}\n"]}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/harness/session/memory.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai/utils/uuid\";\nimport type { Context } from \"../context.ts\";\nimport {\n\tcreateForkSnapshot,\n\ttype ForkDestinationSnapshot,\n\ttype ForkSourceSnapshot,\n\tforkSnapshotWrites,\n} from \"./fork.ts\";\nimport { InMemoryStorageState } from \"./in-memory-storage-state.ts\";\nimport { StorageBackedSession } from \"./session.ts\";\nimport type {\n\tBranch,\n\tCommitResult,\n\tEntry,\n\tEntryQuery,\n\tEntryScan,\n\tEntryStructure,\n\tForkOptions,\n\tIdGenerator,\n\tSession,\n\tSessionCreateOptions,\n\tSessionMetadata,\n\tSessionMutation,\n\tSessionMutationCallback,\n\tSessionRepo,\n\tSessionStats,\n\tStorage,\n\tStorageBranchScan,\n\tUsageRow,\n\tUsageScan,\n\tWrite,\n} from \"./types.ts\";\nimport type { ListElement, ListReadOptions, StoredValue, Value, ValueList } from \"./values.ts\";\n\nexport interface MemoryStorageOptions {\n\tnow?: () => number;\n}\n\nexport interface MemorySessionRepoOptions {\n\tnow?: () => number;\n}\n\nexport class MemoryStorage implements Storage {\n\tprivate readonly now: () => number;\n\tprivate storageState = new InMemoryStorageState();\n\tprivate commitQueue: Promise<void> = Promise.resolve();\n\tprivate state: \"open\" | \"closing\" | \"closed\" = \"open\";\n\tprivate closePromise: Promise<void> | undefined;\n\n\tconstructor(options: MemoryStorageOptions = {}) {\n\t\tthis.now = options.now ?? Date.now;\n\t}\n\n\tasync commit(writes: Write[], _context: Context): Promise<CommitResult> {\n\t\tif (this.state !== \"open\") throw new Error(\"MemoryStorage is closed\");\n\t\tconst result = this.commitQueue.then(() => {\n\t\t\tconst prepared = this.storageState.prepareCommit(writes, this.now());\n\t\t\tconst stats = this.storageState.applyValidated(prepared.writes);\n\t\t\treturn { ...prepared.result, stats };\n\t\t});\n\t\tthis.commitQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n\n\tgetEntries(ids: string[], _context: Context): Promise<Map<string, Entry>> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"MemoryStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.getEntries(ids));\n\t}\n\n\tgetValue<T>(address: Value<T>, _context: Context): Promise<StoredValue<T> | undefined> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"MemoryStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.getValue(address));\n\t}\n\n\tscanValues<T>(prefix: Value<T>, _context: Context): Promise<StoredValue<T>[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"MemoryStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.scanValues(prefix));\n\t}\n\n\tasync readList<T>(\n\t\taddress: ValueList<T>,\n\t\toptions: ListReadOptions | undefined,\n\t\t_context: Context,\n\t): Promise<ListElement<T>[]> {\n\t\tif (this.state !== \"open\") throw new Error(\"MemoryStorage is closed\");\n\t\treturn this.storageState.readList(address, options);\n\t}\n\n\tasync scanBranch(query: StorageBranchScan, _context: Context): Promise<Entry[]> {\n\t\tif (this.state !== \"open\") throw new Error(\"MemoryStorage is closed\");\n\t\treturn this.storageState.scanBranch(query);\n\t}\n\n\tasync scanBranchStructure(query: StorageBranchScan, _context: Context): Promise<EntryStructure[]> {\n\t\tif (this.state !== \"open\") throw new Error(\"MemoryStorage is closed\");\n\t\treturn this.storageState.scanBranchStructure(query);\n\t}\n\n\tscanEntries(query: EntryScan, _context: Context): Promise<Entry[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"MemoryStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.scanEntries(query));\n\t}\n\n\tscanUsage(query: UsageScan, _context: Context): Promise<UsageRow[]> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"MemoryStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.scanUsage(query));\n\t}\n\n\tgetStats(_context: Context): Promise<SessionStats> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"MemoryStorage is closed\"));\n\t\treturn Promise.resolve(this.storageState.getStats());\n\t}\n\n\t/** Capture the state needed to fork at one serialized boundary between commits. */\n\tcaptureForkSource(_context: Context): Promise<ForkSourceSnapshot> {\n\t\tif (this.state !== \"open\") return Promise.reject(new Error(\"MemoryStorage is closed\"));\n\t\tconst result = this.commitQueue.then(() => this.storageState.snapshotEntriesAndValues());\n\t\tthis.commitQueue = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn result;\n\t}\n\n\tclose(_context: Context): Promise<void> {\n\t\tif (this.closePromise !== undefined) return this.closePromise;\n\t\tthis.state = \"closing\";\n\t\tthis.closePromise = this.commitQueue.then(() => {\n\t\t\tthis.state = \"closed\";\n\t\t});\n\t\treturn this.closePromise;\n\t}\n\n\tstatic fromSnapshot(options: MemoryStorageOptions, snapshot: ForkDestinationSnapshot): MemoryStorage {\n\t\tconst storage = new MemoryStorage(options);\n\t\tconst writes = forkSnapshotWrites(snapshot);\n\t\tstorage.storageState.validateCommitted(writes);\n\t\tstorage.storageState.applyValidated(writes);\n\t\treturn storage;\n\t}\n}\n\nconst MEMORY_STORAGE_VERSION = 1;\n\ninterface MemorySessionRecord {\n\tmetadata: SessionMetadata;\n\tstorage: MemoryStorage;\n\tsession: StorageBackedSession;\n\topen: boolean;\n}\n\nclass MemorySessionFacade implements Session {\n\treadonly metadata: SessionMetadata;\n\treadonly idGenerator: IdGenerator;\n\tprivate readonly session: StorageBackedSession;\n\tprivate readonly onClose: () => void;\n\tprivate readonly admitted = new Set<Promise<unknown>>();\n\tprivate readonly closedError = new Error(\"Session is closed\");\n\tprivate state: \"open\" | \"closing\" | \"closed\" = \"open\";\n\tprivate closePromise: Promise<void> | undefined;\n\n\tconstructor(session: StorageBackedSession, onClose: () => void) {\n\t\tthis.session = session;\n\t\tthis.metadata = session.metadata;\n\t\tthis.idGenerator = session.idGenerator;\n\t\tthis.onClose = onClose;\n\t}\n\n\tasync beginMutation(context: Context): Promise<SessionMutation> {\n\t\tlet resolveFinished!: () => void;\n\t\tconst finished = new Promise<void>((resolve) => {\n\t\t\tresolveFinished = resolve;\n\t\t});\n\t\tthis.admitted.add(finished);\n\t\tlet source: SessionMutation;\n\t\ttry {\n\t\t\tsource = await this.admit(() => this.session.beginMutation(context));\n\t\t} catch (error) {\n\t\t\tthis.admitted.delete(finished);\n\t\t\tresolveFinished();\n\t\t\tthrow error;\n\t\t}\n\t\tif (this.state !== \"open\") {\n\t\t\tawait source.end(context);\n\t\t\tthis.admitted.delete(finished);\n\t\t\tresolveFinished();\n\t\t\tthrow this.closedError;\n\t\t}\n\t\tlet ended = false;\n\t\treturn {\n\t\t\tcommit: (writes, commitContext) => source.commit(writes, commitContext),\n\t\t\tend: async (endContext) => {\n\t\t\t\ttry {\n\t\t\t\t\tawait source.end(endContext);\n\t\t\t\t} finally {\n\t\t\t\t\tif (!ended) {\n\t\t\t\t\t\tended = true;\n\t\t\t\t\t\tthis.admitted.delete(finished);\n\t\t\t\t\t\tresolveFinished();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tgetEntries: (ids, readContext) => source.getEntries(ids, readContext),\n\t\t\tgetStats: (readContext) => source.getStats(readContext),\n\t\t\tgetValue: (address, readContext) => source.getValue(address, readContext),\n\t\t\tscanValues: (prefix, readContext) => source.scanValues(prefix, readContext),\n\t\t\treadList: (address, options, readContext) => source.readList(address, options, readContext),\n\t\t\tscanBranch: (query, readContext) => source.scanBranch(query, readContext),\n\t\t};\n\t}\n\n\tmutate<T>(mutation: SessionMutationCallback<T>, context: Context): Promise<T> {\n\t\treturn this.admit(() =>\n\t\t\tthis.session.mutate((mutator, mutationContext) => {\n\t\t\t\tif (this.state !== \"open\") throw this.closedError;\n\t\t\t\treturn mutation(mutator, mutationContext);\n\t\t\t}, context),\n\t\t);\n\t}\n\n\tgetEntries(ids: string[], context: Context): Promise<Map<string, Entry>> {\n\t\treturn this.admit(() => this.session.getEntries(ids, context));\n\t}\n\n\tgetEntry(id: string, context: Context): Promise<Entry | undefined> {\n\t\treturn this.admit(() => this.session.getEntry(id, context));\n\t}\n\n\tgetValue<T>(address: Value<T>, context: Context): Promise<StoredValue<T> | undefined> {\n\t\treturn this.admit(() => this.session.getValue(address, context));\n\t}\n\n\tscanValues<T>(prefix: Value<T>, context: Context): Promise<StoredValue<T>[]> {\n\t\treturn this.admit(() => this.session.scanValues(prefix, context));\n\t}\n\n\treadList<T>(\n\t\taddress: ValueList<T>,\n\t\toptions: ListReadOptions | undefined,\n\t\tcontext: Context,\n\t): Promise<ListElement<T>[]> {\n\t\treturn this.admit(() => this.session.readList(address, options, context));\n\t}\n\n\tscanBranch(query: StorageBranchScan, context: Context): Promise<Entry[]> {\n\t\treturn this.admit(() => this.session.scanBranch(query, context));\n\t}\n\n\tgetStats(context: Context): Promise<SessionStats> {\n\t\treturn this.admit(() => this.session.getStats(context));\n\t}\n\n\tgetName(context: Context): Promise<string | undefined> {\n\t\treturn this.admit(() => this.session.getName(context));\n\t}\n\n\tgetLabel(targetId: string, context: Context): Promise<string | undefined> {\n\t\treturn this.admit(() => this.session.getLabel(targetId, context));\n\t}\n\n\tfindEntries(query: EntryQuery | undefined, context: Context): Promise<Entry[]> {\n\t\treturn this.admit(() => this.session.findEntries(query, context));\n\t}\n\n\tfindEntry(query: EntryQuery | undefined, context: Context): Promise<Entry | undefined> {\n\t\treturn this.admit(() => this.session.findEntry(query, context));\n\t}\n\n\tasync branch(name: string, context: Context): Promise<Branch | undefined> {\n\t\tconst branch = await this.admit(() => this.session.branch(name, context));\n\t\treturn branch === undefined ? undefined : this.wrapBranch(branch);\n\t}\n\n\tasync createBranch(name: string, at: string | null, context: Context): Promise<Branch> {\n\t\treturn this.wrapBranch(await this.admit(() => this.session.createBranch(name, at, context)));\n\t}\n\n\tsetValue<T>(address: Value<T>, next: NoInfer<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.setValue(address, next, context));\n\t}\n\n\tdeleteValue<T>(address: Value<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.deleteValue(address, context));\n\t}\n\n\tappendList<T>(address: ValueList<T>, element: NoInfer<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.appendList(address, element, context));\n\t}\n\n\tdeleteList<T>(address: ValueList<T>, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.deleteList(address, context));\n\t}\n\n\tsetName(name: string | undefined, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.setName(name, context));\n\t}\n\n\tsetLabel(targetId: string, label: string | undefined, context: Context): Promise<void> {\n\t\treturn this.admit(() => this.session.setLabel(targetId, label, context));\n\t}\n\n\tclose(_context: Context): Promise<void> {\n\t\tif (this.closePromise !== undefined) return this.closePromise;\n\t\tthis.state = \"closing\";\n\t\tthis.closePromise = Promise.allSettled([...this.admitted]).then(() => {\n\t\t\tthis.state = \"closed\";\n\t\t\tthis.onClose();\n\t\t});\n\t\treturn this.closePromise;\n\t}\n\n\tprivate wrapBranch(branch: Branch): Branch {\n\t\treturn {\n\t\t\tname: branch.name,\n\t\t\tgetTipId: (context) => this.admit(() => branch.getTipId(context)),\n\t\t\tfindEntries: (query, context) => this.admit(() => branch.findEntries(query, context)),\n\t\t\tfindEntry: (query, context) => this.admit(() => branch.findEntry(query, context)),\n\t\t\tappendMessage: (message, context) => this.admit(() => branch.appendMessage(message, context)),\n\t\t\tappendCustomEntry: (customType, data, context) =>\n\t\t\t\tthis.admit(() => branch.appendCustomEntry(customType, data, context)),\n\t\t};\n\t}\n\n\tprivate admit<T>(operation: () => Promise<T>): Promise<T> {\n\t\tif (this.state !== \"open\") return Promise.reject(this.closedError);\n\t\tlet result: Promise<T>;\n\t\ttry {\n\t\t\tresult = operation();\n\t\t} catch (error) {\n\t\t\tresult = Promise.reject(error);\n\t\t}\n\t\tthis.admitted.add(result);\n\t\tvoid result.then(\n\t\t\t() => this.admitted.delete(result),\n\t\t\t() => this.admitted.delete(result),\n\t\t);\n\t\treturn result;\n\t}\n}\n\nexport class MemorySessionRepo implements SessionRepo {\n\tprivate readonly now: () => number;\n\tprivate readonly sessions = new Map<string, MemorySessionRecord>();\n\tprivate readonly pendingIds = new Set<string>();\n\tprivate closed = false;\n\tprivate closePromise: Promise<void> | undefined;\n\n\tconstructor(options: MemorySessionRepoOptions = {}) {\n\t\tthis.now = options.now ?? Date.now;\n\t}\n\n\tasync create(options: SessionCreateOptions, context: Context): Promise<Session> {\n\t\tthis.assertOpen();\n\t\tconst createdAt = this.now();\n\t\tconst id = options.id ?? uuidv7(createdAt);\n\t\tthis.reserveId(id);\n\t\tconst metadata: SessionMetadata = {\n\t\t\tid,\n\t\t\tcreatedAt,\n\t\t\tstorageVersion: MEMORY_STORAGE_VERSION,\n\t\t\t...(options.parentSessionId === undefined ? {} : { parentSessionId: options.parentSessionId }),\n\t\t};\n\t\tconst storage = new MemoryStorage({ now: this.now });\n\t\tconst session = new StorageBackedSession(metadata, storage);\n\t\ttry {\n\t\t\tconst record: MemorySessionRecord = {\n\t\t\t\tmetadata,\n\t\t\t\tstorage,\n\t\t\t\tsession,\n\t\t\t\topen: true,\n\t\t\t};\n\t\t\tthis.sessions.set(id, record);\n\t\t\treturn this.openRecord(record);\n\t\t} catch (error) {\n\t\t\tawait session.close(context);\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tthis.pendingIds.delete(id);\n\t\t}\n\t}\n\n\topen(metadata: SessionMetadata, _context: Context): Promise<Session> {\n\t\t// Memory sessions are always created at the current storage version, so\n\t\t// persistent-backend version gating does not apply here.\n\t\tthis.assertOpen();\n\t\tconst record = this.sessions.get(metadata.id);\n\t\tif (record === undefined) return Promise.reject(new Error(`Unknown session: ${metadata.id}`));\n\t\tif (record.open) return Promise.reject(new Error(`Session is already open: ${metadata.id}`));\n\t\trecord.open = true;\n\t\treturn Promise.resolve(this.openRecord(record));\n\t}\n\n\tlist(_options: undefined, _context: Context): Promise<SessionMetadata[]> {\n\t\tthis.assertOpen();\n\t\treturn Promise.resolve([...this.sessions.values()].map(({ metadata }) => metadata));\n\t}\n\n\tasync delete(metadata: SessionMetadata, context: Context): Promise<void> {\n\t\tthis.assertOpen();\n\t\tconst record = this.sessions.get(metadata.id);\n\t\tif (record === undefined) throw new Error(`Unknown session: ${metadata.id}`);\n\t\tif (record.open) throw new Error(`Session is open: ${metadata.id}`);\n\t\tawait record.session.close(context);\n\t\tthis.sessions.delete(metadata.id);\n\t}\n\n\tasync fork(source: SessionMetadata, options: ForkOptions, context: Context): Promise<Session> {\n\t\tthis.assertOpen();\n\t\tconst sourceRecord = this.sessions.get(source.id);\n\t\tif (sourceRecord === undefined) throw new Error(`Unknown session: ${source.id}`);\n\t\tconst createdAt = this.now();\n\t\tconst id = options.id ?? uuidv7(createdAt);\n\t\tthis.reserveId(id);\n\n\t\ttry {\n\t\t\tconst snapshot = createForkSnapshot(await sourceRecord.storage.captureForkSource(context), options);\n\t\t\tconst storage = MemoryStorage.fromSnapshot({ now: this.now }, snapshot);\n\t\t\tconst metadata: SessionMetadata = {\n\t\t\t\tid,\n\t\t\t\tcreatedAt,\n\t\t\t\tstorageVersion: MEMORY_STORAGE_VERSION,\n\t\t\t\tparentSessionId: sourceRecord.metadata.id,\n\t\t\t};\n\t\t\tconst session = new StorageBackedSession(metadata, storage);\n\t\t\tconst record: MemorySessionRecord = {\n\t\t\t\tmetadata,\n\t\t\t\tstorage,\n\t\t\t\tsession,\n\t\t\t\topen: true,\n\t\t\t};\n\t\t\tthis.sessions.set(id, record);\n\t\t\treturn this.openRecord(record);\n\t\t} finally {\n\t\t\tthis.pendingIds.delete(id);\n\t\t}\n\t}\n\n\tclose(context: Context): Promise<void> {\n\t\tif (this.closePromise !== undefined) return this.closePromise;\n\t\tthis.closed = true;\n\t\tthis.closePromise = Promise.all([...this.sessions.values()].map(({ session }) => session.close(context))).then(\n\t\t\t() => undefined,\n\t\t);\n\t\treturn this.closePromise;\n\t}\n\n\tprivate openRecord(record: MemorySessionRecord): Session {\n\t\treturn new MemorySessionFacade(record.session, () => {\n\t\t\trecord.open = false;\n\t\t});\n\t}\n\n\tprivate reserveId(id: string): void {\n\t\tif (this.sessions.has(id) || this.pendingIds.has(id)) throw new Error(`Session already exists: ${id}`);\n\t\tthis.pendingIds.add(id);\n\t}\n\n\tprivate assertOpen(): void {\n\t\tif (this.closed) throw new Error(\"MemorySessionRepo is closed\");\n\t}\n}\n"]}