@sema-agent/server 7.150.0 → 7.152.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 (514) hide show
  1. package/MIGRATION.md +451 -0
  2. package/README.md +15 -3
  3. package/README.zh-CN.md +10 -2
  4. package/USAGE.md +144 -87
  5. package/deploy/sema-up/README.md +11 -4
  6. package/deploy/sema-up/chart/Chart.yaml +1 -1
  7. package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
  9. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
  10. package/deploy/sema-up/chart/templates/server.yaml +5 -3
  11. package/deploy/sema-up/chart/values-full-single.yaml +3 -1
  12. package/deploy/sema-up/chart/values.yaml +8 -1
  13. package/deploy/sema-up/cluster-up.sh +7 -6
  14. package/deploy/sema-up/kube-up.sh +6 -6
  15. package/deploy/sema-up/lib/flagshape.sh +36 -8
  16. package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
  17. package/deploy/sema-up/lib/helm-values-kube.py +2 -0
  18. package/deploy/sema-up/machines.example.yaml +3 -1
  19. package/deploy/sema-up/sema-up.sh +22 -16
  20. package/dist/adoption/import.js +3 -3
  21. package/dist/approval-ask-audit-store.d.ts +1 -1
  22. package/dist/approval-ask-machine.d.ts +4 -10
  23. package/dist/approval-ask-retention.d.ts +1 -1
  24. package/dist/approval-card.d.ts +12 -14
  25. package/dist/approval-gate-currency.d.ts +9 -9
  26. package/dist/approval-gate-currency.js +3 -4
  27. package/dist/approval-hmac.d.ts +17 -1
  28. package/dist/approval-hmac.js +7 -1
  29. package/dist/approval-queue-kind.d.ts +1 -1
  30. package/dist/approval.d.ts +2 -2
  31. package/dist/approval.js +2 -2
  32. package/dist/auth-bridge.d.ts +20 -0
  33. package/dist/auth-bridge.js +9 -0
  34. package/dist/background-session-reap.d.ts +1 -1
  35. package/dist/bake-runner/main.d.ts +4 -2
  36. package/dist/bind-host.d.ts +3 -6
  37. package/dist/bind-host.js +4 -7
  38. package/dist/boot/budget-tracing.js +1 -1
  39. package/dist/boot/coordinators.d.ts +1 -1
  40. package/dist/boot/coordinators.js +9 -10
  41. package/dist/boot/device-lane.js +2 -0
  42. package/dist/boot/engine-lease.d.ts +5 -0
  43. package/dist/boot/engine-lease.js +1 -0
  44. package/dist/boot/execution-env.d.ts +9 -14
  45. package/dist/boot/execution-env.js +85 -22
  46. package/dist/boot/execution-lane.js +32 -5
  47. package/dist/boot/late-binds.d.ts +8 -4
  48. package/dist/boot/late-binds.js +7 -1
  49. package/dist/boot/leader.d.ts +31 -30
  50. package/dist/boot/leader.js +38 -28
  51. package/dist/boot/leg-path-adjudication.d.ts +40 -0
  52. package/dist/boot/leg-path-adjudication.js +18 -0
  53. package/dist/boot/memory-consolidation.d.ts +3 -2
  54. package/dist/boot/memory-consolidation.js +6 -6
  55. package/dist/boot/parked-revive-gate.js +3 -15
  56. package/dist/boot/reapers.d.ts +6 -1
  57. package/dist/boot/reapers.js +13 -2
  58. package/dist/boot/resolve-spec.d.ts +3 -3
  59. package/dist/boot/resolve-spec.js +43 -48
  60. package/dist/boot/runner-deps.d.ts +46 -35
  61. package/dist/boot/runner-deps.js +94 -91
  62. package/dist/boot/session-age-out.d.ts +36 -0
  63. package/dist/boot/session-age-out.js +101 -0
  64. package/dist/boot/session-faces.d.ts +5 -14
  65. package/dist/boot/session-faces.js +9 -5
  66. package/dist/boot/shutdown.d.ts +6 -0
  67. package/dist/boot/shutdown.js +10 -4
  68. package/dist/boot/stage-01-config.js +2 -0
  69. package/dist/boot/stage-02-web-admin-pull.js +4 -5
  70. package/dist/boot/stage-05-execution-env.d.ts +5 -3
  71. package/dist/boot/stage-05-execution-env.js +3 -2
  72. package/dist/boot/stage-06-runners.d.ts +9 -4
  73. package/dist/boot/stage-06-runners.js +24 -9
  74. package/dist/boot/stage-07-capability-layer.d.ts +8 -4
  75. package/dist/boot/stage-07-capability-layer.js +3 -2
  76. package/dist/boot/stage-08-reapers.d.ts +8 -4
  77. package/dist/boot/stage-08-reapers.js +4 -2
  78. package/dist/boot/stage-09-leader.d.ts +12 -5
  79. package/dist/boot/stage-09-leader.js +14 -5
  80. package/dist/boot/stage-10-http-server.d.ts +19 -5
  81. package/dist/boot/stage-10-http-server.js +14 -21
  82. package/dist/boot/stores.js +7 -4
  83. package/dist/boot/web-admin.js +5 -8
  84. package/dist/boot/workflow-orchestration.d.ts +7 -2
  85. package/dist/boot/workflow-orchestration.js +24 -7
  86. package/dist/bounded-rotation.d.ts +29 -0
  87. package/dist/bounded-rotation.js +24 -0
  88. package/dist/capabilities/approvals-push.d.ts +3 -3
  89. package/dist/capabilities/scenarios.d.ts +28 -13
  90. package/dist/capabilities/scenarios.js +2 -2
  91. package/dist/capability-facts.d.ts +43 -32
  92. package/dist/capability-facts.js +45 -51
  93. package/dist/card-rule-offers.d.ts +32 -0
  94. package/dist/card-rule-offers.js +130 -0
  95. package/dist/center-credential.d.ts +25 -6
  96. package/dist/center-credential.js +25 -5
  97. package/dist/config-catalog.d.ts +26 -7
  98. package/dist/config-catalog.js +26 -22
  99. package/dist/config-dir-trust.js +4 -2
  100. package/dist/config-invariants.d.ts +20 -8
  101. package/dist/config-invariants.js +55 -12
  102. package/dist/config-lkg.d.ts +5 -19
  103. package/dist/config-lkg.js +8 -62
  104. package/dist/config-provider.d.ts +1 -1
  105. package/dist/config-root-migration.d.ts +2 -2
  106. package/dist/config-types.d.ts +38 -42
  107. package/dist/config.d.ts +58 -7
  108. package/dist/config.js +90 -40
  109. package/dist/control-socket.d.ts +51 -0
  110. package/dist/control-socket.js +115 -0
  111. package/dist/deployment-governance.d.ts +2 -1
  112. package/dist/deployment-shape.d.ts +9 -1
  113. package/dist/deployment-shape.js +2 -1
  114. package/dist/device-protocol.d.ts +5 -4
  115. package/dist/device-protocol.js +1 -1
  116. package/dist/device-ws-hub.d.ts +7 -0
  117. package/dist/device-ws-hub.js +10 -3
  118. package/dist/device-ws-protocol.d.ts +63 -10
  119. package/dist/device-ws-protocol.js +56 -25
  120. package/dist/elicitation.js +2 -2
  121. package/dist/engine-identity.d.ts +19 -7
  122. package/dist/engine-identity.js +10 -2
  123. package/dist/entry-mode-clamp-notice.d.ts +2 -1
  124. package/dist/entry-problems.d.ts +40 -3
  125. package/dist/entry-problems.js +3 -1
  126. package/dist/execution-env-refusal.d.ts +29 -0
  127. package/dist/execution-env-refusal.js +8 -0
  128. package/dist/execution-lane-caps.d.ts +3 -1
  129. package/dist/field-conflict.d.ts +1 -1
  130. package/dist/file-history-capture.d.ts +11 -4
  131. package/dist/file-history-capture.js +9 -6
  132. package/dist/file-history-disclosure.d.ts +7 -5
  133. package/dist/file-history-disclosure.js +7 -5
  134. package/dist/fleet/drain-entry.d.ts +4 -0
  135. package/dist/fleet/engine-signal.d.ts +12 -29
  136. package/dist/fleet/engine-signal.js +1 -7
  137. package/dist/fleet-client.js +2 -5
  138. package/dist/gate-settlement.d.ts +1 -8
  139. package/dist/gate-settlement.js +0 -4
  140. package/dist/history-anchor.js +1 -1
  141. package/dist/hitl-delivery.d.ts +2 -3
  142. package/dist/hitl-delivery.js +0 -2
  143. package/dist/hooks/hook-llm.js +4 -2
  144. package/dist/hooks/hook-runner.d.ts +3 -2
  145. package/dist/hooks/hook-runner.js +18 -3
  146. package/dist/host-decision.d.ts +11 -11
  147. package/dist/host-lsp-manager.d.ts +2 -2
  148. package/dist/http/active-run-conflict.d.ts +35 -2
  149. package/dist/http/active-run-conflict.js +48 -19
  150. package/dist/http/admission.js +17 -2
  151. package/dist/http/approval-sweeps.d.ts +1 -1
  152. package/dist/http/approval-sweeps.js +10 -7
  153. package/dist/http/checkpoint-ctx.d.ts +4 -0
  154. package/dist/http/checkpoint-ctx.js +2 -0
  155. package/dist/http/dispatch.d.ts +8 -3
  156. package/dist/http/dispatch.js +59 -32
  157. package/dist/http/durable-run-leg.js +16 -17
  158. package/dist/http/health-reader.d.ts +16 -9
  159. package/dist/http/health-reader.js +2 -1
  160. package/dist/http/health-self-report.d.ts +9 -1
  161. package/dist/http/health-self-report.js +3 -1
  162. package/dist/http/owner-access.d.ts +33 -14
  163. package/dist/http/owner-access.js +40 -10
  164. package/dist/http/principal-gate.d.ts +49 -21
  165. package/dist/http/principal-gate.js +61 -11
  166. package/dist/http/request-channel.d.ts +23 -0
  167. package/dist/http/request-channel.js +9 -0
  168. package/dist/http/request-guards.js +17 -2
  169. package/dist/http/resume-ctx-read.js +42 -3
  170. package/dist/http/resume-legs.d.ts +4 -3
  171. package/dist/http/resume-legs.js +367 -117
  172. package/dist/http/route-ctx.d.ts +91 -15
  173. package/dist/http/route-ctx.js +17 -0
  174. package/dist/http/route-table.d.ts +5 -1
  175. package/dist/http/route-table.js +4 -0
  176. package/dist/http/routes/admin-config-refresh.js +3 -3
  177. package/dist/http/routes/admin-drain.d.ts +3 -0
  178. package/dist/http/routes/admin-drain.js +7 -7
  179. package/dist/http/routes/admin-memory-optout.d.ts +1 -1
  180. package/dist/http/routes/admin-memory-optout.js +3 -3
  181. package/dist/http/routes/adoption.js +3 -5
  182. package/dist/http/routes/agents-roster.js +2 -3
  183. package/dist/http/routes/approvals-assistant.d.ts +2 -1
  184. package/dist/http/routes/approvals-assistant.js +99 -51
  185. package/dist/http/routes/background.d.ts +3 -3
  186. package/dist/http/routes/capabilities.d.ts +4 -0
  187. package/dist/http/routes/capabilities.js +38 -10
  188. package/dist/http/routes/config-catalog.js +2 -2
  189. package/dist/http/routes/devices.js +1 -1
  190. package/dist/http/routes/diagnostics.d.ts +3 -3
  191. package/dist/http/routes/diagnostics.js +19 -7
  192. package/dist/http/routes/fleet.js +10 -8
  193. package/dist/http/routes/images.js +10 -10
  194. package/dist/http/routes/memory-bundle.js +3 -3
  195. package/dist/http/routes/memory-compliance.js +3 -3
  196. package/dist/http/routes/memory-consolidation.js +2 -2
  197. package/dist/http/routes/memory-origin.js +3 -3
  198. package/dist/http/routes/memory-policy.js +2 -2
  199. package/dist/http/routes/observability.js +3 -3
  200. package/dist/http/routes/projects.d.ts +3 -2
  201. package/dist/http/routes/projects.js +4 -5
  202. package/dist/http/routes/retention-ops.js +3 -3
  203. package/dist/http/routes/rules.js +5 -5
  204. package/dist/http/routes/run-permission-mode.d.ts +2 -1
  205. package/dist/http/routes/run-permission-mode.js +2 -2
  206. package/dist/http/routes/runs.d.ts +4 -9
  207. package/dist/http/routes/runs.js +171 -65
  208. package/dist/http/routes/session-sync.d.ts +22 -9
  209. package/dist/http/routes/session-sync.js +204 -107
  210. package/dist/http/routes/sessions-list.js +13 -7
  211. package/dist/http/routes/sessions.js +30 -15
  212. package/dist/http/routes/tasks.js +46 -41
  213. package/dist/http/routes/trace-usage.js +2 -2
  214. package/dist/http/routes/workflows.js +1 -1
  215. package/dist/http/server.d.ts +30 -30
  216. package/dist/http/server.js +16 -4
  217. package/dist/http/submit-ctx.d.ts +1 -1
  218. package/dist/http/submit-ctx.js +7 -4
  219. package/dist/http/wire-types.d.ts +14 -4
  220. package/dist/human-facing-args.d.ts +33 -0
  221. package/dist/human-facing-args.js +33 -0
  222. package/dist/identity-source.d.ts +20 -3
  223. package/dist/identity-source.js +14 -0
  224. package/dist/index.d.ts +5 -1
  225. package/dist/k8s-api-credentials.d.ts +29 -0
  226. package/dist/k8s-api-credentials.js +25 -0
  227. package/dist/lane-home-probe.d.ts +3 -7
  228. package/dist/lane-home-probe.js +2 -2
  229. package/dist/leader/diffup.d.ts +19 -0
  230. package/dist/leader/diffup.js +7 -0
  231. package/dist/leader/leader.d.ts +116 -11
  232. package/dist/leader/leader.js +69 -5
  233. package/dist/leader/repair-wire.js +2 -2
  234. package/dist/leader/run-entry.d.ts +2 -1
  235. package/dist/leader/run-entry.js +1 -1
  236. package/dist/leader/wire.d.ts +42 -132
  237. package/dist/leader/wire.js +81 -67
  238. package/dist/leg-facts.d.ts +13 -5
  239. package/dist/leg-facts.js +2 -1
  240. package/dist/memory-scope.d.ts +23 -11
  241. package/dist/memory-scope.js +18 -6
  242. package/dist/memory-sync-client.d.ts +30 -2
  243. package/dist/memory-sync-client.js +16 -9
  244. package/dist/model-entry-headers.d.ts +9 -10
  245. package/dist/model-entry-headers.js +0 -4
  246. package/dist/model-entry-refusal.d.ts +7 -4
  247. package/dist/model-entry-refusal.js +11 -5
  248. package/dist/model-plane-face.d.ts +1 -1
  249. package/dist/model-plane-face.js +3 -1
  250. package/dist/model-route-endpoint.d.ts +13 -7
  251. package/dist/model-route-endpoint.js +14 -11
  252. package/dist/model-select.d.ts +22 -0
  253. package/dist/model-select.js +9 -0
  254. package/dist/model-unreachable-notice.d.ts +11 -0
  255. package/dist/model-unreachable-notice.js +4 -4
  256. package/dist/object-store-buckets.d.ts +640 -6
  257. package/dist/object-store-buckets.js +166 -0
  258. package/dist/observability/err-text.d.ts +7 -0
  259. package/dist/observability/err-text.js +5 -0
  260. package/dist/observability/fail-open.d.ts +25 -17
  261. package/dist/observability/fail-open.js +25 -17
  262. package/dist/observability/logger.js +3 -1
  263. package/dist/observability/metrics.js +1 -0
  264. package/dist/operator-roster.d.ts +68 -0
  265. package/dist/operator-roster.js +32 -0
  266. package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
  267. package/dist/orchestration/workflow-notify-journal.js +12 -1
  268. package/dist/orchestration/workflow-park-decision.d.ts +70 -18
  269. package/dist/orchestration/workflow-park-decision.js +49 -10
  270. package/dist/orchestration/workflow-park-holder.d.ts +65 -0
  271. package/dist/orchestration/workflow-park-holder.js +98 -0
  272. package/dist/orchestration/workflow-record-fence.d.ts +36 -0
  273. package/dist/orchestration/workflow-record-fence.js +42 -0
  274. package/dist/outbound-dispatcher.d.ts +71 -8
  275. package/dist/outbound-dispatcher.js +48 -7
  276. package/dist/owner-faces.d.ts +2 -2
  277. package/dist/parked-decide.d.ts +106 -55
  278. package/dist/parked-decide.js +153 -117
  279. package/dist/peer-directory.d.ts +2 -2
  280. package/dist/peer-inbound-face.d.ts +2 -6
  281. package/dist/peer-inbound-face.js +0 -3
  282. package/dist/permission-mode-admission.d.ts +74 -5
  283. package/dist/permission-mode-admission.js +56 -3
  284. package/dist/plugins/adoption-log-sql.d.ts +3 -1
  285. package/dist/plugins/adoption-log-sql.js +7 -1
  286. package/dist/plugins/approval-ask-store-file.d.ts +14 -2
  287. package/dist/plugins/approval-ask-store-file.js +11 -0
  288. package/dist/plugins/approval-ask-store-memory.d.ts +10 -1
  289. package/dist/plugins/approval-ask-store-memory.js +35 -10
  290. package/dist/plugins/approval-ask-store-sql.d.ts +69 -4
  291. package/dist/plugins/approval-ask-store-sql.js +45 -5
  292. package/dist/plugins/approval-exemption-store.js +3 -0
  293. package/dist/plugins/approval-nonce-store.js +2 -0
  294. package/dist/plugins/blob-backend.d.ts +83 -7
  295. package/dist/plugins/blob-backend.js +57 -6
  296. package/dist/plugins/breaker-state-sql.js +2 -0
  297. package/dist/plugins/caching-session-store.d.ts +9 -15
  298. package/dist/plugins/caching-session-store.js +6 -0
  299. package/dist/plugins/checkpoint-index-columns.d.ts +20 -16
  300. package/dist/plugins/checkpoint-index-columns.js +3 -6
  301. package/dist/plugins/checkpoint-store-face.d.ts +119 -61
  302. package/dist/plugins/checkpoint-store-face.js +134 -55
  303. package/dist/plugins/device-store-sql.js +6 -0
  304. package/dist/plugins/error-origin.d.ts +18 -0
  305. package/dist/plugins/error-origin.js +10 -0
  306. package/dist/plugins/execution-placement-sql.js +6 -6
  307. package/dist/plugins/image-bake-store-sql.js +6 -0
  308. package/dist/plugins/image-index-sql.js +4 -0
  309. package/dist/plugins/landed-attendants.d.ts +212 -0
  310. package/dist/plugins/landed-attendants.js +161 -0
  311. package/dist/plugins/leader-run-store-sql.js +4 -0
  312. package/dist/plugins/local-checkpoint-store.d.ts +13 -3
  313. package/dist/plugins/local-checkpoint-store.js +38 -49
  314. package/dist/plugins/local-session-live-reference.d.ts +40 -0
  315. package/dist/plugins/local-session-live-reference.js +39 -0
  316. package/dist/plugins/local-session-store.d.ts +71 -33
  317. package/dist/plugins/local-session-store.js +129 -27
  318. package/dist/plugins/memory-engine-pg.js +4 -0
  319. package/dist/plugins/memory-engine-sql-apply.js +5 -2
  320. package/dist/plugins/memory-engine-tidb.js +4 -0
  321. package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
  322. package/dist/plugins/memory-sync-store-pg.js +5 -0
  323. package/dist/plugins/memory-sync-store-tidb.js +5 -0
  324. package/dist/plugins/one-time-migrations.d.ts +104 -80
  325. package/dist/plugins/one-time-migrations.js +226 -132
  326. package/dist/plugins/org-delivery-quota-store.js +4 -1
  327. package/dist/plugins/outcome-ledger-sql.js +2 -0
  328. package/dist/plugins/permission-rule-store-sql.js +11 -4
  329. package/dist/plugins/pg-cost-quota.js +4 -0
  330. package/dist/plugins/pg-pool.js +35 -10
  331. package/dist/plugins/pg-rate-limiter.js +2 -0
  332. package/dist/plugins/posix-shell-fs.d.ts +6 -1
  333. package/dist/plugins/posix-shell-fs.js +4 -1
  334. package/dist/plugins/remote-env-adb.d.ts +19 -15
  335. package/dist/plugins/remote-env-adb.js +41 -15
  336. package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
  337. package/dist/plugins/remote-env-connect-seat.js +72 -0
  338. package/dist/plugins/remote-env-device.d.ts +22 -5
  339. package/dist/plugins/remote-env-device.js +106 -8
  340. package/dist/plugins/remote-env-e2b.d.ts +15 -6
  341. package/dist/plugins/remote-env-e2b.js +42 -32
  342. package/dist/plugins/remote-env-file-error.js +6 -2
  343. package/dist/plugins/remote-env-host.d.ts +46 -10
  344. package/dist/plugins/remote-env-host.js +124 -52
  345. package/dist/plugins/remote-env-k8s.d.ts +109 -41
  346. package/dist/plugins/remote-env-k8s.js +160 -54
  347. package/dist/plugins/remote-env-local-docker.d.ts +13 -8
  348. package/dist/plugins/remote-env-local-docker.js +34 -41
  349. package/dist/plugins/remote-env-ssh.d.ts +18 -12
  350. package/dist/plugins/remote-env-ssh.js +60 -59
  351. package/dist/plugins/remote-shell.d.ts +98 -1
  352. package/dist/plugins/remote-shell.js +218 -0
  353. package/dist/plugins/replica-registration.d.ts +1 -1
  354. package/dist/plugins/replica-registration.js +1 -1
  355. package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
  356. package/dist/plugins/resume-anchor-store-sql.js +12 -5
  357. package/dist/plugins/retention-lane-store-sql.js +4 -0
  358. package/dist/plugins/retention-sql.d.ts +20 -2
  359. package/dist/plugins/retention-sql.js +11 -0
  360. package/dist/plugins/run-store-sql.d.ts +21 -2
  361. package/dist/plugins/run-store-sql.js +31 -7
  362. package/dist/plugins/s3-presign.d.ts +23 -0
  363. package/dist/plugins/s3-presign.js +37 -3
  364. package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
  365. package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
  366. package/dist/plugins/scheduler-support.d.ts +2 -2
  367. package/dist/plugins/scheduler-support.js +0 -3
  368. package/dist/plugins/schema-consistency.d.ts +4 -2
  369. package/dist/plugins/schema-consistency.js +19 -2
  370. package/dist/plugins/schema-indexes.js +2 -0
  371. package/dist/plugins/send-file-ledger.d.ts +2 -2
  372. package/dist/plugins/send-file-ledger.js +5 -2
  373. package/dist/plugins/send-user-file.d.ts +3 -4
  374. package/dist/plugins/send-user-file.js +56 -52
  375. package/dist/plugins/serving-requirement.d.ts +26 -7
  376. package/dist/plugins/serving-requirement.js +11 -4
  377. package/dist/plugins/session-birth.d.ts +6 -2
  378. package/dist/plugins/session-blob-claim-token.d.ts +15 -0
  379. package/dist/plugins/session-blob-claim-token.js +20 -0
  380. package/dist/plugins/session-blob-namespace.d.ts +46 -0
  381. package/dist/plugins/session-blob-namespace.js +116 -0
  382. package/dist/plugins/session-capture-record-store-sql.js +2 -0
  383. package/dist/plugins/session-ext-table.d.ts +14 -1
  384. package/dist/plugins/session-ext-table.js +5 -1
  385. package/dist/plugins/session-row-sql.d.ts +49 -2
  386. package/dist/plugins/session-row-sql.js +56 -13
  387. package/dist/plugins/session-store-sql.d.ts +34 -18
  388. package/dist/plugins/session-store-sql.js +98 -17
  389. package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
  390. package/dist/plugins/shared-memory-store-sql.js +6 -2
  391. package/dist/plugins/snapshot-bucket-presence.d.ts +25 -2
  392. package/dist/plugins/snapshot-bucket-presence.js +8 -2
  393. package/dist/plugins/sql-driver.d.ts +2 -1
  394. package/dist/plugins/sql-driver.js +18 -3
  395. package/dist/plugins/sql-errors.d.ts +11 -6
  396. package/dist/plugins/sql-errors.js +5 -6
  397. package/dist/plugins/sql-json-column.d.ts +1 -1
  398. package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
  399. package/dist/plugins/stop-then-start-sentence.js +14 -10
  400. package/dist/plugins/stop-then-start.d.ts +109 -0
  401. package/dist/plugins/stop-then-start.js +104 -0
  402. package/dist/plugins/store-backend.d.ts +84 -15
  403. package/dist/plugins/store-backend.js +236 -72
  404. package/dist/plugins/store-boundary.d.ts +57 -0
  405. package/dist/plugins/store-boundary.js +139 -0
  406. package/dist/plugins/store-contracts.d.ts +17 -0
  407. package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
  408. package/dist/plugins/store-fault-sentence-m53.js +25 -0
  409. package/dist/plugins/store-fault.d.ts +26 -7
  410. package/dist/plugins/store-fault.js +18 -2
  411. package/dist/plugins/task-attachment-store.d.ts +2 -1
  412. package/dist/plugins/task-attachment-store.js +14 -1
  413. package/dist/plugins/task-list-store-sql.d.ts +2 -2
  414. package/dist/plugins/task-list-store-sql.js +10 -8
  415. package/dist/plugins/tidb-cost-quota.js +4 -0
  416. package/dist/plugins/tidb-pool.js +21 -25
  417. package/dist/plugins/tidb-rate-limiter.js +4 -0
  418. package/dist/plugins/user-input-ledger-sql.js +4 -0
  419. package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
  420. package/dist/plugins/workflow-run-store-sql.js +64 -4
  421. package/dist/plugins/workspace-custody.d.ts +4 -3
  422. package/dist/plugins/workspace-fill.d.ts +4 -7
  423. package/dist/plugins/workspace-fill.js +2 -1
  424. package/dist/plugins/write-behind-counter.js +5 -0
  425. package/dist/project-context.d.ts +0 -2
  426. package/dist/project-context.js +4 -8
  427. package/dist/project-registry.d.ts +46 -0
  428. package/dist/project-registry.js +44 -0
  429. package/dist/question.d.ts +2 -1
  430. package/dist/question.js +5 -13
  431. package/dist/request-form.d.ts +6 -1
  432. package/dist/request-form.js +4 -1
  433. package/dist/request-key-closure.js +1 -1
  434. package/dist/request-value-closure.d.ts +4 -0
  435. package/dist/request-value-closure.js +10 -0
  436. package/dist/rule-issue-reading.d.ts +1 -1
  437. package/dist/rules-consent.d.ts +1 -1
  438. package/dist/run-acceptance.d.ts +3 -2
  439. package/dist/run-acceptance.js +4 -6
  440. package/dist/run-local.js +9 -9
  441. package/dist/runs.d.ts +54 -16
  442. package/dist/runs.js +67 -13
  443. package/dist/runtime-governance.d.ts +5 -4
  444. package/dist/security.d.ts +30 -32
  445. package/dist/security.js +41 -7
  446. package/dist/sema-config-dir.d.ts +2 -1
  447. package/dist/server-secret-env.d.ts +12 -10
  448. package/dist/server-secret-env.js +24 -15
  449. package/dist/session-bindings.d.ts +82 -0
  450. package/dist/session-bindings.js +18 -0
  451. package/dist/session-children-retire.d.ts +2 -2
  452. package/dist/session-children-retire.js +2 -6
  453. package/dist/session-deletion.d.ts +16 -1
  454. package/dist/session-error-wire.d.ts +3 -3
  455. package/dist/session-error-wire.js +3 -3
  456. package/dist/session-incarnation.d.ts +10 -0
  457. package/dist/session-incarnation.js +10 -1
  458. package/dist/session-kind.d.ts +57 -0
  459. package/dist/session-kind.js +22 -0
  460. package/dist/session-row.d.ts +21 -1
  461. package/dist/session-row.js +7 -1
  462. package/dist/session-sync-kernel.d.ts +24 -14
  463. package/dist/session-sync-kernel.js +3 -6
  464. package/dist/session-sync.d.ts +25 -103
  465. package/dist/session-sync.js +14 -76
  466. package/dist/session-titler.d.ts +10 -3
  467. package/dist/session-titler.js +19 -6
  468. package/dist/ssh-host-key.d.ts +5 -0
  469. package/dist/ssh-host-key.js +3 -0
  470. package/dist/stores-sql/blob-index-sql.d.ts +30 -9
  471. package/dist/stores-sql/blob-index-sql.js +40 -21
  472. package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
  473. package/dist/stores-sql/checkpoint-store-sql.js +70 -146
  474. package/dist/stores-sql/file-history-store-sql.d.ts +113 -15
  475. package/dist/stores-sql/file-history-store-sql.js +205 -95
  476. package/dist/stores-sql/pg-session-storage.d.ts +34 -7
  477. package/dist/stores-sql/pg-session-storage.js +37 -13
  478. package/dist/stores-sql/retention-store-sql.d.ts +1 -9
  479. package/dist/stores-sql/retention-store-sql.js +5 -19
  480. package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
  481. package/dist/stores-sql/session-policy-store-sql.js +61 -44
  482. package/dist/stores-sql/session-write-hooks.d.ts +11 -0
  483. package/dist/stores-sql/tidb-session-store.d.ts +58 -7
  484. package/dist/stores-sql/tidb-session-store.js +37 -13
  485. package/dist/submission-exit.d.ts +3 -2
  486. package/dist/submission-exit.js +9 -1
  487. package/dist/task-cwd.d.ts +2 -2
  488. package/dist/task-settings.d.ts +7 -5
  489. package/dist/task-settings.js +3 -3
  490. package/dist/terminal.d.ts +33 -2
  491. package/dist/terminal.js +139 -9
  492. package/dist/tool-approval.d.ts +465 -507
  493. package/dist/tool-approval.js +606 -1222
  494. package/dist/trace/core-keyset-guard.d.ts +1 -1
  495. package/dist/trace/ledger-events.d.ts +3 -3
  496. package/dist/trace/project.d.ts +2 -3
  497. package/dist/trace/redact.js +3 -2
  498. package/dist/trace/self-minted-wire.d.ts +571 -178
  499. package/dist/trace/self-minted-wire.js +189 -56
  500. package/dist/web-admin-client/apply-effective.js +2 -2
  501. package/dist/web-admin-client/read-warnings.d.ts +2 -2
  502. package/dist/web-admin-client/read-warnings.js +1 -1
  503. package/dist/web-admin-client/types.d.ts +1 -1
  504. package/dist/workspace-space.d.ts +10 -4
  505. package/dist/workspace-space.js +4 -1
  506. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +79 -28
  507. package/package.json +7 -3
  508. package/scripts/embed-minimal.mjs +3 -3
  509. package/wire-changes/server@7.151.0.json +762 -0
  510. package/wire-changes/server@7.152.0.json +900 -0
  511. package/dist/config-d-migration.d.ts +0 -37
  512. package/dist/config-d-migration.js +0 -60
  513. package/dist/http/session-inherit-env.d.ts +0 -36
  514. package/dist/http/session-inherit-env.js +0 -6
@@ -1,18 +1,27 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { captureFileBackupViaEnv, applyFileRestoreViaEnv, fileHistoryModeProvenDifferent, worldStillMatchesMint, annulProofFailure, boundaryPublishVerdict, fileHistoryDescribeTrackKey, fileHistoryTrackKeyOf, fileHistoryResolveTrackKey, fileHistoryExportDigest, validateFileHistoryExport, resolveFileHistoryRetention, fileHistoryBoundariesToKeep, } from "@sema-agent/core";
3
- import { BlobTooLargeError, SqlBlobIndex } from "./blob-index-sql.js";
3
+ import { BlobTooLargeError, SqlBlobIndex, blobGcCutoffAt, hashBatches } from "./blob-index-sql.js";
4
4
  import { mysqlDriver, pgDriver } from "../plugins/sql-driver.js";
5
- import { isMissingColumnError, retryOnDeadlock } from "../plugins/sql-errors.js";
5
+ import { isMissingColumnError, retryOnDeadlock, SqlArbitrationLostError } from "../plugins/sql-errors.js";
6
6
  import { probedMissingColumnRefusal } from "../plugins/schema-drift-sentence.js";
7
7
  import { recordFailOpen } from "../observability/fail-open.js";
8
8
  import { foldCaughtFailure } from "../file-history-disclosure.js";
9
9
  export const FILE_HISTORY_BLOB_TABLE = "file_history_blob";
10
- export const FILE_HISTORY_BLOB_KEY_PREFIX = "file-history/";
10
+ export const FILE_HISTORY_BLOB_GRANT_TABLE = "file_history_blob_grant";
11
+ export const FILE_HISTORY_SCOPED_TABLES = [
12
+ "file_history_boundary_file",
13
+ "file_history_boundary",
14
+ "file_history_reaped_entry",
15
+ "file_history_version",
16
+ "file_history_tracked",
17
+ FILE_HISTORY_BLOB_GRANT_TABLE,
18
+ "file_history_scope",
19
+ ];
11
20
  const sha256hex = (s) => createHash("sha256").update(s).digest("hex");
12
21
  const truthy = (v) => v === true || v === 1 || v === "1";
13
22
  class StagedRefGoneError extends Error {
14
23
  }
15
- class ScopeSentinelVanishedError extends Error {
24
+ class ScopeSentinelVanishedError extends SqlArbitrationLostError {
16
25
  }
17
26
  function reapedEntryRefusal(entryId) {
18
27
  return {
@@ -23,14 +32,89 @@ function reapedEntryRefusal(entryId) {
23
32
  },
24
33
  };
25
34
  }
35
+ export class SqlBlobExchange {
36
+ blobs;
37
+ constructor(blobs) {
38
+ this.blobs = blobs;
39
+ }
40
+ async put(hash, bytes) {
41
+ if (sha256hex(bytes) !== hash) {
42
+ return { ok: false, error: { code: "adopt_failed", message: `blob ${hash}: the bytes do not hash to this address — nothing stored`, permanence: "terminal" } };
43
+ }
44
+ try {
45
+ await this.blobs.put(hash, bytes);
46
+ return { ok: true };
47
+ }
48
+ catch (err) {
49
+ if (err instanceof BlobTooLargeError)
50
+ return { ok: false, error: { code: "adopt_failed", message: err.message, permanence: "terminal", blobCap: { wallSource: err.cap.source } } };
51
+ const f = foldCaughtFailure(err, "sql-blob-exchange.put");
52
+ return { ok: false, error: { code: "snapshot_failed", message: `blob ${hash} write/upload failed: ${f.text}`, ...f.fault } };
53
+ }
54
+ }
55
+ get(hash) {
56
+ return this.blobs.get(hash);
57
+ }
58
+ has(hashes) {
59
+ return this.blobs.has([...hashes]);
60
+ }
61
+ }
62
+ export class SqlBlobLanding {
63
+ db;
64
+ exchange;
65
+ constructor(db, exchange) {
66
+ this.db = db;
67
+ this.exchange = exchange;
68
+ }
69
+ q(mysql, pg) {
70
+ return this.db.dialect === "mysql" ? mysql : pg;
71
+ }
72
+ static ownerKey(landing) {
73
+ return landing.owner ?? "";
74
+ }
75
+ async putAt(landing, hash, bytes) {
76
+ const stored = await this.exchange.put(hash, bytes);
77
+ if (!stored.ok)
78
+ return stored;
79
+ try {
80
+ await this.db.query(this.q(`INSERT INTO ${FILE_HISTORY_BLOB_GRANT_TABLE} (scope, landing_owner, blob_hash, granted_at) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE granted_at = GREATEST(granted_at, VALUES(granted_at))`, `INSERT INTO ${FILE_HISTORY_BLOB_GRANT_TABLE} (scope, landing_owner, blob_hash, granted_at) VALUES ($1,$2,$3,$4) ON CONFLICT (scope, landing_owner, blob_hash) DO UPDATE SET granted_at = GREATEST(${FILE_HISTORY_BLOB_GRANT_TABLE}.granted_at, EXCLUDED.granted_at)`), [landing.sessionId, SqlBlobLanding.ownerKey(landing), hash, new Date()]);
81
+ return { ok: true };
82
+ }
83
+ catch (err) {
84
+ const f = foldCaughtFailure(err, "sql-blob-landing.putAt");
85
+ return { ok: false, error: { code: "snapshot_failed", message: `blob ${hash} was stored but its upload grant could not be recorded: ${f.text}`, ...f.fault } };
86
+ }
87
+ }
88
+ async visibleAt(landing, hashes) {
89
+ const wanted = new Set(hashes);
90
+ if (wanted.size === 0)
91
+ return new Set();
92
+ const candidates = new Set();
93
+ if (landing.occupied) {
94
+ const graph = await this.db.query(this.q("SELECT DISTINCT blob_hash FROM file_history_version WHERE scope = ? AND blob_hash IS NOT NULL", "SELECT DISTINCT blob_hash FROM file_history_version WHERE scope = $1 AND blob_hash IS NOT NULL"), [landing.sessionId]);
95
+ for (const r of graph.rows) {
96
+ const h = String(r.blob_hash);
97
+ if (wanted.has(h))
98
+ candidates.add(h);
99
+ }
100
+ }
101
+ const ungranted = [...wanted].filter((h) => !candidates.has(h));
102
+ for (const batch of hashBatches(ungranted)) {
103
+ const ph = batch.map((_, i) => (this.db.dialect === "mysql" ? "?" : `$${i + 3}`)).join(",");
104
+ const granted = await this.db.query(this.q(`SELECT blob_hash FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE scope = ? AND landing_owner = ? AND blob_hash IN (${ph})`, `SELECT blob_hash FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE scope = $1 AND landing_owner = $2 AND blob_hash IN (${ph})`), [landing.sessionId, SqlBlobLanding.ownerKey(landing), ...batch]);
105
+ for (const r of granted.rows)
106
+ candidates.add(String(r.blob_hash));
107
+ }
108
+ if (candidates.size === 0)
109
+ return new Set();
110
+ return this.exchange.has([...candidates]);
111
+ }
112
+ }
26
113
  export class SqlFileHistoryStore {
27
114
  db;
28
115
  pool;
29
- blobExchange = {
30
- put: (hash, bytes) => this.putExchangedBlob(hash, bytes),
31
- get: (hash) => this.blobs.get(hash),
32
- has: (hashes) => this.blobs.has([...hashes]),
33
- };
116
+ blobExchange;
117
+ blobLanding;
34
118
  blobs;
35
119
  spentAttempts = new Set();
36
120
  activeAttempts = new Set();
@@ -44,6 +128,8 @@ export class SqlFileHistoryStore {
44
128
  ...(opts?.blobSqlMaxBytes !== undefined ? { maxBytes: opts.blobSqlMaxBytes } : {}),
45
129
  ...(opts?.log !== undefined ? { log: opts.log } : {}),
46
130
  });
131
+ this.blobExchange = new SqlBlobExchange(this.blobs);
132
+ this.blobLanding = new SqlBlobLanding(this.db, this.blobExchange);
47
133
  this.boundaryKeep = resolveFileHistoryRetention(this.db.dialect === "mysql" ? "TiDBFileHistoryStore" : "PgFileHistoryStore", opts?.retention);
48
134
  }
49
135
  q(mysql, pg) {
@@ -67,14 +153,17 @@ export class SqlFileHistoryStore {
67
153
  await conn.begin();
68
154
  }
69
155
  restart = true;
70
- for (const scope of ordered) {
71
- await conn.query(this.q("INSERT INTO file_history_scope (scope, created_at_ms) VALUES (?,?) ON DUPLICATE KEY UPDATE scope = scope", "INSERT INTO file_history_scope (scope, created_at_ms) VALUES ($1,$2) ON CONFLICT (scope) DO NOTHING"), [scope, Date.now()]);
72
- const r = await conn.query(this.q("SELECT scope FROM file_history_scope WHERE scope = ? FOR UPDATE", "SELECT scope FROM file_history_scope WHERE scope = $1 FOR UPDATE"), [scope]);
73
- if (!r.rows[0])
74
- throw new ScopeSentinelVanishedError(`could not acquire the scope write lock for "${scope}" (sentinel row kept vanishing)`);
75
- }
156
+ await this.lockScopeOn(conn, ordered);
76
157
  }, (err) => err instanceof ScopeSentinelVanishedError);
77
158
  }
159
+ async lockScopeOn(conn, scopes) {
160
+ for (const scope of [...new Set(scopes)].sort()) {
161
+ await conn.query(this.q("INSERT INTO file_history_scope (scope, created_at_ms) VALUES (?,?) ON DUPLICATE KEY UPDATE scope = scope", "INSERT INTO file_history_scope (scope, created_at_ms) VALUES ($1,$2) ON CONFLICT (scope) DO NOTHING"), [scope, Date.now()]);
162
+ const r = await conn.query(this.q("SELECT scope FROM file_history_scope WHERE scope = ? FOR UPDATE", "SELECT scope FROM file_history_scope WHERE scope = $1 FOR UPDATE"), [scope]);
163
+ if (!r.rows[0])
164
+ throw new ScopeSentinelVanishedError(`could not acquire the scope write lock for "${scope}" (sentinel row kept vanishing)`);
165
+ }
166
+ }
78
167
  async markObserved(scope, keyHash) {
79
168
  const r = await this.db.query(this.q("UPDATE file_history_tracked SET observed_later = 1 WHERE scope = ? AND key_hash = ? AND observed_later = 0", "UPDATE file_history_tracked SET observed_later = TRUE WHERE scope = $1 AND key_hash = $2 AND observed_later = FALSE"), [scope, keyHash]);
80
169
  return r.affected;
@@ -134,7 +223,7 @@ export class SqlFileHistoryStore {
134
223
  return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} kept racing a concurrent retraction — retry` } };
135
224
  }
136
225
  catch (err) {
137
- const f = foldCaughtFailure(err);
226
+ const f = foldCaughtFailure(err, "sql-file-history-store.trackEdit");
138
227
  return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} could not be persisted: ${f.text}`, ...f.fault } };
139
228
  }
140
229
  }
@@ -201,7 +290,7 @@ export class SqlFileHistoryStore {
201
290
  return { ok: false, error: { code: "conflict", message: `first-touch record for ${absPath} was replaced while this retraction was being proven` } };
202
291
  }
203
292
  catch (err) {
204
- const f = foldCaughtFailure(err);
293
+ const f = foldCaughtFailure(err, "sql-file-history-store.annulTrack");
205
294
  return { ok: false, error: { code: "track_failed", message: `annulling the first-touch record for ${absPath} failed: ${f.text}`, ...f.fault } };
206
295
  }
207
296
  }
@@ -309,7 +398,7 @@ export class SqlFileHistoryStore {
309
398
  }
310
399
  }
311
400
  catch (err) {
312
- const f = foldCaughtFailure(err);
401
+ const f = foldCaughtFailure(err, "sql-file-history-store.snapshot");
313
402
  return { ok: false, error: { code: "snapshot_failed", message: f.text, ...f.fault } };
314
403
  }
315
404
  this.activeAttempts.add(lease);
@@ -412,7 +501,7 @@ export class SqlFileHistoryStore {
412
501
  catch (err) {
413
502
  await conn.rollback().catch(() => undefined);
414
503
  this.spentAttempts.add(lease);
415
- const f = foldCaughtFailure(err);
504
+ const f = foldCaughtFailure(err, "sql-file-history-store.snapshot");
416
505
  return { ok: false, error: { code: "snapshot_failed", message: `boundary for entry "${entryId}" could not be committed: ${f.text}`, ...f.fault } };
417
506
  }
418
507
  finally {
@@ -423,7 +512,7 @@ export class SqlFileHistoryStore {
423
512
  }
424
513
  catch (err) {
425
514
  this.spentAttempts.add(lease);
426
- const f = foldCaughtFailure(err);
515
+ const f = foldCaughtFailure(err, "sql-file-history-store.snapshot");
427
516
  return { ok: false, error: { code: "snapshot_failed", message: f.text, ...f.fault } };
428
517
  }
429
518
  finally {
@@ -491,7 +580,7 @@ export class SqlFileHistoryStore {
491
580
  });
492
581
  }
493
582
  catch (err) {
494
- applied = { outcome: "failed", reason: foldCaughtFailure(err).text };
583
+ applied = { outcome: "failed", reason: foldCaughtFailure(err, "sql-file-history-store.restore").text };
495
584
  }
496
585
  if (applied.outcome === "applied")
497
586
  ledger.filesChanged.push(t.trackKey);
@@ -508,7 +597,7 @@ export class SqlFileHistoryStore {
508
597
  }
509
598
  catch (err) {
510
599
  const touched = empty.filesChanged.length > 0 || empty.identicalSkipped.length > 0 || empty.refused.length > 0 || empty.failed.length > 0;
511
- const f = foldCaughtFailure(err);
600
+ const f = foldCaughtFailure(err, "sql-file-history-store.restore");
512
601
  return { outcome: touched ? "partial" : "failed", ...empty, error: { code: "restore_failed", message: f.text, ...f.fault } };
513
602
  }
514
603
  }
@@ -578,11 +667,7 @@ export class SqlFileHistoryStore {
578
667
  try {
579
668
  await conn.begin();
580
669
  await this.lockScope(conn, scope);
581
- let total = 0;
582
- for (const table of ["file_history_boundary_file", "file_history_boundary", "file_history_reaped_entry", "file_history_version", "file_history_tracked", "file_history_scope"]) {
583
- const r = await conn.query(this.q(`DELETE FROM ${table} WHERE scope = ?`, `DELETE FROM ${table} WHERE scope = $1`), [scope]);
584
- total += r.affected;
585
- }
670
+ const total = await this.deleteScopeRowsOn(conn, scope, FILE_HISTORY_SCOPED_TABLES);
586
671
  await conn.commit();
587
672
  return total;
588
673
  }
@@ -594,27 +679,25 @@ export class SqlFileHistoryStore {
594
679
  conn.release();
595
680
  }
596
681
  }
597
- async sweepOrphanBlobs() {
598
- const { rows } = await this.db.query("SELECT blob_hash FROM file_history_blob WHERE blob_hash NOT IN (SELECT blob_hash FROM file_history_version WHERE blob_hash IS NOT NULL)");
599
- const orphans = rows.map((r) => String(r.blob_hash));
600
- if (orphans.length === 0)
601
- return 0;
602
- return this.blobs.sweep(orphans);
682
+ async deleteScopeOn(conn, scope) {
683
+ await this.lockScopeOn(conn, [scope]);
684
+ return this.deleteScopeRowsOn(conn, scope, FILE_HISTORY_SCOPED_TABLES);
603
685
  }
604
- async putExchangedBlob(hash, bytes) {
605
- if (sha256hex(bytes) !== hash) {
606
- return { ok: false, error: { code: "adopt_failed", message: `blob ${hash}: the bytes do not hash to this address — nothing stored`, permanence: "terminal" } };
607
- }
608
- try {
609
- await this.blobs.put(hash, bytes);
610
- return { ok: true };
611
- }
612
- catch (err) {
613
- if (err instanceof BlobTooLargeError)
614
- return { ok: false, error: { code: "adopt_failed", message: err.message, permanence: "terminal", blobCap: { wallSource: err.cap.source } } };
615
- const f = foldCaughtFailure(err);
616
- return { ok: false, error: { code: "snapshot_failed", message: `blob ${hash} write/upload failed: ${f.text}`, ...f.fault } };
686
+ async deleteScopeRowsOn(conn, scope, tables) {
687
+ let total = 0;
688
+ for (const table of tables) {
689
+ const r = await conn.query(this.q(`DELETE FROM ${table} WHERE scope = ?`, `DELETE FROM ${table} WHERE scope = $1`), [scope]);
690
+ total += r.affected;
617
691
  }
692
+ return total;
693
+ }
694
+ async sweepOrphanBlobs() {
695
+ const cutoff = blobGcCutoffAt(Date.now());
696
+ return this.blobs.sweep(async () => {
697
+ await this.db.query(this.q(`DELETE FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE granted_at < ?`, `DELETE FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE granted_at < $1`), [cutoff]);
698
+ const { rows } = await this.db.query(`SELECT blob_hash FROM ${FILE_HISTORY_BLOB_TABLE} WHERE blob_hash NOT IN (SELECT blob_hash FROM file_history_version WHERE blob_hash IS NOT NULL) AND blob_hash NOT IN (SELECT blob_hash FROM ${FILE_HISTORY_BLOB_GRANT_TABLE})`);
699
+ return rows.map((r) => String(r.blob_hash));
700
+ }, cutoff);
618
701
  }
619
702
  async adoptScope(fromScope, toScope) {
620
703
  try {
@@ -650,7 +733,7 @@ export class SqlFileHistoryStore {
650
733
  }
651
734
  }
652
735
  catch (err) {
653
- const f = foldCaughtFailure(err);
736
+ const f = foldCaughtFailure(err, "sql-file-history-store.adoptScope");
654
737
  return { ok: false, error: { code: "adopt_failed", message: `adoptScope failed: ${f.text}`, ...f.fault } };
655
738
  }
656
739
  }
@@ -707,10 +790,10 @@ export class SqlFileHistoryStore {
707
790
  const conn = await this.db.connect();
708
791
  try {
709
792
  await conn.begin();
710
- await this.lockScope(conn, scope);
711
- const out = await this.exportOf(conn, scope, true);
793
+ const held = await conn.query(this.q("SELECT scope FROM file_history_scope WHERE scope = ? FOR UPDATE", "SELECT scope FROM file_history_scope WHERE scope = $1 FOR UPDATE"), [scope]);
794
+ const history = held.rows[0] === undefined ? null : await this.exportOf(conn, scope, true);
712
795
  await conn.commit();
713
- return { ok: true, history: out };
796
+ return { ok: true, history };
714
797
  }
715
798
  catch (err) {
716
799
  await conn.rollback().catch(() => undefined);
@@ -732,7 +815,7 @@ export class SqlFileHistoryStore {
732
815
  bytes = await srcGetBlob(hash);
733
816
  }
734
817
  catch (err) {
735
- const f = foldCaughtFailure(err);
818
+ const f = foldCaughtFailure(err, "sql-file-history-store.verifySourceBlobs");
736
819
  return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} fetch failed: ${f.text}`, ...f.fault } };
737
820
  }
738
821
  if (bytes === undefined)
@@ -745,6 +828,40 @@ export class SqlFileHistoryStore {
745
828
  return { ok: true };
746
829
  }
747
830
  async importHistory(scope, data, srcGetBlob) {
831
+ const plan = await this.prepareImport(scope, data, srcGetBlob, { replace: false });
832
+ if (!plan.ok)
833
+ return plan;
834
+ if (plan.mode === "same")
835
+ return { ok: true };
836
+ try {
837
+ const conn = await this.db.connect();
838
+ try {
839
+ await conn.begin();
840
+ await this.lockScope(conn, scope);
841
+ const out = await this.publishImportLockedOn(conn, scope, data, { replace: false });
842
+ if (out.ok)
843
+ await conn.commit();
844
+ else
845
+ await conn.rollback();
846
+ return out;
847
+ }
848
+ catch (err) {
849
+ await conn.rollback().catch(() => undefined);
850
+ throw err;
851
+ }
852
+ finally {
853
+ conn.release();
854
+ }
855
+ }
856
+ catch (err) {
857
+ return { ok: false, error: this.importFailureOf(err) };
858
+ }
859
+ }
860
+ importFailureOf(err) {
861
+ const f = foldCaughtFailure(err, "sql-file-history-store.importHistory");
862
+ return { code: "adopt_failed", message: `importHistory failed: ${f.text}`, ...f.fault };
863
+ }
864
+ async prepareImport(scope, data, srcGetBlob, opts) {
748
865
  try {
749
866
  const shaped = validateFileHistoryExport(data);
750
867
  if (!shaped.ok)
@@ -762,59 +879,51 @@ export class SqlFileHistoryStore {
762
879
  return exported;
763
880
  const existing = exported.history;
764
881
  const sameGraph = existing !== null && fileHistoryExportDigest(existing) === fileHistoryExportDigest(data);
765
- if (existing !== null && !sameGraph) {
882
+ if (existing !== null && !sameGraph && !opts.replace) {
766
883
  return { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" already holds a DIFFERENT history — a first import requires an empty target and a retry is legal only for the identical envelope (atomic visibility prevents half-graphs; this law prevents publishing the wrong complete graph over locally-grown history)` } };
767
884
  }
768
885
  const verified = await this.verifySourceBlobs(data, srcGetBlob, sameGraph ? undefined : (hash, bytes) => this.blobs.put(hash, bytes));
769
886
  if (!verified.ok)
770
887
  return verified;
771
- if (sameGraph)
772
- return { ok: true };
773
- const conn = await this.db.connect();
774
- try {
775
- await conn.begin();
776
- await this.lockScope(conn, scope);
777
- if (!(await this.scopeEmpty(conn, scope, true))) {
778
- const now = await this.exportOf(conn, scope, true);
779
- if (now !== null && fileHistoryExportDigest(now) === fileHistoryExportDigest(data)) {
780
- await conn.commit();
781
- return { ok: true };
782
- }
783
- await conn.rollback();
784
- return { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" gained a DIFFERENT history while this import was fetching blobs — nothing was published` } };
785
- }
786
- const now = Date.now();
787
- for (const t of data.tracked) {
788
- const keyHash = sha256hex(t.relOrAbsPath);
789
- await conn.query(this.q("INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES (?,?,?,?,?,?,0,?)", "INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES ($1,$2,$3,$4,$5,$6,FALSE,$7)"), [scope, keyHash, t.relOrAbsPath, t.keyKind, t.keyFamily, this.bool(t.baseAvailable), now]);
790
- for (const v of t.versions) {
791
- await conn.query(this.q("INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES (?,?,?,?,?,?,?)", "INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES ($1,$2,$3,$4,$5,$6,$7)"), [scope, keyHash, v.version, v.blobHash, v.mode ?? null, v.parentIdent ?? null, v.backupTime]);
792
- }
793
- }
794
- const seqBase = await conn.query(this.q("SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = ?", "SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = $1"), [scope]);
795
- let publishSeq = Number(seqBase.rows[0].s);
796
- for (const b of data.boundaries) {
797
- publishSeq += 1;
798
- await conn.query(this.q("INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, now, publishSeq]);
799
- for (const f of b.files) {
800
- await conn.query(this.q("INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, sha256hex(f.relOrAbsPath), f.version]);
801
- }
802
- }
803
- await conn.commit();
888
+ return { ok: true, mode: sameGraph ? "same" : "publish" };
889
+ }
890
+ catch (err) {
891
+ return { ok: false, error: this.importFailureOf(err) };
892
+ }
893
+ }
894
+ async publishImportOn(conn, scope, data, plan, opts) {
895
+ if (plan.mode === "same")
896
+ return { ok: true };
897
+ await this.lockScopeOn(conn, [scope]);
898
+ return this.publishImportLockedOn(conn, scope, data, opts);
899
+ }
900
+ async publishImportLockedOn(conn, scope, data, opts) {
901
+ if (!(await this.scopeEmpty(conn, scope, true))) {
902
+ const held = await this.exportOf(conn, scope, true);
903
+ if (held !== null && fileHistoryExportDigest(held) === fileHistoryExportDigest(data))
804
904
  return { ok: true };
805
- }
806
- catch (err) {
807
- await conn.rollback().catch(() => undefined);
808
- throw err;
809
- }
810
- finally {
811
- conn.release();
905
+ if (!opts.replace)
906
+ return { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" gained a DIFFERENT history while this import was fetching blobs — nothing was published` } };
907
+ await this.deleteScopeRowsOn(conn, scope, FILE_HISTORY_SCOPED_TABLES.filter((t) => t !== "file_history_scope"));
908
+ }
909
+ const now = Date.now();
910
+ for (const t of data.tracked) {
911
+ const keyHash = sha256hex(t.relOrAbsPath);
912
+ await conn.query(this.q("INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES (?,?,?,?,?,?,0,?)", "INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES ($1,$2,$3,$4,$5,$6,FALSE,$7)"), [scope, keyHash, t.relOrAbsPath, t.keyKind, t.keyFamily, this.bool(t.baseAvailable), now]);
913
+ for (const v of t.versions) {
914
+ await conn.query(this.q("INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES (?,?,?,?,?,?,?)", "INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES ($1,$2,$3,$4,$5,$6,$7)"), [scope, keyHash, v.version, v.blobHash, v.mode ?? null, v.parentIdent ?? null, v.backupTime]);
812
915
  }
813
916
  }
814
- catch (err) {
815
- const f = foldCaughtFailure(err);
816
- return { ok: false, error: { code: "adopt_failed", message: `importHistory failed: ${f.text}`, ...f.fault } };
917
+ const seqBase = await conn.query(this.q("SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = ?", "SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = $1"), [scope]);
918
+ let publishSeq = Number(seqBase.rows[0].s);
919
+ for (const b of data.boundaries) {
920
+ publishSeq += 1;
921
+ await conn.query(this.q("INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, now, publishSeq]);
922
+ for (const f of b.files) {
923
+ await conn.query(this.q("INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, sha256hex(f.relOrAbsPath), f.version]);
924
+ }
817
925
  }
926
+ return { ok: true };
818
927
  }
819
928
  }
820
929
  export class TiDBFileHistoryStore extends SqlFileHistoryStore {
@@ -836,6 +945,7 @@ export async function assertFileHistorySchema(query, dialect) {
836
945
  ["file_history_scope", "SELECT scope, created_at_ms FROM file_history_scope WHERE 1=0"],
837
946
  ["file_history_reaped_entry", "SELECT scope, entry_id, reaped_at_ms FROM file_history_reaped_entry WHERE 1=0"],
838
947
  [FILE_HISTORY_BLOB_TABLE, `SELECT blob_hash, byte_len, bytes, created_at FROM ${FILE_HISTORY_BLOB_TABLE} WHERE 1=0`],
948
+ [FILE_HISTORY_BLOB_GRANT_TABLE, `SELECT scope, landing_owner, blob_hash, granted_at FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE 1=0`],
839
949
  ];
840
950
  for (const [table, sql] of probes) {
841
951
  try {
@@ -2,9 +2,9 @@ import { type AcquiredSession, type PlacedSessionRow, type SessionHead, type Ses
2
2
  import type { Pool, PoolClient } from "pg";
3
3
  import { WindowedSessionStorage } from "./windowed-session-storage.js";
4
4
  import { type PlacementAcquireOpts } from "../plugins/session-placement.js";
5
- import { type StagingHandle } from "../session-sync-kernel.js";
5
+ import { type EntriesStreamOptions, type StagedCommitOptions, type StagingHandle, type SyncRelation } from "../session-sync-kernel.js";
6
6
  import type { RetentionDeclaration } from "@sema-agent/core";
7
- import { type RegisterReceipt, type WithdrawOutcome } from "../session-incarnation.js";
7
+ import { type RegisterReceipt, type SessionFace, type WithdrawOutcome } from "../session-incarnation.js";
8
8
  import type { SessionWriteHooks } from "./session-write-hooks.js";
9
9
  import { type IndexSpec } from "../plugins/ensure-index.js";
10
10
  import { type SessionDeleteCondition } from "./tidb-session-store.js";
@@ -78,7 +78,7 @@ export declare class PgSessionStore implements SessionStore {
78
78
  /** Idempotently create a session_meta row with an owner (core `SessionStore.register`). Existing owner is never overwritten. */
79
79
  register(sessionId: string, owner: string | null): Promise<void>;
80
80
  /** 出生回执面(TiDB 孪生 {@link TiDBSessionStore.registerWithReceipt} 同义:候选 = 这一次 INSERT 入参里铸的化身)。 */
81
- registerWithReceipt(sessionId: string, owner: string | null): Promise<RegisterReceipt>;
81
+ registerWithReceipt(sessionId: string, owner: string | null, kind?: string): Promise<RegisterReceipt>;
82
82
  /** 条件删除(TiDB 孪生 {@link TiDBSessionStore.deleteSessionIf} 同义)。 */
83
83
  deleteSessionIf(sessionId: string, cond: SessionDeleteCondition): Promise<WithdrawOutcome>;
84
84
  /** acquire 的建行(唯一一处;placed 会话的属主 = `placement.owner` 原样,core 7.62.0 [ref] 盒义务 7 —— TiDB 孪生同名方法同注)。 */
@@ -86,6 +86,8 @@ export declare class PgSessionStore implements SessionStore {
86
86
  /** The one session_meta INSERT. Existing owner is never overwritten.
87
87
  * [ref]:`placement` 与行同一条 INSERT;`DO NOTHING` 臂 ⇒ 已存在行的元组永不被重写(first-write 不可变)。 */
88
88
  private insertMeta;
89
+ /** {@link insertMeta} 那一句,发在给定的连接上(带种类的登记在自己的事务连接上发)。 */
90
+ private insertMetaOn;
89
91
  /** [ref] 义务 6 的廉价探针(TiDB 孪生 {@link TiDBSessionStore.placementOf} 同义)。 */
90
92
  placementOf(sessionId: string): Promise<SessionPlacementRecord | undefined>;
91
93
  /** [ref] 义务 5 —— placed 分区枚举(年龄锚/上界/tupleIncomplete 三条读法与 TiDB 孪生逐字同义,
@@ -128,10 +130,7 @@ export declare class PgSessionStore implements SessionStore {
128
130
  * held connection across the stream → a slow consumer can't pin one). Start cursor = afterSeq ?? -1 (0-based dense).
129
131
  * Resolves to null (NOT an empty iterable) for a missing session — eager `session_meta` probe (BIGINT seq comes
130
132
  * back as a STRING in node-pg → always Number(...) the cursor advance). */
131
- exportEntriesStream(sessionId: string, opts?: {
132
- afterSeq?: number;
133
- batchSize?: number;
134
- }): Promise<AsyncIterable<SessionTreeEntry> | null>;
133
+ exportEntriesStream(sessionId: string, opts: EntriesStreamOptions): Promise<AsyncIterable<SessionTreeEntry> | null>;
135
134
  /** @see TiDBSessionStore.importEntries — 2c session-sync IMPORT: core `validateEntriesForImport` gate FIRST (fail-closed),
136
135
  * then persist its verbatim output (re-seq dense from 0, ids/parents/payload/ts unchanged) in ONE txn, **lock-or-create, meta first**
137
136
  * (占行 → 锁行判是不是本次占下的 → 部署的事务内钩 `import` → 事件);owner = the RE-STAMPED authenticated principal (never the bundle's). */
@@ -160,4 +159,32 @@ export declare class PgSessionStore implements SessionStore {
160
159
  get size(): number;
161
160
  dispose(): void;
162
161
  }
162
+ /**
163
+ * 2c session-sync P1d-β — the PG twin of {@link TiDBStagingHandle} (behaviourally identical; only the SQL dialect
164
+ * differs: `$n` placeholders, `$n::jsonb`, `ON CONFLICT (session_id, entry_id) DO NOTHING`, rowCount, FOR UPDATE,
165
+ * BEGIN/COMMIT handle). Streams entry batches into a shadow session_event partition, then atomically RENAMEs them
166
+ * onto the real session id in ONE txn; session_meta is locked (or claimed, for a fresh push) first and settled last, COMMIT = the commit point.
167
+ */
168
+ /** 暂存句柄(会话同步的推送腿逐批写、提交、撤销;由本店的 `stageImport` 交出)。导出只为组合座给它封口(店边界)。 */
169
+ export declare class PgStagingHandle implements StagingHandle {
170
+ private readonly pool;
171
+ private readonly hooks;
172
+ readonly realSessionId: string;
173
+ readonly stagingId: string;
174
+ private nextSeq;
175
+ private readonly seen;
176
+ constructor(pool: Pool, hooks: SessionWriteHooks, realSessionId: string, stagingId: string);
177
+ /** @see TiDBStagingHandle.appendBatch — DENSE re-seq (skip already-staged ids), idempotent ON CONFLICT (session_id,
178
+ * entry_id) DO NOTHING, one txn/batch. */
179
+ appendBatch(entries: SessionTreeEntry[]): Promise<void>;
180
+ /** @see TiDBStagingHandle.commit — the atomic swap: owner CAS first (lock / claim the session_meta row) → in-commit re-classify (FOR UPDATE)
181
+ * → purge dst → rename staging→real → settle session_meta. Throws StagedCommitOccupantChangedError when the owner cell is not the judged one,
182
+ * SyncConflictError on an unconsented fork/stale flip. */
183
+ commit(owner: string | null, opts: StagedCommitOptions): Promise<{
184
+ relation: SyncRelation["relation"];
185
+ face: SessionFace;
186
+ }>;
187
+ /** @see TiDBStagingHandle.abort — DELETE the staging rows. Idempotent. */
188
+ abort(): Promise<void>;
189
+ }
163
190
  //# sourceMappingURL=pg-session-storage.d.ts.map