@namzu/sdk 38.2.1 → 39.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (493) hide show
  1. package/CHANGELOG.md +700 -0
  2. package/dist/advisory/executor.d.ts +10 -1
  3. package/dist/advisory/executor.d.ts.map +1 -1
  4. package/dist/advisory/executor.js +5 -26
  5. package/dist/advisory/executor.js.map +1 -1
  6. package/dist/advisory/history.d.ts +9 -0
  7. package/dist/advisory/history.d.ts.map +1 -0
  8. package/dist/advisory/history.js +120 -0
  9. package/dist/advisory/history.js.map +1 -0
  10. package/dist/advisory/index.d.ts +1 -1
  11. package/dist/advisory/index.d.ts.map +1 -1
  12. package/dist/advisory/index.js.map +1 -1
  13. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  14. package/dist/agents/ReactiveAgent.js +3 -0
  15. package/dist/agents/ReactiveAgent.js.map +1 -1
  16. package/dist/agents/runAgent.d.ts +10 -0
  17. package/dist/agents/runAgent.d.ts.map +1 -1
  18. package/dist/agents/runAgent.js +3 -0
  19. package/dist/agents/runAgent.js.map +1 -1
  20. package/dist/compaction/manual.d.ts +6 -0
  21. package/dist/compaction/manual.d.ts.map +1 -1
  22. package/dist/compaction/manual.js +21 -2
  23. package/dist/compaction/manual.js.map +1 -1
  24. package/dist/compaction/summary.d.ts.map +1 -1
  25. package/dist/compaction/summary.js +4 -1
  26. package/dist/compaction/summary.js.map +1 -1
  27. package/dist/config/runtime.js +2 -2
  28. package/dist/config/runtime.js.map +1 -1
  29. package/dist/contracts/schemas.js +1 -1
  30. package/dist/contracts/schemas.js.map +1 -1
  31. package/dist/eval/harness-protection.d.ts +18 -0
  32. package/dist/eval/harness-protection.d.ts.map +1 -0
  33. package/dist/eval/harness-protection.js +58 -0
  34. package/dist/eval/harness-protection.js.map +1 -0
  35. package/dist/eval/harness-verification.d.ts +6 -1
  36. package/dist/eval/harness-verification.d.ts.map +1 -1
  37. package/dist/eval/harness-verification.js +19 -2
  38. package/dist/eval/harness-verification.js.map +1 -1
  39. package/dist/eval/index.d.ts +1 -0
  40. package/dist/eval/index.d.ts.map +1 -1
  41. package/dist/eval/index.js.map +1 -1
  42. package/dist/manager/resident/activity.d.ts +50 -0
  43. package/dist/manager/resident/activity.d.ts.map +1 -0
  44. package/dist/manager/resident/activity.js +125 -0
  45. package/dist/manager/resident/activity.js.map +1 -0
  46. package/dist/manager/resident/agenda.d.ts +13 -1
  47. package/dist/manager/resident/agenda.d.ts.map +1 -1
  48. package/dist/manager/resident/agenda.js +40 -5
  49. package/dist/manager/resident/agenda.js.map +1 -1
  50. package/dist/manager/resident/consumption.d.ts +104 -0
  51. package/dist/manager/resident/consumption.d.ts.map +1 -0
  52. package/dist/manager/resident/consumption.js +233 -0
  53. package/dist/manager/resident/consumption.js.map +1 -0
  54. package/dist/manager/resident/evidence-recall.d.ts +24 -0
  55. package/dist/manager/resident/evidence-recall.d.ts.map +1 -0
  56. package/dist/manager/resident/evidence-recall.js +295 -0
  57. package/dist/manager/resident/evidence-recall.js.map +1 -0
  58. package/dist/manager/resident/history-disk.d.ts +10 -0
  59. package/dist/manager/resident/history-disk.d.ts.map +1 -0
  60. package/dist/manager/resident/history-disk.js +50 -0
  61. package/dist/manager/resident/history-disk.js.map +1 -0
  62. package/dist/manager/resident/history.d.ts +79 -0
  63. package/dist/manager/resident/history.d.ts.map +1 -0
  64. package/dist/manager/resident/history.js +203 -0
  65. package/dist/manager/resident/history.js.map +1 -0
  66. package/dist/manager/resident/initiative.d.ts.map +1 -1
  67. package/dist/manager/resident/initiative.js +11 -3
  68. package/dist/manager/resident/initiative.js.map +1 -1
  69. package/dist/manager/resident/learning-cycle.d.ts +131 -0
  70. package/dist/manager/resident/learning-cycle.d.ts.map +1 -0
  71. package/dist/manager/resident/learning-cycle.js +306 -0
  72. package/dist/manager/resident/learning-cycle.js.map +1 -0
  73. package/dist/manager/resident/learning-observation.d.ts +80 -0
  74. package/dist/manager/resident/learning-observation.d.ts.map +1 -0
  75. package/dist/manager/resident/learning-observation.js +22 -0
  76. package/dist/manager/resident/learning-observation.js.map +1 -0
  77. package/dist/manager/resident/learning-store.d.ts +106 -0
  78. package/dist/manager/resident/learning-store.d.ts.map +1 -0
  79. package/dist/manager/resident/learning-store.js +598 -0
  80. package/dist/manager/resident/learning-store.js.map +1 -0
  81. package/dist/manager/resident/learning.d.ts +246 -3
  82. package/dist/manager/resident/learning.d.ts.map +1 -1
  83. package/dist/manager/resident/learning.js +96 -6
  84. package/dist/manager/resident/learning.js.map +1 -1
  85. package/dist/manager/resident/outbox.d.ts +4 -4
  86. package/dist/manager/resident/store.d.ts +37 -4
  87. package/dist/manager/resident/store.d.ts.map +1 -1
  88. package/dist/manager/resident/store.js +27 -3
  89. package/dist/manager/resident/store.js.map +1 -1
  90. package/dist/manager/resident/tool-evidence.d.ts +71 -0
  91. package/dist/manager/resident/tool-evidence.d.ts.map +1 -0
  92. package/dist/manager/resident/tool-evidence.js +285 -0
  93. package/dist/manager/resident/tool-evidence.js.map +1 -0
  94. package/dist/manager/run/persistence.d.ts.map +1 -1
  95. package/dist/manager/run/persistence.js +6 -0
  96. package/dist/manager/run/persistence.js.map +1 -1
  97. package/dist/plugin/loader.d.ts.map +1 -1
  98. package/dist/plugin/loader.js +5 -3
  99. package/dist/plugin/loader.js.map +1 -1
  100. package/dist/prompt/coding-agent-doctrine.d.ts +1 -1
  101. package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
  102. package/dist/prompt/coding-agent-doctrine.js +2 -0
  103. package/dist/prompt/coding-agent-doctrine.js.map +1 -1
  104. package/dist/prompt/index.d.ts +2 -0
  105. package/dist/prompt/index.d.ts.map +1 -1
  106. package/dist/prompt/index.js +1 -0
  107. package/dist/prompt/index.js.map +1 -1
  108. package/dist/prompt/resident-learning.d.ts +19 -0
  109. package/dist/prompt/resident-learning.d.ts.map +1 -0
  110. package/dist/prompt/resident-learning.js +125 -0
  111. package/dist/prompt/resident-learning.js.map +1 -0
  112. package/dist/prompt/resident-step.d.ts +8 -1
  113. package/dist/prompt/resident-step.d.ts.map +1 -1
  114. package/dist/prompt/resident-step.js +65 -4
  115. package/dist/prompt/resident-step.js.map +1 -1
  116. package/dist/provider/collect-chat-completion.d.ts +2 -1
  117. package/dist/provider/collect-chat-completion.d.ts.map +1 -1
  118. package/dist/provider/collect-chat-completion.js +7 -6
  119. package/dist/provider/collect-chat-completion.js.map +1 -1
  120. package/dist/provider/fallback.d.ts.map +1 -1
  121. package/dist/provider/fallback.js +2 -1
  122. package/dist/provider/fallback.js.map +1 -1
  123. package/dist/provider/stream-text.d.ts +16 -0
  124. package/dist/provider/stream-text.d.ts.map +1 -0
  125. package/dist/provider/stream-text.js +51 -0
  126. package/dist/provider/stream-text.js.map +1 -0
  127. package/dist/public-runtime.d.ts +13 -3
  128. package/dist/public-runtime.d.ts.map +1 -1
  129. package/dist/public-runtime.js +12 -3
  130. package/dist/public-runtime.js.map +1 -1
  131. package/dist/public-tools.d.ts +2 -0
  132. package/dist/public-tools.d.ts.map +1 -1
  133. package/dist/public-tools.js +2 -0
  134. package/dist/public-tools.js.map +1 -1
  135. package/dist/public-types.d.ts +15 -3
  136. package/dist/public-types.d.ts.map +1 -1
  137. package/dist/run/LimitChecker.js +3 -3
  138. package/dist/run/LimitChecker.js.map +1 -1
  139. package/dist/run/evidence-query.d.ts +41 -0
  140. package/dist/run/evidence-query.d.ts.map +1 -0
  141. package/dist/run/evidence-query.js +270 -0
  142. package/dist/run/evidence-query.js.map +1 -0
  143. package/dist/run/evidence-recall.d.ts +99 -0
  144. package/dist/run/evidence-recall.d.ts.map +1 -0
  145. package/dist/run/evidence-recall.js +633 -0
  146. package/dist/run/evidence-recall.js.map +1 -0
  147. package/dist/run/index.d.ts +2 -0
  148. package/dist/run/index.d.ts.map +1 -1
  149. package/dist/run/index.js +1 -0
  150. package/dist/run/index.js.map +1 -1
  151. package/dist/run/json-claim-verifier.d.ts +83 -0
  152. package/dist/run/json-claim-verifier.d.ts.map +1 -0
  153. package/dist/run/json-claim-verifier.js +200 -0
  154. package/dist/run/json-claim-verifier.js.map +1 -0
  155. package/dist/run/preparation-context-error.d.ts +10 -0
  156. package/dist/run/preparation-context-error.d.ts.map +1 -0
  157. package/dist/run/preparation-context-error.js +15 -0
  158. package/dist/run/preparation-context-error.js.map +1 -0
  159. package/dist/run-query/index.d.ts +3 -1
  160. package/dist/run-query/index.d.ts.map +1 -1
  161. package/dist/runtime/query/callback-inference.d.ts +8 -0
  162. package/dist/runtime/query/callback-inference.d.ts.map +1 -0
  163. package/dist/runtime/query/callback-inference.js +89 -0
  164. package/dist/runtime/query/callback-inference.js.map +1 -0
  165. package/dist/runtime/query/checkpoint.d.ts +4 -0
  166. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  167. package/dist/runtime/query/checkpoint.js +13 -0
  168. package/dist/runtime/query/checkpoint.js.map +1 -1
  169. package/dist/runtime/query/events.d.ts +1 -0
  170. package/dist/runtime/query/events.d.ts.map +1 -1
  171. package/dist/runtime/query/events.js +18 -0
  172. package/dist/runtime/query/events.js.map +1 -1
  173. package/dist/runtime/query/executor.d.ts +7 -1
  174. package/dist/runtime/query/executor.d.ts.map +1 -1
  175. package/dist/runtime/query/executor.js +38 -7
  176. package/dist/runtime/query/executor.js.map +1 -1
  177. package/dist/runtime/query/file-evidence-context.d.ts +5 -0
  178. package/dist/runtime/query/file-evidence-context.d.ts.map +1 -0
  179. package/dist/runtime/query/file-evidence-context.js +64 -0
  180. package/dist/runtime/query/file-evidence-context.js.map +1 -0
  181. package/dist/runtime/query/guard.d.ts.map +1 -1
  182. package/dist/runtime/query/guard.js +4 -0
  183. package/dist/runtime/query/guard.js.map +1 -1
  184. package/dist/runtime/query/index.d.ts +10 -1
  185. package/dist/runtime/query/index.d.ts.map +1 -1
  186. package/dist/runtime/query/index.js +39 -24
  187. package/dist/runtime/query/index.js.map +1 -1
  188. package/dist/runtime/query/iteration/index.d.ts +9 -31
  189. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  190. package/dist/runtime/query/iteration/index.js +231 -93
  191. package/dist/runtime/query/iteration/index.js.map +1 -1
  192. package/dist/runtime/query/iteration/phases/advisory.d.ts +2 -1
  193. package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
  194. package/dist/runtime/query/iteration/phases/advisory.js +2 -1
  195. package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
  196. package/dist/runtime/query/iteration/phases/context.d.ts +2 -1
  197. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  198. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  199. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  200. package/dist/runtime/query/iteration/phases/tool-review.js +3 -0
  201. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  202. package/dist/runtime/query/iteration/provider-rejected-image.d.ts +2 -1
  203. package/dist/runtime/query/iteration/provider-rejected-image.d.ts.map +1 -1
  204. package/dist/runtime/query/iteration/provider-rejected-image.js +5 -2
  205. package/dist/runtime/query/iteration/provider-rejected-image.js.map +1 -1
  206. package/dist/runtime/query/iteration/stream-turn.d.ts +4 -1
  207. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  208. package/dist/runtime/query/iteration/stream-turn.js +22 -8
  209. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  210. package/dist/runtime/query/resume-pending.d.ts +18 -33
  211. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  212. package/dist/runtime/query/resume-pending.js +59 -42
  213. package/dist/runtime/query/resume-pending.js.map +1 -1
  214. package/dist/runtime/query/review-policy.d.ts +4 -4
  215. package/dist/runtime/query/review-policy.d.ts.map +1 -1
  216. package/dist/runtime/query/review-policy.js +10 -9
  217. package/dist/runtime/query/review-policy.js.map +1 -1
  218. package/dist/runtime/query/sandbox-lifecycle.d.ts.map +1 -1
  219. package/dist/runtime/query/sandbox-lifecycle.js +4 -0
  220. package/dist/runtime/query/sandbox-lifecycle.js.map +1 -1
  221. package/dist/runtime/query/tool-output-budget.d.ts +10 -6
  222. package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
  223. package/dist/runtime/query/tool-output-budget.js +54 -12
  224. package/dist/runtime/query/tool-output-budget.js.map +1 -1
  225. package/dist/runtime/query/tooling.d.ts +3 -1
  226. package/dist/runtime/query/tooling.d.ts.map +1 -1
  227. package/dist/runtime/query/tooling.js +4 -0
  228. package/dist/runtime/query/tooling.js.map +1 -1
  229. package/dist/scheduler/completion-inbox.d.ts +3 -0
  230. package/dist/scheduler/completion-inbox.d.ts.map +1 -1
  231. package/dist/scheduler/completion-inbox.js +28 -0
  232. package/dist/scheduler/completion-inbox.js.map +1 -1
  233. package/dist/store/evidence/compaction-archive.d.ts +109 -0
  234. package/dist/store/evidence/compaction-archive.d.ts.map +1 -0
  235. package/dist/store/evidence/compaction-archive.js +125 -0
  236. package/dist/store/evidence/compaction-archive.js.map +1 -0
  237. package/dist/store/evidence/compaction-provenance.d.ts +7 -0
  238. package/dist/store/evidence/compaction-provenance.d.ts.map +1 -0
  239. package/dist/store/evidence/compaction-provenance.js +49 -0
  240. package/dist/store/evidence/compaction-provenance.js.map +1 -0
  241. package/dist/store/evidence/compaction-text.d.ts +16 -0
  242. package/dist/store/evidence/compaction-text.d.ts.map +1 -0
  243. package/dist/store/evidence/compaction-text.js +51 -0
  244. package/dist/store/evidence/compaction-text.js.map +1 -0
  245. package/dist/store/evidence/disk.d.ts +11 -0
  246. package/dist/store/evidence/disk.d.ts.map +1 -0
  247. package/dist/store/evidence/disk.js +367 -0
  248. package/dist/store/evidence/disk.js.map +1 -0
  249. package/dist/store/evidence/format.d.ts +25 -0
  250. package/dist/store/evidence/format.d.ts.map +1 -0
  251. package/dist/store/evidence/format.js +115 -0
  252. package/dist/store/evidence/format.js.map +1 -0
  253. package/dist/store/evidence/index-page.d.ts +208 -0
  254. package/dist/store/evidence/index-page.d.ts.map +1 -0
  255. package/dist/store/evidence/index-page.js +262 -0
  256. package/dist/store/evidence/index-page.js.map +1 -0
  257. package/dist/store/evidence/io.d.ts +24 -0
  258. package/dist/store/evidence/io.d.ts.map +1 -0
  259. package/dist/store/evidence/io.js +69 -0
  260. package/dist/store/evidence/io.js.map +1 -0
  261. package/dist/store/evidence/linked.d.ts +9 -0
  262. package/dist/store/evidence/linked.d.ts.map +1 -0
  263. package/dist/store/evidence/linked.js +314 -0
  264. package/dist/store/evidence/linked.js.map +1 -0
  265. package/dist/store/evidence/passages.d.ts +15 -0
  266. package/dist/store/evidence/passages.d.ts.map +1 -0
  267. package/dist/store/evidence/passages.js +72 -0
  268. package/dist/store/evidence/passages.js.map +1 -0
  269. package/dist/store/evidence/record-chain.d.ts +42 -0
  270. package/dist/store/evidence/record-chain.d.ts.map +1 -0
  271. package/dist/store/evidence/record-chain.js +111 -0
  272. package/dist/store/evidence/record-chain.js.map +1 -0
  273. package/dist/store/evidence/search-input.d.ts +21 -0
  274. package/dist/store/evidence/search-input.d.ts.map +1 -0
  275. package/dist/store/evidence/search-input.js +44 -0
  276. package/dist/store/evidence/search-input.js.map +1 -0
  277. package/dist/store/evidence/selection.d.ts +9 -0
  278. package/dist/store/evidence/selection.d.ts.map +1 -0
  279. package/dist/store/evidence/selection.js +17 -0
  280. package/dist/store/evidence/selection.js.map +1 -0
  281. package/dist/store/evidence/source-kind.d.ts +11 -0
  282. package/dist/store/evidence/source-kind.d.ts.map +1 -0
  283. package/dist/store/evidence/source-kind.js +26 -0
  284. package/dist/store/evidence/source-kind.js.map +1 -0
  285. package/dist/store/evidence/source-text.d.ts +51 -0
  286. package/dist/store/evidence/source-text.d.ts.map +1 -0
  287. package/dist/store/evidence/source-text.js +213 -0
  288. package/dist/store/evidence/source-text.js.map +1 -0
  289. package/dist/store/evidence/types.d.ts +162 -0
  290. package/dist/store/evidence/types.d.ts.map +1 -0
  291. package/dist/store/evidence/types.js +2 -0
  292. package/dist/store/evidence/types.js.map +1 -0
  293. package/dist/store/memory/disk.d.ts +2 -0
  294. package/dist/store/memory/disk.d.ts.map +1 -1
  295. package/dist/store/memory/disk.js +2 -1
  296. package/dist/store/memory/disk.js.map +1 -1
  297. package/dist/store/run/disk.d.ts +10 -0
  298. package/dist/store/run/disk.d.ts.map +1 -1
  299. package/dist/store/run/disk.js +87 -7
  300. package/dist/store/run/disk.js.map +1 -1
  301. package/dist/store/run/memory.d.ts +1 -0
  302. package/dist/store/run/memory.d.ts.map +1 -1
  303. package/dist/store/run/memory.js +10 -0
  304. package/dist/store/run/memory.js.map +1 -1
  305. package/dist/store/run/tool-executions.d.ts +13 -0
  306. package/dist/store/run/tool-executions.d.ts.map +1 -0
  307. package/dist/store/run/tool-executions.js +99 -0
  308. package/dist/store/run/tool-executions.js.map +1 -0
  309. package/dist/store/session/index.d.ts +2 -0
  310. package/dist/store/session/index.d.ts.map +1 -1
  311. package/dist/store/session/index.js +1 -0
  312. package/dist/store/session/index.js.map +1 -1
  313. package/dist/store/session/sqlite.d.ts +57 -0
  314. package/dist/store/session/sqlite.d.ts.map +1 -0
  315. package/dist/store/session/sqlite.js +430 -0
  316. package/dist/store/session/sqlite.js.map +1 -0
  317. package/dist/tools/builtins/job.d.ts.map +1 -1
  318. package/dist/tools/builtins/job.js +4 -5
  319. package/dist/tools/builtins/job.js.map +1 -1
  320. package/dist/tools/builtins/write-file.js +2 -2
  321. package/dist/tools/builtins/write-file.js.map +1 -1
  322. package/dist/tools/defineTool.d.ts +2 -1
  323. package/dist/tools/defineTool.d.ts.map +1 -1
  324. package/dist/tools/defineTool.js +1 -1
  325. package/dist/tools/defineTool.js.map +1 -1
  326. package/dist/tools/file-read-tracker.d.ts.map +1 -1
  327. package/dist/tools/file-read-tracker.js +12 -3
  328. package/dist/tools/file-read-tracker.js.map +1 -1
  329. package/dist/tools/resident-history.d.ts +10 -0
  330. package/dist/tools/resident-history.d.ts.map +1 -0
  331. package/dist/tools/resident-history.js +80 -0
  332. package/dist/tools/resident-history.js.map +1 -0
  333. package/dist/tools/resident-tool-evidence.d.ts +5 -0
  334. package/dist/tools/resident-tool-evidence.d.ts.map +1 -0
  335. package/dist/tools/resident-tool-evidence.js +57 -0
  336. package/dist/tools/resident-tool-evidence.js.map +1 -0
  337. package/dist/types/advisory/config.d.ts +7 -0
  338. package/dist/types/advisory/config.d.ts.map +1 -1
  339. package/dist/types/agent/reactive.d.ts +1 -0
  340. package/dist/types/agent/reactive.d.ts.map +1 -1
  341. package/dist/types/authorization/index.d.ts +9 -9
  342. package/dist/types/authorization/index.d.ts.map +1 -1
  343. package/dist/types/authorization/index.js +1 -1
  344. package/dist/types/authorization/index.js.map +1 -1
  345. package/dist/types/hitl/index.d.ts +4 -0
  346. package/dist/types/hitl/index.d.ts.map +1 -1
  347. package/dist/types/hitl/index.js.map +1 -1
  348. package/dist/types/message/index.d.ts +16 -2
  349. package/dist/types/message/index.d.ts.map +1 -1
  350. package/dist/types/message/index.js +8 -1
  351. package/dist/types/message/index.js.map +1 -1
  352. package/dist/types/provider/chat.d.ts +2 -0
  353. package/dist/types/provider/chat.d.ts.map +1 -1
  354. package/dist/types/provider/stream.d.ts +4 -0
  355. package/dist/types/provider/stream.d.ts.map +1 -1
  356. package/dist/types/run/answer-review.d.ts +34 -3
  357. package/dist/types/run/answer-review.d.ts.map +1 -1
  358. package/dist/types/run/config.d.ts +3 -0
  359. package/dist/types/run/config.d.ts.map +1 -1
  360. package/dist/types/run/entity.d.ts +7 -0
  361. package/dist/types/run/entity.d.ts.map +1 -1
  362. package/dist/types/run/events.d.ts +31 -8
  363. package/dist/types/run/events.d.ts.map +1 -1
  364. package/dist/types/run/events.js.map +1 -1
  365. package/dist/types/run/prepare-step.d.ts +53 -8
  366. package/dist/types/run/prepare-step.d.ts.map +1 -1
  367. package/dist/types/run/store.d.ts +29 -4
  368. package/dist/types/run/store.d.ts.map +1 -1
  369. package/dist/types/run/store.js +0 -28
  370. package/dist/types/run/store.js.map +1 -1
  371. package/dist/types/tool/index.d.ts +15 -1
  372. package/dist/types/tool/index.d.ts.map +1 -1
  373. package/dist/types/tool/index.js.map +1 -1
  374. package/dist/utils/await-with-abort.d.ts +8 -0
  375. package/dist/utils/await-with-abort.d.ts.map +1 -0
  376. package/dist/utils/await-with-abort.js +28 -0
  377. package/dist/utils/await-with-abort.js.map +1 -0
  378. package/dist/utils/evidence-time.d.ts +3 -0
  379. package/dist/utils/evidence-time.d.ts.map +1 -0
  380. package/dist/utils/evidence-time.js +10 -0
  381. package/dist/utils/evidence-time.js.map +1 -0
  382. package/dist/utils/evidence-tokens.d.ts +13 -0
  383. package/dist/utils/evidence-tokens.d.ts.map +1 -0
  384. package/dist/utils/evidence-tokens.js +29 -0
  385. package/dist/utils/evidence-tokens.js.map +1 -0
  386. package/package.json +1 -1
  387. package/src/advisory/executor.ts +15 -30
  388. package/src/advisory/history.ts +126 -0
  389. package/src/advisory/index.ts +5 -1
  390. package/src/agents/ReactiveAgent.ts +3 -0
  391. package/src/agents/runAgent.ts +14 -1
  392. package/src/compaction/manual.ts +30 -2
  393. package/src/compaction/summary.ts +4 -1
  394. package/src/config/runtime.ts +2 -2
  395. package/src/contracts/schemas.ts +1 -1
  396. package/src/eval/harness-protection.ts +79 -0
  397. package/src/eval/harness-verification.ts +31 -1
  398. package/src/eval/index.ts +1 -0
  399. package/src/manager/resident/activity.ts +187 -0
  400. package/src/manager/resident/agenda.ts +59 -5
  401. package/src/manager/resident/consumption.ts +311 -0
  402. package/src/manager/resident/evidence-recall.ts +363 -0
  403. package/src/manager/resident/history-disk.ts +63 -0
  404. package/src/manager/resident/history.ts +312 -0
  405. package/src/manager/resident/initiative.ts +13 -3
  406. package/src/manager/resident/learning-cycle.ts +499 -0
  407. package/src/manager/resident/learning-observation.ts +39 -0
  408. package/src/manager/resident/learning-store.ts +813 -0
  409. package/src/manager/resident/learning.ts +132 -8
  410. package/src/manager/resident/store.ts +31 -3
  411. package/src/manager/resident/tool-evidence.ts +412 -0
  412. package/src/manager/run/persistence.ts +6 -0
  413. package/src/plugin/loader.ts +8 -3
  414. package/src/prompt/coding-agent-doctrine.ts +2 -0
  415. package/src/prompt/index.ts +2 -0
  416. package/src/prompt/resident-learning.ts +143 -0
  417. package/src/prompt/resident-step.ts +83 -3
  418. package/src/provider/collect-chat-completion.ts +7 -6
  419. package/src/provider/fallback.ts +2 -1
  420. package/src/provider/stream-text.ts +56 -0
  421. package/src/public-runtime.ts +30 -0
  422. package/src/public-tools.ts +3 -0
  423. package/src/public-types.ts +98 -0
  424. package/src/run/LimitChecker.ts +3 -3
  425. package/src/run/evidence-query.ts +333 -0
  426. package/src/run/evidence-recall.ts +854 -0
  427. package/src/run/index.ts +11 -0
  428. package/src/run/json-claim-verifier.ts +298 -0
  429. package/src/run/preparation-context-error.ts +16 -0
  430. package/src/run-query/index.ts +1 -1
  431. package/src/runtime/query/callback-inference.ts +94 -0
  432. package/src/runtime/query/checkpoint.ts +14 -0
  433. package/src/runtime/query/events.ts +22 -0
  434. package/src/runtime/query/executor.ts +51 -9
  435. package/src/runtime/query/file-evidence-context.ts +65 -0
  436. package/src/runtime/query/guard.ts +2 -0
  437. package/src/runtime/query/index.ts +49 -25
  438. package/src/runtime/query/iteration/index.ts +269 -86
  439. package/src/runtime/query/iteration/phases/advisory.ts +3 -0
  440. package/src/runtime/query/iteration/phases/context.ts +2 -0
  441. package/src/runtime/query/iteration/phases/tool-review.ts +3 -0
  442. package/src/runtime/query/iteration/provider-rejected-image.ts +6 -1
  443. package/src/runtime/query/iteration/stream-turn.ts +35 -8
  444. package/src/runtime/query/resume-pending.ts +65 -40
  445. package/src/runtime/query/review-policy.ts +13 -9
  446. package/src/runtime/query/sandbox-lifecycle.ts +3 -0
  447. package/src/runtime/query/tool-output-budget.ts +65 -13
  448. package/src/runtime/query/tooling.ts +7 -1
  449. package/src/scheduler/completion-inbox.ts +26 -0
  450. package/src/store/evidence/compaction-archive.ts +139 -0
  451. package/src/store/evidence/compaction-provenance.ts +52 -0
  452. package/src/store/evidence/compaction-text.ts +61 -0
  453. package/src/store/evidence/disk.ts +461 -0
  454. package/src/store/evidence/format.ts +126 -0
  455. package/src/store/evidence/index-page.ts +292 -0
  456. package/src/store/evidence/io.ts +95 -0
  457. package/src/store/evidence/linked.ts +365 -0
  458. package/src/store/evidence/passages.ts +88 -0
  459. package/src/store/evidence/record-chain.ts +108 -0
  460. package/src/store/evidence/search-input.ts +62 -0
  461. package/src/store/evidence/selection.ts +25 -0
  462. package/src/store/evidence/source-kind.ts +36 -0
  463. package/src/store/evidence/source-text.ts +285 -0
  464. package/src/store/evidence/types.ts +177 -0
  465. package/src/store/memory/disk.ts +4 -1
  466. package/src/store/run/disk.ts +110 -8
  467. package/src/store/run/memory.ts +10 -0
  468. package/src/store/run/tool-executions.ts +112 -0
  469. package/src/store/session/index.ts +2 -0
  470. package/src/store/session/sqlite.ts +584 -0
  471. package/src/tools/builtins/job.ts +4 -5
  472. package/src/tools/builtins/write-file.ts +2 -2
  473. package/src/tools/defineTool.ts +4 -2
  474. package/src/tools/file-read-tracker.ts +8 -2
  475. package/src/tools/resident-history.ts +86 -0
  476. package/src/tools/resident-tool-evidence.ts +68 -0
  477. package/src/types/advisory/config.ts +7 -0
  478. package/src/types/agent/reactive.ts +1 -0
  479. package/src/types/authorization/index.ts +2 -2
  480. package/src/types/hitl/index.ts +4 -0
  481. package/src/types/message/index.ts +20 -0
  482. package/src/types/provider/chat.ts +2 -0
  483. package/src/types/provider/stream.ts +4 -0
  484. package/src/types/run/answer-review.ts +34 -3
  485. package/src/types/run/config.ts +3 -0
  486. package/src/types/run/entity.ts +7 -0
  487. package/src/types/run/events.ts +31 -8
  488. package/src/types/run/prepare-step.ts +59 -8
  489. package/src/types/run/store.ts +35 -4
  490. package/src/types/tool/index.ts +19 -1
  491. package/src/utils/await-with-abort.ts +26 -0
  492. package/src/utils/evidence-time.ts +9 -0
  493. package/src/utils/evidence-tokens.ts +32 -0
@@ -0,0 +1,112 @@
1
+ import { constants } from 'node:fs'
2
+ import { open } from 'node:fs/promises'
3
+ import type { ToolExecutionRecord, ToolExecutionSnapshot } from '../../types/run/store.js'
4
+
5
+ const MAX_LOG_BYTES = 256 * 1024 * 1024
6
+ const MAX_RECORD_BYTES = 4 * 1024 * 1024
7
+
8
+ /** Scan metadata only; compaction attachments and retained output bodies are never loaded. */
9
+ export class ToolExecutionCollector {
10
+ private seq = 0
11
+ private readonly wanted: Set<string>
12
+ private readonly records = new Map<string, ToolExecutionRecord>()
13
+ constructor(
14
+ private readonly runId: string,
15
+ ids: readonly string[],
16
+ ) {
17
+ if (ids.length > 4096) throw new Error('Tool recovery exceeds the 4096-call scan limit.')
18
+ this.wanted = new Set(ids)
19
+ }
20
+ accept(value: unknown): void {
21
+ const event = value as Record<string, unknown> | null
22
+ if (
23
+ !event ||
24
+ typeof event !== 'object' ||
25
+ typeof event.type !== 'string' ||
26
+ event.runId !== this.runId ||
27
+ event.seq !== this.seq + 1
28
+ ) {
29
+ throw new Error('Tool recovery requires a complete, ordered log owned by this run.')
30
+ }
31
+ if (this.seq === 0 && event.type !== 'run_started')
32
+ throw new Error('Tool recovery cannot establish the beginning of this run.')
33
+ this.seq++
34
+ if (event.type !== 'tool_executing' && event.type !== 'tool_completed') return
35
+ if (typeof event.toolUseId !== 'string' || typeof event.toolName !== 'string')
36
+ throw new Error('Tool recovery found an invalid tool identity.')
37
+ if (!this.wanted.has(event.toolUseId)) return
38
+ const identity = { toolUseId: event.toolUseId, toolName: event.toolName }
39
+ if (event.type === 'tool_executing') {
40
+ // A later start invalidates an earlier completion, including retries.
41
+ this.records.set(event.toolUseId, { ...identity, status: 'started' })
42
+ } else {
43
+ if (typeof event.result !== 'string' || typeof event.isError !== 'boolean')
44
+ throw new Error('Tool recovery found an invalid completion.')
45
+ this.records.set(event.toolUseId, {
46
+ ...identity,
47
+ status: 'completed',
48
+ result: event.result,
49
+ isError: event.isError,
50
+ })
51
+ }
52
+ }
53
+ finish(complete = true): ToolExecutionSnapshot {
54
+ return { complete: complete && this.seq > 0, records: this.records }
55
+ }
56
+ }
57
+
58
+ export async function readToolExecutionsIn(
59
+ path: string,
60
+ runId: string,
61
+ ids: readonly string[],
62
+ signal?: AbortSignal,
63
+ ): Promise<ToolExecutionSnapshot> {
64
+ signal?.throwIfAborted()
65
+ const collector = new ToolExecutionCollector(runId, ids)
66
+ const file = await open(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0))
67
+ try {
68
+ const before = await file.stat()
69
+ if (!before.isFile() || before.size > MAX_LOG_BYTES)
70
+ throw new Error('Tool recovery requires a regular transcript within the 256 MiB scan limit.')
71
+ let offset = 0
72
+ let pending = Buffer.alloc(0)
73
+ const buffer = Buffer.alloc(64 * 1024)
74
+ while (offset < before.size) {
75
+ signal?.throwIfAborted()
76
+ const { bytesRead } = await file.read(
77
+ buffer,
78
+ 0,
79
+ Math.min(buffer.length, before.size - offset),
80
+ offset,
81
+ )
82
+ if (bytesRead === 0) throw new Error('Tool recovery transcript was shortened.')
83
+ offset += bytesRead
84
+ pending = Buffer.concat([pending, buffer.subarray(0, bytesRead)])
85
+ let start = 0
86
+ for (;;) {
87
+ const end = pending.indexOf(10, start)
88
+ if (end < 0) break
89
+ if (end - start > MAX_RECORD_BYTES) throw new Error('Tool recovery record exceeds 4 MiB.')
90
+ collector.accept(
91
+ JSON.parse(
92
+ new TextDecoder('utf-8', { fatal: true }).decode(pending.subarray(start, end)),
93
+ ),
94
+ )
95
+ start = end + 1
96
+ }
97
+ pending = Buffer.from(pending.subarray(start))
98
+ if (pending.length > MAX_RECORD_BYTES) throw new Error('Tool recovery record exceeds 4 MiB.')
99
+ }
100
+ signal?.throwIfAborted()
101
+ const after = await file.stat()
102
+ if (
103
+ before.size !== after.size ||
104
+ before.mtimeMs !== after.mtimeMs ||
105
+ before.ctimeMs !== after.ctimeMs
106
+ )
107
+ throw new Error('Tool recovery transcript changed during the scan.')
108
+ return collector.finish(pending.length === 0)
109
+ } finally {
110
+ await file.close()
111
+ }
112
+ }
@@ -8,6 +8,8 @@
8
8
 
9
9
  export { InMemorySessionStore } from './memory.js'
10
10
  export { DiskSessionStore } from './disk.js'
11
+ export { SqliteSessionStore } from './sqlite.js'
12
+ export type { SqliteSessionStoreConfig } from './sqlite.js'
11
13
  export type { DiskSessionStoreConfig } from './disk.js'
12
14
  export type { SessionMessage } from '../../types/session/messages.js'
13
15
  export { getAncestry, getChildren, orderChildren } from './linkage.js'
@@ -0,0 +1,584 @@
1
+ import { mkdirSync } from 'node:fs'
2
+ import { createRequire } from 'node:module'
3
+ import { dirname, resolve } from 'node:path'
4
+ import type { DatabaseSync } from 'node:sqlite'
5
+
6
+ import {
7
+ ProjectRootPathTakenError,
8
+ StaleProjectError,
9
+ StaleSessionError,
10
+ TenantIsolationError,
11
+ } from '../../session/errors.js'
12
+ import { SessionAlreadySummarizedError } from '../../session/summary/errors.js'
13
+ import type {
14
+ MessageId,
15
+ ProjectId,
16
+ SessionId,
17
+ SubSessionId,
18
+ TenantId,
19
+ TopicId,
20
+ } from '../../types/ids/index.js'
21
+ import type { Message } from '../../types/message/index.js'
22
+ import type { Project, ProjectStatus } from '../../types/project/entity.js'
23
+ import type { Session } from '../../types/session/entity.js'
24
+ import type { SessionMessage } from '../../types/session/messages.js'
25
+ import type {
26
+ CreateProjectParams,
27
+ CreateSessionParams,
28
+ CreateSubSessionParams,
29
+ ProjectConfigInput,
30
+ SessionStore,
31
+ SessionView,
32
+ } from '../../types/session/store.js'
33
+ import type { SubSession } from '../../types/session/sub-session.js'
34
+ import type { SessionSummaryRef } from '../../types/summary/ref.js'
35
+ import {
36
+ asProjectId,
37
+ asSessionId,
38
+ asSubSessionId,
39
+ asTenantId,
40
+ asTopicId,
41
+ generateMessageId,
42
+ generateProjectId,
43
+ generateSessionId,
44
+ generateSubSessionId,
45
+ } from '../../utils/id.js'
46
+ import { canonicalizePath } from './canonical-path.js'
47
+ import { type LinkageView, getAncestry, getChildren, orderChildren } from './linkage.js'
48
+
49
+ export interface SqliteSessionStoreConfig {
50
+ /** Absolute SQLite filename. Parent privacy is owned by the host. Requires Node 22.13+. */
51
+ readonly databasePath: string
52
+ /** Inspection never creates a database, changes its schema, or creates journal sidecars. */
53
+ readonly readOnly?: boolean
54
+ }
55
+
56
+ type Table = 'projects' | 'sessions' | 'subsessions' | 'summaries'
57
+ type Row = { body: string; tenant_id: string }
58
+ const SCHEMA_VERSION = 1
59
+ const SCHEMA = `
60
+ CREATE TABLE projects (id TEXT PRIMARY KEY, tenant_id TEXT NOT NULL, root_path TEXT, created_at INTEGER NOT NULL, body TEXT NOT NULL, UNIQUE(tenant_id, root_path));
61
+ CREATE TABLE sessions (id TEXT PRIMARY KEY, tenant_id TEXT NOT NULL, project_id TEXT NOT NULL REFERENCES projects(id), topic_id TEXT NOT NULL, created_at INTEGER NOT NULL, body TEXT NOT NULL);
62
+ CREATE INDEX sessions_project ON sessions(tenant_id, project_id, created_at, id);
63
+ CREATE INDEX sessions_topic ON sessions(tenant_id, topic_id, created_at, id);
64
+ CREATE TABLE subsessions (id TEXT PRIMARY KEY, tenant_id TEXT NOT NULL, parent_id TEXT NOT NULL REFERENCES sessions(id), child_id TEXT NOT NULL REFERENCES sessions(id), body TEXT NOT NULL);
65
+ CREATE INDEX subsessions_parent ON subsessions(tenant_id, parent_id);
66
+ CREATE INDEX subsessions_child ON subsessions(tenant_id, child_id);
67
+ CREATE TABLE summaries (id TEXT PRIMARY KEY REFERENCES sessions(id), tenant_id TEXT NOT NULL, body TEXT NOT NULL);
68
+ CREATE TABLE messages (seq INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL REFERENCES sessions(id), kind TEXT NOT NULL CHECK(kind IN ('message','replacement')), body TEXT NOT NULL);
69
+ CREATE INDEX messages_session ON messages(session_id, seq);
70
+ CREATE INDEX messages_replacement ON messages(session_id, kind, seq);
71
+ `
72
+
73
+ /**
74
+ * Indexed session metadata and append-only conversation records in one database.
75
+ * Operations own short-lived connections; no connection survives an await or
76
+ * needs a finalizer. Writes and CAS checks share one SQLite transaction, including
77
+ * across processes. Run transcripts and artifacts remain owned by RunStore.
78
+ */
79
+ export class SqliteSessionStore implements SessionStore {
80
+ readonly databasePath: string
81
+ private readonly readOnly: boolean
82
+
83
+ constructor(config: SqliteSessionStoreConfig) {
84
+ this.databasePath = resolve(config.databasePath)
85
+ this.readOnly = config.readOnly === true
86
+ }
87
+
88
+ private use<T>(write: boolean, operation: (db: DatabaseSync) => T): T {
89
+ if (write && this.readOnly) throw new Error('Session database is read-only')
90
+ // Loading the optional driver must not make importing the SDK require SQLite.
91
+ let Database: typeof DatabaseSync
92
+ try {
93
+ Database = (createRequire(import.meta.url)('node:sqlite') as typeof import('node:sqlite'))
94
+ .DatabaseSync
95
+ } catch (error) {
96
+ throw new Error('SqliteSessionStore requires Node.js 22.13 or newer.', { cause: error })
97
+ }
98
+ if (!this.readOnly) mkdirSync(dirname(this.databasePath), { recursive: true, mode: 0o700 })
99
+ const db = new Database(this.databasePath, { readOnly: this.readOnly })
100
+ try {
101
+ db.exec('PRAGMA busy_timeout = 5000; PRAGMA foreign_keys = ON;')
102
+ const version = Number(db.prepare('PRAGMA user_version').get()?.user_version)
103
+ if (version !== 0 && version !== SCHEMA_VERSION)
104
+ throw new Error(`Unsupported session database version ${version}`)
105
+ if (version === 0) {
106
+ if (this.readOnly) throw new Error('Session database has not been initialized')
107
+ db.exec('BEGIN IMMEDIATE')
108
+ try {
109
+ // Another first opener may have initialized it while we waited.
110
+ const current = Number(db.prepare('PRAGMA user_version').get()?.user_version)
111
+ if (current === 0) db.exec(`${SCHEMA} PRAGMA user_version = ${SCHEMA_VERSION};`)
112
+ else if (current !== SCHEMA_VERSION)
113
+ throw new Error(`Unsupported session database version ${current}`)
114
+ db.exec('COMMIT')
115
+ } catch (error) {
116
+ db.exec('ROLLBACK')
117
+ throw error
118
+ }
119
+ }
120
+ if (!this.readOnly) db.exec('PRAGMA journal_mode = DELETE; PRAGMA synchronous = FULL;')
121
+ db.exec(write ? 'BEGIN IMMEDIATE' : 'BEGIN')
122
+ try {
123
+ const result = operation(db)
124
+ db.exec('COMMIT')
125
+ return result
126
+ } catch (error) {
127
+ db.exec('ROLLBACK')
128
+ throw error
129
+ }
130
+ } finally {
131
+ db.close()
132
+ }
133
+ }
134
+
135
+ private get<T>(db: DatabaseSync, table: Table, id: string, tenantId: TenantId): T | null {
136
+ asTenantId(tenantId)
137
+ const row = db.prepare(`SELECT body, tenant_id FROM ${table} WHERE id = ?`).get(id) as
138
+ | Row
139
+ | undefined
140
+ if (!row) return null
141
+ if (row.tenant_id !== tenantId)
142
+ throw new TenantIsolationError({ requested: tenantId, resource: `${table}(${id})` })
143
+ return decode<T>(row.body)
144
+ }
145
+
146
+ private requiredSession(db: DatabaseSync, id: SessionId, tenant: TenantId): Session {
147
+ const session = this.get<Session>(db, 'sessions', asSessionId(id), tenant)
148
+ if (!session) throw new Error(`Session ${id} not found`)
149
+ return session
150
+ }
151
+
152
+ async createProject(params: CreateProjectParams, tenantId: TenantId): Promise<Project> {
153
+ if (params.tenantId !== tenantId)
154
+ throw new TenantIsolationError({ requested: tenantId, resource: 'project payload' })
155
+ asTenantId(tenantId)
156
+ const rootPath =
157
+ params.rootPath === undefined ? undefined : await canonicalizePath(params.rootPath)
158
+ return this.use(true, (db) => {
159
+ if (rootPath !== undefined) {
160
+ const existing = db
161
+ .prepare('SELECT id FROM projects WHERE tenant_id = ? AND root_path = ?')
162
+ .get(tenantId, rootPath)
163
+ if (existing)
164
+ throw new ProjectRootPathTakenError({
165
+ rootPath,
166
+ existingProjectId: asProjectId(String(existing.id)),
167
+ })
168
+ }
169
+ const now = new Date()
170
+ const project: Project = {
171
+ id: generateProjectId(),
172
+ tenantId,
173
+ name: params.name,
174
+ config: {
175
+ maxDelegationDepth: params.config?.maxDelegationDepth ?? 4,
176
+ maxDelegationWidth: params.config?.maxDelegationWidth ?? 8,
177
+ maxInterventionDepth: 10,
178
+ },
179
+ status: 'open',
180
+ ownerVersion: 0,
181
+ ...(rootPath === undefined ? {} : { rootPath }),
182
+ createdAt: now,
183
+ updatedAt: now,
184
+ }
185
+ db.prepare('INSERT INTO projects VALUES (?, ?, ?, ?, ?)').run(
186
+ project.id,
187
+ tenantId,
188
+ rootPath ?? null,
189
+ now.getTime(),
190
+ encode(project),
191
+ )
192
+ return project
193
+ })
194
+ }
195
+
196
+ async findProjectByRootPath(rootPath: string, tenantId: TenantId): Promise<Project | null> {
197
+ const canonical = await canonicalizePath(rootPath)
198
+ return this.use(false, (db) => {
199
+ const row = db
200
+ .prepare('SELECT body FROM projects WHERE tenant_id = ? AND root_path = ?')
201
+ .get(asTenantId(tenantId), canonical)
202
+ return row ? decode<Project>(String(row.body)) : null
203
+ })
204
+ }
205
+
206
+ async getProject(id: ProjectId, tenant: TenantId): Promise<Project | null> {
207
+ return this.use(false, (db) => this.get<Project>(db, 'projects', asProjectId(id), tenant))
208
+ }
209
+
210
+ async updateProject(
211
+ id: ProjectId,
212
+ config: ProjectConfigInput,
213
+ tenant: TenantId,
214
+ ): Promise<Project | null> {
215
+ return this.use(true, (db) => {
216
+ const old = this.get<Project>(db, 'projects', asProjectId(id), tenant)
217
+ if (!old) return null
218
+ const project = {
219
+ ...old,
220
+ config: {
221
+ ...old.config,
222
+ ...(config.maxDelegationDepth === undefined
223
+ ? {}
224
+ : { maxDelegationDepth: config.maxDelegationDepth }),
225
+ ...(config.maxDelegationWidth === undefined
226
+ ? {}
227
+ : { maxDelegationWidth: config.maxDelegationWidth }),
228
+ },
229
+ updatedAt: new Date(),
230
+ }
231
+ db.prepare('UPDATE projects SET body = ? WHERE id = ?').run(encode(project), id)
232
+ return project
233
+ })
234
+ }
235
+
236
+ async setProjectStatus(
237
+ id: ProjectId,
238
+ status: ProjectStatus,
239
+ tenant: TenantId,
240
+ expectedOwnerVersion: number,
241
+ ): Promise<Project | null> {
242
+ return this.use(true, (db) => {
243
+ const old = this.get<Project>(db, 'projects', asProjectId(id), tenant)
244
+ if (!old) return null
245
+ if (old.ownerVersion !== expectedOwnerVersion)
246
+ throw new StaleProjectError({
247
+ projectId: id,
248
+ expectedOwnerVersion,
249
+ actualOwnerVersion: old.ownerVersion,
250
+ })
251
+ const project = { ...old, status, ownerVersion: old.ownerVersion + 1, updatedAt: new Date() }
252
+ db.prepare('UPDATE projects SET body = ? WHERE id = ?').run(encode(project), id)
253
+ return project
254
+ })
255
+ }
256
+
257
+ async listProjects(tenant: TenantId): Promise<readonly Project[]> {
258
+ return this.use(false, (db) =>
259
+ db
260
+ .prepare('SELECT body FROM projects WHERE tenant_id = ? ORDER BY created_at, id')
261
+ .all(asTenantId(tenant))
262
+ .map((r) => decode<Project>(String(r.body))),
263
+ )
264
+ }
265
+
266
+ async createSession(params: CreateSessionParams, tenant: TenantId): Promise<Session> {
267
+ return this.use(true, (db) => {
268
+ if (!this.get<Project>(db, 'projects', asProjectId(params.projectId), tenant))
269
+ throw new Error(`Project ${params.projectId} not found`)
270
+ const id = params.id === undefined ? generateSessionId() : asSessionId(params.id)
271
+ if (this.get<Session>(db, 'sessions', id, tenant))
272
+ throw new Error(`Session ${id} already exists`)
273
+ const now = new Date()
274
+ const session: Session = {
275
+ id,
276
+ topicId: asTopicId(params.topicId),
277
+ projectId: params.projectId,
278
+ tenantId: tenant,
279
+ status: 'idle',
280
+ currentActor: params.currentActor,
281
+ previousActors: [],
282
+ workspaceId: null,
283
+ ownerVersion: 0,
284
+ createdAt: now,
285
+ updatedAt: now,
286
+ }
287
+ db.prepare('INSERT INTO sessions VALUES (?, ?, ?, ?, ?, ?)').run(
288
+ id,
289
+ tenant,
290
+ session.projectId,
291
+ session.topicId,
292
+ now.getTime(),
293
+ encode(session),
294
+ )
295
+ return session
296
+ })
297
+ }
298
+
299
+ async getSession(id: SessionId, tenant: TenantId): Promise<Session | null> {
300
+ return this.use(false, (db) => this.get<Session>(db, 'sessions', asSessionId(id), tenant))
301
+ }
302
+
303
+ async listSessionsByProject(id: ProjectId, tenant: TenantId): Promise<readonly Session[]> {
304
+ return this.use(false, (db) =>
305
+ db
306
+ .prepare(
307
+ 'SELECT body FROM sessions WHERE tenant_id = ? AND project_id = ? ORDER BY created_at, id',
308
+ )
309
+ .all(asTenantId(tenant), asProjectId(id))
310
+ .map((r) => decode<Session>(String(r.body))),
311
+ )
312
+ }
313
+
314
+ async listSessionsByTopic(id: TopicId, tenant: TenantId): Promise<readonly Session[]> {
315
+ return this.use(false, (db) =>
316
+ db
317
+ .prepare(
318
+ 'SELECT body FROM sessions WHERE tenant_id = ? AND topic_id = ? ORDER BY created_at, id',
319
+ )
320
+ .all(asTenantId(tenant), asTopicId(id))
321
+ .map((r) => decode<Session>(String(r.body))),
322
+ )
323
+ }
324
+
325
+ async updateSession(
326
+ session: Session,
327
+ tenant: TenantId,
328
+ expectedOwnerVersion?: number,
329
+ ): Promise<void> {
330
+ this.use(true, (db) => {
331
+ const old = this.requiredSession(db, session.id, tenant)
332
+ if (session.tenantId !== tenant)
333
+ throw new TenantIsolationError({ requested: tenant, resource: 'session payload' })
334
+ if (session.projectId !== old.projectId || session.topicId !== old.topicId)
335
+ throw new Error('Session project and topic bindings cannot change')
336
+ if (expectedOwnerVersion !== undefined && old.ownerVersion !== expectedOwnerVersion)
337
+ throw new StaleSessionError({
338
+ sessionId: session.id,
339
+ expectedVersion: expectedOwnerVersion,
340
+ actualVersion: old.ownerVersion,
341
+ })
342
+ db.prepare('UPDATE sessions SET body = ? WHERE id = ?').run(
343
+ encode({ ...session, updatedAt: new Date() }),
344
+ session.id,
345
+ )
346
+ })
347
+ }
348
+
349
+ async deleteSession(id: SessionId, tenant: TenantId): Promise<void> {
350
+ this.use(true, (db) => {
351
+ if (!this.get<Session>(db, 'sessions', asSessionId(id), tenant)) return
352
+ if (
353
+ db
354
+ .prepare('SELECT 1 FROM subsessions WHERE parent_id = ? OR child_id = ? LIMIT 1')
355
+ .get(id, id)
356
+ )
357
+ throw new Error(
358
+ `Session ${id} has attached sub-sessions; delete them before deleting the session`,
359
+ )
360
+ db.prepare('DELETE FROM messages WHERE session_id = ?').run(id)
361
+ db.prepare('DELETE FROM summaries WHERE id = ?').run(id)
362
+ db.prepare('DELETE FROM sessions WHERE id = ?').run(id)
363
+ })
364
+ }
365
+
366
+ async createSubSession(params: CreateSubSessionParams, tenant: TenantId): Promise<SubSession> {
367
+ return this.use(true, (db) => {
368
+ this.requiredSession(db, params.parentSessionId, tenant)
369
+ this.requiredSession(db, params.childSessionId, tenant)
370
+ const now = new Date()
371
+ const sub: SubSession = {
372
+ id: generateSubSessionId(),
373
+ parentSessionId: params.parentSessionId,
374
+ childSessionId: params.childSessionId,
375
+ kind: params.kind,
376
+ status: 'pending',
377
+ spawnedBy: params.spawnedBy,
378
+ spawnedAt: now,
379
+ failureMode: params.failureMode ?? 'delegate',
380
+ completionMode: params.completionMode ?? 'summary_ref',
381
+ workspaceId: null,
382
+ updatedAt: now,
383
+ }
384
+ db.prepare('INSERT INTO subsessions VALUES (?, ?, ?, ?, ?)').run(
385
+ sub.id,
386
+ tenant,
387
+ sub.parentSessionId,
388
+ sub.childSessionId,
389
+ encode(sub),
390
+ )
391
+ return sub
392
+ })
393
+ }
394
+
395
+ async getSubSession(id: SubSessionId, tenant: TenantId): Promise<SubSession | null> {
396
+ return this.use(false, (db) =>
397
+ this.get<SubSession>(db, 'subsessions', asSubSessionId(id), tenant),
398
+ )
399
+ }
400
+
401
+ async updateSubSession(sub: SubSession, tenant: TenantId): Promise<void> {
402
+ this.use(true, (db) => {
403
+ const old = this.get<SubSession>(db, 'subsessions', asSubSessionId(sub.id), tenant)
404
+ if (!old) throw new Error(`SubSession ${sub.id} not found`)
405
+ if (old.parentSessionId !== sub.parentSessionId || old.childSessionId !== sub.childSessionId)
406
+ throw new Error('Sub-session parent and child bindings cannot change')
407
+ db.prepare('UPDATE subsessions SET body = ? WHERE id = ?').run(
408
+ encode({ ...sub, updatedAt: new Date() }),
409
+ sub.id,
410
+ )
411
+ })
412
+ }
413
+
414
+ async deleteSubSession(id: SubSessionId, tenant: TenantId): Promise<void> {
415
+ this.use(true, (db) => {
416
+ if (this.get<SubSession>(db, 'subsessions', asSubSessionId(id), tenant))
417
+ db.prepare('DELETE FROM subsessions WHERE id = ?').run(id)
418
+ })
419
+ }
420
+
421
+ async appendMessage(id: SessionId, message: Message, tenant: TenantId): Promise<MessageId> {
422
+ return this.use(true, (db) => {
423
+ this.requiredSession(db, id, tenant)
424
+ const entry: SessionMessage = {
425
+ id: generateMessageId(),
426
+ sessionId: id,
427
+ tenantId: tenant,
428
+ message,
429
+ at: new Date(),
430
+ }
431
+ db.prepare("INSERT INTO messages (session_id, kind, body) VALUES (?, 'message', ?)").run(
432
+ id,
433
+ encode(entry),
434
+ )
435
+ return entry.id
436
+ })
437
+ }
438
+
439
+ async replaceMessages(
440
+ id: SessionId,
441
+ messages: readonly Message[],
442
+ tenant: TenantId,
443
+ ): Promise<void> {
444
+ this.use(true, (db) => {
445
+ this.requiredSession(db, id, tenant)
446
+ const entries = messages.map(
447
+ (message): SessionMessage => ({
448
+ id: generateMessageId(),
449
+ sessionId: id,
450
+ tenantId: tenant,
451
+ message,
452
+ at: new Date(),
453
+ }),
454
+ )
455
+ db.prepare("INSERT INTO messages (session_id, kind, body) VALUES (?, 'replacement', ?)").run(
456
+ id,
457
+ encode(entries),
458
+ )
459
+ })
460
+ }
461
+
462
+ async loadMessages(id: SessionId, tenant: TenantId): Promise<readonly Message[]> {
463
+ return (await this.loadSessionMessages(id, tenant)).map((entry) => entry.message)
464
+ }
465
+
466
+ async loadSessionMessages(id: SessionId, tenant: TenantId): Promise<readonly SessionMessage[]> {
467
+ return this.use(false, (db) => {
468
+ if (!this.get<Session>(db, 'sessions', asSessionId(id), tenant)) return []
469
+ const replacement = db
470
+ .prepare(
471
+ "SELECT seq, body FROM messages WHERE session_id = ? AND kind = 'replacement' ORDER BY seq DESC LIMIT 1",
472
+ )
473
+ .get(id)
474
+ const entries = replacement
475
+ ? (JSON.parse(String(replacement.body)) as unknown[]).map(decodeMessage)
476
+ : []
477
+ const later = db
478
+ .prepare(
479
+ "SELECT body FROM messages WHERE session_id = ? AND seq > ? AND kind = 'message' ORDER BY seq",
480
+ )
481
+ .all(id, Number(replacement?.seq ?? 0))
482
+ return entries.concat(later.map((row) => decodeMessage(JSON.parse(String(row.body)))))
483
+ })
484
+ }
485
+
486
+ private linkage(db: DatabaseSync, tenant: TenantId): LinkageView {
487
+ return {
488
+ findChildSubSessions: (id) =>
489
+ db
490
+ .prepare('SELECT body FROM subsessions WHERE tenant_id = ? AND parent_id = ?')
491
+ .all(tenant, id)
492
+ .map((r) => decode<SubSession>(String(r.body))),
493
+ findParentSubSession: (id) => {
494
+ const row = db
495
+ .prepare(
496
+ 'SELECT body FROM subsessions WHERE tenant_id = ? AND child_id = ? ORDER BY id LIMIT 1',
497
+ )
498
+ .get(tenant, id)
499
+ return row ? decode<SubSession>(String(row.body)) : null
500
+ },
501
+ }
502
+ }
503
+
504
+ async getChildren(id: SessionId, tenant: TenantId): Promise<readonly SubSession[]> {
505
+ return this.use(false, (db) =>
506
+ this.get<Session>(db, 'sessions', asSessionId(id), tenant)
507
+ ? orderChildren(getChildren(this.linkage(db, tenant), id))
508
+ : [],
509
+ )
510
+ }
511
+
512
+ async getAncestry(id: SessionId, tenant: TenantId): Promise<readonly SessionId[]> {
513
+ return this.use(false, (db) =>
514
+ this.get<Session>(db, 'sessions', asSessionId(id), tenant)
515
+ ? getAncestry(this.linkage(db, tenant), id)
516
+ : [],
517
+ )
518
+ }
519
+
520
+ async drill(id: SessionId, tenant: TenantId): Promise<SessionView | null> {
521
+ return this.use(false, (db) => {
522
+ const session = this.get<Session>(db, 'sessions', asSessionId(id), tenant)
523
+ if (!session) return null
524
+ const view = this.linkage(db, tenant)
525
+ return {
526
+ session,
527
+ children: orderChildren(getChildren(view, id)),
528
+ ancestry: getAncestry(view, id),
529
+ }
530
+ })
531
+ }
532
+
533
+ async recordSummary(
534
+ summary: SessionSummaryRef & { materializedBy: 'kernel' },
535
+ tenant: TenantId,
536
+ ): Promise<void> {
537
+ this.use(true, (db) => {
538
+ if (summary.tenantId !== tenant)
539
+ throw new TenantIsolationError({ requested: tenant, resource: 'summary payload' })
540
+ const session = this.requiredSession(db, summary.sessionRef, tenant)
541
+ const existing = this.get<SessionSummaryRef>(db, 'summaries', summary.sessionRef, tenant)
542
+ if (existing && existing.id !== summary.id)
543
+ throw new SessionAlreadySummarizedError({
544
+ sessionId: session.id,
545
+ existingSummaryId: existing.id,
546
+ })
547
+ if (!existing)
548
+ db.prepare('INSERT INTO summaries VALUES (?, ?, ?)').run(
549
+ session.id,
550
+ tenant,
551
+ encode(summary),
552
+ )
553
+ if (['active', 'locked', 'awaiting_merge'].includes(session.status))
554
+ db.prepare('UPDATE sessions SET body = ? WHERE id = ?').run(
555
+ encode({ ...session, status: 'idle', updatedAt: new Date() }),
556
+ session.id,
557
+ )
558
+ })
559
+ }
560
+
561
+ async getSummary(id: SessionId, tenant: TenantId): Promise<SessionSummaryRef | null> {
562
+ return this.use(false, (db) =>
563
+ this.get<SessionSummaryRef>(db, 'summaries', asSessionId(id), tenant),
564
+ )
565
+ }
566
+ }
567
+
568
+ function encode(value: unknown): string {
569
+ return JSON.stringify(value)
570
+ }
571
+ function decode<T>(body: string): T {
572
+ const value = JSON.parse(body) as Record<string, unknown>
573
+ for (const key of ['createdAt', 'updatedAt', 'spawnedAt', 'archivedAt', 'at']) {
574
+ if (typeof value[key] === 'string') value[key] = new Date(value[key] as string)
575
+ }
576
+ if (Array.isArray(value.keyDecisions)) {
577
+ value.keyDecisions = value.keyDecisions.map((entry) => ({ ...entry, at: new Date(entry.at) }))
578
+ }
579
+ return value as T
580
+ }
581
+ function decodeMessage(value: unknown): SessionMessage {
582
+ const entry = value as SessionMessage
583
+ return { ...entry, at: new Date(entry.at) }
584
+ }