@sema-agent/server 1.322.0 → 2.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 (539) hide show
  1. package/dist/approval-hmac.d.ts +40 -0
  2. package/dist/approval-hmac.js +67 -0
  3. package/dist/approval.d.ts +31 -0
  4. package/dist/approval.js +72 -4
  5. package/dist/audit.d.ts +26 -0
  6. package/dist/audit.js +40 -1
  7. package/dist/auth-bridge.d.ts +10 -0
  8. package/dist/auth-bridge.js +47 -4
  9. package/dist/auth-keys.d.ts +19 -0
  10. package/dist/auth-keys.js +13 -0
  11. package/dist/bake-runner/main.d.ts +5 -0
  12. package/dist/bake-runner/main.js +43 -4
  13. package/dist/bake-runner/protocol.d.ts +57 -0
  14. package/dist/bake-runner/protocol.js +58 -3
  15. package/dist/bake-runner/runner.d.ts +54 -0
  16. package/dist/bake-runner/runner.js +87 -5
  17. package/dist/bench/l8/artifact.d.ts +63 -0
  18. package/dist/bench/l8/artifact.js +61 -2
  19. package/dist/bench/l8/escape.d.ts +36 -0
  20. package/dist/bench/l8/escape.js +25 -0
  21. package/dist/bench/l8/index.d.ts +14 -0
  22. package/dist/bench/l8/index.js +14 -0
  23. package/dist/bench/l8/probes.d.ts +74 -0
  24. package/dist/bench/l8/probes.js +60 -0
  25. package/dist/bench/l8/run-probes.d.ts +43 -0
  26. package/dist/bench/l8/run-probes.js +45 -2
  27. package/dist/bench/s1/arms.d.ts +126 -0
  28. package/dist/bench/s1/arms.js +188 -13
  29. package/dist/bench/s1/live-deps.d.ts +66 -0
  30. package/dist/bench/s1/live-deps.js +249 -11
  31. package/dist/bench/s1/oracle.d.ts +49 -0
  32. package/dist/bench/s1/oracle.js +36 -1
  33. package/dist/bench/s1/repair-oracle-adapter.d.ts +33 -0
  34. package/dist/bench/s1/repair-oracle-adapter.js +30 -0
  35. package/dist/bench/s1/reviewer.d.ts +38 -0
  36. package/dist/bench/s1/reviewer.js +34 -0
  37. package/dist/bench/s1/row.d.ts +77 -0
  38. package/dist/bench/s1/row.js +62 -0
  39. package/dist/bench/s1/run-firm.d.ts +47 -0
  40. package/dist/bench/s1/run-firm.js +70 -4
  41. package/dist/bench/s1/runner-ctx.d.ts +71 -0
  42. package/dist/bench/s1/runner-ctx.js +36 -0
  43. package/dist/bench/s1/tasks.d.ts +108 -0
  44. package/dist/bench/s1/tasks.js +115 -0
  45. package/dist/boot-reclaim.d.ts +19 -0
  46. package/dist/boot-reclaim.js +20 -0
  47. package/dist/brain.d.ts +25 -0
  48. package/dist/brain.js +61 -1
  49. package/dist/budget.d.ts +66 -0
  50. package/dist/budget.js +128 -4
  51. package/dist/capabilities/builtin-tools.d.ts +3 -0
  52. package/dist/capabilities/builtin-tools.js +3 -0
  53. package/dist/capabilities/center-plugins.d.ts +17 -1
  54. package/dist/capabilities/center-plugins.js +45 -4
  55. package/dist/capabilities/center-prompts.d.ts +46 -0
  56. package/dist/capabilities/center-prompts.js +57 -3
  57. package/dist/capabilities/code-review-council.d.ts +28 -0
  58. package/dist/capabilities/code-review-council.js +40 -7
  59. package/dist/capabilities/collab-wire.d.ts +2 -0
  60. package/dist/capabilities/collab-workflows.d.ts +7 -0
  61. package/dist/capabilities/collab-workflows.js +44 -1
  62. package/dist/capabilities/oa-tools.d.ts +6 -0
  63. package/dist/capabilities/oa-tools.js +10 -0
  64. package/dist/capabilities/prompt.d.ts +14 -0
  65. package/dist/capabilities/prompt.js +14 -0
  66. package/dist/capabilities/prompts/code-review.d.ts +14 -0
  67. package/dist/capabilities/prompts/code-review.js +14 -0
  68. package/dist/capabilities/prompts/identity.d.ts +6 -0
  69. package/dist/capabilities/prompts/identity.js +6 -0
  70. package/dist/capabilities/prompts/team.d.ts +4 -0
  71. package/dist/capabilities/prompts/team.js +4 -0
  72. package/dist/capabilities/repo-tools.d.ts +11 -0
  73. package/dist/capabilities/repo-tools.js +8 -0
  74. package/dist/capabilities/sandbox-file-send.d.ts +95 -0
  75. package/dist/capabilities/sandbox-file-send.js +91 -3
  76. package/dist/capabilities/scenarios.d.ts +130 -0
  77. package/dist/capabilities/scenarios.js +180 -7
  78. package/dist/capabilities/select-environment-tool.d.ts +7 -0
  79. package/dist/capabilities/select-environment-tool.js +30 -0
  80. package/dist/capabilities/send-user-file-tool.d.ts +33 -0
  81. package/dist/capabilities/send-user-file-tool.js +65 -1
  82. package/dist/capabilities/skills.d.ts +29 -0
  83. package/dist/capabilities/skills.js +13 -2
  84. package/dist/capabilities/team.d.ts +22 -0
  85. package/dist/capabilities/team.js +22 -2
  86. package/dist/capabilities/tool-defer.d.ts +26 -0
  87. package/dist/capabilities/tool-defer.js +3 -0
  88. package/dist/config-center/apply-effective.d.ts +65 -0
  89. package/dist/config-center/apply-effective.js +204 -12
  90. package/dist/config-center/http-client.d.ts +34 -0
  91. package/dist/config-center/http-client.js +68 -0
  92. package/dist/config-center/restart-signal.d.ts +22 -0
  93. package/dist/config-center/restart-signal.js +39 -0
  94. package/dist/config-center/skills-mcp.d.ts +20 -1
  95. package/dist/config-center/skills-mcp.js +42 -7
  96. package/dist/config-center/types.d.ts +92 -1
  97. package/dist/config-lkg.d.ts +12 -0
  98. package/dist/config-lkg.js +41 -0
  99. package/dist/config-provider.d.ts +78 -0
  100. package/dist/config-provider.js +165 -2
  101. package/dist/config-types.d.ts +546 -0
  102. package/dist/config.d.ts +64 -0
  103. package/dist/config.js +455 -60
  104. package/dist/degenerate-instrument.d.ts +38 -0
  105. package/dist/degenerate-instrument.js +55 -3
  106. package/dist/elicitation.d.ts +39 -0
  107. package/dist/elicitation.js +87 -3
  108. package/dist/env-facts.d.ts +61 -0
  109. package/dist/env-facts.js +73 -7
  110. package/dist/fleet/fleet-bus.d.ts +185 -0
  111. package/dist/fleet/fleet-bus.js +333 -27
  112. package/dist/fleet/subagent-tail-bus.d.ts +11 -0
  113. package/dist/fleet/subagent-tail-bus.js +33 -2
  114. package/dist/fleet-client.d.ts +38 -0
  115. package/dist/fleet-client.js +44 -9
  116. package/dist/fleet-lease.d.ts +46 -0
  117. package/dist/fleet-lease.js +73 -5
  118. package/dist/hooks/branch-transcript.d.ts +8 -0
  119. package/dist/hooks/branch-transcript.js +33 -0
  120. package/dist/hooks/cc-stop-prompt.d.ts +42 -0
  121. package/dist/hooks/cc-stop-prompt.js +43 -1
  122. package/dist/hooks/hook-llm.d.ts +15 -0
  123. package/dist/hooks/hook-llm.js +47 -0
  124. package/dist/hooks/hook-runner.d.ts +89 -0
  125. package/dist/hooks/hook-runner.js +327 -18
  126. package/dist/http/idempotency.d.ts +31 -0
  127. package/dist/http/idempotency.js +34 -0
  128. package/dist/http/principal-gate.d.ts +17 -0
  129. package/dist/http/principal-gate.js +35 -3
  130. package/dist/http/route-ctx.d.ts +36 -0
  131. package/dist/http/routes/approvals-assistant.d.ts +25 -0
  132. package/dist/http/routes/approvals-assistant.js +253 -23
  133. package/dist/http/routes/attachments.js +22 -4
  134. package/dist/http/routes/capabilities.d.ts +7 -0
  135. package/dist/http/routes/capabilities.js +202 -1
  136. package/dist/http/routes/fleet.d.ts +6 -0
  137. package/dist/http/routes/fleet.js +94 -5
  138. package/dist/http/routes/images.d.ts +17 -0
  139. package/dist/http/routes/images.js +222 -14
  140. package/dist/http/routes/leader.d.ts +7 -0
  141. package/dist/http/routes/leader.js +10 -0
  142. package/dist/http/routes/memory-policy.d.ts +6 -0
  143. package/dist/http/routes/memory-policy.js +38 -6
  144. package/dist/http/routes/notify-wake.d.ts +10 -0
  145. package/dist/http/routes/notify-wake.js +19 -3
  146. package/dist/http/routes/observability.d.ts +6 -0
  147. package/dist/http/routes/observability.js +19 -2
  148. package/dist/http/routes/runs.d.ts +15 -0
  149. package/dist/http/routes/runs.js +464 -41
  150. package/dist/http/routes/session-sync.d.ts +15 -0
  151. package/dist/http/routes/session-sync.js +229 -19
  152. package/dist/http/routes/sessions-list.d.ts +6 -0
  153. package/dist/http/routes/sessions-list.js +35 -4
  154. package/dist/http/routes/sessions.d.ts +14 -0
  155. package/dist/http/routes/sessions.js +176 -31
  156. package/dist/http/routes/side-query.d.ts +8 -0
  157. package/dist/http/routes/side-query.js +26 -1
  158. package/dist/http/routes/tasks.d.ts +18 -0
  159. package/dist/http/routes/tasks.js +501 -38
  160. package/dist/http/routes/trace-usage.d.ts +10 -0
  161. package/dist/http/routes/trace-usage.js +66 -14
  162. package/dist/http/routes/workflows.d.ts +12 -0
  163. package/dist/http/routes/workflows.js +180 -19
  164. package/dist/http/run-meta.d.ts +11 -0
  165. package/dist/http/run-meta.js +6 -0
  166. package/dist/http/send.d.ts +19 -0
  167. package/dist/http/send.js +11 -0
  168. package/dist/http/server.d.ts +255 -0
  169. package/dist/http/server.js +921 -75
  170. package/dist/http/sse-log.d.ts +15 -0
  171. package/dist/http/sse-log.js +16 -0
  172. package/dist/http/tar.d.ts +9 -0
  173. package/dist/http/tar.js +21 -5
  174. package/dist/http/wire-gate.d.ts +9 -0
  175. package/dist/http/wire-gate.js +9 -0
  176. package/dist/http/wire-types.d.ts +187 -0
  177. package/dist/http/workspace-content.d.ts +8 -0
  178. package/dist/http/workspace-content.js +10 -0
  179. package/dist/images/bake-validate.d.ts +63 -0
  180. package/dist/images/bake-validate.js +71 -1
  181. package/dist/images/manifest.d.ts +19 -0
  182. package/dist/images/manifest.js +6 -1
  183. package/dist/index.d.ts +1 -5
  184. package/dist/index.js +10 -5
  185. package/dist/key-resolver.d.ts +23 -0
  186. package/dist/key-resolver.js +27 -2
  187. package/dist/leader/diffout.d.ts +23 -0
  188. package/dist/leader/diffout.js +8 -1
  189. package/dist/leader/diffup.d.ts +32 -0
  190. package/dist/leader/diffup.js +43 -0
  191. package/dist/leader/endpoint.d.ts +20 -0
  192. package/dist/leader/endpoint.js +25 -2
  193. package/dist/leader/fanout.d.ts +60 -0
  194. package/dist/leader/fanout.js +29 -3
  195. package/dist/leader/grader-env-factory.d.ts +74 -0
  196. package/dist/leader/grader-env-factory.js +62 -3
  197. package/dist/leader/leader.d.ts +97 -0
  198. package/dist/leader/leader.js +151 -4
  199. package/dist/leader/merge.d.ts +94 -0
  200. package/dist/leader/merge.js +112 -9
  201. package/dist/leader/planner.d.ts +52 -0
  202. package/dist/leader/planner.js +47 -3
  203. package/dist/leader/repair-oracle.d.ts +61 -0
  204. package/dist/leader/repair-oracle.js +59 -1
  205. package/dist/leader/repair-wire.d.ts +78 -0
  206. package/dist/leader/repair-wire.js +79 -2
  207. package/dist/leader/wire.d.ts +79 -0
  208. package/dist/leader/wire.js +255 -8
  209. package/dist/lsp/e2b-bridge.d.ts +16 -0
  210. package/dist/lsp/e2b-bridge.js +32 -4
  211. package/dist/lsp/e2b-manager.d.ts +10 -0
  212. package/dist/lsp/e2b-manager.js +18 -2
  213. package/dist/lsp/lsp-frames.d.ts +12 -0
  214. package/dist/lsp/lsp-frames.js +12 -0
  215. package/dist/lsp/manager.d.ts +12 -0
  216. package/dist/lsp/manager.js +35 -2
  217. package/dist/lsp/types.d.ts +10 -0
  218. package/dist/lsp/ws-transport.d.ts +12 -0
  219. package/dist/lsp/ws-transport.js +53 -5
  220. package/dist/lsp-evict.d.ts +14 -0
  221. package/dist/lsp-evict.js +15 -1
  222. package/dist/main.js +2132 -96
  223. package/dist/memory-export.d.ts +1 -0
  224. package/dist/memory-export.js +4 -0
  225. package/dist/memory-scope.d.ts +49 -0
  226. package/dist/memory-scope.js +87 -4
  227. package/dist/memory-sync-client.d.ts +24 -0
  228. package/dist/memory-sync-client.js +41 -2
  229. package/dist/memory-sync.d.ts +23 -0
  230. package/dist/memory-sync.js +70 -1
  231. package/dist/model-select.d.ts +39 -0
  232. package/dist/model-select.js +42 -1
  233. package/dist/observability/cost-quota.d.ts +20 -0
  234. package/dist/observability/cost-quota.js +4 -0
  235. package/dist/observability/cost-taxonomy.d.ts +45 -0
  236. package/dist/observability/cost-taxonomy.js +34 -0
  237. package/dist/observability/logger.d.ts +1 -0
  238. package/dist/observability/logger.js +6 -0
  239. package/dist/observability/metrics.d.ts +13 -0
  240. package/dist/observability/metrics.js +63 -0
  241. package/dist/observability/otel-exporter.d.ts +9 -0
  242. package/dist/observability/otel-exporter.js +11 -3
  243. package/dist/observability/principal-context.d.ts +9 -0
  244. package/dist/observability/principal-context.js +9 -0
  245. package/dist/observability/prompt-manifest.d.ts +37 -0
  246. package/dist/observability/prompt-manifest.js +35 -1
  247. package/dist/observability/rate-limit.d.ts +10 -0
  248. package/dist/observability/rate-limit.js +1 -0
  249. package/dist/observability/tool-trace.d.ts +24 -0
  250. package/dist/observability/tool-trace.js +41 -1
  251. package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
  252. package/dist/orchestration/hardened-vm-runner.js +119 -4
  253. package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
  254. package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
  255. package/dist/orchestration/hardened-vm-worker.js +27 -0
  256. package/dist/orchestration/subagent-steer.d.ts +44 -0
  257. package/dist/orchestration/subagent-steer.js +45 -1
  258. package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
  259. package/dist/orchestration/workflow-agent-steer.js +80 -1
  260. package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
  261. package/dist/orchestration/workflow-completion-inbox.js +283 -32
  262. package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
  263. package/dist/orchestration/workflow-notify-journal.js +187 -13
  264. package/dist/parked-decide.d.ts +61 -0
  265. package/dist/parked-decide.js +58 -1
  266. package/dist/per-task-image.d.ts +54 -0
  267. package/dist/per-task-image.js +41 -0
  268. package/dist/plan-cache-probe.d.ts +35 -0
  269. package/dist/plan-cache-probe.js +18 -3
  270. package/dist/plugins/approval-exemption-store.d.ts +7 -0
  271. package/dist/plugins/approval-exemption-store.js +28 -2
  272. package/dist/plugins/approval-store-sql.d.ts +64 -0
  273. package/dist/plugins/approval-store-sql.js +32 -0
  274. package/dist/plugins/background-agent-store-sql.d.ts +55 -0
  275. package/dist/plugins/background-agent-store-sql.js +91 -4
  276. package/dist/plugins/background-shell-support.d.ts +98 -0
  277. package/dist/plugins/background-shell-support.js +117 -13
  278. package/dist/plugins/blob-backend.d.ts +104 -0
  279. package/dist/plugins/blob-backend.js +163 -6
  280. package/dist/plugins/breaker-state-sql.d.ts +65 -1
  281. package/dist/plugins/breaker-state-sql.js +46 -8
  282. package/dist/plugins/caching-session-store.d.ts +42 -0
  283. package/dist/plugins/caching-session-store.js +63 -3
  284. package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
  285. package/dist/plugins/checkpoint-store-sql.js +239 -11
  286. package/dist/plugins/file-outcome-sink.d.ts +4 -0
  287. package/dist/plugins/file-outcome-sink.js +9 -0
  288. package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
  289. package/dist/plugins/file-resume-anchor-store.js +43 -4
  290. package/dist/plugins/file-run-store.d.ts +90 -0
  291. package/dist/plugins/file-run-store.js +145 -13
  292. package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
  293. package/dist/plugins/file-snapshot-store-sql.js +178 -10
  294. package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
  295. package/dist/plugins/file-workflow-journal-store.js +10 -0
  296. package/dist/plugins/fork-routing-session-store.d.ts +47 -0
  297. package/dist/plugins/fork-routing-session-store.js +51 -3
  298. package/dist/plugins/host-platform.d.ts +69 -0
  299. package/dist/plugins/host-platform.js +81 -2
  300. package/dist/plugins/image-bake-store-sql.d.ts +136 -1
  301. package/dist/plugins/image-bake-store-sql.js +241 -7
  302. package/dist/plugins/image-index-sql.d.ts +46 -0
  303. package/dist/plugins/image-index-sql.js +113 -4
  304. package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
  305. package/dist/plugins/k8s-bg-scripts.js +88 -4
  306. package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
  307. package/dist/plugins/k8s-exec-protocol.js +41 -0
  308. package/dist/plugins/local-checkpoint-store.d.ts +40 -0
  309. package/dist/plugins/local-checkpoint-store.js +86 -7
  310. package/dist/plugins/local-session-store.d.ts +157 -0
  311. package/dist/plugins/local-session-store.js +289 -34
  312. package/dist/plugins/local-task-attachment-store.js +14 -2
  313. package/dist/plugins/mailbox-store-sql.d.ts +38 -0
  314. package/dist/plugins/mailbox-store-sql.js +39 -6
  315. package/dist/plugins/memory-engine-pg.d.ts +30 -0
  316. package/dist/plugins/memory-engine-pg.js +122 -4
  317. package/dist/plugins/memory-engine-tidb.d.ts +26 -0
  318. package/dist/plugins/memory-engine-tidb.js +115 -5
  319. package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
  320. package/dist/plugins/memory-engine-vector-util.js +5 -0
  321. package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
  322. package/dist/plugins/memory-resume-anchor-store.js +17 -0
  323. package/dist/plugins/memory-run-store.d.ts +63 -0
  324. package/dist/plugins/memory-run-store.js +73 -8
  325. package/dist/plugins/memory-session-policy-store.d.ts +17 -0
  326. package/dist/plugins/memory-session-policy-store.js +17 -0
  327. package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
  328. package/dist/plugins/memory-sync-store-pg.js +45 -2
  329. package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
  330. package/dist/plugins/memory-sync-store-tidb.js +31 -1
  331. package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
  332. package/dist/plugins/outcome-ledger-sql.js +97 -3
  333. package/dist/plugins/pg-approval-store.d.ts +7 -0
  334. package/dist/plugins/pg-approval-store.js +7 -0
  335. package/dist/plugins/pg-breaker-state.d.ts +6 -0
  336. package/dist/plugins/pg-breaker-state.js +6 -0
  337. package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
  338. package/dist/plugins/pg-checkpoint-store.js +8 -0
  339. package/dist/plugins/pg-cost-quota.d.ts +17 -0
  340. package/dist/plugins/pg-cost-quota.js +6 -0
  341. package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
  342. package/dist/plugins/pg-file-snapshot-store.js +6 -0
  343. package/dist/plugins/pg-image-bake.d.ts +9 -0
  344. package/dist/plugins/pg-image-bake.js +9 -0
  345. package/dist/plugins/pg-image-index.d.ts +9 -0
  346. package/dist/plugins/pg-image-index.js +9 -0
  347. package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
  348. package/dist/plugins/pg-outcome-ledger.js +9 -0
  349. package/dist/plugins/pg-pool.d.ts +50 -0
  350. package/dist/plugins/pg-pool.js +78 -0
  351. package/dist/plugins/pg-query.d.ts +11 -0
  352. package/dist/plugins/pg-rate-limiter.d.ts +23 -0
  353. package/dist/plugins/pg-rate-limiter.js +12 -2
  354. package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
  355. package/dist/plugins/pg-resume-anchor-store.js +5 -0
  356. package/dist/plugins/pg-run-store.d.ts +7 -0
  357. package/dist/plugins/pg-run-store.js +7 -0
  358. package/dist/plugins/pg-safe-json.d.ts +13 -0
  359. package/dist/plugins/pg-safe-json.js +40 -4
  360. package/dist/plugins/pg-session-policy-store.d.ts +5 -0
  361. package/dist/plugins/pg-session-policy-store.js +5 -0
  362. package/dist/plugins/pg-session-storage.d.ts +72 -0
  363. package/dist/plugins/pg-session-storage.js +152 -20
  364. package/dist/plugins/pg-session-store.d.ts +10 -0
  365. package/dist/plugins/pg-session-store.js +10 -0
  366. package/dist/plugins/pg-tool-result-store.d.ts +7 -0
  367. package/dist/plugins/pg-tool-result-store.js +7 -0
  368. package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
  369. package/dist/plugins/pg-workflow-journal-store.js +7 -0
  370. package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
  371. package/dist/plugins/pg-workflow-run-store.js +7 -0
  372. package/dist/plugins/posix-shell-fs.d.ts +3 -0
  373. package/dist/plugins/posix-shell-fs.js +31 -1
  374. package/dist/plugins/remote-env-adb.d.ts +25 -0
  375. package/dist/plugins/remote-env-adb.js +95 -12
  376. package/dist/plugins/remote-env-e2b.d.ts +146 -0
  377. package/dist/plugins/remote-env-e2b.js +371 -40
  378. package/dist/plugins/remote-env-file-error.d.ts +34 -0
  379. package/dist/plugins/remote-env-file-error.js +37 -0
  380. package/dist/plugins/remote-env-host.d.ts +151 -0
  381. package/dist/plugins/remote-env-host.js +468 -70
  382. package/dist/plugins/remote-env-k8s.d.ts +135 -0
  383. package/dist/plugins/remote-env-k8s.js +318 -32
  384. package/dist/plugins/remote-env-local-docker.d.ts +65 -0
  385. package/dist/plugins/remote-env-local-docker.js +149 -24
  386. package/dist/plugins/remote-env-ssh.d.ts +35 -0
  387. package/dist/plugins/remote-env-ssh.js +117 -20
  388. package/dist/plugins/remote-scratchpad.d.ts +38 -0
  389. package/dist/plugins/remote-scratchpad.js +32 -2
  390. package/dist/plugins/remote-shell.d.ts +22 -0
  391. package/dist/plugins/remote-shell.js +27 -1
  392. package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
  393. package/dist/plugins/resume-anchor-store-sql.js +11 -0
  394. package/dist/plugins/roster-store-sql.d.ts +27 -0
  395. package/dist/plugins/roster-store-sql.js +54 -0
  396. package/dist/plugins/run-store-sql.d.ts +194 -0
  397. package/dist/plugins/run-store-sql.js +210 -9
  398. package/dist/plugins/s3-presign.d.ts +20 -0
  399. package/dist/plugins/s3-presign.js +49 -2
  400. package/dist/plugins/scheduler-support.d.ts +12 -0
  401. package/dist/plugins/scheduler-support.js +75 -3
  402. package/dist/plugins/send-file-ledger.d.ts +15 -0
  403. package/dist/plugins/send-file-ledger.js +53 -4
  404. package/dist/plugins/send-user-file.d.ts +77 -0
  405. package/dist/plugins/send-user-file.js +92 -4
  406. package/dist/plugins/session-policy-store-sql.d.ts +15 -0
  407. package/dist/plugins/session-policy-store-sql.js +75 -3
  408. package/dist/plugins/session-store.d.ts +45 -0
  409. package/dist/plugins/session-store.js +51 -0
  410. package/dist/plugins/sql-driver.d.ts +77 -0
  411. package/dist/plugins/sql-driver.js +4 -0
  412. package/dist/plugins/sql-escape.d.ts +8 -0
  413. package/dist/plugins/sql-escape.js +8 -0
  414. package/dist/plugins/sql-row-helpers.d.ts +25 -0
  415. package/dist/plugins/sql-row-helpers.js +25 -0
  416. package/dist/plugins/store-backend.d.ts +103 -0
  417. package/dist/plugins/store-backend.js +120 -27
  418. package/dist/plugins/store-contracts.d.ts +62 -0
  419. package/dist/plugins/store-contracts.js +3 -0
  420. package/dist/plugins/task-attachment-store.d.ts +60 -0
  421. package/dist/plugins/task-attachment-store.js +49 -3
  422. package/dist/plugins/task-list-store-sql.d.ts +25 -0
  423. package/dist/plugins/task-list-store-sql.js +21 -0
  424. package/dist/plugins/tidb-approval-store.d.ts +6 -0
  425. package/dist/plugins/tidb-approval-store.js +6 -0
  426. package/dist/plugins/tidb-breaker-state.d.ts +5 -0
  427. package/dist/plugins/tidb-breaker-state.js +5 -0
  428. package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
  429. package/dist/plugins/tidb-checkpoint-store.js +7 -0
  430. package/dist/plugins/tidb-cost-quota.d.ts +6 -0
  431. package/dist/plugins/tidb-cost-quota.js +1 -0
  432. package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
  433. package/dist/plugins/tidb-file-snapshot-store.js +6 -0
  434. package/dist/plugins/tidb-image-bake.d.ts +8 -0
  435. package/dist/plugins/tidb-image-bake.js +8 -0
  436. package/dist/plugins/tidb-image-index.d.ts +8 -0
  437. package/dist/plugins/tidb-image-index.js +8 -0
  438. package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
  439. package/dist/plugins/tidb-outcome-ledger.js +10 -0
  440. package/dist/plugins/tidb-pool.d.ts +56 -0
  441. package/dist/plugins/tidb-pool.js +181 -1
  442. package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
  443. package/dist/plugins/tidb-rate-limiter.js +5 -2
  444. package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
  445. package/dist/plugins/tidb-resume-anchor-store.js +5 -0
  446. package/dist/plugins/tidb-run-store.d.ts +7 -0
  447. package/dist/plugins/tidb-run-store.js +7 -0
  448. package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
  449. package/dist/plugins/tidb-session-policy-store.js +5 -0
  450. package/dist/plugins/tidb-session-storage.d.ts +43 -0
  451. package/dist/plugins/tidb-session-storage.js +62 -3
  452. package/dist/plugins/tidb-session-store.d.ts +142 -0
  453. package/dist/plugins/tidb-session-store.js +264 -16
  454. package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
  455. package/dist/plugins/tidb-tool-result-store.js +7 -0
  456. package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
  457. package/dist/plugins/tidb-workflow-journal-store.js +7 -0
  458. package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
  459. package/dist/plugins/tidb-workflow-run-store.js +8 -0
  460. package/dist/plugins/tool-result-store-sql.d.ts +58 -0
  461. package/dist/plugins/tool-result-store-sql.js +38 -2
  462. package/dist/plugins/web-search.d.ts +35 -0
  463. package/dist/plugins/web-search.js +45 -9
  464. package/dist/plugins/workflow-journal-limits.d.ts +10 -0
  465. package/dist/plugins/workflow-journal-limits.js +10 -0
  466. package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
  467. package/dist/plugins/workflow-journal-store-sql.js +59 -3
  468. package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
  469. package/dist/plugins/workflow-run-store-sql.js +84 -6
  470. package/dist/plugins/worktree-isolation.d.ts +45 -0
  471. package/dist/plugins/worktree-isolation.js +105 -6
  472. package/dist/plugins/write-behind-counter.d.ts +56 -1
  473. package/dist/plugins/write-behind-counter.js +53 -14
  474. package/dist/principal-jwt.d.ts +24 -0
  475. package/dist/principal-jwt.js +60 -5
  476. package/dist/project-memory.d.ts +22 -0
  477. package/dist/project-memory.js +144 -15
  478. package/dist/prompts-domain-validate.d.ts +28 -0
  479. package/dist/prompts-domain-validate.js +42 -1
  480. package/dist/question.d.ts +33 -0
  481. package/dist/question.js +69 -2
  482. package/dist/resource-suspend.d.ts +21 -0
  483. package/dist/resource-suspend.js +16 -0
  484. package/dist/router/route-orchestration.d.ts +78 -0
  485. package/dist/router/route-orchestration.js +77 -0
  486. package/dist/run-local.d.ts +32 -0
  487. package/dist/run-local.js +172 -8
  488. package/dist/runs.d.ts +189 -4
  489. package/dist/runs.js +465 -24
  490. package/dist/runtime-caps-resolver.d.ts +106 -0
  491. package/dist/runtime-caps-resolver.js +89 -4
  492. package/dist/runtime-governance.d.ts +84 -0
  493. package/dist/runtime-governance.js +127 -1
  494. package/dist/sandbox-pkg-source.d.ts +23 -0
  495. package/dist/sandbox-pkg-source.js +37 -0
  496. package/dist/sealed-key.d.ts +54 -0
  497. package/dist/sealed-key.js +68 -3
  498. package/dist/security.d.ts +108 -0
  499. package/dist/security.js +145 -6
  500. package/dist/sema-registry.d.ts +21 -0
  501. package/dist/sema-registry.js +21 -0
  502. package/dist/session-leaf-bus.d.ts +31 -0
  503. package/dist/session-leaf-bus.js +32 -0
  504. package/dist/session-sync-content.d.ts +46 -0
  505. package/dist/session-sync-content.js +47 -1
  506. package/dist/session-sync-kernel.d.ts +89 -0
  507. package/dist/session-sync-kernel.js +48 -3
  508. package/dist/session-sync.d.ts +125 -0
  509. package/dist/session-sync.js +181 -8
  510. package/dist/session-titler.d.ts +26 -0
  511. package/dist/session-titler.js +41 -7
  512. package/dist/session-watch.d.ts +53 -1
  513. package/dist/session-watch.js +73 -9
  514. package/dist/sighup-idle.d.ts +30 -0
  515. package/dist/sighup-idle.js +12 -1
  516. package/dist/spec-fields.d.ts +91 -3
  517. package/dist/spec-fields.js +116 -4
  518. package/dist/task-cwd.d.ts +50 -0
  519. package/dist/task-cwd.js +68 -1
  520. package/dist/task-mcp.d.ts +47 -0
  521. package/dist/task-mcp.js +29 -0
  522. package/dist/task-settings.d.ts +175 -0
  523. package/dist/task-settings.js +226 -11
  524. package/dist/task-workflow.d.ts +67 -0
  525. package/dist/task-workflow.js +75 -8
  526. package/dist/tool-approval.d.ts +91 -0
  527. package/dist/tool-approval.js +215 -0
  528. package/dist/trace/artifacts.d.ts +9 -0
  529. package/dist/trace/artifacts.js +30 -5
  530. package/dist/trace/core-keyset-guard.d.ts +18 -0
  531. package/dist/trace/ledger-sink.d.ts +43 -0
  532. package/dist/trace/ledger-sink.js +64 -5
  533. package/dist/trace/project.d.ts +133 -0
  534. package/dist/trace/project.js +189 -2
  535. package/dist/trace/redact.d.ts +19 -0
  536. package/dist/trace/redact.js +66 -9
  537. package/dist/usage-analytics.d.ts +26 -0
  538. package/dist/usage-analytics.js +26 -3
  539. package/package.json +1 -1
@@ -1,10 +1,27 @@
1
+ /**
2
+ * TiDB-backed Session event-log center (L1) — the durable "persistence center".
3
+ *
4
+ * Implements core's `SessionStore`. `acquire` rebuilds a session from its append-only event log
5
+ * (= wake/resume), so any stateless runner instance can continue it. Cross-instance write safety is
6
+ * enforced by the storage layer's compare-and-set (core's F2 seam); crash consistency (orphan
7
+ * tool-call after a mid-turn crash) is handled by the Runner calling `reconcileInterruptedSession`
8
+ * on acquire (core's F1).
9
+ *
10
+ * Persistence only. **Tenant authorization (who may wake which session) lives in the service layer**
11
+ * (`src/security.ts`), which uses `ownerOf` / `register` below. The store does not infer identity.
12
+ */
13
+ // 🔴 core 1.403 迁移(2026-07-25):runtime 构造用法,`Session` → `StoredSession`(见 audit.ts 同款注释)。
1
14
  import { StoredSession, SessionError, uuidv7, validateEntriesForImport, leafIdAfterEntry } from "@sema-agent/core";
2
15
  import { TiDBSessionStorage } from "./tidb-session-storage.js";
3
16
  import { escapeLike } from "./sql-escape.js";
4
17
  import { classifySyncRelationshipByIds, SyncConflictError, stagingIdFor, STAGING_ID_MARKER, } from "../session-sync-kernel.js";
18
+ /** Staging-row reaper grace window — a staging session's rows are GC'able only if it has NO session_meta (never
19
+ * committed) AND its OLDEST row is older than this (an in-flight stream keeps appending fresh rows → safe). Mirrors
20
+ * the file-snapshot store's BLOB_GC_GRACE_MS discipline (an in-flight import must never be reaped mid-stream). */
5
21
  const STAGING_GC_GRACE_MS = 3_600_000;
6
22
  export class TiDBSessionStore {
7
23
  pool;
24
+ /** In-flight acquisitions keyed by id, so concurrent acquire(sameId) in one process share one. */
8
25
  pending = new Map();
9
26
  constructor(pool) {
10
27
  this.pool = pool;
@@ -15,6 +32,10 @@ export class TiDBSessionStore {
15
32
  await this.register(id, null);
16
33
  return this.load(id);
17
34
  }
35
+ // design/114 Phase3 (F1): a `requireExisting` acquire NEVER creates and can REJECT (not_found) — it MUST bypass
36
+ // the shared create-dedup `pending`, else a concurrent create-capable waiter awaiting that same promise would
37
+ // inherit the not_found rejection instead of creating-on-miss. Two concurrent requireExisting opens each just
38
+ // wake independently (both resolve or both fail loud) — harmless (it only opens, never double-creates).
18
39
  if (opts?.requireExisting)
19
40
  return this.load(sessionId, true);
20
41
  const inflight = this.pending.get(sessionId);
@@ -27,18 +48,25 @@ export class TiDBSessionStore {
27
48
  async load(sessionId, requireExisting = false) {
28
49
  let storage = await TiDBSessionStorage.wake(this.pool, sessionId);
29
50
  if (!storage) {
51
+ // design/114 Phase3: `requireExisting` ⇒ FAIL LOUD on a genuinely missing session (no session_meta row),
52
+ // never the silent create-on-miss that turns a reuse-style warm-resume into a fresh empty run. core's
53
+ // prepare-task maps this store `not_found` to the caller-facing `resume.session_not_found`.
30
54
  if (requireExisting)
31
55
  throw new SessionError("not_found", `session ${sessionId} not found`);
56
+ // No meta row yet (a caller-chosen brand-new id the service didn't pre-register). Create it
57
+ // ownerless; only the caller who chose this id can reach it, and it holds no prior data.
32
58
  await this.register(sessionId, null);
33
59
  storage = await TiDBSessionStorage.wake(this.pool, sessionId);
34
60
  }
35
61
  return { session: new StoredSession(storage), sessionId };
36
62
  }
63
+ /** Idempotently create a session_meta row with an owner. Existing owner is never overwritten. */
37
64
  async register(sessionId, owner) {
38
65
  const now = new Date();
39
66
  await this.pool.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq) " +
40
67
  "VALUES (?,?,?,?,NULL,0) ON DUPLICATE KEY UPDATE session_id = session_id", [sessionId, owner, now, now]);
41
68
  }
69
+ /** Owner principal of a session, `null` if registered ownerless, `undefined` if no such session. */
42
70
  async ownerOf(sessionId) {
43
71
  const [rows] = await this.pool.query("SELECT owner FROM session_meta WHERE session_id = ?", [sessionId]);
44
72
  if (rows.length === 0)
@@ -51,39 +79,73 @@ export class TiDBSessionStore {
51
79
  sessionId,
52
80
  ]);
53
81
  }
82
+ /** E18 — the session's current leaf `SessionTreeEntry.id` (`session_meta.leaf_id`, set transactionally on every
83
+ * persist). A single SELECT, NO acquire/lock/CAS — safe to call mid-run (write-safety is the append-time CAS, not
84
+ * an acquire lease) and cache-bypassing (the resume-at turn-capture reads it without touching the warm session).
85
+ * Returns the leaf id, or null when the session has none / no such session. */
54
86
  async getLeafId(sessionId) {
55
87
  const [rows] = await this.pool.query("SELECT leaf_id FROM session_meta WHERE session_id = ?", [sessionId]);
56
88
  return rows[0] ? (rows[0].leaf_id ?? null) : null;
57
89
  }
90
+ /** [1196] 六轮复审:owner+leafId **单行原子快照**(SSE watch 探针的租户围栏读)——两独立 SELECT 在
91
+ * delete/reclaim 缝里可拼出「旧 owner+新 leaf」混世代组合;单 SELECT 单行=天然一致。undefined=无此会话。 */
58
92
  async getHead(sessionId) {
59
93
  const [rows] = await this.pool.query("SELECT owner, leaf_id FROM session_meta WHERE session_id = ?", [sessionId]);
60
94
  if (rows.length === 0)
61
95
  return undefined;
62
96
  return { owner: rows[0].owner ?? null, leafId: rows[0].leaf_id ?? null };
63
97
  }
98
+ /** Durable history is retained; just drop any in-flight cache entry. */
64
99
  async release(sessionId) {
65
100
  this.pending.delete(sessionId);
66
101
  }
102
+ // ───────────────────────── SessionRepo seam (§0.5 session-ownership) ─────────────────────────
103
+ // E16/E17/E21: the service EXTENDS core's `SessionRepo` (list/fork/delete) over its OWN session_meta /
104
+ // session_event tables — a `TiDBSessionRepo`-style implementation (core's `PgSessionRepo` targets core's
105
+ // own `agent_*` tables, so it can't be consumed directly; the dossier §0.5 prescribes a backend-mirrored
106
+ // impl here). Enumeration + lifecycle now come from the SESSION abstraction (session identity), not the
107
+ // `task_run` runs ledger; `task_run` retreats to a pure runs ledger that only SUPPLIES run-level preview.
108
+ /**
109
+ * E16 — list the caller's sessions (CC /resume picker), keyset-paginated newest-first by last activity.
110
+ * Session IDENTITY/enumeration comes from `session_meta` (owner-filtered on the service's OWN owner column);
111
+ * a LEFT JOIN onto the `task_run` runs ledger supplies run-level PREVIEW (latest run's objective/status,
112
+ * run count) but never gates which sessions exist — a session with zero runs still lists (preview null/0).
113
+ * Keyset on `(updated_at, session_id)`; `updated_at` is the session's last-activity marker (touch on every
114
+ * run/append). The shipped {@link SessionSummary} shape is preserved (additive): `lastActivityAt` =
115
+ * `session_meta.updated_at`, `firstActivityAt` = `session_meta.created_at`.
116
+ */
67
117
  async listSessions(opts) {
68
118
  const params = [];
69
119
  const where = [];
70
120
  if (opts.owner) {
71
- where.push("sm.owner = ?");
121
+ where.push("sm.owner = ?"); // idx_owner — the per-user view (a principal is PINNED to its own at the route)
72
122
  params.push(opts.owner);
73
123
  }
74
124
  if (opts.q) {
125
+ // `?q=` search: match sessions where ANY run's objective preview contains q (EXISTS on the
126
+ // runs ledger — better recall than latest-run-only, still session-granular). LOWER-LIKE = collation-proof
127
+ // case-insensitivity (TiDB table collation may be _bin); escapeLike + ESCAPE pins the wildcard semantics
128
+ // (deployment baseline: default sql_mode — under NO_BACKSLASH_ESCAPES the '\\' literal would break, a
129
+ // known escapeLike-family boundary shared with the tool-result store).
130
+ // No tr.owner predicate BY DESIGN: the outer WHERE already proves the session is the caller's;
131
+ // a same-session_id foreign-owner run requires DB write access to fabricate (session_meta PK + uuidv7),
132
+ // and an owner predicate would drop the LEGITIMATE mixed-owner form (anonymous run → principal attach,
133
+ // the E21 diverged-owner case) — recall loss for a 1-bit defense against an attacker who can already write.
75
134
  where.push("EXISTS (SELECT 1 FROM task_run tr WHERE tr.session_id = sm.session_id AND LOWER(tr.objective_preview) LIKE LOWER(?) ESCAPE '\\\\')");
76
135
  params.push(`%${escapeLike(opts.q)}%`);
77
136
  }
78
137
  if (opts.cursor) {
79
- where.push("(sm.updated_at < ? OR (sm.updated_at = ? AND sm.session_id < ?))");
138
+ where.push("(sm.updated_at < ? OR (sm.updated_at = ? AND sm.session_id < ?))"); // keyset: strictly older, ties by id
80
139
  params.push(new Date(opts.cursor.lastActivityAt), new Date(opts.cursor.lastActivityAt), opts.cursor.sessionId);
81
140
  }
141
+ // The run-preview JOIN: the LATEST run per session (rn=1, ties broken by task_id so EXACTLY one row joins —
142
+ // a bare MAX(created_at) JOIN would fan out the outer row when two runs share a created_at) + a count rollup.
143
+ // A LEFT JOIN keeps sessions with NO runs (preview NULL, run_count 0). Bounded by per-tenant data today.
82
144
  const sql = "SELECT sm.session_id, sm.owner, sm.updated_at AS last_activity, sm.created_at AS first_activity, sm.title, " +
83
145
  " COALESCE(r.run_count, 0) AS run_count, latest.objective_preview, latest.status, latest.task_id AS last_run_id " +
84
146
  "FROM session_meta sm " +
85
147
  "LEFT JOIN (SELECT session_id, COUNT(*) AS run_count FROM task_run GROUP BY session_id) r ON r.session_id = sm.session_id " +
86
- "LEFT JOIN (SELECT session_id, objective_preview, status, task_id FROM (" +
148
+ "LEFT JOIN (SELECT session_id, objective_preview, status, task_id FROM (" + // K-5c: carry the rn=1 run's task_id
87
149
  " SELECT session_id, objective_preview, status, task_id, " +
88
150
  " ROW_NUMBER() OVER (PARTITION BY session_id ORDER BY created_at DESC, task_id DESC) AS rn FROM task_run" +
89
151
  " ) lr WHERE rn = 1) latest ON latest.session_id = sm.session_id " +
@@ -99,33 +161,55 @@ export class TiDBSessionStore {
99
161
  runCount: Number(r.run_count),
100
162
  objectivePreview: r.objective_preview ?? null,
101
163
  lastStatus: r.status == null ? "" : String(r.status),
102
- lastRunId: r.last_run_id ?? null,
103
- title: r.title ?? null,
164
+ lastRunId: r.last_run_id ?? null, // K-5c: latest run id = the live-tail re-attach anchor (null if no runs)
165
+ title: r.title ?? null, // auto-generated title (null = not yet titled)
104
166
  }));
105
167
  }
168
+ /** Cheap pre-LLM probe: "none" = session_meta row not yet REGISTERED (createRun fires
169
+ * before the Runner's session acquire — the titler retries), "untitled" / "titled" as read. */
106
170
  async probeTitle(sessionId) {
107
171
  const [rows] = await this.pool.query("SELECT title FROM session_meta WHERE session_id = ?", [sessionId]);
108
172
  if (!rows[0])
109
173
  return "none";
110
174
  return rows[0].title == null ? "untitled" : "titled";
111
175
  }
176
+ /** Write-once auto-title: lands ONLY when title IS NULL (a concurrent/prior title wins;
177
+ * the user-facing rename layer is BFF-side). Returns whether this call set it. */
112
178
  async setTitleIfNull(sessionId, title) {
113
179
  const [r] = await this.pool.query("UPDATE session_meta SET title = ? WHERE session_id = ? AND title IS NULL", [title, sessionId]);
114
180
  return r.affectedRows > 0;
115
181
  }
182
+ /**
183
+ * E17 — fork a session: copy its WHOLE durable history to a NEW uuidv7 session owned by `owner`, mirroring
184
+ * core's `PgSessionRepo.fork`. Entry ids / parent links are per-session and copy VERBATIM; only `seq` is
185
+ * re-densified from 0 in the new session. The new leaf = the source leaf (session_meta.leaf_id).
186
+ * Returns the new sessionId, or null if the source does not exist (the route maps that to 404).
187
+ *
188
+ * 🔴 FULL history, NOT `wake().getEntries()` (adversarial-review MEDIUM): `wake` loads only the bounded tail
189
+ * `[floor..leaf]` from the latest compaction floor (F3), so forking via it would copy only the active tail of a
190
+ * COMPACTED session and SILENTLY LOSE all pre-compaction history (contradicting the whole-history-copy intent).
191
+ * We instead SELECT the entire `session_event` log ordered by seq — every durable entry, compaction floor
192
+ * bypassed — and re-seq it dense from 0 into the new session, ids/parents/payload byte-verbatim.
193
+ */
116
194
  async fork(sourceId, owner) {
195
+ // The source's authoritative leaf (and existence check) come from session_meta — null meta ⇒ unknown source.
117
196
  const [metaRows] = await this.pool.query("SELECT leaf_id FROM session_meta WHERE session_id = ?", [sourceId]);
118
197
  if (!metaRows[0])
119
198
  return null;
120
199
  const leafId = metaRows[0].leaf_id ?? null;
200
+ // FULL durable history (compaction floor bypassed) — every entry, oldest first. payload is the stored entry blob.
121
201
  const [eventRows] = await this.pool.query("SELECT entry_id, parent_id, type, payload, ts FROM session_event WHERE session_id = ? ORDER BY seq ASC", [sourceId]);
122
202
  const newId = uuidv7();
123
203
  const now = new Date();
124
204
  const conn = await this.pool.getConnection();
125
205
  try {
126
206
  await conn.beginTransaction();
207
+ // Entries land BEFORE the session_meta row (mirrors core BUG-1): the meta row is the commit point —
208
+ // a mid-fork failure leaves orphan events with NO meta row (invisible to wake), never a half-session.
127
209
  for (let seq = 0; seq < eventRows.length; seq++) {
128
210
  const r = eventRows[seq];
211
+ // Copy the payload blob VERBATIM (string or already-parsed object); re-stringify only an object so the
212
+ // INSERT binds a JSON string. entry_id/parent_id/type/ts are carried over unchanged; only seq is re-densified.
129
213
  const payload = typeof r.payload === "string" ? r.payload : JSON.stringify(r.payload);
130
214
  await conn.query("INSERT INTO session_event (session_id, seq, entry_id, parent_id, type, payload, ts) VALUES (?,?,?,?,?,?,?)", [newId, seq, r.entry_id, r.parent_id ?? null, r.type, payload, r.ts]);
131
215
  }
@@ -138,6 +222,7 @@ export class TiDBSessionStore {
138
222
  await conn.rollback();
139
223
  }
140
224
  catch {
225
+ /* ignore */
141
226
  }
142
227
  throw err instanceof SessionError ? err : new SessionError("storage", `fork of session ${sourceId} failed`, err instanceof Error ? err : undefined);
143
228
  }
@@ -145,46 +230,100 @@ export class TiDBSessionStore {
145
230
  conn.release();
146
231
  }
147
232
  }
233
+ /**
234
+ * 2c session-sync — EXPORT a session's full durable entry log for cross-backend migration. This is the
235
+ * READ half of {@link fork}, surfaced as the core `SessionRepo.exportEntries` seam: the WHOLE `session_event` log,
236
+ * oldest-first, ids/parents/payload/ts VERBATIM, with the compaction floor BYPASSED (NOT `wake().getEntries()`,
237
+ * which returns only the bounded `[floor..leaf]` tail and would silently truncate pre-floor history — see fork's
238
+ * note at :149-152). Returns `null` if the source does not exist (no `session_meta` row), mirroring fork's null
239
+ * semantics; an existing-but-empty session returns `[]`. The owner is NOT exported — import re-stamps it (§9).
240
+ */
148
241
  async exportEntries(sessionId) {
242
+ // Existence check = session_meta (a session with zero events but a meta row is a real, empty session ⇒ []).
149
243
  const [metaRows] = await this.pool.query("SELECT 1 FROM session_meta WHERE session_id = ?", [sessionId]);
150
244
  if (!metaRows[0])
151
245
  return null;
246
+ // FULL durable log (compaction floor bypassed) — every entry, oldest first. payload is the stored entry blob.
152
247
  const [eventRows] = await this.pool.query("SELECT entry_id, parent_id, type, payload, ts FROM session_event WHERE session_id = ? ORDER BY seq ASC", [sessionId]);
248
+ // The export contract is `SessionTreeEntry[]` (the full entry blob), not the column projection. The stored
249
+ // `payload` IS the verbatim entry (id/parentId/timestamp + variant fields) — parse a string blob, pass an
250
+ // already-parsed object (mysql2 returns JSON columns parsed) through.
153
251
  return eventRows.map((r) => (typeof r.payload === "string" ? JSON.parse(r.payload) : r.payload));
154
252
  }
253
+ /**
254
+ * 2c session-sync P1d-α (PULL streaming) — the IDS-ONLY projection of {@link exportEntries}: the entry ids of the
255
+ * WHOLE durable log, oldest-first (`SELECT entry_id … ORDER BY seq ASC`), with no payloads. Small even for a huge
256
+ * session, so the PULL `GET /sync/manifest` can carry it (and feed it to `classifySyncRelationshipByIds`) instead of
257
+ * the entries. Returns `null` if the source does not exist (no `session_meta` row), mirroring {@link exportEntries}.
258
+ */
155
259
  async listEntryIds(sessionId) {
156
260
  const [metaRows] = await this.pool.query("SELECT 1 FROM session_meta WHERE session_id = ?", [sessionId]);
157
261
  if (!metaRows[0])
158
- return null;
262
+ return null; // no such session (mirror exportEntries' null)
159
263
  const [rows] = await this.pool.query("SELECT entry_id FROM session_event WHERE session_id = ? ORDER BY seq ASC", [sessionId]);
160
264
  return rows.map((r) => String(r.entry_id));
161
265
  }
266
+ /**
267
+ * 2c session-sync P1d-α (PULL streaming) — STREAM the WHOLE durable log (compaction floor bypassed), oldest-first,
268
+ * as an async generator that KEYSET-PAGES the `session_event` table: mysql2 buffers a plain SELECT, so a 1M-row
269
+ * session would OOM if read in one shot. Instead the generator loops `… WHERE seq > cursor ORDER BY seq ASC LIMIT K`
270
+ * (K = `opts.batchSize ?? 500`), advancing the cursor to the last `seq` of each batch, until a SHORT page (fewer than
271
+ * K rows) ends the stream. Each batch is its OWN `pool.query` (a pooled connection acquired + released per batch), so
272
+ * a slow NDJSON consumer can NEVER pin one connection across the whole stream (the clay-mandated concurrency
273
+ * discipline). Start cursor = `opts.afterSeq ?? -1` (seq is 0-based dense, so `> -1` = from seq 0).
274
+ *
275
+ * Resolves to `null` (NOT an empty async-iterable) when the session does not exist — checked via `session_meta`
276
+ * EAGERLY here (before returning the iterable), exactly like {@link exportEntries}, so a missing session is distinct
277
+ * from a real-but-empty one (an empty stream). payload is parsed like {@link exportEntries} (string → JSON.parse,
278
+ * object passthrough). The check is eager (the method is async) because a generator body is lazy — it can't decide
279
+ * `null` vs. iterable on its own first pull.
280
+ */
162
281
  async exportEntriesStream(sessionId, opts) {
163
282
  const [metaRows] = await this.pool.query("SELECT 1 FROM session_meta WHERE session_id = ?", [sessionId]);
164
283
  if (!metaRows[0])
165
- return null;
284
+ return null; // no such session (mirror exportEntries' null) — NOT an empty iterable
166
285
  const pool = this.pool;
167
286
  const batchSize = opts?.batchSize ?? 500;
168
287
  async function* gen() {
169
- let cursor = opts?.afterSeq ?? -1;
288
+ let cursor = opts?.afterSeq ?? -1; // seq is 0-based dense → > -1 starts at seq 0
170
289
  for (;;) {
290
+ // ONE pooled query per batch (NOT a held connection across the whole stream) — keyset on (session_id, seq).
171
291
  const [rows] = await pool.query("SELECT seq, payload FROM session_event WHERE session_id = ? AND seq > ? ORDER BY seq ASC LIMIT ?", [sessionId, cursor, batchSize]);
172
292
  for (const r of rows) {
173
293
  const p = r.payload;
174
294
  yield (typeof p === "string" ? JSON.parse(p) : p);
175
295
  }
176
296
  if (rows.length < batchSize)
177
- return;
178
- cursor = Number(rows[rows.length - 1].seq);
297
+ return; // short page = end of log (no further round-trip)
298
+ cursor = Number(rows[rows.length - 1].seq); // advance the keyset cursor to the last seq seen
179
299
  }
180
300
  }
181
301
  return gen();
182
302
  }
303
+ /**
304
+ * 2c session-sync — IMPORT a verbatim entry log (from another backend's {@link exportEntries}) into a
305
+ * (typically NEW) `sessionId`. This is the WRITE half of {@link fork}, surfaced as `SessionRepo.importEntries`,
306
+ * with two 2c-mandated differences from fork:
307
+ * (a) OWNER RE-STAMP (§9): `owner` is the AUTHENTICATED importing principal passed by the caller; the bundle's
308
+ * own owner is NEVER trusted (a local push is always owner=null → would become an ownerless cloud session
309
+ * any anonymous caller could attach to). Mirrors the fork route's server-side `scope.gateOwner`.
310
+ * (b) the single INVARIANT GATE is core's {@link validateEntriesForImport} (unique ids / parent-before-child /
311
+ * exactly-one-root / leaf-resolvable / structural refs present) — we persist its VERBATIM output and do NOT
312
+ * re-implement any of those checks in SQL ([[core-service-boundary]]; the same discipline fork's hand-SQL
313
+ * was warned about). A violation throws `SessionError("invalid_session")` and NOTHING is written.
314
+ * The write itself mirrors fork: re-seq dense from 0, entry_id/parent_id/payload/ts verbatim, in ONE txn with
315
+ * `session_meta` LAST as the commit point (a mid-import crash leaves orphan events with no meta = invisible to
316
+ * wake, never a half-session). The leaf is the replayed leaf (core's `leafIdAfterEntry`), matching core's import.
317
+ */
183
318
  async importEntries(sessionId, owner, entries) {
319
+ // Fail-CLOSED invariant gate FIRST (before any write) — returns the entries verbatim or throws invalid_session.
184
320
  const validated = validateEntriesForImport(entries);
185
321
  const conn = await this.pool.getConnection();
186
322
  try {
187
323
  await conn.beginTransaction();
324
+ // The shared insert body (entries re-seq dense from 0, then session_meta LAST as the commit point). A plain
325
+ // INSERT — assumes a FRESH sessionId; a duplicate (session already present) crashes on the PK. replaceEntries
326
+ // is the idempotent-over-existing path (it DELETEs first inside the same txn).
188
327
  await this.insertValidatedLog(conn, sessionId, owner, validated);
189
328
  await conn.commit();
190
329
  }
@@ -193,22 +332,36 @@ export class TiDBSessionStore {
193
332
  await conn.rollback();
194
333
  }
195
334
  catch {
335
+ /* ignore */
196
336
  }
197
337
  if (err instanceof SessionError)
198
- throw err;
338
+ throw err; // invalid_session (gate) / conflict — pass through
199
339
  throw new SessionError("storage", `import of session ${sessionId} failed`, err instanceof Error ? err : undefined);
200
340
  }
201
341
  finally {
202
342
  conn.release();
203
343
  }
204
344
  }
345
+ /**
346
+ * 2c session-sync (§7/§8) — IDEMPOTENT REPLACE: purge any existing conversation log for `sessionId` then re-import
347
+ * `entries` verbatim under `owner`, ALL in ONE txn. Unlike {@link importEntries} (a plain INSERT that crashes on a
348
+ * duplicate PK when the session already exists at the destination), replace is safe to run OVER an existing session
349
+ * — the §7 fast-forward path and a §8 retry-to-completion both land on it. The validate gate runs FIRST (fail-closed,
350
+ * before any write), then DELETE events + the OWNER-GUARDED meta delete (defense-in-depth, mirrors {@link deleteSession}
351
+ * — a wrong-owner caller can never replace another tenant's session), then the SAME shared insert body importEntries
352
+ * uses (so there is ONE source of the insert logic, no copy-paste drift). session_meta is still written LAST = commit
353
+ * point, so a mid-replace crash (post-delete, pre-insert) leaves orphan-free state (no meta = invisible to wake).
354
+ */
205
355
  async replaceEntries(sessionId, owner, entries) {
206
- const validated = validateEntriesForImport(entries);
356
+ const validated = validateEntriesForImport(entries); // fail-closed gate BEFORE any write (mirrors importEntries)
207
357
  const conn = await this.pool.getConnection();
208
358
  try {
209
359
  await conn.beginTransaction();
360
+ // Purge the existing log first (idempotent: a missing session deletes 0 rows). Events first, then the
361
+ // owner-guarded meta delete (`owner <=> ?` — a legacy null-owner session matches owner=null), defense-in-depth.
210
362
  await conn.query("DELETE FROM session_event WHERE session_id = ?", [sessionId]);
211
363
  await conn.query("DELETE FROM session_meta WHERE session_id = ? AND owner <=> ?", [sessionId, owner]);
364
+ // …then re-insert the validated log (entries + meta-as-commit-point) via the SHARED body.
212
365
  await this.insertValidatedLog(conn, sessionId, owner, validated);
213
366
  await conn.commit();
214
367
  }
@@ -217,35 +370,70 @@ export class TiDBSessionStore {
217
370
  await conn.rollback();
218
371
  }
219
372
  catch {
373
+ /* ignore */
220
374
  }
221
375
  if (err instanceof SessionError)
222
- throw err;
376
+ throw err; // invalid_session (gate) / conflict — pass through
223
377
  throw new SessionError("storage", `replace of session ${sessionId} failed`, err instanceof Error ? err : undefined);
224
378
  }
225
379
  finally {
226
380
  conn.release();
227
381
  }
228
382
  }
383
+ /**
384
+ * Shared insert half of {@link importEntries} / {@link replaceEntries} (ONE source of the insert logic, no drift):
385
+ * write the validated entries re-seq dense from 0 (entry_id/parent_id/type/ts verbatim), THEN session_meta LAST as
386
+ * the commit point. Runs inside the caller's open transaction (`conn`) so the caller owns begin/commit/rollback.
387
+ * `validated` is the OUTPUT of {@link validateEntriesForImport} (the caller runs the gate before opening the txn).
388
+ */
229
389
  async insertValidatedLog(conn, sessionId, owner, validated) {
390
+ // The replayed leaf (last entry's leaf target, mirroring core resolveLeafId / validateEntriesForImport).
230
391
  let leafId = null;
231
392
  for (const e of validated)
232
- leafId = leafIdAfterEntry(e);
393
+ leafId = leafIdAfterEntry(e); // replayed leaf — core's exported helper (no service copy)
233
394
  const now = new Date();
395
+ // Entries land BEFORE session_meta (mirrors fork / core BUG-1): the meta row is the commit point.
234
396
  for (let seq = 0; seq < validated.length; seq++) {
235
397
  const e = validated[seq];
398
+ // payload = the verbatim entry blob (stringified for the JSON column bind); entry_id/parent_id/type/ts carried
399
+ // over unchanged from the entry; only seq is re-densified. ts comes from the entry's own ISO timestamp.
236
400
  await conn.query("INSERT INTO session_event (session_id, seq, entry_id, parent_id, type, payload, ts) VALUES (?,?,?,?,?,?,?)", [sessionId, seq, e.id, e.parentId ?? null, e.type, JSON.stringify(e), new Date(e.timestamp)]);
237
401
  }
402
+ // session_meta LAST = commit point. owner = the RE-STAMPED authenticated principal (never the bundle's).
238
403
  await conn.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq) VALUES (?,?,?,?,?,?)", [sessionId, owner, now, now, leafId, validated.length]);
239
404
  }
405
+ /**
406
+ * 2c session-sync P1d-β (PUSH streaming, §15) — begin a STAGED import into `realSessionId` under the shadow id
407
+ * `${realSessionId}#stg-${token}`. The route mints the uuidv7 `token` (the store never calls uuidv7/Date.now itself
408
+ * → the staging id is deterministic + the route owns the lease key). Returns a {@link TiDBStagingHandle} the route
409
+ * streams entry batches into ({@link StagingHandle.appendBatch}) then commits ({@link StagingHandle.commit}, the
410
+ * atomic swap) or aborts. No row is touched here — the handle is a stateless cursor over this pool.
411
+ */
240
412
  beginImportStaging(realSessionId, token) {
241
413
  return new TiDBStagingHandle(this.pool, realSessionId, stagingIdFor(realSessionId, token));
242
414
  }
415
+ /**
416
+ * 2c session-sync P1d-β (staged-row inspection) — read the rows STAGED under `stagingId` (NO session_meta probe — a
417
+ * staging id has no meta row by construction, so {@link exportEntries} would return null), oldest-first. The Phase-B
418
+ * import gate is now the per-line {@link StreamingImportValidator} (core 1.143.0) run during the stream, so this
419
+ * is no longer the validation path; it remains the staged-row inspection seam (tests/diagnostics). Returns `[]` for an
420
+ * empty/unknown staging id.
421
+ */
243
422
  async readStagedEntries(stagingId) {
244
423
  const [rows] = await this.pool.query("SELECT payload FROM session_event WHERE session_id = ? ORDER BY seq ASC", [stagingId]);
245
424
  return rows.map((r) => (typeof r.payload === "string" ? JSON.parse(r.payload) : r.payload));
246
425
  }
426
+ /**
427
+ * 2c session-sync P1d-β (§4) — reaper for ABANDONED staging sessions: DELETE session_event rows under a staging id
428
+ * (`session_id LIKE '%#stg-%'`) that has NO session_meta (never committed → invisible orphans) AND whose OLDEST
429
+ * staged row is older than the grace window (an IN-FLIGHT stream keeps appending fresh `ts` rows → its MIN(ts) is
430
+ * recent → it is NOT reaped, exactly like sweepOrphanBlobs' created_at grace). Per-staging-id, so a slow but live
431
+ * stream is never reaped while another abandoned one is. Returns the affected row count. Driven by main.ts's reaper.
432
+ */
247
433
  async sweepStagingSessions() {
248
434
  const cutoff = new Date(Date.now() - STAGING_GC_GRACE_MS);
435
+ // Candidate staging ids = those with rows older than the cutoff AND no meta row. GROUP BY so an in-flight id (its
436
+ // MIN(ts) recent) is excluded; LEFT JOIN session_meta so a (defensively) committed staging id is never touched.
249
437
  const [cands] = await this.pool.query("SELECT se.session_id FROM session_event se LEFT JOIN session_meta sm ON sm.session_id = se.session_id " +
250
438
  "WHERE se.session_id LIKE ? AND sm.session_id IS NULL " +
251
439
  "GROUP BY se.session_id HAVING MIN(se.ts) < ?", [`%${STAGING_ID_MARKER}%`, cutoff]);
@@ -256,11 +444,28 @@ export class TiDBSessionStore {
256
444
  }
257
445
  return removed;
258
446
  }
447
+ /**
448
+ * E21 — purge a session's CONVERSATION HISTORY (session_meta + session_event). Idempotent: a missing
449
+ * session is a no-op (returns false). The service's OWN run-ledger / checkpoint / tool-result rows are
450
+ * purged separately by the route's `purgeSession` coordinator — this method owns only the session
451
+ * abstraction's tables (the `SessionRepo.delete` half).
452
+ *
453
+ * `owner` is the single-DB-fleet null-safe SQL owner guard on `session_meta.owner` (defense-in-depth — the
454
+ * route already owner-gates; `<=>` so a legacy null-owner session matches owner=null). session_event carries
455
+ * no owner column, so its purge is GATED on the owner-matched meta delete: if the meta DELETE matched 0 rows
456
+ * (wrong owner / already gone) we skip the event delete — so a wrong-owner caller can never strand-delete
457
+ * another tenant's events. Meta is deleted FIRST (mirrors core BUG-2: once it's gone, wake is `null`
458
+ * regardless of leftover events; if a crash interleaves, orphan events with NO meta are invisible, never a
459
+ * half-session), and the event purge only runs after that owner-matched commit point.
460
+ */
259
461
  async deleteSession(sessionId, owner) {
260
462
  const conn = await this.pool.getConnection();
261
463
  try {
262
464
  await conn.beginTransaction();
465
+ // Meta row FIRST + owner-guarded: once it's gone, wake is `null` regardless of leftover events.
263
466
  const [metaRes] = await conn.query("DELETE FROM session_meta WHERE session_id = ? AND owner <=> ?", [sessionId, owner]);
467
+ // Only purge events when the OWNER-matched meta row was removed — gates the un-owner-columned event table
468
+ // through the meta owner check (a wrong-owner / already-gone session removes 0 meta rows → skip the events).
264
469
  if (metaRes.affectedRows > 0)
265
470
  await conn.query("DELETE FROM session_event WHERE session_id = ?", [sessionId]);
266
471
  await conn.commit();
@@ -271,6 +476,7 @@ export class TiDBSessionStore {
271
476
  await conn.rollback();
272
477
  }
273
478
  catch {
479
+ /* ignore */
274
480
  }
275
481
  throw err;
276
482
  }
@@ -279,30 +485,53 @@ export class TiDBSessionStore {
279
485
  }
280
486
  }
281
487
  get size() {
488
+ // Best-effort: durable store reloads per acquire (no long-lived cache), so report in-flight only.
282
489
  return this.pending.size;
283
490
  }
284
491
  dispose() {
492
+ // The pool is owned by main.ts and closed there; nothing process-local to release.
285
493
  this.pending.clear();
286
494
  }
287
495
  }
496
+ /**
497
+ * 2c session-sync P1d-β (PUSH streaming, §15 + §4) — a TiDB {@link StagingHandle}: stream entry batches into a SHADOW
498
+ * `session_event` partition (the staging id, NO meta row → invisible to wake), then atomically SWAP them into the real
499
+ * session id. Server memory is bounded by the in-flight batch (one txn per batch), not the whole log. The swap is a
500
+ * row-key RENAME (`UPDATE session_event SET session_id`) — metadata-only, NO payload re-copy — so the commit cost is
501
+ * the rename + a DELETE of the (purged) dst rows, in ONE txn, with session_meta written LAST = the sole commit point.
502
+ */
288
503
  class TiDBStagingHandle {
289
504
  pool;
290
505
  realSessionId;
291
506
  stagingId;
507
+ /** Running DENSE seq counter for the staging rows. Advanced ONLY for a logically-NEW entry id (tracked in `seen`), so
508
+ * a re-streamed entry (Phase-B resume) is skipped and the staged seqs stay dense 0..N-1 (NO holes that would collide
509
+ * with a future F2 leaf_seq append on the committed session). */
292
510
  nextSeq = 0;
511
+ /** Entry ids already staged by THIS handle — a resume re-streams from the start, so dedup keeps seqs dense + idempotent. */
293
512
  seen = new Set();
294
513
  constructor(pool, realSessionId, stagingId) {
295
514
  this.pool = pool;
296
515
  this.realSessionId = realSessionId;
297
516
  this.stagingId = stagingId;
298
517
  }
518
+ /** Append a batch to the staging id, re-seq'd DENSE from the running counter (skipping ids already staged), IDEMPOTENTLY
519
+ * (ON DUPLICATE KEY UPDATE on the `(session_id, entry_id)` uk is the durable backstop too). One txn per batch
520
+ * (bounded). NO meta row is written (the staging id stays invisible). ts is the entry's own ISO timestamp (verbatim). */
299
521
  async appendBatch(entries) {
522
+ // Build the NEW rows (skip already-staged ids — resume dedup keeps seqs dense), then ONE multi-row INSERT for the
523
+ // whole batch (bounded → bounded packet/txn) instead of N round-trips. ON DUPLICATE KEY UPDATE is the durable
524
+ // backstop for the rare case a dup slips past `seen` (e.g. a concurrent re-stream).
300
525
  const rows = [];
301
526
  const tuples = [];
302
527
  for (const e of entries) {
303
528
  if (this.seen.has(e.id))
304
529
  continue;
305
530
  tuples.push("(?,?,?,?,?,?,?)");
531
+ // 对抗复查 A-1(CRITICAL):staging 行的 ts 必须是「行插入时间」——写源 entry 的历史 timestamp 会让
532
+ // reaper 的 MIN(ts)<cutoff 判据把「正在导入的历史会话」当成弃置 staging 删掉(导入 1 小时前的会话
533
+ // =导入中被 reap)。真时间源恒在 payload(e.timestamp);ts 列的唯一读消费=fork 的行拷贝(carry-over
534
+ // 一致)与 reaper 活性判据,写 now 零语义破坏。
306
535
  rows.push(this.stagingId, this.nextSeq, e.id, e.parentId ?? null, e.type, JSON.stringify(e), new Date());
307
536
  this.seen.add(e.id);
308
537
  this.nextSeq++;
@@ -317,22 +546,40 @@ class TiDBStagingHandle {
317
546
  throw err instanceof SessionError ? err : new SessionError("storage", `staged append for ${this.realSessionId} failed`, err instanceof Error ? err : undefined);
318
547
  }
319
548
  }
549
+ /**
550
+ * The ATOMIC swap (ONE txn), §15 commit:
551
+ * 1. IN-COMMIT RE-CLASSIFY (closes the Phase-A plan→commit TOCTOU): read the dst's CURRENT entry ids + the staged
552
+ * ids under `FOR UPDATE` (row-locks serialize a concurrent commit/run) → classifySyncRelationshipByIds. A flip
553
+ * to fork/stale WITHOUT `resolution:"overwrite-dst"` → ROLLBACK → throw SyncConflictError (route → 409).
554
+ * 2. DELETE the dst's existing session_event rows (the replaceEntries purge).
555
+ * 3. UPDATE session_event SET session_id = real WHERE session_id = staging (the row-key RENAME — metadata only).
556
+ * 4. INSERT/UPSERT session_meta(real, owner, leaf_id=replayedLeaf, leaf_seq=N) LAST = the sole commit point.
557
+ * A crash before COMMIT: the DELETE+rename roll back (dst untouched) and the staging rows keep no meta = invisible
558
+ * orphans (reaped by sweepStagingSessions). `owner` is the re-stamped importing principal (§9).
559
+ */
320
560
  async commit(owner, opts) {
321
561
  const conn = await this.pool.getConnection();
322
562
  try {
323
563
  await conn.beginTransaction();
564
+ // (1) in-commit re-classify — read BOTH logs' ids oldest-first under FOR UPDATE (serialize against a racing
565
+ // commit/append to the dst). The staged ids ARE the source (already dense 0..N-1 under the staging id).
324
566
  const [stagedRows] = await conn.query("SELECT entry_id FROM session_event WHERE session_id = ? ORDER BY seq ASC FOR UPDATE", [this.stagingId]);
325
567
  const [dstRows] = await conn.query("SELECT entry_id FROM session_event WHERE session_id = ? ORDER BY seq ASC FOR UPDATE", [this.realSessionId]);
326
568
  const [dstMeta] = await conn.query("SELECT 1 FROM session_meta WHERE session_id = ?", [this.realSessionId]);
327
569
  const srcIds = stagedRows.map((r) => String(r.entry_id));
328
- const dstIds = dstMeta[0] ? dstRows.map((r) => String(r.entry_id)) : null;
570
+ const dstIds = dstMeta[0] ? dstRows.map((r) => String(r.entry_id)) : null; // no dst meta ⇒ fresh (no dst log to relate to)
329
571
  const rel = classifySyncRelationshipByIds(srcIds, dstIds);
330
572
  if ((rel.relation === "fork" || rel.relation === "stale") && opts?.resolution !== "overwrite-dst") {
331
573
  await conn.rollback();
332
574
  throw new SyncConflictError(this.realSessionId, rel);
333
575
  }
576
+ // (2) purge the dst's existing log (the replaceEntries purge; idempotent — fresh deletes 0).
334
577
  await conn.query("DELETE FROM session_event WHERE session_id = ?", [this.realSessionId]);
578
+ // (3) RENAME the staged rows onto the real session id (row-key UPDATE — metadata only, NO payload re-copy). seq is
579
+ // already dense 0..N-1 under the staging id (appendBatch re-seq'd it), so no re-densify is needed on rename.
335
580
  await conn.query("UPDATE session_event SET session_id = ? WHERE session_id = ?", [this.realSessionId, this.stagingId]);
581
+ // (4) session_meta LAST = the sole commit point. The replayed leaf = the last staged entry's leaf target — read
582
+ // the last staged payload (now renamed) to compute leafIdAfterEntry (core's helper; no service re-statement).
336
583
  const [lastRow] = await conn.query("SELECT payload FROM session_event WHERE session_id = ? ORDER BY seq DESC LIMIT 1", [this.realSessionId]);
337
584
  let leafId = null;
338
585
  if (lastRow[0]) {
@@ -350,7 +597,7 @@ class TiDBStagingHandle {
350
597
  try {
351
598
  await conn.rollback();
352
599
  }
353
- catch { }
600
+ catch { /* ignore */ }
354
601
  if (err instanceof SyncConflictError || err instanceof SessionError)
355
602
  throw err;
356
603
  throw new SessionError("storage", `staged commit for ${this.realSessionId} failed`, err instanceof Error ? err : undefined);
@@ -359,6 +606,7 @@ class TiDBStagingHandle {
359
606
  conn.release();
360
607
  }
361
608
  }
609
+ /** Drop the staging rows (Phase B aborted before commit). Idempotent (a missing staging id deletes 0). */
362
610
  async abort() {
363
611
  await this.pool.query("DELETE FROM session_event WHERE session_id = ?", [this.stagingId]);
364
612
  }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * MySQL-protocol (TiDB) `ToolResultStore` — the implementation now lives in the single-file dual-dialect
3
+ * `tool-result-store-sql.ts` (design/158 A12 定型半场). This file is the historical import path: the class
4
+ * name and ctor shape are re-exported unchanged, so store-backend.ts and every suite are untouched.
5
+ */
1
6
  export { TiDBToolResultStore, SqlToolResultStore } from "./tool-result-store-sql.js";
2
7
  export { escapeLike } from "./sql-escape.js";
3
8
  //# sourceMappingURL=tidb-tool-result-store.d.ts.map
@@ -1,3 +1,10 @@
1
+ /**
2
+ * MySQL-protocol (TiDB) `ToolResultStore` — the implementation now lives in the single-file dual-dialect
3
+ * `tool-result-store-sql.ts` (design/158 A12 定型半场). This file is the historical import path: the class
4
+ * name and ctor shape are re-exported unchanged, so store-backend.ts and every suite are untouched.
5
+ */
1
6
  export { TiDBToolResultStore, SqlToolResultStore } from "./tool-result-store-sql.js";
7
+ // Back-compat re-export: escapeLike LIVES in sql-escape.ts (design/158 A3, backend-neutral leaf);
8
+ // import from there in new code.
2
9
  export { escapeLike } from "./sql-escape.js";
3
10
  //# sourceMappingURL=tidb-tool-result-store.js.map
@@ -1,2 +1,9 @@
1
+ /**
2
+ * Thin re-export shim (design/158 A12 collapse). The real implementation is the single-file dual-dialect
3
+ * {@link import("./workflow-journal-store-sql.js").SqlWorkflowJournalStore} — see that file for the durable
4
+ * {@link WorkflowJournalStore} contract, the schema, and the TiDB/PG dialect-delta ledger. This name (and ctor
5
+ * arity: `(pool: MySqlPool)`) survives unchanged so every consumer (store-backend.ts, the extreme/integration/
6
+ * resume-fork-probe suites) is untouched.
7
+ */
1
8
  export { TiDBWorkflowJournalStore } from "./workflow-journal-store-sql.js";
2
9
  //# sourceMappingURL=tidb-workflow-journal-store.d.ts.map
@@ -1,2 +1,9 @@
1
+ /**
2
+ * Thin re-export shim (design/158 A12 collapse). The real implementation is the single-file dual-dialect
3
+ * {@link import("./workflow-journal-store-sql.js").SqlWorkflowJournalStore} — see that file for the durable
4
+ * {@link WorkflowJournalStore} contract, the schema, and the TiDB/PG dialect-delta ledger. This name (and ctor
5
+ * arity: `(pool: MySqlPool)`) survives unchanged so every consumer (store-backend.ts, the extreme/integration/
6
+ * resume-fork-probe suites) is untouched.
7
+ */
1
8
  export { TiDBWorkflowJournalStore } from "./workflow-journal-store-sql.js";
2
9
  //# sourceMappingURL=tidb-workflow-journal-store.js.map
@@ -1,2 +1,10 @@
1
+ /**
2
+ * Thin re-export shim (design/158 A12 扇出): the TiDB `WorkflowRunStore`/`WorkflowCompletionInbox`/
3
+ * `WorkflowNotifyJournalStore` twins now live collapsed with their PG dialect siblings in the
4
+ * single-file dual-dialect `workflow-run-store-sql.ts`. Class names, ctor arity, and the exported
5
+ * `MAX_RUN_BLOB_BYTES` / `slimOversizeRun` / `InboxWarn` surface stay EXACTLY as they were — every
6
+ * consumer (store-backend.ts, the DB-integration + slim-oversize-run suites) imports from THIS path
7
+ * unchanged.
8
+ */
1
9
  export { MAX_RUN_BLOB_BYTES, slimOversizeRun, type InboxWarn, TiDBWorkflowRunStore, TiDBWorkflowCompletionInbox, TiDBWorkflowNotifyJournalStore, } from "./workflow-run-store-sql.js";
2
10
  //# sourceMappingURL=tidb-workflow-run-store.d.ts.map