@myagentroam/agent 0.11.33 → 0.11.34

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 (856) hide show
  1. package/dist/cli/catalog-file.d.ts +78 -0
  2. package/dist/cli/catalog-file.js +102 -0
  3. package/dist/cli/codex-auth-file.d.ts +1 -1
  4. package/dist/cli/codex-auth-file.js +9 -10
  5. package/dist/cli/main.js +44 -54
  6. package/dist/error.d.ts +15 -0
  7. package/dist/error.js +74 -0
  8. package/dist/extensions/agents.d.ts +100 -0
  9. package/dist/extensions/agents.js +121 -0
  10. package/dist/extensions/capabilities.d.ts +4 -0
  11. package/dist/extensions/commands.d.ts +23 -0
  12. package/dist/extensions/commands.js +45 -0
  13. package/dist/extensions/compaction.d.ts +36 -0
  14. package/dist/extensions/contracts.d.ts +147 -0
  15. package/dist/extensions/data.d.ts +81 -0
  16. package/dist/extensions/data.js +78 -0
  17. package/dist/extensions/environment.d.ts +39 -0
  18. package/dist/extensions/environment.js +52 -0
  19. package/dist/extensions/files.d.ts +68 -0
  20. package/dist/extensions/files.js +26 -0
  21. package/dist/extensions/hooks.d.ts +32 -0
  22. package/dist/extensions/host-ports.d.ts +24 -0
  23. package/dist/extensions/manager.d.ts +42 -0
  24. package/dist/extensions/manager.js +457 -0
  25. package/dist/extensions/mcp.d.ts +116 -0
  26. package/dist/extensions/mcp.js +434 -0
  27. package/dist/extensions/model-request.d.ts +65 -0
  28. package/dist/extensions/model-request.js +197 -0
  29. package/dist/extensions/model-stream.d.ts +18 -0
  30. package/dist/extensions/model-stream.js +108 -0
  31. package/dist/extensions/models.d.ts +46 -0
  32. package/dist/extensions/models.js +7 -0
  33. package/dist/extensions/network.d.ts +40 -0
  34. package/dist/extensions/network.js +97 -0
  35. package/dist/extensions/operation.d.ts +32 -0
  36. package/dist/extensions/processes.d.ts +64 -0
  37. package/dist/extensions/processes.js +284 -0
  38. package/dist/extensions/prompt-composition.d.ts +38 -0
  39. package/dist/extensions/prompt-composition.js +100 -0
  40. package/dist/extensions/prompt-input.d.ts +30 -0
  41. package/dist/extensions/prompt-input.js +48 -0
  42. package/dist/extensions/prompts.d.ts +31 -0
  43. package/dist/extensions/prompts.js +88 -0
  44. package/dist/extensions/resources.d.ts +26 -0
  45. package/dist/extensions/resources.js +221 -0
  46. package/dist/extensions/services.d.ts +31 -0
  47. package/dist/extensions/services.js +61 -0
  48. package/dist/extensions/session-api.d.ts +6 -0
  49. package/dist/extensions/session-api.js +52 -0
  50. package/dist/extensions/session-input.d.ts +184 -0
  51. package/dist/extensions/session-input.js +422 -0
  52. package/dist/extensions/session-messages.d.ts +41 -0
  53. package/dist/extensions/session-messages.js +76 -0
  54. package/dist/extensions/session-tools.d.ts +32 -0
  55. package/dist/extensions/session-tools.js +208 -0
  56. package/dist/extensions/session.d.ts +60 -0
  57. package/dist/extensions/session.js +265 -0
  58. package/dist/extensions/settings.d.ts +76 -0
  59. package/dist/extensions/settings.js +115 -0
  60. package/dist/extensions/store.d.ts +10 -0
  61. package/dist/extensions/store.js +131 -0
  62. package/dist/extensions/tool-runtime.d.ts +16 -0
  63. package/dist/extensions/tools.d.ts +80 -0
  64. package/dist/extensions/tools.js +270 -0
  65. package/dist/extensions.d.ts +22 -0
  66. package/dist/host/contracts.d.ts +58 -0
  67. package/dist/host/contracts.js +18 -0
  68. package/dist/host/description.d.ts +19 -0
  69. package/dist/host/local-agent-host.d.ts +96 -0
  70. package/dist/host/local-agent-host.js +429 -0
  71. package/dist/host/local-exec-tool.d.ts +26 -0
  72. package/dist/host/local-exec-tool.js +686 -0
  73. package/dist/host/local-file-access.d.ts +30 -0
  74. package/dist/host/local-file-access.js +107 -0
  75. package/dist/host/local-network-access.d.ts +6 -0
  76. package/dist/host/local-network-access.js +101 -0
  77. package/dist/host/local-process-executor.d.ts +5 -0
  78. package/dist/host/local-process-executor.js +17 -0
  79. package/dist/host/local-session-environment.d.ts +18 -0
  80. package/dist/host/local-shell.d.ts +3 -0
  81. package/dist/host/local-tool-registry.d.ts +34 -0
  82. package/dist/host/local-tool-registry.js +134 -0
  83. package/dist/host/network.d.ts +5 -0
  84. package/dist/host/network.js +42 -0
  85. package/dist/host/process-control.d.ts +2 -0
  86. package/dist/host/process-control.js +26 -0
  87. package/dist/host/skill-contract.d.ts +6 -0
  88. package/dist/host.d.ts +17 -0
  89. package/dist/host.js +3 -0
  90. package/dist/index.d.ts +26 -51
  91. package/dist/index.js +9 -12
  92. package/dist/model/anthropic-messages.d.ts +10 -0
  93. package/dist/model/anthropic-messages.js +692 -0
  94. package/dist/model/anthropic-thinking.js +33 -0
  95. package/dist/model/configuration.d.ts +111 -0
  96. package/dist/model/configuration.js +201 -0
  97. package/dist/model/contracts.d.ts +229 -0
  98. package/dist/model/http.d.ts +13 -0
  99. package/dist/model/http.js +119 -0
  100. package/dist/model/image-contract.d.ts +10 -0
  101. package/dist/model/image.d.ts +9 -0
  102. package/dist/model/inline-media-budget.d.ts +7 -0
  103. package/dist/model/inline-media-budget.js +36 -0
  104. package/dist/model/input-images.d.ts +3 -0
  105. package/dist/model/input-images.js +16 -0
  106. package/dist/model/openai-responses.d.ts +59 -0
  107. package/dist/model/openai-responses.js +1586 -0
  108. package/dist/model/recovery.js +80 -0
  109. package/dist/model/request-configuration.d.ts +17 -0
  110. package/dist/model/request-configuration.js +47 -0
  111. package/dist/model/responses-event-projection.d.ts +24 -0
  112. package/dist/model/responses-event-projection.js +194 -0
  113. package/dist/model/responses-request.d.ts +5 -0
  114. package/dist/model/responses-request.js +363 -0
  115. package/dist/model/responses-session-cache.d.ts +33 -0
  116. package/dist/model/responses-session-cache.js +64 -0
  117. package/dist/model/runtime-credential.d.ts +1 -0
  118. package/dist/model/runtime-credential.js +1 -0
  119. package/dist/model/sse.js +281 -0
  120. package/dist/model/text-blocks.js +40 -0
  121. package/dist/model/tool-declarations.d.ts +4 -0
  122. package/dist/model/tool-definition-projection.d.ts +6 -0
  123. package/dist/model/tool-definition-projection.js +11 -0
  124. package/dist/model/tool-schema.d.ts +2 -0
  125. package/dist/model/tool-schema.js +17 -0
  126. package/dist/model/transport-test.d.ts +10 -0
  127. package/dist/model/transport-test.js +27 -0
  128. package/dist/model/usage-observer.d.ts +5 -0
  129. package/dist/model/usage.d.ts +40 -0
  130. package/dist/network/credential-runtime.d.ts +8 -0
  131. package/dist/network/credential-runtime.js +72 -0
  132. package/dist/network/credentials.d.ts +20 -0
  133. package/dist/network/credentials.js +18 -0
  134. package/dist/network/http.d.ts +20 -0
  135. package/dist/network/http.js +421 -0
  136. package/dist/network/product-user-agent.d.ts +5 -0
  137. package/dist/network/product-user-agent.js +22 -0
  138. package/dist/network/transport-error.d.ts +5 -0
  139. package/dist/network/transport-error.js +31 -0
  140. package/dist/process/contracts.d.ts +26 -0
  141. package/dist/prompts/index.d.ts +20 -0
  142. package/dist/prompts/index.js +49 -0
  143. package/dist/prompts/prompt-sections.d.ts +6 -0
  144. package/dist/prompts/prompt-sections.js +6 -0
  145. package/dist/prompts/read-context.js +152 -0
  146. package/dist/runtime/compaction/contracts.d.ts +23 -0
  147. package/dist/runtime/compaction/coordinator.js +88 -0
  148. package/dist/runtime/compaction/generate.d.ts +31 -0
  149. package/dist/runtime/compaction/generate.js +84 -0
  150. package/dist/runtime/compaction/history.d.ts +16 -0
  151. package/dist/runtime/compaction/operation.d.ts +30 -0
  152. package/dist/runtime/compaction/operation.js +131 -0
  153. package/dist/runtime/compaction/requests.d.ts +16 -0
  154. package/dist/runtime/compaction/requests.js +114 -0
  155. package/dist/runtime/compaction/retained-context.d.ts +6 -0
  156. package/dist/runtime/compaction/retained-context.js +48 -0
  157. package/dist/runtime/compaction/smart.d.ts +14 -0
  158. package/dist/runtime/compaction/smart.js +59 -0
  159. package/dist/runtime/context/contextual-blocks.d.ts +31 -0
  160. package/dist/runtime/context/contextual-blocks.js +158 -0
  161. package/dist/runtime/context/environment.d.ts +5 -0
  162. package/dist/runtime/context/gc-candidates-code.d.ts +6 -0
  163. package/dist/runtime/context/gc-candidates-code.js +102 -0
  164. package/dist/runtime/context/gc-candidates-exec.d.ts +6 -0
  165. package/dist/runtime/context/gc-candidates-exec.js +131 -0
  166. package/dist/runtime/context/gc-candidates-read-patch.d.ts +7 -0
  167. package/dist/runtime/context/gc-candidates-read-patch.js +118 -0
  168. package/dist/runtime/context/gc-candidates-subagent.d.ts +6 -0
  169. package/dist/runtime/context/gc-candidates-subagent.js +100 -0
  170. package/dist/runtime/context/gc-candidates-web.d.ts +6 -0
  171. package/dist/runtime/context/gc-candidates-web.js +58 -0
  172. package/dist/runtime/context/gc-candidates.d.ts +12 -0
  173. package/dist/runtime/context/gc-candidates.js +192 -0
  174. package/dist/runtime/context/gc-contracts.d.ts +57 -0
  175. package/dist/runtime/context/gc-economics.d.ts +48 -0
  176. package/dist/runtime/context/gc-economics.js +161 -0
  177. package/dist/runtime/context/gc-runtime.d.ts +43 -0
  178. package/dist/runtime/context/gc-tokens.d.ts +26 -0
  179. package/dist/runtime/context/gc-tokens.js +106 -0
  180. package/dist/runtime/context/gc.d.ts +7 -0
  181. package/dist/runtime/context/gc.js +552 -0
  182. package/dist/runtime/context/instructions.d.ts +37 -0
  183. package/dist/runtime/context/instructions.js +297 -0
  184. package/dist/runtime/context/normalize.d.ts +5 -0
  185. package/dist/runtime/context/projection.d.ts +23 -0
  186. package/dist/runtime/context/projection.js +284 -0
  187. package/dist/runtime/context/request-budget.d.ts +5 -0
  188. package/dist/runtime/context/request-budget.js +25 -0
  189. package/dist/runtime/context/restore.d.ts +27 -0
  190. package/dist/runtime/context/restore.js +186 -0
  191. package/dist/runtime/context/usage.d.ts +17 -0
  192. package/dist/runtime/context/usage.js +124 -0
  193. package/dist/runtime/context/world-state.d.ts +34 -0
  194. package/dist/runtime/context/world-state.js +232 -0
  195. package/dist/runtime/contracts.d.ts +29 -0
  196. package/dist/runtime/event-projection.d.ts +14 -0
  197. package/dist/runtime/event-projection.js +87 -0
  198. package/dist/runtime/events.d.ts +195 -0
  199. package/dist/runtime/execution-handle.d.ts +12 -0
  200. package/dist/runtime/execution-handle.js +1 -0
  201. package/dist/runtime/execution.d.ts +55 -0
  202. package/dist/runtime/execution.js +444 -0
  203. package/dist/runtime/model-progress.js +85 -0
  204. package/dist/runtime/resource-publication.d.ts +27 -0
  205. package/dist/runtime/resource-publication.js +60 -0
  206. package/dist/runtime/tool-round-contract.d.ts +19 -0
  207. package/dist/runtime/tool-round-contract.js +1 -0
  208. package/dist/runtime/wait.js +82 -0
  209. package/dist/sandbox/linux/bubblewrap-sandbox-executor.d.ts +1 -1
  210. package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +8 -8
  211. package/dist/sdk/agent.d.ts +7 -0
  212. package/dist/sdk/agent.js +321 -0
  213. package/dist/sdk/execution-code-mode.d.ts +18 -0
  214. package/dist/sdk/execution-code-mode.js +51 -0
  215. package/dist/sdk/execution-compact-commit.d.ts +23 -0
  216. package/dist/sdk/execution-compact-commit.js +41 -0
  217. package/dist/sdk/execution-compact-extension.d.ts +12 -0
  218. package/dist/sdk/execution-compact-extension.js +46 -0
  219. package/dist/sdk/execution-compact-generation.d.ts +17 -0
  220. package/dist/sdk/execution-compact-generation.js +30 -0
  221. package/dist/sdk/execution-compaction-flight.d.ts +31 -0
  222. package/dist/sdk/execution-compaction-flight.js +50 -0
  223. package/dist/sdk/execution-compaction.d.ts +47 -0
  224. package/dist/sdk/execution-compaction.js +121 -0
  225. package/dist/sdk/execution-context-coordinator.d.ts +56 -0
  226. package/dist/sdk/execution-context-coordinator.js +102 -0
  227. package/dist/sdk/execution-input.d.ts +58 -0
  228. package/dist/sdk/execution-input.js +266 -0
  229. package/dist/sdk/execution-model-context.d.ts +52 -0
  230. package/dist/sdk/execution-model-context.js +156 -0
  231. package/dist/sdk/execution-model-lifecycle.d.ts +39 -0
  232. package/dist/sdk/execution-model-lifecycle.js +73 -0
  233. package/dist/sdk/execution-model-request.d.ts +40 -0
  234. package/dist/sdk/execution-model-request.js +45 -0
  235. package/dist/sdk/execution-round-preparation.d.ts +11 -0
  236. package/dist/sdk/execution-round-preparation.js +18 -0
  237. package/dist/sdk/execution-round-request.d.ts +30 -0
  238. package/dist/sdk/execution-round-request.js +31 -0
  239. package/dist/sdk/execution-tool-catalog.d.ts +46 -0
  240. package/dist/sdk/execution-tool-catalog.js +103 -0
  241. package/dist/sdk/execution-tool-scope.d.ts +67 -0
  242. package/dist/sdk/execution-tool-scope.js +147 -0
  243. package/dist/sdk/extension-agent-controller.d.ts +3 -0
  244. package/dist/sdk/extension-agent-controller.js +69 -0
  245. package/dist/sdk/extension-agents.d.ts +9 -0
  246. package/dist/sdk/extension-agents.js +58 -0
  247. package/dist/sdk/extension-models.d.ts +17 -0
  248. package/dist/sdk/extension-models.js +142 -0
  249. package/dist/sdk/extension-session-launch.d.ts +18 -0
  250. package/dist/sdk/extension-session-launch.js +73 -0
  251. package/dist/sdk/extension-session.d.ts +30 -0
  252. package/dist/sdk/extension-session.js +107 -0
  253. package/dist/sdk/extension-tool-runtime.d.ts +2 -0
  254. package/dist/sdk/extension-tool-runtime.js +14 -0
  255. package/dist/sdk/extension-tools.d.ts +16 -0
  256. package/dist/sdk/extension-tools.js +126 -0
  257. package/dist/sdk/model-input-projection.d.ts +4 -0
  258. package/dist/sdk/model-input-projection.js +27 -0
  259. package/dist/sdk/model-runtime.d.ts +21 -0
  260. package/dist/sdk/model-runtime.js +91 -0
  261. package/dist/sdk/native-steer.d.ts +20 -0
  262. package/dist/sdk/native-steer.js +84 -0
  263. package/dist/sdk/request-preparation.d.ts +9 -0
  264. package/dist/sdk/resource-input.d.ts +33 -0
  265. package/dist/sdk/resource-input.js +402 -0
  266. package/dist/sdk/session-catalog.d.ts +2 -0
  267. package/dist/sdk/session-catalog.js +12 -0
  268. package/dist/sdk/session-composition.d.ts +54 -0
  269. package/dist/sdk/session-composition.js +1 -0
  270. package/dist/sdk/session-execution-factory.d.ts +43 -0
  271. package/dist/sdk/session-execution-factory.js +937 -0
  272. package/dist/sdk/session-execution.d.ts +163 -0
  273. package/dist/sdk/session-execution.js +388 -0
  274. package/dist/sdk/session-extension-messages.d.ts +16 -0
  275. package/dist/sdk/session-extension-messages.js +64 -0
  276. package/dist/sdk/session-extension-prompt.d.ts +35 -0
  277. package/dist/sdk/session-extension-prompt.js +62 -0
  278. package/dist/sdk/session-maintenance.d.ts +25 -0
  279. package/dist/sdk/session-maintenance.js +205 -0
  280. package/dist/sdk/session-model-adapters.d.ts +28 -0
  281. package/dist/sdk/session-model-adapters.js +96 -0
  282. package/dist/sdk/session-open.d.ts +22 -0
  283. package/dist/sdk/session-open.js +44 -0
  284. package/dist/sdk/session-registry.d.ts +17 -0
  285. package/dist/sdk/session-registry.js +83 -0
  286. package/dist/sdk/session-runtime.d.ts +72 -0
  287. package/dist/sdk/session-runtime.js +205 -0
  288. package/dist/sdk/session.d.ts +3 -0
  289. package/dist/sdk/session.js +313 -0
  290. package/dist/sdk/subagent-backend.d.ts +3 -0
  291. package/dist/sdk/subagent-backend.js +49 -0
  292. package/dist/sdk/types.d.ts +80 -0
  293. package/dist/sdk/types.js +1 -0
  294. package/dist/session/catalog.d.ts +70 -0
  295. package/dist/session/catalog.js +194 -0
  296. package/dist/session/code-observation-contract.d.ts +40 -0
  297. package/dist/session/code-observation-contract.js +1 -0
  298. package/dist/session/code-observation-projection.d.ts +54 -0
  299. package/dist/session/code-observation-projection.js +165 -0
  300. package/dist/session/code-state.d.ts +27 -0
  301. package/dist/session/code-state.js +89 -0
  302. package/dist/session/context-gc-checkpoint.d.ts +26 -0
  303. package/dist/session/context-gc-checkpoint.js +935 -0
  304. package/dist/session/context-gc-contract.d.ts +141 -0
  305. package/dist/session/context-gc-contract.js +1 -0
  306. package/dist/session/context-gc-observations.d.ts +58 -0
  307. package/dist/session/context-gc-observations.js +187 -0
  308. package/dist/session/context-gc-replacements.d.ts +63 -0
  309. package/dist/session/context-gc-subagent.d.ts +54 -0
  310. package/dist/session/deferred-input.d.ts +5 -0
  311. package/dist/session/deferred-input.js +74 -0
  312. package/dist/session/extension-checkpoint.d.ts +8 -0
  313. package/dist/session/extension-checkpoint.js +30 -0
  314. package/dist/session/history-input-limits.d.ts +4 -0
  315. package/dist/session/history-input-limits.js +4 -0
  316. package/dist/session/inline-media-contract.d.ts +16 -0
  317. package/dist/session/inline-media-contract.js +1 -0
  318. package/dist/session/inline-media.d.ts +26 -0
  319. package/dist/session/inline-media.js +138 -0
  320. package/dist/session/model-request.d.ts +14 -0
  321. package/dist/session/model-request.js +1 -0
  322. package/dist/session/record-contract.d.ts +19 -0
  323. package/dist/session/record-contract.js +1 -0
  324. package/dist/session/record-projection.d.ts +6 -0
  325. package/dist/session/record-projection.js +80 -0
  326. package/dist/session/resource-contract.d.ts +9 -0
  327. package/dist/session/resource-contract.js +1 -0
  328. package/dist/session/rollback.d.ts +13 -0
  329. package/dist/session/rollback.js +46 -0
  330. package/dist/session/store/contracts.d.ts +160 -0
  331. package/dist/session/store/contracts.js +1 -0
  332. package/dist/session/store/current-state.d.ts +17 -0
  333. package/dist/session/store/current-state.js +53 -0
  334. package/dist/session/store/execution-state.d.ts +13 -0
  335. package/dist/session/store/execution-state.js +103 -0
  336. package/dist/session/store/index.d.ts +4 -0
  337. package/dist/session/store/index.js +2 -0
  338. package/dist/session/store/jsonl/directory-index.d.ts +26 -0
  339. package/dist/session/store/jsonl/directory-index.js +283 -0
  340. package/dist/session/store/jsonl/fs-durability.d.ts +3 -0
  341. package/dist/session/store/jsonl/fs-durability.js +17 -0
  342. package/dist/session/store/jsonl/history-replacement.d.ts +48 -0
  343. package/dist/session/store/jsonl/history-replacement.js +147 -0
  344. package/dist/session/store/jsonl/history.d.ts +25 -0
  345. package/dist/session/store/jsonl/history.js +181 -0
  346. package/dist/session/store/jsonl/images.d.ts +19 -0
  347. package/dist/session/store/jsonl/images.js +122 -0
  348. package/dist/session/store/jsonl/index-transaction.d.ts +13 -0
  349. package/dist/session/store/jsonl/index-transaction.js +87 -0
  350. package/dist/session/store/jsonl/jsonl-admission.d.ts +10 -0
  351. package/dist/session/store/jsonl/jsonl-admission.js +205 -0
  352. package/dist/session/store/jsonl/jsonl-codec.d.ts +11 -0
  353. package/dist/session/store/jsonl/jsonl-codec.js +138 -0
  354. package/dist/session/store/jsonl/jsonl-migration.d.ts +12 -0
  355. package/dist/session/store/jsonl/jsonl-migration.js +105 -0
  356. package/dist/session/store/jsonl/jsonl-store.d.ts +171 -0
  357. package/dist/session/store/jsonl/jsonl-store.js +2482 -0
  358. package/dist/session/store/jsonl/open-recovery.d.ts +13 -0
  359. package/dist/session/store/jsonl/open-recovery.js +131 -0
  360. package/dist/session/store/jsonl/read-pins.d.ts +4 -0
  361. package/dist/session/store/jsonl/read-pins.js +131 -0
  362. package/dist/session/store/jsonl/record-append.d.ts +16 -0
  363. package/dist/session/store/jsonl/record-append.js +49 -0
  364. package/dist/session/store/jsonl/records.d.ts +30 -0
  365. package/dist/session/store/jsonl/records.js +313 -0
  366. package/dist/session/store/jsonl/resources.d.ts +19 -0
  367. package/dist/session/store/jsonl/resources.js +209 -0
  368. package/dist/session/store/jsonl/store-pool.d.ts +12 -0
  369. package/dist/session/store/jsonl/store-pool.js +55 -0
  370. package/dist/session/store/jsonl/transaction-recovery.d.ts +48 -0
  371. package/dist/session/store/jsonl/transaction-recovery.js +374 -0
  372. package/dist/session/store/jsonl/tree-maintenance.d.ts +12 -0
  373. package/dist/session/store/jsonl/tree-maintenance.js +59 -0
  374. package/dist/session/store/types.d.ts +69 -0
  375. package/dist/session/store/types.js +1 -0
  376. package/dist/session/summary.d.ts +18 -0
  377. package/dist/session/summary.js +1 -0
  378. package/dist/session/todo.d.ts +11 -0
  379. package/dist/session/todo.js +30 -0
  380. package/dist/session/tool-result-resources.d.ts +27 -0
  381. package/dist/session/tool-result-resources.js +255 -0
  382. package/dist/session/types.js +1 -0
  383. package/dist/session/user-history.d.ts +17 -0
  384. package/dist/session/user-history.js +1 -0
  385. package/dist/session-store.d.ts +2 -0
  386. package/dist/session-store.js +1 -0
  387. package/dist/shared/auto-title.d.ts +3 -3
  388. package/dist/shared/auto-title.js +6 -6
  389. package/dist/shared/model-text.d.ts +8 -8
  390. package/dist/shared/model-text.js +8 -7
  391. package/dist/storage/file-lock.js +83 -0
  392. package/dist/subagent/contracts.d.ts +107 -0
  393. package/dist/subagent/contracts.js +1 -0
  394. package/dist/subagent/limits.d.ts +17 -0
  395. package/dist/subagent/limits.js +17 -0
  396. package/dist/subagent/model-update.js +81 -0
  397. package/dist/subagent/session-controller.d.ts +148 -0
  398. package/dist/subagent/session-controller.js +1761 -0
  399. package/dist/subagent/wait-targets.d.ts +10 -0
  400. package/dist/subagent/wait-targets.js +26 -0
  401. package/dist/subagent/wait.d.ts +26 -0
  402. package/dist/subagent/wait.js +73 -0
  403. package/dist/tools/agent/agent-cancel.d.ts +7 -0
  404. package/dist/tools/agent/agent-cancel.js +29 -0
  405. package/dist/tools/agent/agent-message.d.ts +7 -0
  406. package/dist/tools/agent/agent-message.js +57 -0
  407. package/dist/tools/agent/agent-start.d.ts +12 -0
  408. package/dist/tools/agent/agent-start.js +106 -0
  409. package/dist/tools/agent/agent-wait.d.ts +7 -0
  410. package/dist/tools/agent/agent-wait.js +91 -0
  411. package/dist/tools/agent/question.d.ts +7 -0
  412. package/dist/tools/agent/question.js +125 -0
  413. package/dist/tools/agent/skill.d.ts +11 -0
  414. package/dist/tools/agent/skill.js +38 -0
  415. package/dist/tools/agent/sleep.d.ts +9 -0
  416. package/dist/tools/agent/sleep.js +54 -0
  417. package/dist/tools/agent/smart-compact.d.ts +9 -0
  418. package/dist/tools/agent/smart-compact.js +23 -0
  419. package/dist/tools/agent/todo-read.d.ts +14 -0
  420. package/dist/tools/agent/todo-write.d.ts +14 -0
  421. package/dist/tools/agent/todo-write.js +66 -0
  422. package/dist/tools/agent/todo.d.ts +25 -0
  423. package/dist/tools/agent/todo.js +32 -0
  424. package/dist/tools/callers.d.ts +7 -0
  425. package/dist/tools/callers.js +39 -0
  426. package/dist/tools/code-mode/cells.d.ts +29 -0
  427. package/dist/tools/code-mode/cells.js +338 -0
  428. package/dist/tools/code-mode/dispatch.d.ts +20 -0
  429. package/dist/tools/code-mode/dispatch.js +80 -0
  430. package/dist/tools/code-mode/engine.d.ts +60 -0
  431. package/dist/tools/code-mode/engine.js +1 -0
  432. package/dist/tools/code-mode/index.d.ts +31 -0
  433. package/dist/tools/code-mode/index.js +751 -0
  434. package/dist/tools/code-mode/observations.d.ts +8 -0
  435. package/dist/tools/code-mode/observations.js +64 -0
  436. package/dist/tools/code-mode/worker.d.ts +1 -0
  437. package/dist/tools/contracts.d.ts +193 -0
  438. package/dist/tools/contracts.js +1 -0
  439. package/dist/tools/definition-projection.d.ts +1 -0
  440. package/dist/tools/definition-projection.js +1 -0
  441. package/dist/tools/execution-limits.d.ts +69 -0
  442. package/dist/tools/execution-limits.js +58 -0
  443. package/dist/tools/execution.d.ts +30 -0
  444. package/dist/tools/execution.js +191 -0
  445. package/dist/tools/local/apply-patch-parser.js +177 -0
  446. package/dist/tools/local/apply-patch.d.ts +19 -0
  447. package/dist/tools/local/apply-patch.js +489 -0
  448. package/dist/tools/local/exec.d.ts +28 -0
  449. package/dist/tools/local/exec.js +194 -0
  450. package/dist/tools/local/image-processing.js +146 -0
  451. package/dist/tools/local/read.d.ts +43 -0
  452. package/dist/tools/local/read.js +470 -0
  453. package/dist/tools/local/view-image.d.ts +15 -0
  454. package/dist/tools/local/view-image.js +317 -0
  455. package/dist/tools/mcp/catalog.js +220 -0
  456. package/dist/tools/mcp/history.d.ts +4 -0
  457. package/dist/tools/mcp/tool-search.d.ts +45 -0
  458. package/dist/tools/mcp/tool-search.js +294 -0
  459. package/dist/tools/output-projection.d.ts +18 -0
  460. package/dist/tools/output-projection.js +341 -0
  461. package/dist/tools/permission-contract.d.ts +25 -0
  462. package/dist/tools/permission-contract.js +1 -0
  463. package/dist/tools/permissions.d.ts +61 -0
  464. package/dist/tools/permissions.js +237 -0
  465. package/dist/tools/registry.d.ts +7 -0
  466. package/dist/tools/result-extension-contract.d.ts +37 -0
  467. package/dist/tools/result-extension-contract.js +32 -0
  468. package/dist/tools/result-extensions.d.ts +12 -0
  469. package/dist/tools/result-extensions.js +104 -0
  470. package/dist/tools/runtime-context.d.ts +89 -0
  471. package/dist/tools/runtime-context.js +1 -0
  472. package/dist/tools/runtime-resource-handles.js +28 -0
  473. package/dist/tools/runtime.js +77 -0
  474. package/dist/tools/scheduler.d.ts +12 -0
  475. package/dist/tools/shared/path-resolver.js +133 -0
  476. package/dist/tools/wait.d.ts +1 -0
  477. package/dist/tools/wait.js +1 -0
  478. package/package.json +15 -3
  479. package/dist/agent-core/error.d.ts +0 -15
  480. package/dist/agent-core/error.js +0 -74
  481. package/dist/agent-core/extensions/agents.d.ts +0 -79
  482. package/dist/agent-core/extensions/agents.js +0 -186
  483. package/dist/agent-core/extensions/compaction.d.ts +0 -48
  484. package/dist/agent-core/extensions/contracts.d.ts +0 -265
  485. package/dist/agent-core/extensions/data.d.ts +0 -84
  486. package/dist/agent-core/extensions/data.js +0 -83
  487. package/dist/agent-core/extensions/environment.d.ts +0 -27
  488. package/dist/agent-core/extensions/environment.js +0 -52
  489. package/dist/agent-core/extensions/files.d.ts +0 -64
  490. package/dist/agent-core/extensions/files.js +0 -26
  491. package/dist/agent-core/extensions/hooks.d.ts +0 -32
  492. package/dist/agent-core/extensions/manager.d.ts +0 -39
  493. package/dist/agent-core/extensions/manager.js +0 -458
  494. package/dist/agent-core/extensions/mcp.d.ts +0 -99
  495. package/dist/agent-core/extensions/mcp.js +0 -433
  496. package/dist/agent-core/extensions/model-request.d.ts +0 -56
  497. package/dist/agent-core/extensions/model-request.js +0 -197
  498. package/dist/agent-core/extensions/model-stream.d.ts +0 -9
  499. package/dist/agent-core/extensions/model-stream.js +0 -108
  500. package/dist/agent-core/extensions/models.d.ts +0 -43
  501. package/dist/agent-core/extensions/network.d.ts +0 -32
  502. package/dist/agent-core/extensions/network.js +0 -97
  503. package/dist/agent-core/extensions/operation.d.ts +0 -30
  504. package/dist/agent-core/extensions/processes.d.ts +0 -52
  505. package/dist/agent-core/extensions/processes.js +0 -284
  506. package/dist/agent-core/extensions/prompt-composition.d.ts +0 -24
  507. package/dist/agent-core/extensions/prompt-composition.js +0 -106
  508. package/dist/agent-core/extensions/prompt-input.d.ts +0 -23
  509. package/dist/agent-core/extensions/prompt-input.js +0 -48
  510. package/dist/agent-core/extensions/resources.d.ts +0 -27
  511. package/dist/agent-core/extensions/resources.js +0 -221
  512. package/dist/agent-core/extensions/services.d.ts +0 -31
  513. package/dist/agent-core/extensions/services.js +0 -61
  514. package/dist/agent-core/extensions/session-input.d.ts +0 -163
  515. package/dist/agent-core/extensions/session-input.js +0 -411
  516. package/dist/agent-core/extensions/session-messages.d.ts +0 -41
  517. package/dist/agent-core/extensions/session-messages.js +0 -76
  518. package/dist/agent-core/extensions/session.d.ts +0 -69
  519. package/dist/agent-core/extensions/session.js +0 -607
  520. package/dist/agent-core/extensions/settings.d.ts +0 -59
  521. package/dist/agent-core/extensions/settings.js +0 -115
  522. package/dist/agent-core/extensions/store.d.ts +0 -10
  523. package/dist/agent-core/extensions/store.js +0 -131
  524. package/dist/agent-core/extensions/tools.d.ts +0 -61
  525. package/dist/agent-core/extensions/tools.js +0 -269
  526. package/dist/agent-core/host/contracts.d.ts +0 -100
  527. package/dist/agent-core/host/contracts.js +0 -18
  528. package/dist/agent-core/host/local-agent-host.d.ts +0 -96
  529. package/dist/agent-core/host/local-agent-host.js +0 -425
  530. package/dist/agent-core/host/local-file-access.d.ts +0 -30
  531. package/dist/agent-core/host/local-file-access.js +0 -107
  532. package/dist/agent-core/host/local-network-access.d.ts +0 -6
  533. package/dist/agent-core/host/local-network-access.js +0 -101
  534. package/dist/agent-core/host/local-process-executor.d.ts +0 -29
  535. package/dist/agent-core/host/local-process-executor.js +0 -41
  536. package/dist/agent-core/host/local-session-environment.d.ts +0 -18
  537. package/dist/agent-core/host/local-shell.d.ts +0 -3
  538. package/dist/agent-core/host/network.d.ts +0 -4
  539. package/dist/agent-core/host/network.js +0 -6
  540. package/dist/agent-core/model/anthropic-messages.d.ts +0 -10
  541. package/dist/agent-core/model/anthropic-messages.js +0 -707
  542. package/dist/agent-core/model/anthropic-thinking.js +0 -33
  543. package/dist/agent-core/model/catalog-file.d.ts +0 -80
  544. package/dist/agent-core/model/catalog-file.js +0 -103
  545. package/dist/agent-core/model/configuration.d.ts +0 -127
  546. package/dist/agent-core/model/configuration.js +0 -168
  547. package/dist/agent-core/model/contracts.d.ts +0 -229
  548. package/dist/agent-core/model/http.d.ts +0 -27
  549. package/dist/agent-core/model/http.js +0 -534
  550. package/dist/agent-core/model/image.d.ts +0 -17
  551. package/dist/agent-core/model/openai-responses.d.ts +0 -77
  552. package/dist/agent-core/model/openai-responses.js +0 -2123
  553. package/dist/agent-core/model/product-user-agent.d.ts +0 -5
  554. package/dist/agent-core/model/product-user-agent.js +0 -22
  555. package/dist/agent-core/model/recovery.js +0 -80
  556. package/dist/agent-core/model/request-configuration.d.ts +0 -17
  557. package/dist/agent-core/model/request-configuration.js +0 -47
  558. package/dist/agent-core/model/runtime-credential.d.ts +0 -8
  559. package/dist/agent-core/model/runtime-credential.js +0 -72
  560. package/dist/agent-core/model/sse.js +0 -281
  561. package/dist/agent-core/model/text-blocks.js +0 -40
  562. package/dist/agent-core/model/tool-declarations.d.ts +0 -4
  563. package/dist/agent-core/model/transport-test.d.ts +0 -3
  564. package/dist/agent-core/model/transport-test.js +0 -23
  565. package/dist/agent-core/model/usage-observer.d.ts +0 -31
  566. package/dist/agent-core/prompts/index.d.ts +0 -20
  567. package/dist/agent-core/prompts/index.js +0 -49
  568. package/dist/agent-core/runtime/compaction/coordinator.js +0 -88
  569. package/dist/agent-core/runtime/compaction/generate.d.ts +0 -28
  570. package/dist/agent-core/runtime/compaction/generate.js +0 -84
  571. package/dist/agent-core/runtime/compaction/history.d.ts +0 -16
  572. package/dist/agent-core/runtime/compaction/operation.d.ts +0 -29
  573. package/dist/agent-core/runtime/compaction/operation.js +0 -131
  574. package/dist/agent-core/runtime/compaction/requests.d.ts +0 -16
  575. package/dist/agent-core/runtime/compaction/requests.js +0 -114
  576. package/dist/agent-core/runtime/compaction/retained-context.d.ts +0 -6
  577. package/dist/agent-core/runtime/compaction/retained-context.js +0 -47
  578. package/dist/agent-core/runtime/compaction/smart.d.ts +0 -14
  579. package/dist/agent-core/runtime/compaction/smart.js +0 -59
  580. package/dist/agent-core/runtime/context/contextual-blocks.d.ts +0 -30
  581. package/dist/agent-core/runtime/context/contextual-blocks.js +0 -146
  582. package/dist/agent-core/runtime/context/environment.d.ts +0 -5
  583. package/dist/agent-core/runtime/context/gc-runtime.d.ts +0 -38
  584. package/dist/agent-core/runtime/context/gc-tokens.d.ts +0 -25
  585. package/dist/agent-core/runtime/context/gc-tokens.js +0 -103
  586. package/dist/agent-core/runtime/context/gc.d.ts +0 -75
  587. package/dist/agent-core/runtime/context/gc.js +0 -1386
  588. package/dist/agent-core/runtime/context/instructions.d.ts +0 -37
  589. package/dist/agent-core/runtime/context/instructions.js +0 -297
  590. package/dist/agent-core/runtime/context/normalize.d.ts +0 -5
  591. package/dist/agent-core/runtime/context/projection.d.ts +0 -23
  592. package/dist/agent-core/runtime/context/projection.js +0 -284
  593. package/dist/agent-core/runtime/context/request-budget.d.ts +0 -4
  594. package/dist/agent-core/runtime/context/request-budget.js +0 -25
  595. package/dist/agent-core/runtime/context/restore.d.ts +0 -25
  596. package/dist/agent-core/runtime/context/restore.js +0 -186
  597. package/dist/agent-core/runtime/context/usage.d.ts +0 -17
  598. package/dist/agent-core/runtime/context/usage.js +0 -124
  599. package/dist/agent-core/runtime/context/world-state.d.ts +0 -33
  600. package/dist/agent-core/runtime/context/world-state.js +0 -232
  601. package/dist/agent-core/runtime/contracts.d.ts +0 -41
  602. package/dist/agent-core/runtime/event-projection.d.ts +0 -14
  603. package/dist/agent-core/runtime/event-projection.js +0 -87
  604. package/dist/agent-core/runtime/events.d.ts +0 -197
  605. package/dist/agent-core/runtime/execution-handle.d.ts +0 -12
  606. package/dist/agent-core/runtime/execution.d.ts +0 -50
  607. package/dist/agent-core/runtime/execution.js +0 -445
  608. package/dist/agent-core/runtime/model-progress.js +0 -85
  609. package/dist/agent-core/runtime/resource-publication.d.ts +0 -8
  610. package/dist/agent-core/runtime/resource-publication.js +0 -60
  611. package/dist/agent-core/sdk/agent.d.ts +0 -11
  612. package/dist/agent-core/sdk/agent.js +0 -474
  613. package/dist/agent-core/sdk/extension-agents.d.ts +0 -9
  614. package/dist/agent-core/sdk/extension-agents.js +0 -58
  615. package/dist/agent-core/sdk/extension-models.d.ts +0 -13
  616. package/dist/agent-core/sdk/extension-models.js +0 -137
  617. package/dist/agent-core/sdk/extension-session.d.ts +0 -30
  618. package/dist/agent-core/sdk/extension-session.js +0 -105
  619. package/dist/agent-core/sdk/extension-tools.d.ts +0 -16
  620. package/dist/agent-core/sdk/extension-tools.js +0 -126
  621. package/dist/agent-core/sdk/model-runtime.d.ts +0 -18
  622. package/dist/agent-core/sdk/model-runtime.js +0 -93
  623. package/dist/agent-core/sdk/native-steer.d.ts +0 -20
  624. package/dist/agent-core/sdk/native-steer.js +0 -84
  625. package/dist/agent-core/sdk/request-preparation.d.ts +0 -7
  626. package/dist/agent-core/sdk/resource-input.d.ts +0 -32
  627. package/dist/agent-core/sdk/resource-input.js +0 -403
  628. package/dist/agent-core/sdk/session.d.ts +0 -94
  629. package/dist/agent-core/sdk/session.js +0 -2377
  630. package/dist/agent-core/sdk/subagent-backend.d.ts +0 -3
  631. package/dist/agent-core/sdk/subagent-backend.js +0 -49
  632. package/dist/agent-core/sdk/types.d.ts +0 -81
  633. package/dist/agent-core/session/catalog.d.ts +0 -99
  634. package/dist/agent-core/session/catalog.js +0 -200
  635. package/dist/agent-core/session/context-gc-checkpoint.d.ts +0 -165
  636. package/dist/agent-core/session/context-gc-checkpoint.js +0 -935
  637. package/dist/agent-core/session/context-gc-observations.d.ts +0 -60
  638. package/dist/agent-core/session/context-gc-observations.js +0 -187
  639. package/dist/agent-core/session/context-gc-replacements.d.ts +0 -62
  640. package/dist/agent-core/session/context-gc-subagent.d.ts +0 -53
  641. package/dist/agent-core/session/deferred-input.d.ts +0 -5
  642. package/dist/agent-core/session/deferred-input.js +0 -74
  643. package/dist/agent-core/session/inline-media.d.ts +0 -45
  644. package/dist/agent-core/session/inline-media.js +0 -163
  645. package/dist/agent-core/session/rollback.d.ts +0 -13
  646. package/dist/agent-core/session/rollback.js +0 -46
  647. package/dist/agent-core/session/store/contracts.d.ts +0 -158
  648. package/dist/agent-core/session/store/current-state.d.ts +0 -17
  649. package/dist/agent-core/session/store/current-state.js +0 -53
  650. package/dist/agent-core/session/store/directory-index.d.ts +0 -18
  651. package/dist/agent-core/session/store/directory-index.js +0 -169
  652. package/dist/agent-core/session/store/execution-state.d.ts +0 -18
  653. package/dist/agent-core/session/store/execution-state.js +0 -175
  654. package/dist/agent-core/session/store/history.d.ts +0 -25
  655. package/dist/agent-core/session/store/history.js +0 -181
  656. package/dist/agent-core/session/store/images.d.ts +0 -19
  657. package/dist/agent-core/session/store/images.js +0 -110
  658. package/dist/agent-core/session/store/index.d.ts +0 -4
  659. package/dist/agent-core/session/store/index.js +0 -2
  660. package/dist/agent-core/session/store/jsonl-store.d.ts +0 -171
  661. package/dist/agent-core/session/store/jsonl-store.js +0 -2078
  662. package/dist/agent-core/session/store/records.d.ts +0 -23
  663. package/dist/agent-core/session/store/records.js +0 -261
  664. package/dist/agent-core/session/store/resources.d.ts +0 -26
  665. package/dist/agent-core/session/store/resources.js +0 -197
  666. package/dist/agent-core/session/store/types.d.ts +0 -82
  667. package/dist/agent-core/session/tool-result-resources.d.ts +0 -26
  668. package/dist/agent-core/session/tool-result-resources.js +0 -256
  669. package/dist/agent-core/session/transaction-recovery.d.ts +0 -16
  670. package/dist/agent-core/session/transaction-recovery.js +0 -135
  671. package/dist/agent-core/storage/file-lock.js +0 -83
  672. package/dist/agent-core/subagent/contracts.d.ts +0 -117
  673. package/dist/agent-core/subagent/model-update.js +0 -81
  674. package/dist/agent-core/subagent/scheduler.d.ts +0 -135
  675. package/dist/agent-core/subagent/scheduler.js +0 -369
  676. package/dist/agent-core/subagent/session-controller.d.ts +0 -138
  677. package/dist/agent-core/subagent/session-controller.js +0 -1594
  678. package/dist/agent-core/subagent/wait.d.ts +0 -14
  679. package/dist/agent-core/subagent/wait.js +0 -32
  680. package/dist/agent-core/tools/agent/agent-cancel.d.ts +0 -7
  681. package/dist/agent-core/tools/agent/agent-cancel.js +0 -29
  682. package/dist/agent-core/tools/agent/agent-message.d.ts +0 -7
  683. package/dist/agent-core/tools/agent/agent-message.js +0 -57
  684. package/dist/agent-core/tools/agent/agent-start.d.ts +0 -12
  685. package/dist/agent-core/tools/agent/agent-start.js +0 -106
  686. package/dist/agent-core/tools/agent/agent-wait.d.ts +0 -7
  687. package/dist/agent-core/tools/agent/agent-wait.js +0 -91
  688. package/dist/agent-core/tools/agent/question.d.ts +0 -7
  689. package/dist/agent-core/tools/agent/question.js +0 -125
  690. package/dist/agent-core/tools/agent/skill.d.ts +0 -11
  691. package/dist/agent-core/tools/agent/skill.js +0 -38
  692. package/dist/agent-core/tools/agent/sleep.d.ts +0 -12
  693. package/dist/agent-core/tools/agent/sleep.js +0 -54
  694. package/dist/agent-core/tools/agent/smart-compact.d.ts +0 -9
  695. package/dist/agent-core/tools/agent/smart-compact.js +0 -23
  696. package/dist/agent-core/tools/agent/todo-read.d.ts +0 -14
  697. package/dist/agent-core/tools/agent/todo-write.d.ts +0 -14
  698. package/dist/agent-core/tools/agent/todo-write.js +0 -66
  699. package/dist/agent-core/tools/agent/todo.d.ts +0 -26
  700. package/dist/agent-core/tools/agent/todo.js +0 -60
  701. package/dist/agent-core/tools/callers.d.ts +0 -6
  702. package/dist/agent-core/tools/callers.js +0 -39
  703. package/dist/agent-core/tools/code-mode/cells.d.ts +0 -29
  704. package/dist/agent-core/tools/code-mode/cells.js +0 -337
  705. package/dist/agent-core/tools/code-mode/dispatch.d.ts +0 -20
  706. package/dist/agent-core/tools/code-mode/dispatch.js +0 -80
  707. package/dist/agent-core/tools/code-mode/engine.d.ts +0 -60
  708. package/dist/agent-core/tools/code-mode/index.d.ts +0 -29
  709. package/dist/agent-core/tools/code-mode/index.js +0 -749
  710. package/dist/agent-core/tools/code-mode/observations.d.ts +0 -98
  711. package/dist/agent-core/tools/code-mode/observations.js +0 -228
  712. package/dist/agent-core/tools/code-mode/state.d.ts +0 -9
  713. package/dist/agent-core/tools/code-mode/state.js +0 -82
  714. package/dist/agent-core/tools/contracts.d.ts +0 -211
  715. package/dist/agent-core/tools/definition-projection.d.ts +0 -7
  716. package/dist/agent-core/tools/definition-projection.js +0 -26
  717. package/dist/agent-core/tools/execution-limits.d.ts +0 -69
  718. package/dist/agent-core/tools/execution-limits.js +0 -69
  719. package/dist/agent-core/tools/execution.d.ts +0 -46
  720. package/dist/agent-core/tools/execution.js +0 -191
  721. package/dist/agent-core/tools/local/apply-patch-parser.js +0 -177
  722. package/dist/agent-core/tools/local/apply-patch.d.ts +0 -19
  723. package/dist/agent-core/tools/local/apply-patch.js +0 -489
  724. package/dist/agent-core/tools/local/exec.d.ts +0 -53
  725. package/dist/agent-core/tools/local/exec.js +0 -877
  726. package/dist/agent-core/tools/local/image-processing.js +0 -146
  727. package/dist/agent-core/tools/local/read-context.js +0 -152
  728. package/dist/agent-core/tools/local/read.d.ts +0 -43
  729. package/dist/agent-core/tools/local/read.js +0 -470
  730. package/dist/agent-core/tools/local/registry.d.ts +0 -34
  731. package/dist/agent-core/tools/local/registry.js +0 -132
  732. package/dist/agent-core/tools/local/view-image.d.ts +0 -15
  733. package/dist/agent-core/tools/local/view-image.js +0 -317
  734. package/dist/agent-core/tools/local/workspace-tools.d.ts +0 -12
  735. package/dist/agent-core/tools/local/workspace-tools.js +0 -28
  736. package/dist/agent-core/tools/mcp/catalog.js +0 -220
  737. package/dist/agent-core/tools/mcp/history.d.ts +0 -4
  738. package/dist/agent-core/tools/mcp/tool-search.d.ts +0 -45
  739. package/dist/agent-core/tools/mcp/tool-search.js +0 -294
  740. package/dist/agent-core/tools/output-projection.d.ts +0 -18
  741. package/dist/agent-core/tools/output-projection.js +0 -341
  742. package/dist/agent-core/tools/permissions.d.ts +0 -85
  743. package/dist/agent-core/tools/permissions.js +0 -237
  744. package/dist/agent-core/tools/registry.d.ts +0 -7
  745. package/dist/agent-core/tools/result-extensions.d.ts +0 -46
  746. package/dist/agent-core/tools/result-extensions.js +0 -134
  747. package/dist/agent-core/tools/runtime-context.d.ts +0 -74
  748. package/dist/agent-core/tools/runtime-resource-handles.js +0 -28
  749. package/dist/agent-core/tools/runtime.js +0 -77
  750. package/dist/agent-core/tools/scheduler.d.ts +0 -12
  751. package/dist/agent-core/tools/shared/path-resolver.js +0 -133
  752. package/dist/agent-core/tools/wait.js +0 -82
  753. /package/dist/{agent-core/extensions/models.js → extensions/capabilities.js} +0 -0
  754. /package/dist/{agent-core/extensions → extensions}/compaction.js +0 -0
  755. /package/dist/{agent-core/model → extensions}/contracts.js +0 -0
  756. /package/dist/{agent-core/extensions → extensions}/hooks.js +0 -0
  757. /package/dist/{agent-core/runtime/context/contracts.js → extensions/host-ports.js} +0 -0
  758. /package/dist/{agent-core/extensions → extensions}/operation.js +0 -0
  759. /package/dist/{agent-core/runtime/contracts.js → extensions/tool-runtime.js} +0 -0
  760. /package/dist/{agent-core/extensions/contracts.js → extensions.js} +0 -0
  761. /package/dist/{agent-core/runtime/events.js → host/description.js} +0 -0
  762. /package/dist/{agent-core/host → host}/local-session-environment.js +0 -0
  763. /package/dist/{agent-core/host → host}/local-shell.js +0 -0
  764. /package/dist/{agent-core/runtime/execution-handle.js → host/skill-contract.js} +0 -0
  765. /package/dist/{agent-core/model → model}/anthropic-thinking.d.ts +0 -0
  766. /package/dist/{agent-core/model → model}/attempt-diagnostics.d.ts +0 -0
  767. /package/dist/{agent-core/model → model}/attempt-diagnostics.js +0 -0
  768. /package/dist/{agent-core/session/store → model}/contracts.js +0 -0
  769. /package/dist/{agent-core/sdk/types.js → model/image-contract.js} +0 -0
  770. /package/dist/{agent-core/model → model}/image.js +0 -0
  771. /package/dist/{agent-core/model → model}/native-context.d.ts +0 -0
  772. /package/dist/{agent-core/model → model}/native-context.js +0 -0
  773. /package/dist/{agent-core/model → model}/recovery.d.ts +0 -0
  774. /package/dist/{agent-core/model → model}/sse.d.ts +0 -0
  775. /package/dist/{agent-core/model → model}/text-blocks.d.ts +0 -0
  776. /package/dist/{agent-core/model → model}/tool-declarations.js +0 -0
  777. /package/dist/{agent-core/model → model}/tool-input.d.ts +0 -0
  778. /package/dist/{agent-core/model → model}/tool-input.js +0 -0
  779. /package/dist/{agent-core/model → model}/usage-observer.js +0 -0
  780. /package/dist/{agent-core/session/store/types.js → model/usage.js} +0 -0
  781. /package/dist/{agent-core/subagent → process}/contracts.js +0 -0
  782. /package/dist/{agent-core/prompts → prompts}/compact.d.ts +0 -0
  783. /package/dist/{agent-core/prompts → prompts}/compact.js +0 -0
  784. /package/dist/{agent-core/prompts → prompts}/core.d.ts +0 -0
  785. /package/dist/{agent-core/prompts → prompts}/core.js +0 -0
  786. /package/dist/{agent-core/prompts → prompts}/markup.d.ts +0 -0
  787. /package/dist/{agent-core/prompts → prompts}/markup.js +0 -0
  788. /package/dist/{agent-core/prompts → prompts}/modes.d.ts +0 -0
  789. /package/dist/{agent-core/prompts → prompts}/modes.js +0 -0
  790. /package/dist/{agent-core/prompts → prompts}/output.d.ts +0 -0
  791. /package/dist/{agent-core/prompts → prompts}/output.js +0 -0
  792. /package/dist/{agent-core/prompts → prompts}/permissions.d.ts +0 -0
  793. /package/dist/{agent-core/prompts → prompts}/permissions.js +0 -0
  794. /package/dist/{agent-core/tools/local → prompts}/read-context.d.ts +0 -0
  795. /package/dist/{agent-core/prompts → prompts}/resources.d.ts +0 -0
  796. /package/dist/{agent-core/prompts → prompts}/resources.js +0 -0
  797. /package/dist/{agent-core/prompts → prompts}/subagent.d.ts +0 -0
  798. /package/dist/{agent-core/prompts → prompts}/subagent.js +0 -0
  799. /package/dist/{agent-core/prompts → prompts}/workflow.d.ts +0 -0
  800. /package/dist/{agent-core/prompts → prompts}/workflow.js +0 -0
  801. /package/dist/{agent-core/runtime → runtime}/async-queue.d.ts +0 -0
  802. /package/dist/{agent-core/runtime → runtime}/async-queue.js +0 -0
  803. /package/dist/{agent-core/tools → runtime/compaction}/contracts.js +0 -0
  804. /package/dist/{agent-core/runtime → runtime}/compaction/coordinator.d.ts +0 -0
  805. /package/dist/{agent-core/runtime → runtime}/compaction/history.js +0 -0
  806. /package/dist/{agent-core/runtime → runtime}/context/contracts.d.ts +0 -0
  807. /package/dist/{agent-core/session/types.js → runtime/context/contracts.js} +0 -0
  808. /package/dist/{agent-core/runtime → runtime}/context/environment.js +0 -0
  809. /package/dist/{agent-core/tools/code-mode/engine.js → runtime/context/gc-contracts.js} +0 -0
  810. /package/dist/{agent-core/runtime → runtime}/context/gc-runtime.js +0 -0
  811. /package/dist/{agent-core/runtime → runtime}/context/normalize.js +0 -0
  812. /package/dist/{agent-core/tools/code-mode/worker.d.ts → runtime/contracts.js} +0 -0
  813. /package/dist/{agent-core/tools/runtime-context.js → runtime/events.js} +0 -0
  814. /package/dist/{agent-core/runtime → runtime}/execution-policy.d.ts +0 -0
  815. /package/dist/{agent-core/runtime → runtime}/execution-policy.js +0 -0
  816. /package/dist/{agent-core/runtime → runtime}/model-generation-timing.d.ts +0 -0
  817. /package/dist/{agent-core/runtime → runtime}/model-generation-timing.js +0 -0
  818. /package/dist/{agent-core/runtime → runtime}/model-progress.d.ts +0 -0
  819. /package/dist/{agent-core/runtime → runtime}/plan-output.d.ts +0 -0
  820. /package/dist/{agent-core/runtime → runtime}/plan-output.js +0 -0
  821. /package/dist/{agent-core/tools/public-metadata.d.ts → runtime/public-tool-metadata.d.ts} +0 -0
  822. /package/dist/{agent-core/tools/public-metadata.js → runtime/public-tool-metadata.js} +0 -0
  823. /package/dist/{agent-core/runtime → runtime}/token-budget.d.ts +0 -0
  824. /package/dist/{agent-core/runtime → runtime}/token-budget.js +0 -0
  825. /package/dist/{agent-core/tools → runtime}/wait.d.ts +0 -0
  826. /package/dist/{agent-core/sdk → sdk}/request-preparation.js +0 -0
  827. /package/dist/{agent-core/session → session}/context-gc-markup.d.ts +0 -0
  828. /package/dist/{agent-core/session → session}/context-gc-markup.js +0 -0
  829. /package/dist/{agent-core/session → session}/context-gc-replacements.js +0 -0
  830. /package/dist/{agent-core/session → session}/context-gc-subagent.js +0 -0
  831. /package/dist/{agent-core/session → session}/types.d.ts +0 -0
  832. /package/dist/{agent-core/storage → storage}/file-lock.d.ts +0 -0
  833. /package/dist/{agent-core/subagent → subagent}/model-update.d.ts +0 -0
  834. /package/dist/{agent-core/tools → tools}/agent/todo-read.js +0 -0
  835. /package/dist/{agent-core/tools → tools}/code-mode/quickjs-engine.d.ts +0 -0
  836. /package/dist/{agent-core/tools → tools}/code-mode/quickjs-engine.js +0 -0
  837. /package/dist/{agent-core/tools → tools}/code-mode/text-output.d.ts +0 -0
  838. /package/dist/{agent-core/tools → tools}/code-mode/text-output.js +0 -0
  839. /package/dist/{agent-core/tools → tools}/code-mode/worker.js +0 -0
  840. /package/dist/{agent-core/tools → tools}/file-change-diff.d.ts +0 -0
  841. /package/dist/{agent-core/tools → tools}/file-change-diff.js +0 -0
  842. /package/dist/{agent-core/tools → tools}/input-diagnostics/source-preview.d.ts +0 -0
  843. /package/dist/{agent-core/tools → tools}/input-diagnostics/source-preview.js +0 -0
  844. /package/dist/{agent-core/tools → tools}/input.d.ts +0 -0
  845. /package/dist/{agent-core/tools → tools}/input.js +0 -0
  846. /package/dist/{agent-core/tools → tools}/local/apply-patch-parser.d.ts +0 -0
  847. /package/dist/{agent-core/tools → tools}/local/image-processing.d.ts +0 -0
  848. /package/dist/{agent-core/tools → tools}/mcp/catalog.d.ts +0 -0
  849. /package/dist/{agent-core/tools → tools}/mcp/history.js +0 -0
  850. /package/dist/{agent-core/tools → tools}/registry.js +0 -0
  851. /package/dist/{agent-core/tools → tools}/runtime-resource-handles.d.ts +0 -0
  852. /package/dist/{agent-core/tools → tools}/runtime.d.ts +0 -0
  853. /package/dist/{agent-core/tools → tools}/scheduler.js +0 -0
  854. /package/dist/{agent-core/tools → tools}/shared/patch-result.d.ts +0 -0
  855. /package/dist/{agent-core/tools → tools}/shared/patch-result.js +0 -0
  856. /package/dist/{agent-core/tools → tools}/shared/path-resolver.d.ts +0 -0
@@ -0,0 +1,2482 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { rollbackBoundaryIndex } from '../../rollback.js';
3
+ import { inlineMediaHistory } from '../../inline-media.js';
4
+ import { lstat, mkdir, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ import { isDeepStrictEqual } from 'node:util';
7
+ import { AgentError } from '../../../error.js';
8
+ import { isModelImageUrl } from '../../../model/image.js';
9
+ import { cloneCoreJson } from '../../extension-checkpoint.js';
10
+ import { acquireFileLock } from '../../../storage/file-lock.js';
11
+ import { todoItemsFromSnapshot } from '../../todo.js';
12
+ import { applyCodeModeStateMutations, parseCodeModeStateMutations, restoreCodeModeState } from '../../code-state.js';
13
+ import { contextGcBaseFromRecords, contextGcCheckpointIntervalEligible, latestValidContextGcCheckpoint, normalizeContextGcReplacements, sameContextGcBase, validateContextGcCheckpoint } from '../../context-gc-checkpoint.js';
14
+ import { copyToolResultResources, recordToolResources, readToolResultResource, writeToolResultResource } from '../../tool-result-resources.js';
15
+ import { beginTreeDeleteTransaction, finishTreeDelete, finishTreeDeletePreparation, readTreeDeleteTransaction, recoverSessionStorageTransaction, stageTreeDelete } from './transaction-recovery.js';
16
+ import { extensionCheckpointFromPayload, indexExtensionCheckpoint, restoreExtensionCheckpoint, updateSessionCurrentState } from '../current-state.js';
17
+ import { decodeSessionListCursor, encodeSessionListCursor, mergeSessionDerivedCache, normalizeSessionSource, persistFormatSelection, readSessionIndex, restoreSessionIndexMeta, sessionListFilter, sessionMatchesFilter, sessionTreeIds, upgradeSessionIndex } from './directory-index.js';
18
+ import { admitWorldStateVersion, preflightRetiredRecovery, preflightV1Session, preflightV2Recovery } from './jsonl-admission.js';
19
+ import { prepareJsonlV2Generation } from './jsonl-migration.js';
20
+ import { syncJsonlDirectory } from './fs-durability.js';
21
+ import { withSessionReadDrain, withSessionReadPin } from './read-pins.js';
22
+ import { deriveExecutionState, executionModelFromRecord, isCompactCheckpoint, isNativeUserTurn, sameResumeIndex, userMessagePreviewFromRecord } from '../execution-state.js';
23
+ import { forkedPayload, stageSessionSegments } from './history.js';
24
+ import { MAX_INPUT_IMAGES, copyGeneratedImages, generatedImageFileNames, inputImageReference, inputImageReferences, readInputImageBytes } from './images.js';
25
+ import { persistResource, setResourceUrl, readResource, copyResources, resourceFiles } from './resources.js';
26
+ import { CONTEXTUAL_WORLD_STATE_FILE, openJsonlIndex, reclaimUnpublishedSessions, recoverContextualWorldStateTransactions, recoverJsonlTail, sessionDirectoryExists } from './open-recovery.js';
27
+ import { JsonlStorePool } from './store-pool.js';
28
+ import { acquireTreeMaintenance } from './tree-maintenance.js';
29
+ import { commitSessionIndex, ParentPublicationRejected } from './index-transaction.js';
30
+ import { replaceSessionHistory } from './history-replacement.js';
31
+ import { appendSessionRecord } from './record-append.js';
32
+ import { MAX_SEGMENT_BYTES, SessionHistoryPageReader, readRecords, readRecordsFromHead, readRecordsFromTail } from './records.js';
33
+ const MAX_CONTEXTUAL_WORLD_STATE_BYTES = 8 * 1024 * 1024;
34
+ /** SDK-owned JSONL history with per-HOME in-process sharing and cross-process file locks. */
35
+ export class JsonlSessionStore {
36
+ static #pool = new JsonlStorePool();
37
+ #shared;
38
+ #maintenance = new WeakMap();
39
+ #leaseClosed = false;
40
+ constructor(shared) {
41
+ this.#shared = shared;
42
+ }
43
+ static async open(home) {
44
+ const root = join(home, '.mar', 'agent');
45
+ return new JsonlSessionStore(await JsonlSessionStore.#pool.acquire(root, () => JsonlSessionStore.#openExclusive(root)));
46
+ }
47
+ /** Create a missing index only without Session directories; recover journals and marked creations. */
48
+ static async #openExclusive(root) {
49
+ const index = await openJsonlIndex(root);
50
+ return {
51
+ root,
52
+ index,
53
+ indexOperations: Promise.resolve(),
54
+ pendingSessions: new Map(),
55
+ references: 1,
56
+ closed: false,
57
+ indexDirty: false,
58
+ dirtySessionVersions: new Map(),
59
+ derivedOnlyDirtySessions: new Set(),
60
+ pendingPublishIds: new Set(),
61
+ codeStateWrites: new Map(),
62
+ recordWrites: new Map(),
63
+ writerLeases: new Map(),
64
+ segments: new Map(),
65
+ executionModelReads: new Map(),
66
+ historyPages: new SessionHistoryPageReader(),
67
+ rootConfirmed: false,
68
+ migrationFailures: new Map()
69
+ };
70
+ }
71
+ /** Merge dirty metadata with disk membership; only createdIds publish locally new entries. */
72
+ async #saveIndex(deletedIds, createdIds = [], onPersisted) {
73
+ return this.#serializeIndexOperation(() => this.#commitIndex(deletedIds, createdIds, onPersisted));
74
+ }
75
+ async #serializeIndexOperation(operation) {
76
+ const next = this.#shared.indexOperations.then(operation, operation);
77
+ this.#shared.indexOperations = next.then(() => undefined, () => undefined);
78
+ return next;
79
+ }
80
+ async #commitIndex(deletedIds, createdIds = [], onPersisted, storageSelection, deleteExpected) {
81
+ if (this.#shared.rootFailure)
82
+ throw this.#shared.rootFailure.error;
83
+ await commitSessionIndex(this.#shared.root, () => ({
84
+ index: this.#shared.index,
85
+ dirty: new Map(this.#shared.dirtySessionVersions),
86
+ derivedOnly: new Set(this.#shared.derivedOnlyDirtySessions)
87
+ }), (updated, dirty, created) => {
88
+ for (const [id, version] of dirty) {
89
+ // A different creation still needs its own index transaction to publish its directory.
90
+ if (this.#shared.pendingPublishIds.has(id) && !created.has(id))
91
+ continue;
92
+ if (this.#shared.dirtySessionVersions.get(id) === version) {
93
+ this.#shared.dirtySessionVersions.delete(id);
94
+ this.#shared.derivedOnlyDirtySessions.delete(id);
95
+ }
96
+ }
97
+ for (const id of created)
98
+ this.#shared.pendingPublishIds.delete(id);
99
+ const published = new Set(updated.sessions.map((session) => session.id));
100
+ const pending = this.#shared.index.sessions.filter((session) => this.#shared.dirtySessionVersions.has(session.id) &&
101
+ (published.has(session.id) || this.#shared.pendingPublishIds.has(session.id)));
102
+ const replacements = new Map(pending.map((session) => [session.id, session]));
103
+ this.#shared.index = {
104
+ ...updated,
105
+ sessions: [
106
+ ...updated.sessions.map((session) => {
107
+ const local = replacements.get(session.id);
108
+ if (!local)
109
+ return session;
110
+ return session.storage === undefined ? local : { ...local, storage: session.storage };
111
+ }),
112
+ ...pending.filter((session) => !published.has(session.id))
113
+ ]
114
+ };
115
+ this.#shared.indexDirty = this.#shared.dirtySessionVersions.size > 0;
116
+ }, deletedIds, createdIds, onPersisted, storageSelection, deleteExpected);
117
+ }
118
+ /** Fence new opens of the legacy SDK without waiting on any Session while holding the index lock. */
119
+ async #ensureRootV2() {
120
+ if (this.#shared.rootFailure)
121
+ throw this.#shared.rootFailure.error;
122
+ if (this.#shared.rootConfirmed && this.#shared.index.version === 2) {
123
+ await this.#refreshIndex();
124
+ if (this.#shared.index.version === 2) {
125
+ await this.#recoverPublications();
126
+ return;
127
+ }
128
+ }
129
+ await this.#serializeIndexOperation(async () => {
130
+ if (this.#shared.rootFailure)
131
+ throw this.#shared.rootFailure.error;
132
+ const path = join(this.#shared.root, 'sessions', 'index.json');
133
+ const release = await acquireFileLock(join(this.#shared.root, 'sessions', 'index.lock'));
134
+ let failure;
135
+ try {
136
+ const disk = await readSessionIndex(path);
137
+ if (!disk)
138
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session index is missing.');
139
+ try {
140
+ if (disk.version === 1)
141
+ await persistFormatSelection(path, upgradeSessionIndex(disk));
142
+ else
143
+ await syncJsonlDirectory(join(this.#shared.root, 'sessions'));
144
+ }
145
+ catch (error) {
146
+ // A failed rename or directory sync is not proof that the fence is absent.
147
+ await readSessionIndex(path).catch(() => undefined);
148
+ this.#shared.rootFailure = { error };
149
+ throw error;
150
+ }
151
+ this.#shared.rootConfirmed = true;
152
+ }
153
+ catch (error) {
154
+ failure = error;
155
+ throw error;
156
+ }
157
+ finally {
158
+ if (failure !== undefined)
159
+ await release().catch(() => undefined);
160
+ else
161
+ await release();
162
+ }
163
+ await this.#readCurrentIndex();
164
+ });
165
+ await this.#recoverPublications();
166
+ }
167
+ async #recoverPublications() {
168
+ this.#shared.publicationRecovery ??= reclaimUnpublishedSessions(this.#shared.root);
169
+ await this.#shared.publicationRecovery;
170
+ }
171
+ async #refreshIndex() {
172
+ return this.#serializeIndexOperation(() => this.#readCurrentIndex());
173
+ }
174
+ async #readCurrentIndex() {
175
+ const disk = await readSessionIndex(join(this.#shared.root, 'sessions', 'index.json'));
176
+ if (!disk)
177
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session index is missing.');
178
+ // A local unflushed revision may exceed another writer's committed revision.
179
+ // Always refresh membership from disk, then overlay only our pending changes.
180
+ const local = new Map(this.#shared.index.sessions.map((session) => [session.id, session]));
181
+ const published = new Set(disk.sessions.map((session) => session.id));
182
+ this.#shared.index = {
183
+ ...disk,
184
+ revision: this.#shared.indexDirty || this.#shared.pendingPublishIds.size > 0
185
+ ? Math.max(disk.revision, this.#shared.index.revision)
186
+ : disk.revision,
187
+ sessions: disk.sessions
188
+ .map((session) => {
189
+ const current = local.get(session.id);
190
+ if (!current || !this.#shared.dirtySessionVersions.has(session.id))
191
+ return session;
192
+ return this.#shared.derivedOnlyDirtySessions.has(session.id)
193
+ ? mergeSessionDerivedCache(session, current)
194
+ : session.storage === undefined
195
+ ? current
196
+ : { ...current, storage: session.storage };
197
+ })
198
+ .concat(this.#shared.index.sessions.filter((session) => this.#shared.pendingPublishIds.has(session.id) && !published.has(session.id)))
199
+ };
200
+ }
201
+ /** Hold the new Session lock and mark its directory until JSONL and index publication finish. */
202
+ async #beginUnpublishedSession(sessionId) {
203
+ const directory = join(this.#shared.root, 'sessions', sessionId);
204
+ await mkdir(directory);
205
+ const release = await acquireFileLock(join(directory, 'lock'), 'Session already has a writer.', 0);
206
+ try {
207
+ await writeFile(join(directory, 'publication-pending'), '1', {
208
+ mode: 0o600,
209
+ flag: 'wx',
210
+ flush: true
211
+ });
212
+ }
213
+ catch (error) {
214
+ await release();
215
+ await rm(directory, { recursive: true, force: true });
216
+ throw error;
217
+ }
218
+ return { directory, release };
219
+ }
220
+ async createSession(input) {
221
+ this.#assertOpen();
222
+ const source = normalizeSessionSource(input.source);
223
+ if (source.type !== 'subagent')
224
+ return this.#createSession(input, source);
225
+ // Publish under the parent's existing serial domain so tree admission cannot miss a child.
226
+ return this.#serializeRecordOperation(source.parentSessionId, async () => {
227
+ this.#assertOpen();
228
+ if (this.#shared.writerLeases.get(source.parentSessionId)?.maintenance)
229
+ throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Session is under maintenance.');
230
+ const release = await this.#acquirePublicationGate(source.parentSessionId, 5000);
231
+ let failure;
232
+ try {
233
+ await this.#recoverPendingTreeDelete(source.parentSessionId);
234
+ if (this.#shared.writerLeases.get(source.parentSessionId)?.maintenance)
235
+ throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Session is under maintenance.');
236
+ await this.getSession(source.parentSessionId);
237
+ return await this.#createSession(input, source);
238
+ }
239
+ catch (error) {
240
+ failure = error;
241
+ throw error;
242
+ }
243
+ finally {
244
+ if (failure !== undefined)
245
+ await release().catch(() => undefined);
246
+ else
247
+ await release();
248
+ }
249
+ });
250
+ }
251
+ async #acquirePublicationGate(sessionId, waitMs = 0) {
252
+ this.#sessionRoot(sessionId);
253
+ const directory = join(this.#shared.root, 'sessions', '.publication-locks');
254
+ await mkdir(directory, { recursive: true, mode: 0o700 });
255
+ return acquireFileLock(join(directory, sessionId), 'Session is under maintenance.', waitMs);
256
+ }
257
+ /** Append the durable creation record before making this Session visible in the index. */
258
+ async #createSession(input, source) {
259
+ await this.#ensureRootV2();
260
+ const id = randomUUID();
261
+ const now = new Date().toISOString();
262
+ const meta = {
263
+ id,
264
+ title: input.title ?? 'New session',
265
+ workspace: input.workspace,
266
+ createdAt: now,
267
+ lastActivityAt: now,
268
+ source,
269
+ storage: { encoding: 2, generation: randomUUID() },
270
+ nextSequence: 1,
271
+ automaticTitlePending: input.title === undefined,
272
+ resume: {
273
+ version: 1,
274
+ userTurns: 0,
275
+ todoRevision: 0,
276
+ executionModelIndexed: true,
277
+ firstUserMessageIndexed: true
278
+ },
279
+ segments: []
280
+ };
281
+ const publication = await this.#beginUnpublishedSession(id);
282
+ this.#shared.segments.set(id, 1);
283
+ this.#shared.pendingSessions.set(id, meta);
284
+ let discard = false;
285
+ let creationFailure;
286
+ try {
287
+ try {
288
+ const generationDirectory = this.#directoryForMeta(id, meta);
289
+ await mkdir(generationDirectory, { recursive: true, mode: 0o700 });
290
+ await syncJsonlDirectory(join(publication.directory, 'v2'));
291
+ await syncJsonlDirectory(publication.directory);
292
+ await this.append(id, {
293
+ type: 'session.created',
294
+ payload: {
295
+ title: meta.title,
296
+ workspace: meta.workspace,
297
+ automaticTitle: input.title === undefined,
298
+ source: meta.source
299
+ }
300
+ });
301
+ await syncJsonlDirectory(generationDirectory);
302
+ }
303
+ catch (error) {
304
+ this.#shared.pendingSessions.delete(id);
305
+ this.#shared.segments.delete(id);
306
+ discard = true;
307
+ throw error;
308
+ }
309
+ this.#shared.pendingSessions.delete(id);
310
+ this.#shared.index.sessions.unshift(meta);
311
+ this.#shared.pendingPublishIds.add(id);
312
+ this.#markIndexDirty(id);
313
+ let persisted = false;
314
+ try {
315
+ await this.#saveIndex(undefined, [id], () => {
316
+ persisted = true;
317
+ });
318
+ }
319
+ catch (error) {
320
+ if (!persisted) {
321
+ if (error instanceof ParentPublicationRejected) {
322
+ discard = true;
323
+ this.#shared.index.sessions = this.#shared.index.sessions.filter((item) => item.id !== id);
324
+ this.#shared.segments.delete(id);
325
+ this.#shared.pendingPublishIds.delete(id);
326
+ this.#shared.dirtySessionVersions.delete(id);
327
+ this.#shared.indexDirty = this.#shared.dirtySessionVersions.size > 0;
328
+ throw error;
329
+ }
330
+ // A failed lock release can follow a committed index rename; do not unpublish that Session.
331
+ // If the index cannot be read, leave the disk marker for recovery and keep the original error.
332
+ const disk = await readSessionIndex(join(this.#shared.root, 'sessions', 'index.json')).catch(() => undefined);
333
+ if (disk?.sessions.some((session) => session.id === id)) {
334
+ this.#shared.pendingPublishIds.delete(id);
335
+ this.#shared.dirtySessionVersions.delete(id);
336
+ this.#shared.indexDirty = this.#shared.dirtySessionVersions.size > 0;
337
+ this.#shared.migrationFailures.set(id, { error, unreadable: true });
338
+ throw error;
339
+ }
340
+ else {
341
+ // Keep the marker until disk membership can be checked during recovery.
342
+ this.#shared.index.sessions = this.#shared.index.sessions.filter((item) => item.id !== id);
343
+ this.#shared.segments.delete(id);
344
+ this.#shared.pendingPublishIds.delete(id);
345
+ this.#shared.dirtySessionVersions.delete(id);
346
+ this.#shared.indexDirty = this.#shared.dirtySessionVersions.size > 0;
347
+ throw error;
348
+ }
349
+ }
350
+ }
351
+ await rm(join(publication.directory, 'publication-pending'), { force: true });
352
+ return meta;
353
+ }
354
+ catch (error) {
355
+ creationFailure = error;
356
+ throw error;
357
+ }
358
+ finally {
359
+ if (creationFailure !== undefined) {
360
+ await publication.release().catch(() => undefined);
361
+ if (discard)
362
+ await rm(publication.directory, { recursive: true, force: true }).catch(() => undefined);
363
+ }
364
+ else
365
+ await publication.release();
366
+ }
367
+ }
368
+ #sessionDirectory(sessionId) {
369
+ this.#assertOpen();
370
+ const migrationFailure = this.#shared.migrationFailures.get(sessionId);
371
+ if (migrationFailure?.unreadable)
372
+ throw migrationFailure.error;
373
+ const failure = this.#shared.writerLeases.get(sessionId)?.historyFailure;
374
+ if (failure)
375
+ throw failure.error;
376
+ if (!this.#shared.index.sessions.some((session) => session.id === sessionId) &&
377
+ !this.#shared.pendingSessions.has(sessionId))
378
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
379
+ const meta = this.#shared.pendingSessions.get(sessionId) ??
380
+ this.#shared.index.sessions.find((session) => session.id === sessionId);
381
+ return this.#directoryForMeta(sessionId, meta);
382
+ }
383
+ #directoryForMeta(sessionId, meta) {
384
+ const root = join(this.#shared.root, 'sessions', sessionId);
385
+ return meta?.storage?.encoding === 2 ? join(root, 'v2', meta.storage.generation) : root;
386
+ }
387
+ #sessionRoot(sessionId) {
388
+ if (!/^[0-9a-f-]{36}$/iu.test(sessionId))
389
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
390
+ return join(this.#shared.root, 'sessions', sessionId);
391
+ }
392
+ #encoding(sessionId) {
393
+ const meta = this.#shared.pendingSessions.get(sessionId) ??
394
+ this.#shared.index.sessions.find((session) => session.id === sessionId);
395
+ return meta?.storage?.encoding ?? 1;
396
+ }
397
+ async readContextualWorldState(sessionId) {
398
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
399
+ await this.#refreshIndex();
400
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
401
+ if (!meta)
402
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
403
+ await this.#segmentPaths(sessionId, meta);
404
+ const path = join(this.#directoryForMeta(sessionId, meta), CONTEXTUAL_WORLD_STATE_FILE);
405
+ try {
406
+ const envelope = JSON.parse(await readFile(path, 'utf8'));
407
+ admitWorldStateVersion(envelope);
408
+ if (envelope.version !== 1 ||
409
+ !Number.isSafeInteger(envelope.historySequence) ||
410
+ envelope.historySequence < 1 ||
411
+ envelope.historySequence >= meta.nextSequence)
412
+ return undefined;
413
+ return envelope.state;
414
+ }
415
+ catch (error) {
416
+ if (error instanceof AgentError && error.code === 'MAR_AGENT_SESSION_VERSION_UNSUPPORTED')
417
+ throw error;
418
+ return undefined;
419
+ }
420
+ });
421
+ }
422
+ async writeContextualWorldState(sessionId, state) {
423
+ return this.#serializeRecordOperation(sessionId, () => this.#withWriteAdmission(sessionId, async () => {
424
+ const directory = this.#sessionDirectory(sessionId);
425
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
426
+ if (!meta)
427
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
428
+ const path = join(directory, CONTEXTUAL_WORLD_STATE_FILE);
429
+ const temporary = `${path}.${randomUUID()}.tmp`;
430
+ const serialized = JSON.stringify({
431
+ version: 1,
432
+ historySequence: meta.nextSequence - 1,
433
+ state
434
+ });
435
+ if (Buffer.byteLength(serialized) > MAX_CONTEXTUAL_WORLD_STATE_BYTES)
436
+ throw new AgentError('MAR_AGENT_HOST_LIMIT_EXCEEDED', 'Contextual world state exceeds the storage limit.');
437
+ try {
438
+ await writeFile(temporary, serialized, { mode: 0o600, flag: 'wx' });
439
+ await rename(temporary, path);
440
+ }
441
+ finally {
442
+ await rm(temporary, { force: true });
443
+ }
444
+ }));
445
+ }
446
+ /** Mark each image pending before publication; turn.user or lease recovery resolves ownership. */
447
+ async persistInputImages(sessionId, images) {
448
+ this.#assertOpen();
449
+ if (images.length === 0)
450
+ return [];
451
+ if (images.length > MAX_INPUT_IMAGES)
452
+ throw new AgentError('MAR_AGENT_HOST_LIMIT_EXCEEDED', 'Too many image inputs were provided.');
453
+ const resources = [];
454
+ let total = 0;
455
+ for (const image of images) {
456
+ if ((image.url !== undefined && !isModelImageUrl(image.url)) ||
457
+ (image.urlExpiresAt !== undefined &&
458
+ (!Number.isSafeInteger(image.urlExpiresAt) ||
459
+ image.urlExpiresAt <= 0 ||
460
+ image.url === undefined)))
461
+ throw new AgentError('MAR_AGENT_SESSION_INPUT_INVALID', 'Image model URL is invalid.');
462
+ let resource = await this.persistResource(sessionId, image);
463
+ if (image.url !== undefined && image.urlExpiresAt !== undefined)
464
+ resource = await this.setResourceUrl(sessionId, resource.resourceId, {
465
+ url: image.url,
466
+ urlExpiresAt: image.urlExpiresAt
467
+ });
468
+ total += resource.byteSize;
469
+ if (resource.byteSize > 5 * 1024 * 1024 || total > 10 * 1024 * 1024)
470
+ throw new AgentError('MAR_AGENT_HOST_LIMIT_EXCEEDED', 'Image input exceeds the supported size limit.');
471
+ resources.push({
472
+ ...resource,
473
+ resourceInputVersion: 1,
474
+ name: image.name
475
+ });
476
+ }
477
+ return resources;
478
+ }
479
+ async persistResource(sessionId, image) {
480
+ this.#assertOpen();
481
+ return this.#serializeRecordOperation(sessionId, () => this.#withWriteAdmission(sessionId, () => persistResource(join(this.#sessionDirectory(sessionId), 'resources'), image), true));
482
+ }
483
+ async setResourceUrl(sessionId, resourceId, published) {
484
+ this.#assertOpen();
485
+ return this.#serializeRecordOperation(sessionId, () => this.#withWriteAdmission(sessionId, () => setResourceUrl(join(this.#sessionDirectory(sessionId), 'resources'), resourceId, published)));
486
+ }
487
+ async readResource(sessionId, resourceId) {
488
+ this.#assertOpen();
489
+ if (!/^[a-f0-9]{64}$/u.test(resourceId))
490
+ return undefined;
491
+ return this.#serializeRecordOperation(sessionId, () => withSessionReadPin(this.#sessionRoot(sessionId), async () => {
492
+ await this.#refreshIndex();
493
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
494
+ if (!meta)
495
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
496
+ await this.#segmentPaths(sessionId, meta);
497
+ const directory = join(this.#directoryForMeta(sessionId, meta), 'resources');
498
+ let pending = false;
499
+ try {
500
+ await lstat(join(directory, `.${resourceId}.pending`));
501
+ pending = true;
502
+ }
503
+ catch (cause) {
504
+ if (cause.code !== 'ENOENT')
505
+ throw new AgentError('MAR_AGENT_IMAGE_UNAVAILABLE', 'Session image resource is unavailable.', {
506
+ cause
507
+ });
508
+ }
509
+ if (pending &&
510
+ (this.#shared.writerLeases.get(sessionId)?.appendFailure !== undefined ||
511
+ !resourceFiles(await this.#readRecords(sessionId, meta)).has(`${resourceId}.bin`)))
512
+ return undefined;
513
+ return readResource(directory, resourceId);
514
+ }));
515
+ }
516
+ async writeToolResultResource(sessionId, text) {
517
+ this.#assertOpen();
518
+ if (!this.#shared.index.sessions.some((item) => item.id === sessionId))
519
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
520
+ return this.#serializeRecordOperation(sessionId, () => this.#withWriteAdmission(sessionId, () => writeToolResultResource(this.#sessionDirectory(sessionId), text), true));
521
+ }
522
+ async readToolResultResource(sessionId, input) {
523
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
524
+ this.#assertOpen();
525
+ await this.#refreshIndex();
526
+ if (!this.#shared.index.sessions.some((item) => item.id === sessionId))
527
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
528
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
529
+ await this.#segmentPaths(sessionId, meta);
530
+ return readToolResultResource(this.#directoryForMeta(sessionId, meta), sessionId, input, async (sequence) => {
531
+ return (await this.#shared.historyPages.read(meta, { beforeSequence: sequence + 1, limit: 1 }, () => this.#segmentPaths(sessionId, meta))).records.find((record) => record.sequence === sequence);
532
+ });
533
+ });
534
+ }
535
+ async readInputImages(sessionId, value) {
536
+ this.#assertOpen();
537
+ const references = inputImageReferences(Array.isArray(value) ? value.filter((item) => item?.resourceInputVersion === 1) : undefined);
538
+ if (references.length === 0)
539
+ return [];
540
+ const images = [];
541
+ for (const reference of references) {
542
+ if (reference.resourceId === undefined)
543
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session resource identity is missing.');
544
+ images.push({
545
+ resourceInputVersion: 1,
546
+ mimeType: reference.mimeType,
547
+ byteSize: reference.byteSize,
548
+ resourceId: reference.resourceId,
549
+ ...(reference.url === undefined ? {} : { url: reference.url }),
550
+ ...(reference.urlExpiresAt === undefined ? {} : { urlExpiresAt: reference.urlExpiresAt })
551
+ });
552
+ }
553
+ return images;
554
+ }
555
+ async readInputImage(sessionId, input) {
556
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
557
+ this.#assertOpen();
558
+ if (!Number.isSafeInteger(input.sequence) ||
559
+ input.sequence < 1 ||
560
+ input.sequence >= Number.MAX_SAFE_INTEGER ||
561
+ !Number.isSafeInteger(input.imageIndex) ||
562
+ input.imageIndex < 0)
563
+ return undefined;
564
+ await this.#refreshIndex();
565
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
566
+ if (!meta)
567
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
568
+ await this.#assertReadable(sessionId, meta);
569
+ const page = await this.#shared.historyPages.read(meta, {
570
+ limit: 1,
571
+ beforeSequence: input.sequence + 1
572
+ }, () => this.#segmentPaths(sessionId, meta));
573
+ const record = page.records[0];
574
+ if (record?.sequence !== input.sequence ||
575
+ record.type !== 'turn.user' ||
576
+ !isObject(record.payload))
577
+ return undefined;
578
+ if (!Array.isArray(record.payload.images) || input.imageIndex >= record.payload.images.length)
579
+ return undefined;
580
+ if (record.payload.images[input.imageIndex]?.resourceInputVersion !== 1)
581
+ return undefined;
582
+ const reference = inputImageReference(record.payload.images[input.imageIndex]);
583
+ if (reference === undefined)
584
+ return undefined;
585
+ if (reference.resourceId === undefined)
586
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session resource identity is missing.');
587
+ const data = await readInputImageBytes(join(this.#directoryForMeta(sessionId, meta), 'resources'), reference);
588
+ return {
589
+ name: reference.name,
590
+ resourceInputVersion: 1,
591
+ resourceId: reference.resourceId,
592
+ mimeType: reference.mimeType,
593
+ byteSize: reference.byteSize,
594
+ sha256: reference.sha256,
595
+ ...(reference.url === undefined ? {} : { url: reference.url }),
596
+ ...(reference.urlExpiresAt === undefined ? {} : { urlExpiresAt: reference.urlExpiresAt }),
597
+ dataBase64: data.toString('base64')
598
+ };
599
+ });
600
+ }
601
+ async forkSession(sourceSessionId, input) {
602
+ return this.#serializeRecordOperation(sourceSessionId, async () => {
603
+ this.#assertOpen();
604
+ await this.#recoverPendingTreeDelete(sourceSessionId);
605
+ if (this.#shared.writerLeases.has(sourceSessionId))
606
+ throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Session already has a writer.');
607
+ const sourceRoot = join(this.#shared.root, 'sessions', sourceSessionId);
608
+ const release = await acquireFileLock(join(sourceRoot, 'lock'));
609
+ try {
610
+ await this.#refreshIndex();
611
+ const source = this.#shared.index.sessions.find((item) => item.id === sourceSessionId);
612
+ if (!source)
613
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
614
+ if (source.storage?.encoding !== 2)
615
+ await preflightV1Session(sourceRoot);
616
+ await this.#ensureRootV2();
617
+ const records = await this.#readRecords(sourceSessionId);
618
+ const boundaryIndex = input.boundaryTurnId === null
619
+ ? -1
620
+ : records.findLastIndex((record) => record.turnId === input.boundaryTurnId);
621
+ if (input.boundaryTurnId !== null && boundaryIndex < 0)
622
+ throw new AgentError('MAR_AGENT_REWIND_TARGET_INVALID', 'Session rewind target was not found.');
623
+ const createdAt = new Date().toISOString();
624
+ const target = {
625
+ id: randomUUID(),
626
+ title: input.title,
627
+ workspace: source.workspace,
628
+ createdAt,
629
+ lastActivityAt: createdAt,
630
+ source: { type: 'user' },
631
+ storage: { encoding: 2, generation: randomUUID() },
632
+ nextSequence: 1,
633
+ automaticTitlePending: false,
634
+ resume: {
635
+ version: 1,
636
+ userTurns: 0,
637
+ todoRevision: 0,
638
+ executionModelIndexed: true,
639
+ firstUserMessageIndexed: true
640
+ },
641
+ segments: []
642
+ };
643
+ const publication = await this.#beginUnpublishedSession(target.id);
644
+ this.#shared.segments.set(target.id, 1);
645
+ this.#shared.pendingSessions.set(target.id, target);
646
+ let discard = false;
647
+ try {
648
+ await mkdir(join(publication.directory, 'v2'), { mode: 0o700 });
649
+ await mkdir(this.#sessionDirectory(target.id), { mode: 0o700 });
650
+ await syncJsonlDirectory(join(publication.directory, 'v2'));
651
+ await syncJsonlDirectory(publication.directory);
652
+ const copied = [
653
+ {
654
+ recordId: randomUUID(),
655
+ sequence: 1,
656
+ timestamp: createdAt,
657
+ sessionId: target.id,
658
+ type: 'session.created',
659
+ payload: {
660
+ title: target.title,
661
+ workspace: target.workspace,
662
+ automaticTitle: false,
663
+ source: target.source
664
+ }
665
+ }
666
+ ];
667
+ const retained = input.boundaryTurnId === null ? [] : records.slice(1, boundaryIndex + 1);
668
+ const inlineState = inlineMediaHistory(retained).state;
669
+ const stateAnchor = inlineState &&
670
+ retained.findLast((record) => record.type === 'resource.window' || record.type === 'compact.completed');
671
+ const forkIdentities = new Map();
672
+ for (const record of retained) {
673
+ if (record.type === 'context.gc.completed' || record.type === 'responses.continuation')
674
+ continue;
675
+ const identity = { recordId: randomUUID(), sequence: copied.length + 1 };
676
+ forkIdentities.set(record.recordId, identity);
677
+ copied.push({
678
+ ...identity,
679
+ sessionId: target.id,
680
+ type: record.type,
681
+ payload: forkedPayload(record.type, record === stateAnchor
682
+ ? record.type === 'resource.window'
683
+ ? inlineState
684
+ : {
685
+ ...record.payload,
686
+ inlineMediaState: inlineState
687
+ }
688
+ : record.payload, sourceSessionId, target.id, input.title, forkIdentities),
689
+ ...(record.executionId === undefined ? {} : { executionId: record.executionId }),
690
+ ...(record.turnId === undefined ? {} : { turnId: record.turnId }),
691
+ timestamp: record.timestamp
692
+ });
693
+ }
694
+ // A fork is unpublished until every segment and referenced image is durable.
695
+ const staged = await stageSessionSegments(this.#sessionDirectory(target.id), copied, 'fork');
696
+ for (const file of staged.files)
697
+ await rename(file.temporaryPath, file.path);
698
+ target.segments = staged.segments;
699
+ target.nextSequence = copied.length + 1;
700
+ this.#shared.segments.set(target.id, staged.segments.length);
701
+ for (const record of copied)
702
+ this.#applyRecordToResumeIndex(target, record);
703
+ await copyToolResultResources(this.#sessionDirectory(sourceSessionId), this.#sessionDirectory(target.id), copied);
704
+ await copyGeneratedImages(sourceRoot, publication.directory, generatedImageFileNames(retained));
705
+ await copyResources(this.#sessionDirectory(sourceSessionId), this.#sessionDirectory(target.id), retained);
706
+ for (const path of [
707
+ join(this.#sessionDirectory(target.id), 'resources'),
708
+ join(this.#sessionDirectory(target.id), 'tool_results'),
709
+ join(this.#sessionRoot(target.id), 'generated_images')
710
+ ])
711
+ if (await sessionDirectoryExists(path))
712
+ await syncJsonlDirectory(path);
713
+ await syncJsonlDirectory(this.#sessionDirectory(target.id));
714
+ await syncJsonlDirectory(this.#sessionRoot(target.id));
715
+ target.lastActivityAt = target.createdAt;
716
+ this.#shared.pendingSessions.delete(target.id);
717
+ this.#shared.index = {
718
+ version: 2,
719
+ revision: this.#shared.index.revision + 1,
720
+ sessions: [target, ...this.#shared.index.sessions]
721
+ };
722
+ this.#shared.pendingPublishIds.add(target.id);
723
+ this.#markIndexDirty(target.id);
724
+ let persisted = false;
725
+ try {
726
+ await this.#saveIndex(undefined, [target.id], () => {
727
+ persisted = true;
728
+ });
729
+ }
730
+ catch (error) {
731
+ if (!persisted)
732
+ throw error;
733
+ }
734
+ await rm(join(publication.directory, 'publication-pending'), { force: true });
735
+ return {
736
+ id: target.id,
737
+ title: target.title,
738
+ workspace: target.workspace,
739
+ createdAt: target.createdAt,
740
+ lastActivityAt: target.createdAt,
741
+ source: target.source
742
+ };
743
+ }
744
+ catch (error) {
745
+ this.#shared.pendingSessions.delete(target.id);
746
+ const disk = await readSessionIndex(join(this.#shared.root, 'sessions', 'index.json'));
747
+ if (disk?.sessions.some((session) => session.id === target.id)) {
748
+ this.#shared.migrationFailures.set(target.id, { error, unreadable: true });
749
+ throw error;
750
+ }
751
+ const publishedIndex = this.#shared.index.sessions.findIndex((item) => item.id === target.id);
752
+ if (publishedIndex >= 0) {
753
+ this.#shared.index.sessions.splice(publishedIndex, 1);
754
+ this.#shared.index.revision++;
755
+ this.#shared.pendingPublishIds.delete(target.id);
756
+ this.#shared.dirtySessionVersions.delete(target.id);
757
+ this.#shared.indexDirty = this.#shared.dirtySessionVersions.size > 0;
758
+ }
759
+ this.#shared.segments.delete(target.id);
760
+ discard = true;
761
+ throw error;
762
+ }
763
+ finally {
764
+ try {
765
+ await publication.release();
766
+ }
767
+ finally {
768
+ if (discard)
769
+ await rm(publication.directory, { recursive: true, force: true });
770
+ }
771
+ }
772
+ }
773
+ finally {
774
+ await release();
775
+ }
776
+ });
777
+ }
778
+ /** Replace history under a journal; the indexed transaction ID decides the commit side. */
779
+ async rollbackSession(sessionId, input) {
780
+ this.#assertOpen();
781
+ const release = await this.acquireSessionLease(sessionId);
782
+ let failed = false;
783
+ try {
784
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
785
+ if (!meta)
786
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
787
+ const records = await this.read(sessionId);
788
+ if (records[0]?.type !== 'session.created')
789
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.');
790
+ const boundaryIndex = rollbackBoundaryIndex(records, input);
791
+ const retained = records
792
+ .slice(0, boundaryIndex + 1)
793
+ .filter((record) => record.type !== 'responses.continuation');
794
+ return await this.#replaceHistory(meta, retained, { kind: 'rollback' });
795
+ }
796
+ catch (error) {
797
+ failed = true;
798
+ throw error;
799
+ }
800
+ finally {
801
+ if (failed)
802
+ await release().catch(() => undefined);
803
+ else
804
+ await release();
805
+ }
806
+ }
807
+ async updateTitle(sessionId, title, input = {}, owner) {
808
+ this.#assertOpen();
809
+ const normalized = title.trim();
810
+ if (!normalized)
811
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Session title is required.');
812
+ const release = await this.acquireSessionLease(sessionId, owner);
813
+ try {
814
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
815
+ if (input.expectedTitle !== undefined && meta.title !== input.expectedTitle)
816
+ return false;
817
+ if (input.automatic || input.executionId !== undefined) {
818
+ const records = await this.read(sessionId);
819
+ const latestTitle = records.findLast((record) => record.type === 'session.title.updated');
820
+ if (input.automatic &&
821
+ (records[0]?.payload?.automaticTitle !== true ||
822
+ latestTitle?.payload?.automatic === false))
823
+ return false;
824
+ if (input.executionId !== undefined &&
825
+ records.findLast((record) => record.type === 'turn.user')?.executionId !==
826
+ input.executionId)
827
+ return false;
828
+ }
829
+ await this.append(sessionId, {
830
+ type: 'session.title.updated',
831
+ payload: { title: normalized, automatic: input.automatic === true },
832
+ ...(input.executionId ? { executionId: input.executionId } : {}),
833
+ ...(input.turnId ? { turnId: input.turnId } : {})
834
+ });
835
+ return true;
836
+ }
837
+ finally {
838
+ await release();
839
+ }
840
+ }
841
+ /** Reset history with the same recovery journal while preserving the Session identity. */
842
+ async clearSession(sessionId, maintenance) {
843
+ this.#assertOpen();
844
+ const holding = maintenance ?? (await this.acquireSessionMaintenance(sessionId, 'clear'));
845
+ this.#assertMaintenance(sessionId, 'clear', holding);
846
+ let failed = false;
847
+ try {
848
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
849
+ if (!meta)
850
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
851
+ const records = await this.read(sessionId);
852
+ if (records[0]?.type !== 'session.created')
853
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.');
854
+ const clearedAt = new Date().toISOString();
855
+ const retained = [
856
+ {
857
+ recordId: randomUUID(),
858
+ sequence: 1,
859
+ timestamp: meta.createdAt,
860
+ sessionId,
861
+ type: 'session.created',
862
+ payload: {
863
+ title: meta.title,
864
+ workspace: meta.workspace,
865
+ automaticTitle: meta.automaticTitlePending === true,
866
+ source: normalizeSessionSource(meta.source)
867
+ }
868
+ }
869
+ ];
870
+ return await this.#replaceHistory(meta, retained, { kind: 'clear', clearedAt });
871
+ }
872
+ catch (error) {
873
+ failed = true;
874
+ throw error;
875
+ }
876
+ finally {
877
+ if (!maintenance) {
878
+ const releasing = holding.release();
879
+ if (failed)
880
+ await releasing.catch(() => undefined);
881
+ else
882
+ await releasing;
883
+ }
884
+ }
885
+ }
886
+ /** Called only while rollback or clear holds the maintenance lease. */
887
+ async #replaceHistory(meta, retained, operation) {
888
+ const sessionId = meta.id;
889
+ const shared = this.#shared;
890
+ let indexConfirmed = false;
891
+ const before = structuredClone(meta);
892
+ const invalidate = (error) => {
893
+ const writer = shared.writerLeases.get(sessionId);
894
+ if (writer) {
895
+ writer.appendFailure ??= { error };
896
+ writer.historyFailure ??= { error };
897
+ delete writer.codeState;
898
+ delete writer.extensionCheckpoints;
899
+ }
900
+ shared.dirtySessionVersions.delete(sessionId);
901
+ shared.derivedOnlyDirtySessions.delete(sessionId);
902
+ shared.indexDirty = shared.dirtySessionVersions.size > 0;
903
+ shared.segments.delete(sessionId);
904
+ };
905
+ const targetGeneration = operation.kind === 'clear' && (meta.storage?.encoding ?? 1) === 1 ? randomUUID() : undefined;
906
+ return withSessionReadDrain(this.#sessionRoot(sessionId), async () => {
907
+ if (targetGeneration !== undefined) {
908
+ const parent = join(this.#sessionRoot(sessionId), 'v2');
909
+ await mkdir(parent, { recursive: true, mode: 0o700 });
910
+ await mkdir(join(parent, targetGeneration), { mode: 0o700 });
911
+ await syncJsonlDirectory(parent);
912
+ await syncJsonlDirectory(this.#sessionRoot(sessionId));
913
+ }
914
+ const result = await replaceSessionHistory(meta, retained, operation, {
915
+ directory: this.#sessionDirectory(sessionId),
916
+ sessionDirectory: this.#sessionRoot(sessionId),
917
+ ...(targetGeneration === undefined ? {} : { targetGeneration }),
918
+ segmentPaths: () => this.#segmentPaths(sessionId),
919
+ settleIndex: (request, recover) => this.#serializeIndexOperation(async () => {
920
+ let current;
921
+ let previous;
922
+ let previousRevision = 0;
923
+ let previousSegment;
924
+ try {
925
+ if (request.kind === 'recover')
926
+ throw request.error;
927
+ const change = request.change;
928
+ current = shared.index.sessions.find((item) => item.id === sessionId);
929
+ if (!current)
930
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session index entry is missing.');
931
+ previous = structuredClone(current);
932
+ previousRevision = shared.index.revision;
933
+ previousSegment = shared.segments.get(sessionId);
934
+ if (change.kind === 'rollback') {
935
+ current.title = change.title ?? current.title;
936
+ current.lastActivityAt = new Date().toISOString();
937
+ current.automaticTitlePending = change.state.automaticTitlePending;
938
+ current.resume = change.state.resume;
939
+ }
940
+ else {
941
+ current.lastActivityAt = change.clearedAt;
942
+ current.resume = {
943
+ version: 1,
944
+ userTurns: 0,
945
+ todoRevision: 0,
946
+ firstUserMessageIndexed: true
947
+ };
948
+ }
949
+ current.nextSequence = change.nextSequence;
950
+ current.storageTransactionId = change.transactionId;
951
+ current.segments = change.segments;
952
+ if (change.targetGeneration !== undefined)
953
+ current.storage = { encoding: 2, generation: change.targetGeneration };
954
+ shared.segments.set(sessionId, change.kind === 'clear' ? 1 : (change.segments.at(-1)?.number ?? 1));
955
+ shared.index.revision++;
956
+ this.#markIndexDirty(sessionId);
957
+ await this.#commitIndex(undefined, [], () => {
958
+ indexConfirmed = true;
959
+ }, targetGeneration === undefined
960
+ ? undefined
961
+ : { before, generation: targetGeneration });
962
+ return { status: 'committed', meta: structuredClone(current) };
963
+ }
964
+ catch (error) {
965
+ try {
966
+ const selected = await this.#storageTransactionCommitted(sessionId, request.kind === 'apply' ? request.change.transactionId : request.transactionId);
967
+ if (selected && !indexConfirmed)
968
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'History transaction durability is uncertain.');
969
+ if (selected) {
970
+ shared.dirtySessionVersions.delete(sessionId);
971
+ shared.indexDirty = shared.dirtySessionVersions.size > 0;
972
+ await recover(true);
973
+ return { status: 'committed', meta: structuredClone(current), error };
974
+ }
975
+ await recover(false);
976
+ if (current && previous) {
977
+ restoreSessionIndexMeta(current, previous);
978
+ shared.index.revision = previousRevision;
979
+ if (previousSegment === undefined)
980
+ shared.segments.delete(sessionId);
981
+ else
982
+ shared.segments.set(sessionId, previousSegment);
983
+ this.#markIndexDirty(sessionId);
984
+ }
985
+ return { status: 'not-committed', error };
986
+ }
987
+ catch {
988
+ invalidate(error);
989
+ return { status: 'unknown', error };
990
+ }
991
+ }
992
+ })
993
+ });
994
+ if (result.status === 'unknown' ||
995
+ (result.status === 'committed' && result.recoveryRequired)) {
996
+ invalidate(result.error);
997
+ }
998
+ if (result.status !== 'committed' || result.error !== undefined)
999
+ throw result.error;
1000
+ shared.migrationFailures.delete(sessionId);
1001
+ return {
1002
+ id: result.meta.id,
1003
+ title: result.meta.title,
1004
+ workspace: result.meta.workspace,
1005
+ createdAt: result.meta.createdAt,
1006
+ lastActivityAt: result.meta.lastActivityAt,
1007
+ source: normalizeSessionSource(result.meta.source)
1008
+ };
1009
+ });
1010
+ }
1011
+ async getSession(sessionId) {
1012
+ this.#assertOpen();
1013
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
1014
+ await this.#refreshIndex();
1015
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
1016
+ if (!meta)
1017
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1018
+ return {
1019
+ id: meta.id,
1020
+ title: meta.title,
1021
+ workspace: meta.workspace,
1022
+ createdAt: meta.createdAt,
1023
+ lastActivityAt: meta.lastActivityAt,
1024
+ source: normalizeSessionSource(meta.source),
1025
+ automaticTitlePending: meta.automaticTitlePending === true
1026
+ };
1027
+ }, true);
1028
+ }
1029
+ /** Serialize physical writes and honor cancellation before entering the writer. */
1030
+ async append(sessionId, input, options = {}) {
1031
+ this.#assertOpen();
1032
+ options.signal?.throwIfAborted();
1033
+ return this.#serializeRecordOperation(sessionId, () => this.#withWriteAdmission(sessionId, async () => {
1034
+ options.signal?.throwIfAborted();
1035
+ const writer = this.#shared.writerLeases.get(sessionId);
1036
+ try {
1037
+ const result = await this.#appendRecord(sessionId, input);
1038
+ if (writer?.pendingResource) {
1039
+ for (const name of resourceFiles([result]))
1040
+ if (name.endsWith('.bin'))
1041
+ writer.pendingResource.delete(`image:${name.slice(0, -4)}`);
1042
+ for (const resource of recordToolResources(result))
1043
+ writer.pendingResource.delete(`tool:${resource.resourceRef}`);
1044
+ if (writer.pendingResource.size === 0) {
1045
+ delete writer.pendingResource;
1046
+ writer.retained--;
1047
+ await this.#releaseUnusedWriter(sessionId, writer);
1048
+ }
1049
+ }
1050
+ return result;
1051
+ }
1052
+ catch (error) {
1053
+ if (writer?.pendingResource && !writer.executing && !writer.appendFailure) {
1054
+ delete writer.pendingResource;
1055
+ writer.retained--;
1056
+ await this.#releaseUnusedWriter(sessionId, writer).catch(() => undefined);
1057
+ }
1058
+ throw error;
1059
+ }
1060
+ }));
1061
+ }
1062
+ /** Called inside the Session serial queue; existing leases already own the physical lock. */
1063
+ async #withWriteAdmission(sessionId, action, holdPending = false) {
1064
+ if (this.#shared.pendingSessions.has(sessionId))
1065
+ return action();
1066
+ const existing = this.#shared.writerLeases.get(sessionId);
1067
+ if (existing) {
1068
+ const recoveryFailure = this.#shared.migrationFailures.get(sessionId);
1069
+ if (recoveryFailure)
1070
+ throw recoveryFailure.error;
1071
+ if (existing.appendFailure)
1072
+ throw existing.appendFailure.error;
1073
+ if (existing.historyFailure)
1074
+ throw existing.historyFailure.error;
1075
+ if (existing.maintenance)
1076
+ throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Session is under maintenance.');
1077
+ const result = await action();
1078
+ if (holdPending && existing.pendingResource)
1079
+ this.#trackPendingResource(existing, result);
1080
+ return result;
1081
+ }
1082
+ const release = await this.#acquireSessionLease(sessionId);
1083
+ const writer = { owner: undefined, executing: false, retained: 0, release };
1084
+ this.#shared.writerLeases.set(sessionId, writer);
1085
+ let failure;
1086
+ try {
1087
+ const result = await action();
1088
+ if (holdPending) {
1089
+ writer.pendingResource = new Set();
1090
+ this.#trackPendingResource(writer, result);
1091
+ writer.retained++;
1092
+ }
1093
+ return result;
1094
+ }
1095
+ catch (error) {
1096
+ failure = error;
1097
+ throw error;
1098
+ }
1099
+ finally {
1100
+ if (failure !== undefined)
1101
+ await this.#releaseUnusedWriter(sessionId, writer).catch(() => undefined);
1102
+ else
1103
+ await this.#releaseUnusedWriter(sessionId, writer);
1104
+ }
1105
+ }
1106
+ #trackPendingResource(writer, value) {
1107
+ if (!isObject(value) || !writer.pendingResource)
1108
+ return;
1109
+ if (typeof value.resourceId === 'string')
1110
+ writer.pendingResource.add(`image:${value.resourceId}`);
1111
+ if (typeof value.resourceRef === 'string')
1112
+ writer.pendingResource.add(`tool:${value.resourceRef}`);
1113
+ }
1114
+ async #serializeRecordOperation(sessionId, action) {
1115
+ const operation = (this.#shared.recordWrites.get(sessionId) ?? Promise.resolve())
1116
+ .catch(() => undefined)
1117
+ .then(action);
1118
+ this.#shared.recordWrites.set(sessionId, operation);
1119
+ try {
1120
+ return await operation;
1121
+ }
1122
+ finally {
1123
+ if (this.#shared.recordWrites.get(sessionId) === operation)
1124
+ this.#shared.recordWrites.delete(sessionId);
1125
+ }
1126
+ }
1127
+ async #appendRecord(sessionId, input) {
1128
+ this.#assertOpen();
1129
+ const recoveryFailure = this.#shared.migrationFailures.get(sessionId);
1130
+ if (recoveryFailure)
1131
+ throw recoveryFailure.error;
1132
+ const writer = this.#shared.writerLeases.get(sessionId);
1133
+ if (writer?.appendFailure)
1134
+ throw writer.appendFailure.error;
1135
+ const before = this.#shared.index.sessions.find((item) => item.id === sessionId) ??
1136
+ this.#shared.pendingSessions.get(sessionId);
1137
+ if (!before)
1138
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1139
+ const published = !this.#shared.pendingSessions.has(sessionId);
1140
+ return appendSessionRecord(sessionId, input, {
1141
+ sequence: before.nextSequence,
1142
+ directory: () => this.#sessionDirectory(sessionId),
1143
+ readRecordAtSequence: (sequence) => this.#readRecordAtSequence(before, sequence),
1144
+ currentSegment: () => this.#currentSegment(sessionId),
1145
+ segmentPath: (segment) => this.#segmentPath(sessionId, segment),
1146
+ setCurrentSegment: (segment) => this.#shared.segments.set(sessionId, segment),
1147
+ markWriteFailure: (error) => {
1148
+ if (writer)
1149
+ writer.appendFailure = { error };
1150
+ },
1151
+ invalidateAfterWriteFailure: () => {
1152
+ // A failed write/sync/close can leave a complete record on disk.
1153
+ const current = this.#shared.index.sessions.find((item) => item.id === sessionId) ?? before;
1154
+ if (current.resume?.userTurns !== undefined) {
1155
+ delete current.resume.userTurns;
1156
+ if (published)
1157
+ this.#markIndexDirty(sessionId);
1158
+ }
1159
+ const lease = this.#shared.writerLeases.get(sessionId);
1160
+ if (lease) {
1161
+ delete lease.codeState;
1162
+ delete lease.extensionCheckpoints;
1163
+ }
1164
+ },
1165
+ publish: (record, serialized, segment) => {
1166
+ // Index refreshes and commits can replace metadata during file I/O. Publish all
1167
+ // durable-record metadata onto the current entry without another await boundary.
1168
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId) ??
1169
+ this.#shared.pendingSessions.get(sessionId);
1170
+ if (!meta)
1171
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1172
+ meta.nextSequence = record.sequence + 1;
1173
+ const segmentMetadata = meta.segments ?? (meta.segments = []);
1174
+ const known = segmentMetadata.find((item) => item.number === segment);
1175
+ if (known) {
1176
+ known.lastSequence = record.sequence;
1177
+ known.bytes += Buffer.byteLength(serialized);
1178
+ }
1179
+ else
1180
+ segmentMetadata.push({
1181
+ number: segment,
1182
+ firstSequence: record.sequence,
1183
+ lastSequence: record.sequence,
1184
+ bytes: Buffer.byteLength(serialized)
1185
+ });
1186
+ meta.lastActivityAt = record.timestamp;
1187
+ this.#applyRecordToResumeIndex(meta, record);
1188
+ if (published) {
1189
+ this.#shared.index.revision++;
1190
+ this.#markIndexDirty(sessionId);
1191
+ }
1192
+ updateSessionCurrentState(this.#shared.writerLeases.get(sessionId), record.type, serialized);
1193
+ }
1194
+ });
1195
+ }
1196
+ async read(sessionId) {
1197
+ return this.#serializeRecordOperation(sessionId, () => this.#readRecords(sessionId));
1198
+ }
1199
+ async #readRecords(sessionId, selectedMeta) {
1200
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
1201
+ this.#assertOpen();
1202
+ if (!selectedMeta)
1203
+ await this.#refreshIndex();
1204
+ const failure = this.#shared.writerLeases.get(sessionId)?.historyFailure;
1205
+ if (failure)
1206
+ throw failure.error;
1207
+ const migrationFailure = this.#shared.migrationFailures.get(sessionId);
1208
+ if (migrationFailure?.unreadable)
1209
+ throw migrationFailure.error;
1210
+ try {
1211
+ const records = [];
1212
+ const meta = selectedMeta ?? this.#shared.index.sessions.find((item) => item.id === sessionId);
1213
+ const encoding = meta?.storage?.encoding ?? 1;
1214
+ for (const path of await this.#segmentPaths(sessionId, meta))
1215
+ records.push(...(await readRecords(path, encoding)));
1216
+ return records;
1217
+ }
1218
+ catch (cause) {
1219
+ if (cause instanceof AgentError)
1220
+ throw cause;
1221
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.', { cause });
1222
+ }
1223
+ });
1224
+ }
1225
+ async readCodeModeState(sessionId) {
1226
+ return this.#serializeRecordOperation(sessionId, () => withSessionReadPin(this.#sessionRoot(sessionId), () => this.#readCodeModeState(sessionId)));
1227
+ }
1228
+ async #readCodeModeState(sessionId) {
1229
+ this.#assertOpen();
1230
+ const lease = this.#shared.writerLeases.get(sessionId);
1231
+ if (lease?.owner === undefined)
1232
+ return restoreCodeModeState(await this.#readRecords(sessionId));
1233
+ lease.codeState ??= restoreCodeModeState(await this.#readRecords(sessionId));
1234
+ return applyCodeModeStateMutations(lease.codeState, []);
1235
+ }
1236
+ async readExtensionCheckpoint(sessionId, extensionId, key) {
1237
+ return this.#serializeRecordOperation(sessionId, () => withSessionReadPin(this.#sessionRoot(sessionId), () => this.#readExtensionCheckpoint(sessionId, extensionId, key)));
1238
+ }
1239
+ async #readExtensionCheckpoint(sessionId, extensionId, key) {
1240
+ this.#assertOpen();
1241
+ const lease = this.#shared.writerLeases.get(sessionId);
1242
+ if (lease?.owner === undefined)
1243
+ return restoreExtensionCheckpoint(await this.#readRecords(sessionId), extensionId, key);
1244
+ if (!lease.extensionCheckpoints) {
1245
+ const index = new Map();
1246
+ for (const record of await this.#readRecords(sessionId))
1247
+ if (record.type === 'extension.checkpoint.updated')
1248
+ indexExtensionCheckpoint(index, record.payload);
1249
+ lease.extensionCheckpoints = index;
1250
+ }
1251
+ return extensionCheckpointFromPayload(lease.extensionCheckpoints.get(extensionId)?.get(key));
1252
+ }
1253
+ async writeExtensionCheckpoint(sessionId, extensionId, key, value, expectedRevision, input) {
1254
+ if (typeof key !== 'string' ||
1255
+ (expectedRevision !== undefined &&
1256
+ (!Number.isSafeInteger(expectedRevision) || expectedRevision < 0)))
1257
+ throw new AgentError('MAR_AGENT_EXTENSION_DATA_INVALID', 'Checkpoint key or expected revision is invalid.');
1258
+ const copied = value === undefined ? undefined : cloneCoreJson(value);
1259
+ input.signal.throwIfAborted();
1260
+ const release = await this.acquireSessionWriteLease(sessionId, input.owner);
1261
+ try {
1262
+ return await this.#serializeRecordOperation(sessionId, async () => {
1263
+ const current = await this.#readExtensionCheckpoint(sessionId, extensionId, key);
1264
+ if (expectedRevision !== undefined && expectedRevision !== current.revision)
1265
+ throw new AgentError('MAR_AGENT_EXTENSION_DATA_CONFLICT', 'Checkpoint revision changed before commit.');
1266
+ input.signal.throwIfAborted();
1267
+ const revision = current.revision + 1;
1268
+ await this.#appendRecord(sessionId, {
1269
+ type: 'extension.checkpoint.updated',
1270
+ payload: {
1271
+ extensionId,
1272
+ key,
1273
+ revision,
1274
+ ...(copied === undefined ? { deleted: true } : { value: copied })
1275
+ },
1276
+ ...(input.executionId ? { executionId: input.executionId } : {}),
1277
+ ...(input.turnId ? { turnId: input.turnId } : {})
1278
+ });
1279
+ return { revision, ...(copied === undefined ? {} : { value: cloneCoreJson(copied) }) };
1280
+ });
1281
+ }
1282
+ finally {
1283
+ await release();
1284
+ }
1285
+ }
1286
+ async commitCodeModeState(sessionId, mutations, input) {
1287
+ const operation = (this.#shared.codeStateWrites.get(sessionId) ?? Promise.resolve())
1288
+ .catch(() => undefined)
1289
+ .then(async () => {
1290
+ const parsed = parseCodeModeStateMutations(mutations);
1291
+ if (parsed.length === 0)
1292
+ return this.readCodeModeState(sessionId);
1293
+ const current = await this.readCodeModeState(sessionId);
1294
+ if (input.expectedState && !isDeepStrictEqual(current, input.expectedState))
1295
+ throw new AgentError('MAR_AGENT_CODE_STATE_CONFLICT', 'Session state changed while this cell was running.');
1296
+ const state = applyCodeModeStateMutations(current, parsed);
1297
+ await this.append(sessionId, {
1298
+ type: 'code.state.updated',
1299
+ payload: { mutations: parsed },
1300
+ executionId: input.executionId,
1301
+ turnId: input.turnId
1302
+ });
1303
+ return state;
1304
+ });
1305
+ this.#shared.codeStateWrites.set(sessionId, operation);
1306
+ try {
1307
+ return await operation;
1308
+ }
1309
+ finally {
1310
+ if (this.#shared.codeStateWrites.get(sessionId) === operation)
1311
+ this.#shared.codeStateWrites.delete(sessionId);
1312
+ }
1313
+ }
1314
+ async readExecutionState(sessionId) {
1315
+ return this.#serializeRecordOperation(sessionId, () => withSessionReadPin(this.#sessionRoot(sessionId), async () => {
1316
+ this.#assertOpen();
1317
+ await this.#refreshIndex();
1318
+ const failure = this.#shared.writerLeases.get(sessionId)?.historyFailure;
1319
+ if (failure)
1320
+ throw failure.error;
1321
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
1322
+ if (!meta)
1323
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1324
+ await this.#assertReadable(sessionId, meta);
1325
+ if (meta.resume?.version !== 1 ||
1326
+ typeof meta.automaticTitlePending !== 'boolean' ||
1327
+ meta.resume.compactSequence === undefined)
1328
+ return this.#rebuildExecutionState(meta);
1329
+ try {
1330
+ const contextRecords = await this.#readFromSequence(meta, meta.resume.compactSequence);
1331
+ if (contextRecords[0]?.sequence !== meta.resume.compactSequence ||
1332
+ !isCompactCheckpoint(contextRecords[0]) ||
1333
+ contextRecords.some((record, index) => index > 0 && isCompactCheckpoint(record)))
1334
+ return this.#rebuildExecutionState(meta);
1335
+ const todo = await this.#readIndexedTodo(meta, contextRecords);
1336
+ if (!todo)
1337
+ return this.#rebuildExecutionState(meta);
1338
+ return {
1339
+ automaticTitlePending: meta.automaticTitlePending,
1340
+ todo,
1341
+ contextRecords
1342
+ };
1343
+ }
1344
+ catch {
1345
+ return this.#rebuildExecutionState(meta);
1346
+ }
1347
+ }));
1348
+ }
1349
+ /** Compare the planned sequence inside the existing record writer queue. */
1350
+ async commitContextGc(sessionId, draft, planningRecords) {
1351
+ this.#assertOpen();
1352
+ const records = planningRecords ?? (await this.readExecutionState(sessionId)).contextRecords;
1353
+ return this.#serializeRecordOperation(sessionId, () => this.#withWriteAdmission(sessionId, async () => {
1354
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
1355
+ if (!meta)
1356
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1357
+ const boundarySequence = meta.nextSequence - 1;
1358
+ if (boundarySequence !== draft.boundarySequence)
1359
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC projection changed before checkpoint commit.');
1360
+ if (records.at(-1)?.sequence !== boundarySequence ||
1361
+ records.at(-1)?.sessionId !== sessionId ||
1362
+ !sameContextGcBase(contextGcBaseFromRecords(records, boundarySequence), draft.base))
1363
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC planning boundary is invalid.');
1364
+ const previous = latestValidContextGcCheckpoint(records, boundarySequence);
1365
+ if ((!draft.inlineMedia || draft.inlineMedia.reason === 'TEXT_GC') &&
1366
+ !contextGcCheckpointIntervalEligible(draft.trigger, previous?.payload.trigger))
1367
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint interval validation failed.');
1368
+ const plannedReplacements = normalizeContextGcReplacements(draft.replacements);
1369
+ if (!plannedReplacements || (plannedReplacements.length === 0 && !draft.inlineMedia))
1370
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint must contain a replacement.');
1371
+ const replacements = normalizeContextGcReplacements([
1372
+ ...(previous?.payload.replacements ?? []),
1373
+ ...plannedReplacements
1374
+ ]);
1375
+ if (!replacements ||
1376
+ (previous &&
1377
+ isDeepStrictEqual(replacements, previous.payload.replacements) &&
1378
+ (!draft.inlineMedia ||
1379
+ isDeepStrictEqual(draft.inlineMedia, previous.payload.inlineMedia))))
1380
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC replacement map is invalid.');
1381
+ const payload = {
1382
+ ...structuredClone(draft),
1383
+ checkpointId: randomUUID(),
1384
+ generation: (previous?.payload.generation ?? 0) + 1,
1385
+ replacements
1386
+ };
1387
+ const candidate = {
1388
+ recordId: randomUUID(),
1389
+ sequence: boundarySequence + 1,
1390
+ timestamp: new Date().toISOString(),
1391
+ sessionId,
1392
+ type: 'context.gc.completed',
1393
+ payload
1394
+ };
1395
+ if (Buffer.byteLength(JSON.stringify(payload)) >= MAX_SEGMENT_BYTES ||
1396
+ validateContextGcCheckpoint(records, candidate, meta.workspace, previous?.payload.replacements) === undefined)
1397
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint validation failed.');
1398
+ const turnId = records.findLast((record) => record.type === 'execution.header')?.turnId;
1399
+ return this.#appendRecord(sessionId, {
1400
+ type: 'context.gc.completed',
1401
+ ...(turnId === undefined ? {} : { turnId }),
1402
+ payload
1403
+ });
1404
+ }));
1405
+ }
1406
+ async readPage(sessionId, input = {}) {
1407
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
1408
+ await this.#refreshIndex();
1409
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
1410
+ if (!meta)
1411
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1412
+ await this.#assertReadable(sessionId, meta);
1413
+ return this.#shared.historyPages.read(meta, input, () => this.#segmentPaths(sessionId, meta));
1414
+ });
1415
+ }
1416
+ async compact(sessionId, input, options = {}) {
1417
+ if (!input.summary.trim())
1418
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Compact summary is required.');
1419
+ const recoveryFailure = this.#shared.migrationFailures.get(sessionId);
1420
+ if (recoveryFailure && this.#shared.writerLeases.has(sessionId))
1421
+ throw recoveryFailure.error;
1422
+ await this.#recoverPendingTreeDelete(sessionId);
1423
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
1424
+ if (!meta)
1425
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1426
+ return this.append(sessionId, {
1427
+ type: 'compact.completed',
1428
+ payload: {
1429
+ summary: input.summary,
1430
+ ...(input.pendingInputs?.length ? { pendingInputs: input.pendingInputs } : {}),
1431
+ ...(input.snapshotRecordId === undefined
1432
+ ? {}
1433
+ : { snapshotRecordId: input.snapshotRecordId }),
1434
+ ...(input.snapshotMessageCount === undefined
1435
+ ? {}
1436
+ : { snapshotMessageCount: input.snapshotMessageCount }),
1437
+ ...(input.replacementHistory === undefined
1438
+ ? {}
1439
+ : { replacementHistory: input.replacementHistory }),
1440
+ ...(input.retainedModelContext?.length
1441
+ ? { retainedModelContext: input.retainedModelContext }
1442
+ : {}),
1443
+ ...(input.inlineMediaState ? { inlineMediaState: input.inlineMediaState } : {}),
1444
+ ...(input.environment === undefined ? {} : { environment: input.environment }),
1445
+ boundarySequence: meta.nextSequence - 1,
1446
+ automatic: input.automatic === true,
1447
+ ...(input.modelId === undefined ? {} : { modelId: input.modelId }),
1448
+ ...(input.contextWindowTokens === undefined
1449
+ ? {}
1450
+ : { contextWindowTokens: input.contextWindowTokens }),
1451
+ ...(input.usage === undefined ? {} : { usage: input.usage })
1452
+ },
1453
+ ...(input.executionId ? { executionId: input.executionId } : {}),
1454
+ ...(input.turnId ? { turnId: input.turnId } : {})
1455
+ }, options);
1456
+ }
1457
+ /** A warm cell retains physical writer ownership between Executions of the same Agent. */
1458
+ async acquireSessionLease(sessionId, owner) {
1459
+ return this.#serializeRecordOperation(sessionId, async () => {
1460
+ this.#assertOpen();
1461
+ let lease = this.#shared.writerLeases.get(sessionId);
1462
+ if (lease) {
1463
+ const adoptPending = !!lease.pendingResource && !lease.executing && lease.owner === undefined;
1464
+ if (lease.maintenance ||
1465
+ lease.executing ||
1466
+ (!adoptPending && (owner === undefined || lease.owner !== owner)))
1467
+ throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Session already has a writer.');
1468
+ if (lease.appendFailure)
1469
+ throw lease.appendFailure.error;
1470
+ if (adoptPending)
1471
+ lease.owner = owner;
1472
+ lease.executing = true;
1473
+ }
1474
+ else {
1475
+ const release = await this.#acquireSessionLease(sessionId);
1476
+ lease = { owner, executing: true, retained: 0, release };
1477
+ this.#shared.writerLeases.set(sessionId, lease);
1478
+ }
1479
+ const current = lease;
1480
+ let released = false;
1481
+ return () => this.#serializeRecordOperation(sessionId, async () => {
1482
+ if (released)
1483
+ return;
1484
+ released = true;
1485
+ current.executing = false;
1486
+ if (current.pendingResource) {
1487
+ delete current.pendingResource;
1488
+ current.retained--;
1489
+ }
1490
+ await this.#releaseUnusedWriter(sessionId, current);
1491
+ });
1492
+ });
1493
+ }
1494
+ hasRetainedSessionLease(sessionId, owner) {
1495
+ const lease = this.#shared.writerLeases.get(sessionId);
1496
+ return lease?.owner === owner && lease.retained > 0;
1497
+ }
1498
+ async acquireSessionMaintenance(sessionId, kind, owner) {
1499
+ this.#assertOpen();
1500
+ await this.#recoverPendingTreeDelete(sessionId);
1501
+ return acquireTreeMaintenance({
1502
+ sessionId,
1503
+ kind,
1504
+ tree: () => this.sessionTree(sessionId),
1505
+ acquire: (id, holding, registerGate) => this.#serializeRecordOperation(id, async () => {
1506
+ this.#assertOpen();
1507
+ registerGate(await this.#acquirePublicationGate(id));
1508
+ let writer = this.#shared.writerLeases.get(id);
1509
+ if (writer &&
1510
+ (writer.maintenance ||
1511
+ owner === undefined ||
1512
+ writer.owner !== owner ||
1513
+ (kind === 'clear' && writer.executing)))
1514
+ throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Session already has a writer.');
1515
+ if (!writer) {
1516
+ const release = kind === 'delete' && !(await sessionDirectoryExists(this.#sessionRoot(id)))
1517
+ ? async () => { }
1518
+ : await this.#acquireSessionLease(id, kind);
1519
+ writer = { owner, executing: false, retained: 0, release };
1520
+ this.#shared.writerLeases.set(id, writer);
1521
+ }
1522
+ writer.maintenance = holding;
1523
+ const current = writer;
1524
+ return () => this.#serializeRecordOperation(id, async () => {
1525
+ delete current.maintenance;
1526
+ await this.#releaseUnusedWriter(id, current);
1527
+ });
1528
+ }),
1529
+ admitted: (holding) => this.#maintenance.set(holding, { sessionId, kind }),
1530
+ released: (holding) => this.#maintenance.delete(holding)
1531
+ });
1532
+ }
1533
+ #assertMaintenance(sessionId, kind, holding) {
1534
+ const current = this.#maintenance.get(holding);
1535
+ if (current?.sessionId !== sessionId || current.kind !== kind)
1536
+ throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Session maintenance ownership is invalid.');
1537
+ }
1538
+ /** Native writes join their Agent's sole writer, without admitting another Execution. */
1539
+ async acquireSessionWriteLease(sessionId, owner) {
1540
+ return this.#serializeRecordOperation(sessionId, async () => {
1541
+ this.#assertOpen();
1542
+ let lease = this.#shared.writerLeases.get(sessionId);
1543
+ const recoveryFailure = this.#shared.migrationFailures.get(sessionId);
1544
+ if (lease && recoveryFailure)
1545
+ throw recoveryFailure.error;
1546
+ if (lease && (lease.maintenance || lease.owner !== owner))
1547
+ throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Session already has a writer.');
1548
+ if (lease?.appendFailure)
1549
+ throw lease.appendFailure.error;
1550
+ if (!lease) {
1551
+ const release = await this.#acquireSessionLease(sessionId);
1552
+ lease = { owner, executing: false, retained: 0, release };
1553
+ this.#shared.writerLeases.set(sessionId, lease);
1554
+ }
1555
+ lease.retained++;
1556
+ const current = lease;
1557
+ let released = false;
1558
+ return () => this.#serializeRecordOperation(sessionId, async () => {
1559
+ if (released)
1560
+ return;
1561
+ released = true;
1562
+ current.retained--;
1563
+ await this.#releaseUnusedWriter(sessionId, current);
1564
+ });
1565
+ });
1566
+ }
1567
+ async retainSessionLease(sessionId, owner) {
1568
+ return this.#serializeRecordOperation(sessionId, async () => {
1569
+ const lease = this.#shared.writerLeases.get(sessionId);
1570
+ if (!lease || lease.maintenance || !lease.executing || lease.owner !== owner)
1571
+ throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Retained work requires its originating Session writer.');
1572
+ lease.retained++;
1573
+ let released = false;
1574
+ return () => this.#serializeRecordOperation(sessionId, async () => {
1575
+ if (released)
1576
+ return;
1577
+ released = true;
1578
+ lease.retained--;
1579
+ await this.#releaseUnusedWriter(sessionId, lease);
1580
+ });
1581
+ });
1582
+ }
1583
+ async #releaseUnusedWriter(sessionId, lease) {
1584
+ if (lease.maintenance || lease.executing || lease.retained)
1585
+ return;
1586
+ try {
1587
+ await lease.release();
1588
+ }
1589
+ finally {
1590
+ delete lease.codeState;
1591
+ delete lease.extensionCheckpoints;
1592
+ this.#shared.writerLeases.delete(sessionId);
1593
+ }
1594
+ }
1595
+ /** Recover files under the sole writer lock; flush dirty index state before releasing it. */
1596
+ async #acquireSessionLease(sessionId, mode = 'write') {
1597
+ this.#assertOpen();
1598
+ await this.#recoverPendingTreeDelete(sessionId);
1599
+ const priorFailure = this.#shared.migrationFailures.get(sessionId);
1600
+ if (priorFailure && (mode === 'write' || (mode === 'clear' && priorFailure.unreadable)))
1601
+ throw priorFailure.error;
1602
+ await this.#refreshIndex();
1603
+ if (!this.#shared.index.sessions.some((item) => item.id === sessionId))
1604
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1605
+ const path = join(this.#shared.root, 'sessions', sessionId, 'lock');
1606
+ const release = await acquireFileLock(path, 'Session already has a writer.', 0);
1607
+ try {
1608
+ const disk = await readSessionIndex(join(this.#shared.root, 'sessions', 'index.json'));
1609
+ if (!disk)
1610
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session index is missing.');
1611
+ const current = disk.sessions.find((item) => item.id === sessionId);
1612
+ if (!current)
1613
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1614
+ if (mode !== 'delete') {
1615
+ const sessionRoot = join(this.#shared.root, 'sessions', sessionId);
1616
+ if ((current.storage?.encoding ?? 1) === 1) {
1617
+ await preflightV1Session(sessionRoot);
1618
+ await preflightRetiredRecovery(sessionRoot, sessionRoot);
1619
+ }
1620
+ else {
1621
+ if (await sessionDirectoryExists(join(sessionRoot, 'storage-transaction.json'))) {
1622
+ await preflightV1Session(sessionRoot);
1623
+ await preflightRetiredRecovery(sessionRoot, sessionRoot);
1624
+ }
1625
+ const activeDirectory = this.#directoryForMeta(sessionId, current);
1626
+ await preflightV2Recovery(activeDirectory);
1627
+ await preflightRetiredRecovery(sessionRoot, activeDirectory);
1628
+ }
1629
+ }
1630
+ await this.#ensureRootV2();
1631
+ await rm(join(this.#sessionRoot(sessionId), 'publication-pending'), { force: true });
1632
+ if (mode !== 'delete') {
1633
+ await withSessionReadDrain(this.#sessionRoot(sessionId), async () => {
1634
+ await this.#refreshIndex();
1635
+ const sessionRoot = this.#sessionRoot(sessionId);
1636
+ const activeDirectory = this.#sessionDirectory(sessionId);
1637
+ if (activeDirectory !== sessionRoot &&
1638
+ (await sessionDirectoryExists(join(sessionRoot, 'storage-transaction.json'))))
1639
+ await recoverSessionStorageTransaction(sessionRoot, current.storageTransactionId, sessionRoot);
1640
+ await recoverSessionStorageTransaction(activeDirectory, current.storageTransactionId, sessionRoot);
1641
+ await recoverContextualWorldStateTransactions(this.#shared.root, current);
1642
+ await this.#refreshIndex();
1643
+ await this.#reconcileTail(sessionId);
1644
+ });
1645
+ if (mode === 'clear' && this.#shared.indexDirty)
1646
+ await this.#saveIndex();
1647
+ if (mode === 'write' && this.#encoding(sessionId) === 1) {
1648
+ if (this.#shared.indexDirty)
1649
+ await this.#saveIndex();
1650
+ await this.#migrateV1Session(sessionId);
1651
+ }
1652
+ }
1653
+ }
1654
+ catch (error) {
1655
+ await release().catch(() => undefined);
1656
+ throw error;
1657
+ }
1658
+ return async () => {
1659
+ let failure;
1660
+ try {
1661
+ if (this.#shared.indexDirty)
1662
+ await this.#saveIndex();
1663
+ }
1664
+ catch (error) {
1665
+ failure = error;
1666
+ throw error;
1667
+ }
1668
+ finally {
1669
+ if (failure !== undefined)
1670
+ await release().catch(() => undefined);
1671
+ else
1672
+ await release();
1673
+ }
1674
+ };
1675
+ }
1676
+ /** The Session lock is held; conversion is outside the short index selection transaction. */
1677
+ async #migrateV1Session(sessionId) {
1678
+ const source = join(this.#shared.root, 'sessions', sessionId);
1679
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
1680
+ if (!meta)
1681
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1682
+ const generation = randomUUID();
1683
+ const parent = join(source, 'v2');
1684
+ const destination = join(parent, generation);
1685
+ let commitAttempted = false;
1686
+ let visible = 'v1';
1687
+ try {
1688
+ await mkdir(parent, { recursive: true, mode: 0o700 });
1689
+ const candidate = await prepareJsonlV2Generation({
1690
+ source,
1691
+ destination,
1692
+ sessionId,
1693
+ nextSequence: meta.nextSequence
1694
+ });
1695
+ await syncJsonlDirectory(parent);
1696
+ await syncJsonlDirectory(source);
1697
+ await this.#serializeIndexOperation(async () => {
1698
+ const path = join(this.#shared.root, 'sessions', 'index.json');
1699
+ const release = await acquireFileLock(join(this.#shared.root, 'sessions', 'index.lock'));
1700
+ let failure;
1701
+ try {
1702
+ const disk = await readSessionIndex(path);
1703
+ const current = disk?.sessions.find((item) => item.id === sessionId);
1704
+ if (!disk ||
1705
+ disk.version !== 2 ||
1706
+ !current ||
1707
+ current.storage?.encoding !== 1 ||
1708
+ current.nextSequence !== meta.nextSequence ||
1709
+ current.storageTransactionId !== meta.storageTransactionId)
1710
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session migration index changed.');
1711
+ const replacement = {
1712
+ ...current,
1713
+ storage: { encoding: 2, generation },
1714
+ segments: candidate.segments
1715
+ };
1716
+ const updated = {
1717
+ ...disk,
1718
+ sessions: disk.sessions.map((entry) => (entry.id === sessionId ? replacement : entry))
1719
+ };
1720
+ commitAttempted = true;
1721
+ try {
1722
+ await persistFormatSelection(path, updated);
1723
+ visible = 'v2';
1724
+ }
1725
+ catch (error) {
1726
+ const check = await readSessionIndex(path).catch(() => undefined);
1727
+ const choice = check?.sessions.find((entry) => entry.id === sessionId)?.storage;
1728
+ visible =
1729
+ choice?.encoding === 1
1730
+ ? 'v1'
1731
+ : choice?.encoding === 2 && choice.generation === generation
1732
+ ? 'v2'
1733
+ : 'unknown';
1734
+ throw error;
1735
+ }
1736
+ }
1737
+ catch (error) {
1738
+ failure = error;
1739
+ throw error;
1740
+ }
1741
+ finally {
1742
+ if (failure !== undefined)
1743
+ await release().catch(() => undefined);
1744
+ else
1745
+ await release();
1746
+ }
1747
+ await this.#readCurrentIndex();
1748
+ });
1749
+ this.#shared.segments.delete(sessionId);
1750
+ }
1751
+ catch (error) {
1752
+ if (visible === 'v1') {
1753
+ // This candidate cannot be selected; preserve the original failure if cleanup fails.
1754
+ await rm(destination, { recursive: true, force: true })
1755
+ .then(() => syncJsonlDirectory(parent))
1756
+ .catch(() => undefined);
1757
+ }
1758
+ this.#shared.migrationFailures.set(sessionId, {
1759
+ error,
1760
+ unreadable: commitAttempted && visible !== 'v1'
1761
+ });
1762
+ throw error;
1763
+ }
1764
+ }
1765
+ async list(input = {}) {
1766
+ this.#assertOpen();
1767
+ await this.#refreshIndex();
1768
+ const filter = sessionListFilter(input);
1769
+ const start = decodeSessionListCursor(input.cursor, this.#shared.index.revision, filter);
1770
+ const limit = Math.min(200, Math.max(1, input.limit ?? 50));
1771
+ const ordered = this.#shared.index.sessions
1772
+ .filter((session) => sessionMatchesFilter(session, filter))
1773
+ .sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt));
1774
+ const sessions = ordered.slice(start, start + limit).map((session) => ({
1775
+ id: session.id,
1776
+ title: session.title,
1777
+ ...(session.resume?.firstUserMessagePreview === undefined
1778
+ ? {}
1779
+ : { firstUserMessagePreview: session.resume.firstUserMessagePreview }),
1780
+ workspace: session.workspace,
1781
+ createdAt: session.createdAt,
1782
+ lastActivityAt: session.lastActivityAt,
1783
+ source: normalizeSessionSource(session.source),
1784
+ ...(session.resume?.modelId === undefined
1785
+ ? {}
1786
+ : {
1787
+ modelId: session.resume.modelId,
1788
+ ...(session.resume.modelName === undefined
1789
+ ? {}
1790
+ : { modelName: session.resume.modelName }),
1791
+ ...(session.resume.reasoningEffort === undefined
1792
+ ? {}
1793
+ : { reasoningEffort: session.resume.reasoningEffort })
1794
+ })
1795
+ }));
1796
+ const next = start + limit < ordered.length
1797
+ ? encodeSessionListCursor(this.#shared.index.revision, start + limit, filter)
1798
+ : undefined;
1799
+ return { sessions, ...(next ? { nextCursor: next } : {}) };
1800
+ }
1801
+ async listSubagentChildren(parentSessionId) {
1802
+ this.#assertOpen();
1803
+ if (!/^[0-9a-f-]{36}$/iu.test(parentSessionId))
1804
+ return [];
1805
+ return withSessionReadPin(this.#sessionRoot(parentSessionId), async () => {
1806
+ await this.#refreshIndex();
1807
+ return this.#shared.index.sessions
1808
+ .map((session) => ({ session, source: normalizeSessionSource(session.source) }))
1809
+ .filter((item) => item.source.type === 'subagent' && item.source.parentSessionId === parentSessionId)
1810
+ .map(({ session, source }) => ({
1811
+ id: session.id,
1812
+ title: session.title,
1813
+ workspace: session.workspace,
1814
+ createdAt: session.createdAt,
1815
+ lastActivityAt: session.lastActivityAt,
1816
+ source,
1817
+ ...(session.resume?.modelId === undefined
1818
+ ? {}
1819
+ : {
1820
+ modelId: session.resume.modelId,
1821
+ ...(session.resume.modelName === undefined
1822
+ ? {}
1823
+ : { modelName: session.resume.modelName }),
1824
+ ...(session.resume.reasoningEffort === undefined
1825
+ ? {}
1826
+ : { reasoningEffort: session.resume.reasoningEffort })
1827
+ })
1828
+ }));
1829
+ }, true);
1830
+ }
1831
+ async executionConfiguration(sessionId) {
1832
+ this.#assertOpen();
1833
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
1834
+ await this.#refreshIndex();
1835
+ let meta = this.#shared.index.sessions.find((session) => session.id === sessionId);
1836
+ if (meta === undefined)
1837
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1838
+ if (meta.resume?.executionModelIndexed !== true) {
1839
+ await this.#ensureExecutionModelIndexed(sessionId);
1840
+ meta = this.#shared.index.sessions.find((session) => session.id === sessionId);
1841
+ if (meta === undefined)
1842
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1843
+ }
1844
+ return meta.resume?.modelId === undefined
1845
+ ? undefined
1846
+ : {
1847
+ modelId: meta.resume.modelId,
1848
+ ...(meta.resume.modelName === undefined ? {} : { modelName: meta.resume.modelName }),
1849
+ ...(meta.resume.reasoningEffort === undefined
1850
+ ? {}
1851
+ : { reasoningEffort: meta.resume.reasoningEffort })
1852
+ };
1853
+ }, true);
1854
+ }
1855
+ async sessionTree(sessionId) {
1856
+ this.#assertOpen();
1857
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
1858
+ await this.#refreshIndex();
1859
+ if (!this.#shared.index.sessions.some((session) => session.id === sessionId))
1860
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1861
+ return sessionTreeIds(this.#shared.index.sessions, sessionId);
1862
+ }, true);
1863
+ }
1864
+ #applyRecordToResumeIndex(meta, record) {
1865
+ if (record.type === 'turn.user')
1866
+ meta.automaticTitlePending = false;
1867
+ if (record.type === 'session.title.updated' && isObject(record.payload)) {
1868
+ if (typeof record.payload.title === 'string')
1869
+ meta.title = record.payload.title;
1870
+ meta.automaticTitlePending = false;
1871
+ }
1872
+ const resume = meta.resume;
1873
+ if (resume?.version !== 1 || !Number.isSafeInteger(resume.todoRevision))
1874
+ return;
1875
+ if (resume.userTurns !== undefined && isNativeUserTurn(record))
1876
+ resume.userTurns++;
1877
+ if (resume.firstUserMessageIndexed === true && resume.firstUserMessagePreview === undefined) {
1878
+ const preview = userMessagePreviewFromRecord(record);
1879
+ if (preview !== undefined)
1880
+ resume.firstUserMessagePreview = preview;
1881
+ }
1882
+ const executionModel = executionModelFromRecord(record);
1883
+ if (executionModel !== undefined) {
1884
+ resume.executionModelIndexed = true;
1885
+ resume.modelId = executionModel.modelId;
1886
+ if (executionModel.modelName === undefined)
1887
+ delete resume.modelName;
1888
+ else
1889
+ resume.modelName = executionModel.modelName;
1890
+ if (executionModel.reasoningEffort === undefined)
1891
+ delete resume.reasoningEffort;
1892
+ else
1893
+ resume.reasoningEffort = executionModel.reasoningEffort;
1894
+ }
1895
+ if (isCompactCheckpoint(record))
1896
+ resume.compactSequence = record.sequence;
1897
+ if (record.type !== 'todo.updated' || !todoItemsFromSnapshot(record.payload))
1898
+ return;
1899
+ resume.todoSequence = record.sequence;
1900
+ resume.todoRevision++;
1901
+ }
1902
+ async #readIndexedTodo(meta, contextRecords) {
1903
+ const resume = meta.resume;
1904
+ if (resume?.version !== 1 ||
1905
+ !Number.isSafeInteger(resume.todoRevision) ||
1906
+ resume.todoRevision < 0)
1907
+ return undefined;
1908
+ const latestContextTodo = contextRecords.findLast((record) => record.type === 'todo.updated' && todoItemsFromSnapshot(record.payload) !== undefined);
1909
+ if (latestContextTodo &&
1910
+ (resume.todoSequence === undefined || latestContextTodo.sequence !== resume.todoSequence))
1911
+ return undefined;
1912
+ if (resume.todoSequence === undefined)
1913
+ return resume.todoRevision === 0 ? { revision: 0, items: [] } : undefined;
1914
+ if (resume.todoRevision === 0)
1915
+ return undefined;
1916
+ const record = contextRecords.find((item) => item.sequence === resume.todoSequence) ??
1917
+ (await this.#readRecordAtSequence(meta, resume.todoSequence));
1918
+ if (record?.type !== 'todo.updated')
1919
+ return undefined;
1920
+ const items = todoItemsFromSnapshot(record.payload);
1921
+ return items ? { revision: resume.todoRevision, items } : undefined;
1922
+ }
1923
+ async #readRecordAtSequence(meta, sequence) {
1924
+ const segment = meta.segments?.find((item) => item.firstSequence <= sequence && item.lastSequence >= sequence);
1925
+ if (!segment)
1926
+ return undefined;
1927
+ return (await readRecords(this.#segmentPath(meta.id, segment.number, meta), meta.storage?.encoding ?? 1)).find((record) => record.sequence === sequence);
1928
+ }
1929
+ async #readFromSequence(meta, sequence) {
1930
+ const segments = (meta.segments ?? [])
1931
+ .filter((item) => item.lastSequence >= sequence)
1932
+ .sort((left, right) => left.number - right.number);
1933
+ if (segments.length === 0)
1934
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session resume index is invalid.');
1935
+ const records = [];
1936
+ for (const segment of segments)
1937
+ records.push(...(await readRecords(this.#segmentPath(meta.id, segment.number, meta), meta.storage?.encoding ?? 1)).filter((record) => record.sequence >= sequence));
1938
+ return records;
1939
+ }
1940
+ async #rebuildExecutionState(meta) {
1941
+ const state = deriveExecutionState(await this.#readRecords(meta.id, meta));
1942
+ if (meta.automaticTitlePending !== state.automaticTitlePending ||
1943
+ !sameResumeIndex(meta.resume, state.resume)) {
1944
+ meta.automaticTitlePending = state.automaticTitlePending;
1945
+ meta.resume = state.resume;
1946
+ this.#shared.index.revision++;
1947
+ if ((meta.storage?.encoding ?? 1) === 2)
1948
+ this.#markIndexDirty(meta.id);
1949
+ }
1950
+ return {
1951
+ automaticTitlePending: state.automaticTitlePending,
1952
+ todo: state.todo,
1953
+ contextRecords: state.contextRecords
1954
+ };
1955
+ }
1956
+ /** Counts native input records, not the post-Compact model context. */
1957
+ async userTurnCount(sessionId) {
1958
+ return this.#serializeRecordOperation(sessionId, () => withSessionReadPin(this.#sessionRoot(sessionId), async () => {
1959
+ this.#assertOpen();
1960
+ await this.#refreshIndex();
1961
+ const before = this.#shared.index.sessions.find((session) => session.id === sessionId);
1962
+ if (!before)
1963
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1964
+ const indexed = before.resume?.userTurns;
1965
+ if (indexed !== undefined && this.#shared.writerLeases.has(sessionId))
1966
+ return indexed;
1967
+ const nextSequence = before.nextSequence;
1968
+ const transactionId = before.storageTransactionId;
1969
+ const paths = await this.#segmentPaths(sessionId, before);
1970
+ const encoding = before.storage?.encoding ?? 1;
1971
+ let count = indexed ?? 0;
1972
+ let lastSequence = 0;
1973
+ let reachedPrefix = false;
1974
+ if (indexed !== undefined) {
1975
+ // No local writer: a previous writer may have committed bytes but not its index.
1976
+ for (const path of [...paths].reverse()) {
1977
+ for await (const record of readRecordsFromTail(path, undefined, encoding)) {
1978
+ lastSequence = Math.max(lastSequence, record.sequence);
1979
+ if (record.sequence < nextSequence) {
1980
+ reachedPrefix = true;
1981
+ break;
1982
+ }
1983
+ if (isNativeUserTurn(record))
1984
+ count++;
1985
+ }
1986
+ if (reachedPrefix)
1987
+ break;
1988
+ }
1989
+ }
1990
+ if (indexed === undefined || lastSequence < nextSequence - 1) {
1991
+ count = 0;
1992
+ lastSequence = 0;
1993
+ for (const path of paths) {
1994
+ for await (const record of readRecordsFromHead(path, encoding)) {
1995
+ lastSequence = record.sequence;
1996
+ if (isNativeUserTurn(record))
1997
+ count++;
1998
+ }
1999
+ }
2000
+ }
2001
+ await this.#refreshIndex();
2002
+ const current = this.#shared.index.sessions.find((session) => session.id === sessionId);
2003
+ if (!current)
2004
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
2005
+ if (current.storageTransactionId !== transactionId) {
2006
+ // The indexed prefix no longer belongs to this history. Fall back to the
2007
+ // ordinary physical read boundary without caching or a conflict error.
2008
+ count = 0;
2009
+ for (const path of await this.#segmentPaths(sessionId, current))
2010
+ for await (const record of readRecordsFromHead(path, current.storage?.encoding ?? 1))
2011
+ if (isNativeUserTurn(record))
2012
+ count++;
2013
+ return count;
2014
+ }
2015
+ if (current.nextSequence === nextSequence &&
2016
+ lastSequence === nextSequence - 1 &&
2017
+ current.resume?.userTurns === undefined) {
2018
+ (current.resume ??= { version: 1, todoRevision: 0 }).userTurns = count;
2019
+ this.#markIndexDirty(sessionId, true);
2020
+ }
2021
+ return count;
2022
+ }));
2023
+ }
2024
+ async firstUserMessagePreview(sessionId) {
2025
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
2026
+ this.#assertOpen();
2027
+ await this.#refreshIndex();
2028
+ await this.#ensureFirstUserMessageIndexed(sessionId);
2029
+ return this.#shared.index.sessions.find((session) => session.id === sessionId)?.resume
2030
+ ?.firstUserMessagePreview;
2031
+ });
2032
+ }
2033
+ async #ensureFirstUserMessageIndexed(sessionId) {
2034
+ for (;;) {
2035
+ const before = this.#shared.index.sessions.find((session) => session.id === sessionId);
2036
+ if (before === undefined)
2037
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
2038
+ if (before.resume?.firstUserMessageIndexed === true)
2039
+ return;
2040
+ const nextSequence = before.nextSequence;
2041
+ const transactionId = before.storageTransactionId;
2042
+ let preview;
2043
+ try {
2044
+ for (const path of await this.#segmentPaths(sessionId, before)) {
2045
+ for await (const record of readRecordsFromHead(path, before.storage?.encoding ?? 1)) {
2046
+ preview = userMessagePreviewFromRecord(record);
2047
+ if (preview !== undefined)
2048
+ break;
2049
+ }
2050
+ if (preview !== undefined)
2051
+ break;
2052
+ }
2053
+ }
2054
+ catch (error) {
2055
+ if (error.code !== 'ENOENT' &&
2056
+ !(error instanceof AgentError && error.code === 'MAR_AGENT_SESSION_NOT_FOUND'))
2057
+ throw error;
2058
+ }
2059
+ await this.#refreshIndex();
2060
+ const current = this.#shared.index.sessions.find((session) => session.id === sessionId);
2061
+ if (current === undefined)
2062
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
2063
+ if (current.resume?.firstUserMessageIndexed === true)
2064
+ return;
2065
+ if (current.nextSequence !== nextSequence || current.storageTransactionId !== transactionId)
2066
+ continue;
2067
+ const resume = (current.resume ??= { version: 1, todoRevision: 0 });
2068
+ resume.firstUserMessageIndexed = true;
2069
+ if (preview !== undefined)
2070
+ resume.firstUserMessagePreview = preview;
2071
+ // Derived preview caches do not change list membership, ordering or filters.
2072
+ this.#markIndexDirty(sessionId, true);
2073
+ return;
2074
+ }
2075
+ }
2076
+ async #ensureExecutionModelIndexed(sessionId) {
2077
+ const pending = this.#shared.executionModelReads.get(sessionId);
2078
+ if (pending !== undefined)
2079
+ return pending;
2080
+ const read = this.#backfillExecutionModel(sessionId).finally(() => {
2081
+ if (this.#shared.executionModelReads.get(sessionId) === read)
2082
+ this.#shared.executionModelReads.delete(sessionId);
2083
+ });
2084
+ this.#shared.executionModelReads.set(sessionId, read);
2085
+ return read;
2086
+ }
2087
+ async #backfillExecutionModel(sessionId) {
2088
+ for (;;) {
2089
+ const before = this.#shared.index.sessions.find((session) => session.id === sessionId);
2090
+ if (before === undefined)
2091
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
2092
+ if (before.resume?.executionModelIndexed === true)
2093
+ return;
2094
+ const nextSequence = before.nextSequence;
2095
+ const transactionId = before.storageTransactionId;
2096
+ const model = await this.#readLatestExecutionModel(sessionId);
2097
+ // Refresh can replace metadata objects while unrelated sessions are being read.
2098
+ // Merge only into the current entry, and retry if the authoritative history changed.
2099
+ await this.#refreshIndex();
2100
+ const current = this.#shared.index.sessions.find((session) => session.id === sessionId);
2101
+ if (current === undefined)
2102
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
2103
+ if (current.resume?.executionModelIndexed === true)
2104
+ return;
2105
+ if (current.nextSequence !== nextSequence || current.storageTransactionId !== transactionId)
2106
+ continue;
2107
+ // A missing resume index stays incomplete (no compact boundary); execution
2108
+ // recovery will rebuild it separately instead of doing so during discovery.
2109
+ const resume = (current.resume ??= { version: 1, todoRevision: 0 });
2110
+ resume.executionModelIndexed = true;
2111
+ delete resume.modelId;
2112
+ delete resume.modelName;
2113
+ delete resume.reasoningEffort;
2114
+ if (model !== undefined)
2115
+ Object.assign(resume, model);
2116
+ this.#shared.index.revision++;
2117
+ if ((current.storage?.encoding ?? 1) === 2)
2118
+ this.#markIndexDirty(sessionId);
2119
+ return;
2120
+ }
2121
+ }
2122
+ async #readLatestExecutionModel(sessionId) {
2123
+ return withSessionReadPin(this.#sessionRoot(sessionId), async () => {
2124
+ try {
2125
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
2126
+ for (const path of (await this.#segmentPaths(sessionId, meta)).reverse())
2127
+ for await (const record of readRecordsFromTail(path, undefined, meta?.storage?.encoding ?? 1)) {
2128
+ const model = executionModelFromRecord(record);
2129
+ if (model !== undefined)
2130
+ return model;
2131
+ }
2132
+ return undefined;
2133
+ }
2134
+ catch (error) {
2135
+ if (error.code === 'ENOENT' ||
2136
+ (error instanceof AgentError && error.code === 'MAR_AGENT_SESSION_NOT_FOUND'))
2137
+ return undefined;
2138
+ throw error;
2139
+ }
2140
+ });
2141
+ }
2142
+ async #withTreeReadDrains(ids, action) {
2143
+ const ordered = [...ids].sort();
2144
+ const take = (index) => index === ordered.length
2145
+ ? action()
2146
+ : withSessionReadDrain(this.#sessionRoot(ordered[index]), () => take(index + 1));
2147
+ return take(0);
2148
+ }
2149
+ async #treeDeleteCommitted(transaction) {
2150
+ const root = join(this.#shared.root, 'sessions');
2151
+ return this.#serializeIndexOperation(async () => {
2152
+ const release = await acquireFileLock(join(root, 'index.lock'));
2153
+ let failure;
2154
+ try {
2155
+ // Lock against another rename between durability confirmation and reading the decision.
2156
+ await syncJsonlDirectory(root);
2157
+ const disk = await readSessionIndex(join(root, 'index.json'));
2158
+ if (!disk)
2159
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session index is missing.');
2160
+ const count = transaction.members.filter((member) => disk.sessions.some((entry) => entry.id === member.id)).length;
2161
+ if (count !== 0 && count !== transaction.members.length)
2162
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session deletion outcome is indeterminate.');
2163
+ if (count !== 0)
2164
+ for (const member of transaction.members) {
2165
+ const current = disk.sessions.find((entry) => entry.id === member.id);
2166
+ const identity = member.identity;
2167
+ if (current.createdAt !== identity.createdAt ||
2168
+ current.workspace !== identity.workspace ||
2169
+ current.nextSequence !== identity.nextSequence ||
2170
+ current.storageTransactionId !== identity.storageTransactionId ||
2171
+ !isDeepStrictEqual(current.source, identity.source) ||
2172
+ !isDeepStrictEqual(current.storage, identity.storage))
2173
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session deletion identity changed.');
2174
+ }
2175
+ return count === 0;
2176
+ }
2177
+ catch (error) {
2178
+ failure = error;
2179
+ throw error;
2180
+ }
2181
+ finally {
2182
+ if (failure !== undefined)
2183
+ await release().catch(() => undefined);
2184
+ else
2185
+ await release();
2186
+ }
2187
+ });
2188
+ }
2189
+ async #recoverPendingTreeDelete(sessionId) {
2190
+ this.#sessionRoot(sessionId);
2191
+ const root = join(this.#shared.root, 'sessions');
2192
+ const transaction = await readTreeDeleteTransaction(root, sessionId);
2193
+ if (!transaction)
2194
+ return;
2195
+ const releases = [];
2196
+ let failure;
2197
+ try {
2198
+ for (const member of [...transaction.members].sort((a, b) => a.id.localeCompare(b.id))) {
2199
+ if (await sessionDirectoryExists(join(root, member.id)))
2200
+ releases.push(await acquireFileLock(join(root, member.id, 'lock'), 'Session already has a writer.', 0));
2201
+ }
2202
+ await this.#withTreeReadDrains(transaction.members.map((member) => member.id), async () => {
2203
+ // Confirm the journal phase is durable before choosing its recovery path.
2204
+ await syncJsonlDirectory(join(root, '.delete-pending'));
2205
+ const current = await readTreeDeleteTransaction(root, sessionId);
2206
+ if (!current)
2207
+ return;
2208
+ if (current.id !== transaction.id)
2209
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session deletion journal changed.');
2210
+ if (current.phase === 'preparing' || current.phase === 'restored')
2211
+ await finishTreeDeletePreparation(root, current, syncJsonlDirectory);
2212
+ else {
2213
+ const committed = await this.#treeDeleteCommitted(current);
2214
+ await finishTreeDelete(root, current, committed, syncJsonlDirectory);
2215
+ }
2216
+ });
2217
+ for (const member of transaction.members)
2218
+ this.#shared.migrationFailures.delete(member.id);
2219
+ await this.#refreshIndex();
2220
+ }
2221
+ catch (error) {
2222
+ failure = error;
2223
+ throw error;
2224
+ }
2225
+ finally {
2226
+ let releaseFailure;
2227
+ for (const release of releases.reverse()) {
2228
+ try {
2229
+ await release();
2230
+ }
2231
+ catch (error) {
2232
+ releaseFailure ??= error;
2233
+ }
2234
+ }
2235
+ if (failure === undefined && releaseFailure !== undefined)
2236
+ throw releaseFailure;
2237
+ }
2238
+ }
2239
+ async delete(sessionId, maintenance) {
2240
+ this.#assertOpen();
2241
+ const holding = maintenance ?? (await this.acquireSessionMaintenance(sessionId, 'delete'));
2242
+ this.#assertMaintenance(sessionId, 'delete', holding);
2243
+ const tree = [sessionId, ...holding.sessionIds.filter((id) => id !== sessionId)];
2244
+ let failed = false;
2245
+ try {
2246
+ // Same-owner Executions may have left newer target metadata dirty in memory.
2247
+ // Publish that state before using it as the tree deletion CAS baseline.
2248
+ if (this.#shared.indexDirty)
2249
+ await this.#saveIndex();
2250
+ const root = join(this.#shared.root, 'sessions');
2251
+ const expected = tree.map((id) => {
2252
+ const meta = this.#shared.index.sessions.find((entry) => entry.id === id);
2253
+ if (!meta)
2254
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
2255
+ return structuredClone(meta);
2256
+ });
2257
+ const members = await Promise.all(expected.map(async (meta) => ({
2258
+ id: meta.id,
2259
+ existed: await sessionDirectoryExists(this.#sessionRoot(meta.id)),
2260
+ identity: {
2261
+ createdAt: meta.createdAt,
2262
+ workspace: meta.workspace,
2263
+ ...(meta.source === undefined ? {} : { source: meta.source }),
2264
+ ...(meta.storage === undefined ? {} : { storage: meta.storage }),
2265
+ ...(meta.storageTransactionId === undefined
2266
+ ? {}
2267
+ : { storageTransactionId: meta.storageTransactionId }),
2268
+ nextSequence: meta.nextSequence
2269
+ }
2270
+ })));
2271
+ const deleted = members.find((member) => member.id === sessionId)?.existed ?? false;
2272
+ const transaction = {
2273
+ version: 1,
2274
+ kind: 'delete',
2275
+ id: randomUUID(),
2276
+ members
2277
+ };
2278
+ await this.#withTreeReadDrains(tree, async () => {
2279
+ let committed = false;
2280
+ try {
2281
+ await beginTreeDeleteTransaction(root, transaction, syncJsonlDirectory);
2282
+ await stageTreeDelete(root, transaction, syncJsonlDirectory);
2283
+ await this.#serializeIndexOperation(() => this.#commitIndex(tree, [], () => {
2284
+ committed = true;
2285
+ }, undefined, expected));
2286
+ await finishTreeDelete(root, transaction, true, syncJsonlDirectory);
2287
+ }
2288
+ catch (error) {
2289
+ try {
2290
+ let pending = await readTreeDeleteTransaction(root, sessionId);
2291
+ if (pending && pending.id !== transaction.id)
2292
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session deletion journal changed.');
2293
+ if (pending) {
2294
+ await syncJsonlDirectory(join(root, '.delete-pending'));
2295
+ pending = await readTreeDeleteTransaction(root, sessionId);
2296
+ if (!pending || pending.id !== transaction.id)
2297
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session deletion journal changed.');
2298
+ if (pending.phase === 'preparing' || pending.phase === 'restored')
2299
+ await finishTreeDeletePreparation(root, pending, syncJsonlDirectory);
2300
+ else {
2301
+ if (!committed)
2302
+ committed = await this.#treeDeleteCommitted(pending);
2303
+ await finishTreeDelete(root, pending, committed, syncJsonlDirectory);
2304
+ }
2305
+ await this.#refreshIndex();
2306
+ }
2307
+ }
2308
+ catch {
2309
+ for (const member of members)
2310
+ this.#shared.migrationFailures.set(member.id, { error, unreadable: true });
2311
+ }
2312
+ throw error;
2313
+ }
2314
+ });
2315
+ for (const id of tree)
2316
+ this.#shared.segments.delete(id);
2317
+ return { deleted };
2318
+ }
2319
+ catch (error) {
2320
+ failed = true;
2321
+ throw error;
2322
+ }
2323
+ finally {
2324
+ if (!maintenance) {
2325
+ const releasing = holding.release();
2326
+ if (failed)
2327
+ await releasing.catch(() => undefined);
2328
+ else
2329
+ await releasing;
2330
+ }
2331
+ }
2332
+ }
2333
+ #assertOpen() {
2334
+ if (this.#leaseClosed || this.#shared.closed)
2335
+ throw new AgentError('MAR_AGENT_DISPOSED', 'Session store is closed.');
2336
+ }
2337
+ #markIndexDirty(sessionId, derivedOnly = false) {
2338
+ if (derivedOnly && this.#encoding(sessionId) === 1)
2339
+ return;
2340
+ if (!derivedOnly)
2341
+ this.#shared.derivedOnlyDirtySessions.delete(sessionId);
2342
+ else if (!this.#shared.dirtySessionVersions.has(sessionId))
2343
+ this.#shared.derivedOnlyDirtySessions.add(sessionId);
2344
+ this.#shared.indexDirty = true;
2345
+ this.#shared.dirtySessionVersions.set(sessionId, (this.#shared.dirtySessionVersions.get(sessionId) ?? 0) + 1);
2346
+ }
2347
+ async #storageTransactionCommitted(sessionId, transactionId) {
2348
+ const disk = await readSessionIndex(join(this.#shared.root, 'sessions', 'index.json'));
2349
+ if (!disk)
2350
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session index is missing.');
2351
+ const session = disk.sessions.find((item) => item.id === sessionId);
2352
+ if (!session)
2353
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session index entry is missing.');
2354
+ return session.storageTransactionId === transactionId;
2355
+ }
2356
+ #segmentPath(sessionId, segment, meta) {
2357
+ return join(meta ? this.#directoryForMeta(sessionId, meta) : this.#sessionDirectory(sessionId), `events-${String(segment).padStart(6, '0')}.jsonl`);
2358
+ }
2359
+ async #assertReadable(sessionId, meta) {
2360
+ const failure = this.#shared.migrationFailures.get(sessionId);
2361
+ if (failure?.unreadable)
2362
+ throw failure.error;
2363
+ const historyFailure = this.#shared.writerLeases.get(sessionId)?.historyFailure;
2364
+ if (historyFailure)
2365
+ throw historyFailure.error;
2366
+ const directories = new Set([
2367
+ this.#sessionRoot(sessionId),
2368
+ this.#directoryForMeta(sessionId, meta)
2369
+ ]);
2370
+ for (const directory of directories) {
2371
+ try {
2372
+ await lstat(join(directory, 'storage-transaction.json'));
2373
+ }
2374
+ catch (error) {
2375
+ if (error.code === 'ENOENT')
2376
+ continue;
2377
+ throw error;
2378
+ }
2379
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session recovery is required.');
2380
+ }
2381
+ }
2382
+ async #segmentPaths(sessionId, meta) {
2383
+ const migrationFailure = this.#shared.migrationFailures.get(sessionId);
2384
+ if (migrationFailure?.unreadable)
2385
+ throw migrationFailure.error;
2386
+ const failure = this.#shared.writerLeases.get(sessionId)?.historyFailure;
2387
+ if (failure)
2388
+ throw failure.error;
2389
+ const selected = meta ?? this.#shared.index.sessions.find((item) => item.id === sessionId);
2390
+ if (selected)
2391
+ await this.#assertReadable(sessionId, selected);
2392
+ const directory = meta
2393
+ ? this.#directoryForMeta(sessionId, meta)
2394
+ : this.#sessionDirectory(sessionId);
2395
+ const entries = await readdir(directory);
2396
+ if (entries.includes('storage-transaction.json'))
2397
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session recovery is required.');
2398
+ const names = entries.filter((name) => /^events-\d{6}\.jsonl$/.test(name)).sort();
2399
+ if (names.length === 0)
2400
+ throw new AgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
2401
+ return names.map((name) => join(directory, name));
2402
+ }
2403
+ async #currentSegment(sessionId) {
2404
+ const cached = this.#shared.segments.get(sessionId);
2405
+ if (cached !== undefined)
2406
+ return cached;
2407
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
2408
+ const indexed = meta?.segments?.at(-1)?.number;
2409
+ if (indexed !== undefined) {
2410
+ this.#shared.segments.set(sessionId, indexed);
2411
+ return indexed;
2412
+ }
2413
+ const paths = await this.#segmentPaths(sessionId);
2414
+ const match = /events-(\d{6})\.jsonl$/.exec(paths.at(-1));
2415
+ const segment = Number(match?.[1] ?? 1);
2416
+ this.#shared.segments.set(sessionId, segment);
2417
+ return segment;
2418
+ }
2419
+ /** Repair the last segment and pending images under the lease, then sync sequence metadata. */
2420
+ async #reconcileTail(sessionId) {
2421
+ const paths = await this.#segmentPaths(sessionId);
2422
+ const latestPath = paths.at(-1);
2423
+ const { records, segment } = await recoverJsonlTail(this.#sessionDirectory(sessionId), latestPath, () => this.#readRecords(sessionId), this.#encoding(sessionId));
2424
+ const last = records.at(-1);
2425
+ this.#shared.segments.set(sessionId, segment);
2426
+ if (last === undefined)
2427
+ throw new AgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.');
2428
+ const bytes = (await stat(latestPath)).size;
2429
+ const firstSequence = records[0].sequence;
2430
+ // Tail recovery must publish onto metadata that is current after all file I/O.
2431
+ const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
2432
+ const known = meta.segments?.find((item) => item.number === segment);
2433
+ const titleRecord = records.findLast((record) => record.type === 'session.title.updated' &&
2434
+ typeof record.payload.title === 'string');
2435
+ const recoveredTitle = titleRecord?.payload?.title;
2436
+ const changed = meta.nextSequence !== last.sequence + 1 ||
2437
+ known?.bytes !== bytes ||
2438
+ (recoveredTitle !== undefined && meta.title !== recoveredTitle);
2439
+ meta.nextSequence = last.sequence + 1;
2440
+ if (recoveredTitle !== undefined)
2441
+ meta.title = recoveredTitle;
2442
+ meta.lastActivityAt =
2443
+ meta.lastActivityAt < last.timestamp ? last.timestamp : meta.lastActivityAt;
2444
+ if (!meta.segments)
2445
+ meta.segments = [];
2446
+ if (known) {
2447
+ known.firstSequence = firstSequence;
2448
+ known.lastSequence = last.sequence;
2449
+ known.bytes = bytes;
2450
+ }
2451
+ else
2452
+ meta.segments.push({ number: segment, firstSequence, lastSequence: last.sequence, bytes });
2453
+ if (changed) {
2454
+ delete meta.automaticTitlePending;
2455
+ delete meta.resume;
2456
+ this.#shared.index.revision++;
2457
+ this.#markIndexDirty(sessionId);
2458
+ }
2459
+ }
2460
+ async close() {
2461
+ if (this.#leaseClosed)
2462
+ return;
2463
+ this.#leaseClosed = true;
2464
+ await JsonlSessionStore.#pool.release(this.#shared, () => {
2465
+ const pending = [...this.#shared.writerLeases.entries()].filter(([, writer]) => writer.pendingResource && !writer.executing && !writer.maintenance);
2466
+ if (!pending.length && !this.#shared.indexDirty)
2467
+ return undefined;
2468
+ return (async () => {
2469
+ for (const [sessionId, writer] of pending) {
2470
+ delete writer.pendingResource;
2471
+ writer.retained--;
2472
+ await this.#releaseUnusedWriter(sessionId, writer);
2473
+ }
2474
+ if (this.#shared.indexDirty)
2475
+ await this.#saveIndex();
2476
+ })();
2477
+ });
2478
+ }
2479
+ }
2480
+ function isObject(value) {
2481
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
2482
+ }