@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,7 +1,8 @@
1
1
  import { once } from "node:events";
2
2
  import { sessionLogDigest, sessionLogDigestsComparable, validateFileHistoryExport } from "@sema-agent/core";
3
3
  import { StringDecoder } from "node:string_decoder";
4
- import { FileHistoryUnreadableError, blobGetterOf, exportSessionManifest, exportedFileHistory, fileHistoryImportFace, replayFileHistory, replayPolicyRecords, wipeSessionAttendants } from "../../session-sync.js";
4
+ import { FileHistoryUnreadableError, NO_VISIBLE_BLOBS, exportSessionManifest } from "../../session-sync.js";
5
+ import { fileHistoryImportFace } from "../../plugins/landed-attendants.js";
5
6
  import * as facts from "../../capability-facts.js";
6
7
  import { classifySyncRelationshipByIds, createStagedLogFeed, MalformedImportEntryError, newStagingToken, readImportAnchors, SyncConflictError } from "../../session-sync-kernel.js";
7
8
  import { isUuidShape } from "../../security.js";
@@ -9,7 +10,7 @@ import { sendJson, sendError, sendSessionError, sendSessionPolicyError, logReque
9
10
  import { StampedSessionArchiveError } from "../../session-error-wire.js";
10
11
  import { buildDisplaySafeUrl } from "../../trace/redact.js";
11
12
  import { storeFaultClassOf } from "../../plugins/store-fault.js";
12
- import { enter, readSessionAgent, readSyncGate, refuse } from "../owner-access.js";
13
+ import { enter, readSessionAgent, readSyncGate, recheckSyncGate, refuse } from "../owner-access.js";
13
14
  import { listFilterOf, ownerKeyOf, sameKey } from "../../owner-faces.js";
14
15
  const SYNC_BLOB_MAX_BYTES = 64 * 1024 * 1024;
15
16
  const SYNC_NDJSON_LINE_MAX_BYTES = 8 * 1024 * 1024;
@@ -17,12 +18,18 @@ import { SHA256_HEX_RE } from "../../digest-form.js";
17
18
  import { assertNever } from "../route-ctx.js";
18
19
  import { readSessionRulesRecords, describeSessionRulesRecordProblem } from "../../session-policy-wire.js";
19
20
  import { readSessionPinned, readSessionTitle } from "../../session-row.js";
21
+ import { incarnationLogPrefix, SessionOccupantChangedError } from "../../session-incarnation.js";
20
22
  import { defaultTaskRegistry } from "@sema-agent/core";
21
23
  import { SessionActiveRunError, SessionForkInProgressError, SessionWriterPresentError } from "../../execution-placement.js";
22
24
  import { probeSessionChildren, sessionTenantScope } from "../../session-children-retire.js";
23
25
  import { liveChildrenRefusal } from "./background.js";
24
- export function importLeaseKey(landingOwner, sessionId) {
25
- return JSON.stringify([landingOwner, sessionId]);
26
+ export function landingOf(gate, scope, sessionId) {
27
+ return gate.occupant !== undefined
28
+ ? { sessionId, owner: gate.occupant.owner, occupied: true }
29
+ : { sessionId, owner: scope.fleetWide ? null : scope.gateOwner, occupied: false };
30
+ }
31
+ export function importLeaseKey(landing) {
32
+ return JSON.stringify([landing.owner, landing.sessionId]);
26
33
  }
27
34
  export function createSessionSyncLocal() {
28
35
  const pendingStagings = new Map();
@@ -106,6 +113,7 @@ export async function handleSessionSync(req, res, match, ctx) {
106
113
  }
107
114
  const gateFace = gate.face;
108
115
  const owner = gateFace === undefined ? undefined : gateFace.owner;
116
+ const landing = landingOf(gate, scope, sessionId);
109
117
  const sendSessionAbsent = (reason) => refuse(syncEntry, res, reason);
110
118
  const pullGateOk = () => {
111
119
  if (!gate.mayPull) {
@@ -121,6 +129,33 @@ export async function handleSessionSync(req, res, match, ctx) {
121
129
  }
122
130
  return true;
123
131
  };
132
+ const stillAdmitted = async (port) => {
133
+ const admitted = port === "pull" ? gate.face : gate.occupant;
134
+ return admitted === undefined || (await recheckSyncGate(sessionStorage, sessionId, admitted, port));
135
+ };
136
+ const pullAnswer = async (send) => {
137
+ let same;
138
+ try {
139
+ same = await stillAdmitted("pull");
140
+ }
141
+ catch (e) {
142
+ if (sendPullUnreadable(req, res, deps.logger, e))
143
+ return;
144
+ throw e;
145
+ }
146
+ if (!same) {
147
+ sendSessionAbsent("missing");
148
+ return;
149
+ }
150
+ send();
151
+ };
152
+ const pushAnswer = async (send) => {
153
+ if (!(await stillAdmitted("push"))) {
154
+ sendError(res, 409, "conflict", "sync conflict");
155
+ return;
156
+ }
157
+ send();
158
+ };
124
159
  const replaySessionRow = async (row, face) => {
125
160
  if (Object.keys(row).length === 0)
126
161
  return true;
@@ -166,27 +201,46 @@ export async function handleSessionSync(req, res, match, ctx) {
166
201
  }
167
202
  };
168
203
  const canReplayHistory = fileHistoryImportFace(historyStore) !== undefined;
169
- const replayHistory = async (envelope, allowReplace) => {
170
- const r = await replayFileHistory(historyStore, sessionId, envelope, blobGetterOf(historyStore), { allowReplace });
171
- return r.ok ? undefined : r;
204
+ const landAttendants = async (attendants, landed, plan) => {
205
+ if (plan.wipe && !(await attendants.wipe(sessionId, landed)).landed)
206
+ return { kind: "gone", leg: "wipe" };
207
+ if (plan.fileHistory !== null && canReplayHistory) {
208
+ const h = await attendants.replayHistory(sessionId, landed, plan.fileHistory, plan.getBlob, { allowReplace: plan.allowReplace });
209
+ if (!h.landed)
210
+ return { kind: "gone", leg: "file_history" };
211
+ if (!h.value.ok)
212
+ return { kind: "history_failed", failure: h.value };
213
+ }
214
+ if (plan.policy.length > 0 && !(await attendants.replayPolicy(sessionId, landed, plan.policy, plan.operator)).landed)
215
+ return { kind: "gone", leg: "policy" };
216
+ if (plan.anchors.length > 0 && !(await attendants.putAnchors(sessionId, landed, plan.anchors, plan.owner)).landed)
217
+ return { kind: "gone", leg: "anchors" };
218
+ if (!(await replaySessionRow(plan.row, landed)))
219
+ return { kind: "gone", leg: "row" };
220
+ return { kind: "landed" };
221
+ };
222
+ const sendLandedOccupantGone = (arm, leg, landed) => {
223
+ deps.logger?.warn?.("session_sync_landed_occupant_gone", { sessionId, arm, leg, landed: incarnationLogPrefix(landed.incarnation) });
224
+ deps.metrics?.inc("session_sync_landed_occupant_gone_total", { arm, leg }, 1);
225
+ sendError(res, 409, "conflict", "sync conflict");
172
226
  };
173
227
  if (match.decl.id === "session-sync-manifest") {
174
228
  if (!pullGateOk())
175
229
  return;
176
- let out;
230
+ let manifest;
177
231
  try {
178
- out = await exportSessionManifest(sessionId, backend, historyStore);
232
+ manifest = await exportSessionManifest(sessionId, backend, historyStore);
179
233
  }
180
234
  catch (e) {
181
235
  if (sendSessionPolicyError(res, e) || sendPullUnreadable(req, res, deps.logger, e))
182
236
  return;
183
237
  throw e;
184
238
  }
185
- if (out === null) {
239
+ if (manifest === null) {
186
240
  sendSessionAbsent("missing");
187
241
  return;
188
242
  }
189
- sendJson(res, 200, { manifest: out.manifest });
243
+ await pullAnswer(() => sendJson(res, 200, { manifest }));
190
244
  return;
191
245
  }
192
246
  if (match.decl.id === "session-sync-entries") {
@@ -202,9 +256,11 @@ export async function handleSessionSync(req, res, match, ctx) {
202
256
  }
203
257
  afterSeq = n;
204
258
  }
259
+ const recheck = async () => { if (!(await stillAdmitted("pull")))
260
+ throw new SessionOccupantChangedError(sessionId); };
205
261
  let it;
206
262
  try {
207
- it = await sessionStorage.exportEntriesStream(sessionId, afterSeq === undefined ? undefined : { afterSeq });
263
+ it = await sessionStorage.exportEntriesStream(sessionId, { ...(afterSeq === undefined ? {} : { afterSeq }), recheck });
208
264
  }
209
265
  catch (e) {
210
266
  if (sendPullUnreadable(req, res, deps.logger, e))
@@ -215,6 +271,19 @@ export async function handleSessionSync(req, res, match, ctx) {
215
271
  sendSessionAbsent("missing");
216
272
  return;
217
273
  }
274
+ let openSame;
275
+ try {
276
+ openSame = await stillAdmitted("pull");
277
+ }
278
+ catch (e) {
279
+ if (sendPullUnreadable(req, res, deps.logger, e))
280
+ return;
281
+ throw e;
282
+ }
283
+ if (!openSame) {
284
+ sendSessionAbsent("missing");
285
+ return;
286
+ }
218
287
  res.writeHead(200, { "content-type": "application/x-ndjson", "transfer-encoding": "chunked" });
219
288
  const write = async (line) => { if (!res.write(line))
220
289
  await once(res, "drain"); };
@@ -229,15 +298,18 @@ export async function handleSessionSync(req, res, match, ctx) {
229
298
  res.end();
230
299
  }
231
300
  catch (e) {
232
- deps.logger?.error?.("sync entries stream failed", { sessionId, count, error: msg(e) });
301
+ if (e instanceof SessionOccupantChangedError)
302
+ deps.logger?.info?.("session_sync_pull_occupant_changed", { sessionId, count });
303
+ else
304
+ deps.logger?.error?.("sync entries stream failed", { sessionId, count, error: msg(e) });
233
305
  res.end();
234
306
  }
235
307
  return;
236
308
  }
237
309
  if (match.decl.id === "session-sync-history-blob") {
238
- const blobs = facts.sessionSyncFileHistory(deps);
239
- if (!blobs.available) {
240
- sendSessionSyncUnavailable(res, blobs.why);
310
+ const faces = facts.sessionSyncFileHistory(deps);
311
+ if (!faces.available) {
312
+ sendSessionSyncUnavailable(res, faces.why);
241
313
  return;
242
314
  }
243
315
  if (!pullGateOk())
@@ -251,45 +323,45 @@ export async function handleSessionSync(req, res, match, ctx) {
251
323
  sendError(res, 400, "request.id_invalid", "blob hash must be 64 lowercase-hex chars");
252
324
  return;
253
325
  }
254
- const fs = blobs.historyStore;
255
- const exchange = blobs.blobExchange;
256
- let envelope;
326
+ let visible;
257
327
  try {
258
- envelope = await exportedFileHistory(fs, sessionId);
328
+ visible = await faces.blobs.visible(landing, [hash]);
259
329
  }
260
330
  catch (e) {
261
331
  if (sendPullUnreadable(req, res, deps.logger, e))
262
332
  return;
263
333
  throw e;
264
334
  }
265
- const referenced = envelope !== null && envelope.tracked.some((t) => t.versions.some((v) => v.blobHash === hash));
266
- if (!referenced) {
267
- sendError(res, 404, "not_found.blob", "blob not found");
335
+ if (!visible.hashes.has(hash)) {
336
+ await pullAnswer(() => sendError(res, 404, "not_found.blob", "blob not found"));
268
337
  return;
269
338
  }
270
339
  let bytes;
271
340
  try {
272
- bytes = await exchange.get(hash);
341
+ bytes = await visible.get(hash);
273
342
  }
274
343
  catch (e) {
275
344
  if (sendPullUnreadable(req, res, deps.logger, e))
276
345
  return;
277
346
  throw e;
278
347
  }
279
- if (!bytes) {
280
- sendError(res, 404, "not_found.blob", "blob not found");
348
+ const found = bytes;
349
+ if (!found) {
350
+ await pullAnswer(() => sendError(res, 404, "not_found.blob", "blob not found"));
281
351
  return;
282
352
  }
283
- res.writeHead(200, { "content-type": "application/octet-stream" });
284
- res.end(Buffer.from(bytes));
353
+ await pullAnswer(() => {
354
+ res.writeHead(200, { "content-type": "application/octet-stream" });
355
+ res.end(Buffer.from(found));
356
+ });
285
357
  return;
286
358
  }
287
359
  if (match.decl.id === "session-sync-blob-put") {
288
360
  if (rateLimited(req, res))
289
361
  return;
290
- const blobs = facts.sessionSyncFileHistory(deps);
291
- if (!blobs.available) {
292
- sendSessionSyncUnavailable(res, blobs.why);
362
+ const faces = facts.sessionSyncFileHistory(deps);
363
+ if (!faces.available) {
364
+ sendSessionSyncUnavailable(res, faces.why);
293
365
  return;
294
366
  }
295
367
  if (!pushGateOk())
@@ -300,7 +372,7 @@ export async function handleSessionSync(req, res, match, ctx) {
300
372
  return;
301
373
  }
302
374
  const body = await readRawBody(req, SYNC_BLOB_MAX_BYTES);
303
- const put = await blobs.blobExchange.put(hash, new Uint8Array(body));
375
+ const put = await faces.blobs.put(landing, hash, new Uint8Array(body));
304
376
  if (!put.ok) {
305
377
  if (put.error.blobCap !== undefined) {
306
378
  sendError(res, 413, "blob_too_large_for_sql", put.error.message, { wallSource: put.error.blobCap.wallSource });
@@ -386,10 +458,14 @@ export async function handleSessionSync(req, res, match, ctx) {
386
458
  const entryIds = body.entryIds;
387
459
  const policy = policyRead.records;
388
460
  const anchors = anchorsRead.anchors;
389
- const dstIds = (await sessionStorage.listEntryIds?.(sessionId)) ?? null;
461
+ const dstIds = gate.occupant === undefined ? null : ((await sessionStorage.listEntryIds?.(sessionId)) ?? null);
390
462
  const relA = classifySyncRelationshipByIds(entryIds, dstIds);
391
463
  const refusalA = await firstPhaseRefusal(sessionStorage, sessionId, relA.relation, resolution === "overwrite-dst");
392
464
  if (refusalA !== undefined) {
465
+ if (!(await stillAdmitted("push"))) {
466
+ sendError(res, 409, "conflict", "sync conflict");
467
+ return;
468
+ }
393
469
  if (refusalA.kind === "stamped") {
394
470
  if (sendSessionError(res, refusalA.error, "import"))
395
471
  return;
@@ -398,15 +474,21 @@ export async function handleSessionSync(req, res, match, ctx) {
398
474
  sendError(res, 409, "conflict", "sync conflict", { relation: relA });
399
475
  return;
400
476
  }
477
+ let visible = NO_VISIBLE_BLOBS;
401
478
  if (fileHistory !== null) {
402
479
  const distinct = new Set();
403
480
  for (const t of fileHistory.tracked)
404
481
  for (const v of t.versions)
405
482
  if (v.blobHash !== null)
406
483
  distinct.add(v.blobHash);
407
- if (await firstMissingBlob(facts.sessionSyncFileHistory(deps), [...distinct]) !== undefined) {
408
- sendMissingBlob(res);
409
- return;
484
+ if (distinct.size > 0) {
485
+ const faces = facts.sessionSyncFileHistory(deps);
486
+ if (faces.available)
487
+ visible = await faces.blobs.visible(landing, [...distinct]);
488
+ if ([...distinct].some((h) => !visible.hashes.has(h))) {
489
+ await pushAnswer(() => sendMissingBlob(res));
490
+ return;
491
+ }
410
492
  }
411
493
  }
412
494
  let payloadVerified = false;
@@ -432,10 +514,10 @@ export async function handleSessionSync(req, res, match, ctx) {
432
514
  case "mirror":
433
515
  break;
434
516
  case "writer":
435
- sendSessionWriter(res);
517
+ await pushAnswer(() => sendSessionWriter(res));
436
518
  return;
437
519
  case "forking":
438
- sendError(res, 409, "conflict.fork_in_progress", new SessionForkInProgressError(sessionId).message);
520
+ await pushAnswer(() => sendError(res, 409, "conflict.fork_in_progress", new SessionForkInProgressError(sessionId).message));
439
521
  return;
440
522
  default: {
441
523
  const unknownRole = placed.cell;
@@ -443,12 +525,13 @@ export async function handleSessionSync(req, res, match, ctx) {
443
525
  }
444
526
  }
445
527
  }
446
- const activeNow = await activityOf(gateFace);
528
+ const activeNow = gate.occupant === undefined ? undefined : await activityOf(gateFace);
447
529
  if (activeNow !== undefined) {
448
- sendActivity(activeNow, "open");
530
+ await pushAnswer(() => sendActivity(activeNow, "open"));
449
531
  return;
450
532
  }
451
533
  if (relA.relation === "identical" && !digestSaysDiffer) {
534
+ const attendantsA = backend.landedAttendants();
452
535
  const seat = sessionStorage.executionPlacement;
453
536
  if (seat !== undefined) {
454
537
  if (gateFace === undefined) {
@@ -474,38 +557,41 @@ export async function handleSessionSync(req, res, match, ctx) {
474
557
  }
475
558
  }
476
559
  }
477
- if (fileHistory !== null && canReplayHistory) {
478
- const failed = await replayHistory(fileHistory, resolution === "overwrite-dst");
479
- if (failed !== undefined) {
480
- sendFileHistoryReplayFailure(res, failed);
560
+ if (gateFace === undefined) {
561
+ sendError(res, 409, "conflict", "sync conflict");
562
+ return;
563
+ }
564
+ let landedA;
565
+ try {
566
+ landedA = await landAttendants(attendantsA, gateFace, { wipe: false, fileHistory, getBlob: visible.get, allowReplace: resolution === "overwrite-dst", policy, operator: operatorOk, anchors, owner: importingPrincipal, row });
567
+ }
568
+ catch (e) {
569
+ if (sendSessionPolicyError(res, e))
481
570
  return;
482
- }
571
+ throw e;
483
572
  }
484
- if (deps.sessionPolicyStore) {
485
- try {
486
- await replayPolicyRecords(deps.sessionPolicyStore, sessionId, policy, operatorOk);
487
- }
488
- catch (e) {
489
- if (sendSessionPolicyError(res, e))
490
- return;
491
- throw e;
573
+ switch (landedA.kind) {
574
+ case "landed":
575
+ break;
576
+ case "gone":
577
+ sendLandedOccupantGone("identical", landedA.leg, gateFace);
578
+ return;
579
+ case "history_failed":
580
+ sendFileHistoryReplayFailure(res, landedA.failure);
581
+ return;
582
+ default: {
583
+ const unhandled = landedA;
584
+ throw new Error(`session sync: unknown landing answer ${JSON.stringify(unhandled)}`);
492
585
  }
493
586
  }
494
- if (deps.resumeAnchorStore)
495
- for (const a of anchors)
496
- await deps.resumeAnchorStore.put(sessionId, a.eventId, a.entryId, importingPrincipal);
497
- if (!(await replaySessionRow(row, gateFace))) {
498
- sendError(res, 409, "conflict", "sync conflict");
499
- return;
500
- }
501
- sendJson(res, 200, {
587
+ await pushAnswer(() => sendJson(res, 200, {
502
588
  relation: "identical",
503
589
  basis: payloadVerified ? "entry-ids+digest" : "entry-ids",
504
590
  payloadVerified,
505
- });
591
+ }));
506
592
  return;
507
593
  }
508
- const leaseKey = importLeaseKey(gate.occupant !== undefined ? gate.occupant.owner : importingPrincipal, sessionId);
594
+ const leaseKey = importLeaseKey(landing);
509
595
  const staleSecRaw = deps.config.syncImportLeaseStaleSec;
510
596
  const staleSec = typeof staleSecRaw === "number" && Number.isFinite(staleSecRaw) ? staleSecRaw : 600;
511
597
  const staleMs = staleSec * 1000;
@@ -514,8 +600,12 @@ export async function handleSessionSync(req, res, match, ctx) {
514
600
  const heldLease = importLeases.get(leaseKey);
515
601
  if (heldLease) {
516
602
  const retryAfterSec = staleMs > 0 ? Math.max(1, Math.ceil((staleMs - (Date.now() - heldLease.at)) / 1000)) : undefined;
517
- sendError(res, 409, "import_in_flight", "an import is already in flight for this session"
518
- + (retryAfterSec !== undefined ? ` (a stalled holder is taken over after ${staleSec}s of inactivity; retry in ~${retryAfterSec}s)` : ""), retryAfterSec !== undefined ? { retryAfterSec } : undefined);
603
+ await pushAnswer(() => sendError(res, 409, "import_in_flight", "an import is already in flight for this session"
604
+ + (retryAfterSec !== undefined ? ` (a stalled holder is taken over after ${staleSec}s of inactivity; retry in ~${retryAfterSec}s)` : ""), retryAfterSec !== undefined ? { retryAfterSec } : undefined));
605
+ return;
606
+ }
607
+ if (!(await stillAdmitted("push"))) {
608
+ sendError(res, 409, "conflict", "sync conflict");
519
609
  return;
520
610
  }
521
611
  const token = newStagingToken();
@@ -524,7 +614,7 @@ export async function handleSessionSync(req, res, match, ctx) {
524
614
  importLeases.set(leaseKey, { at: Date.now(), stagingId, sessionId });
525
615
  pendingStagings.set(stagingId, {
526
616
  handle, realSessionId: sessionId, owner: importingPrincipal, ...(resolution ? { resolution } : {}), operatorOk,
527
- fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: ownerKeyOf(scope.gateOwner), expectedOwner: owner, leaseKey,
617
+ fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: ownerKeyOf(scope.gateOwner), expectedOccupant: gateFace, leaseKey, visible,
528
618
  });
529
619
  sendJson(res, 200, { stagingId, relation: relA.relation });
530
620
  return;
@@ -610,19 +700,22 @@ export async function handleSessionSync(req, res, match, ctx) {
610
700
  return;
611
701
  throw e;
612
702
  }
613
- let mayPushAtCommit;
703
+ let gateAtCommit;
614
704
  let activeAtCommit;
705
+ let activeStillAdmitted = true;
615
706
  try {
616
- const gateAtCommit = await judgeSessionGate();
617
- mayPushAtCommit = gateAtCommit.mayPush;
618
- activeAtCommit = mayPushAtCommit ? await activityOf(gateAtCommit.face) : undefined;
707
+ gateAtCommit = await judgeSessionGate();
708
+ const atCommit = gateAtCommit.occupant;
709
+ activeAtCommit = gateAtCommit.mayPush && atCommit !== undefined ? await activityOf(gateAtCommit.face) : undefined;
710
+ if (activeAtCommit !== undefined && atCommit !== undefined)
711
+ activeStillAdmitted = await recheckSyncGate(sessionStorage, sessionId, atCommit, "push");
619
712
  }
620
713
  catch (e) {
621
714
  await pending.handle.abort().catch(() => undefined);
622
715
  cleanupStaging(stagingId);
623
716
  throw e;
624
717
  }
625
- if (!mayPushAtCommit) {
718
+ if (!gateAtCommit.mayPush) {
626
719
  await pending.handle.abort().catch(() => undefined);
627
720
  cleanupStaging(stagingId);
628
721
  sendSessionAbsent("not_visible");
@@ -631,37 +724,44 @@ export async function handleSessionSync(req, res, match, ctx) {
631
724
  if (activeAtCommit !== undefined) {
632
725
  await pending.handle.abort().catch(() => undefined);
633
726
  cleanupStaging(stagingId);
727
+ if (!activeStillAdmitted) {
728
+ sendError(res, 409, "conflict", "sync conflict");
729
+ return;
730
+ }
634
731
  sendActivity(activeAtCommit, "streamed");
635
732
  return;
636
733
  }
637
734
  try {
638
- const committed = await pending.handle.commit(pending.owner, { expectedOwner: pending.expectedOwner, ...(pending.resolution ? { resolution: pending.resolution } : {}) });
639
- if (pending.resolution === "overwrite-dst" && (committed.relation === "fork" || committed.relation === "stale")) {
640
- await wipeSessionAttendants({ fileHistoryStore: historyStore, sessionPolicyStore: deps.sessionPolicyStore, resumeAnchorStore: deps.resumeAnchorStore }, sessionId);
641
- }
642
- if (pending.fileHistory !== null && canReplayHistory) {
643
- const failed = await replayHistory(pending.fileHistory, pending.resolution === "overwrite-dst");
644
- if (failed !== undefined) {
645
- sendFileHistoryReplayFailure(res, failed);
646
- cleanupStaging(stagingId);
647
- return;
648
- }
649
- }
650
- const policyStore = deps.sessionPolicyStore;
651
- if (policyStore)
652
- await replayPolicyRecords(policyStore, sessionId, pending.policy, pending.operatorOk);
653
- const anchorStore = deps.resumeAnchorStore;
654
- if (anchorStore)
655
- for (const a of pending.anchors)
656
- await anchorStore.put(sessionId, a.eventId, a.entryId, pending.owner);
657
- const rowLanded = await replaySessionRow(pending.row, committed.face);
735
+ const attendantsB = backend.landedAttendants();
736
+ const committed = await pending.handle.commit(pending.owner, { expectedOccupant: pending.expectedOccupant, ...(pending.resolution ? { resolution: pending.resolution } : {}) });
658
737
  sessionStorage.evict?.(sessionId);
738
+ const landedB = await landAttendants(attendantsB, committed.face, {
739
+ wipe: pending.resolution === "overwrite-dst" && (committed.relation === "fork" || committed.relation === "stale"),
740
+ fileHistory: pending.fileHistory,
741
+ getBlob: pending.visible.get,
742
+ allowReplace: pending.resolution === "overwrite-dst",
743
+ policy: pending.policy,
744
+ operator: pending.operatorOk,
745
+ anchors: pending.anchors,
746
+ owner: pending.owner,
747
+ row: pending.row,
748
+ });
659
749
  cleanupStaging(stagingId);
660
- if (!rowLanded) {
661
- sendError(res, 409, "conflict", "sync conflict");
662
- return;
750
+ switch (landedB.kind) {
751
+ case "landed":
752
+ sendJson(res, 200, { relation: committed.relation });
753
+ return;
754
+ case "gone":
755
+ sendLandedOccupantGone("commit", landedB.leg, committed.face);
756
+ return;
757
+ case "history_failed":
758
+ sendFileHistoryReplayFailure(res, landedB.failure);
759
+ return;
760
+ default: {
761
+ const unhandled = landedB;
762
+ throw new Error(`session sync: unknown landing answer ${JSON.stringify(unhandled)}`);
763
+ }
663
764
  }
664
- sendJson(res, 200, { relation: committed.relation });
665
765
  }
666
766
  catch (e) {
667
767
  await pending.handle.abort().catch(() => undefined);
@@ -700,9 +800,17 @@ export async function handleSessionSync(req, res, match, ctx) {
700
800
  sendError(res, 400, "request.field_invalid", "entryIds must be an array of strings");
701
801
  return;
702
802
  }
703
- const dst = await sessionStorage.exportEntries(sessionId);
803
+ const dst = gate.occupant === undefined ? null : await sessionStorage.exportEntries(sessionId);
704
804
  const relation = classifySyncRelationshipByIds(body.entryIds, dst ? dst.map((e) => e.id) : null);
805
+ if (gate.occupant === undefined) {
806
+ sendJson(res, 200, relation);
807
+ return;
808
+ }
705
809
  const refusal = await firstPhaseRefusal(sessionStorage, sessionId, relation.relation, false);
810
+ if (!(await stillAdmitted("push"))) {
811
+ sendError(res, 409, "conflict", "sync conflict");
812
+ return;
813
+ }
706
814
  if (refusal?.kind === "stamped") {
707
815
  if (sendSessionError(res, refusal.error, "import"))
708
816
  return;
@@ -771,14 +879,6 @@ function sendFileHistoryReplayFailure(res, failure) {
771
879
  const { code, permanence } = failure.error;
772
880
  sendError(res, 422, code, `file history import failed (${code})`, permanence === undefined ? undefined : { permanence });
773
881
  }
774
- async function firstMissingBlob(blobFaces, referenced) {
775
- if (referenced.length === 0)
776
- return undefined;
777
- if (!blobFaces.available)
778
- return referenced[0];
779
- const present = await blobFaces.blobExchange.has(referenced);
780
- return referenced.find((h) => !present.has(h));
781
- }
782
882
  function sendSessionSyncUnavailable(res, why) {
783
883
  switch (why) {
784
884
  case "store_backend_absent":
@@ -791,9 +891,6 @@ function sendSessionSyncUnavailable(res, why) {
791
891
  case "session_import_staging_absent":
792
892
  sendError(res, 501, "capability.session_store_required", "staged session import requires a durable session store");
793
893
  return;
794
- case "file_history_store_absent":
795
- sendError(res, 501, "capability.snapshot_store_required", "session sync is not available on this deployment: no file-history store is wired, so there is no file history to export or import");
796
- return;
797
894
  case "policy_purge_absent":
798
895
  sendError(res, 501, "capability.policy_purge_required", "session sync is not available on this deployment: the session-policy store has no deleteBySession purge verb, so an overwrite-dst import could not wipe the destination's stale policy rows. Every in-tree policy store carries it since core 1.423 — upgrade the policy store");
799
896
  return;
@@ -1,8 +1,9 @@
1
1
  import { isUuidV7 } from "../../security.js";
2
2
  import { sendJson, sendError } from "../send.js";
3
3
  import { sendUnauthorized } from "../principal-gate.js";
4
- import { routeListFilter } from "../owner-access.js";
4
+ import { listOwnerOf, listVisibleSessions, routeListFilter } from "../owner-access.js";
5
5
  import { filterFingerprint } from "../cursor-fingerprint.js";
6
+ import { SESSION_KINDS, isSessionKind } from "../../session-kind.js";
6
7
  import { sessionTempoOfRunStatus } from "../../plugins/store-contracts.js";
7
8
  import { assertNever } from "../route-ctx.js";
8
9
  import { PRINCIPAL_MAX_BYTES } from "../../principal-shape.js";
@@ -21,8 +22,7 @@ export async function handleSessionsList(req, res, match, ctx) {
21
22
  sendError(res, 501, "capability.session_store_required", "session list requires a durable session store (DB_BACKEND=mysql|pg|local)");
22
23
  return;
23
24
  }
24
- const lister = listing.lister;
25
- await handleSessionList(res, lister, new URLSearchParams(match.search), gateOwner, includeUnowned);
25
+ await handleSessionList(res, listing.lister, new URLSearchParams(match.search), { fleetWide, gateOwner, includeUnowned });
26
26
  return;
27
27
  }
28
28
  case "sendfile-links": {
@@ -109,18 +109,24 @@ function decodeSessionCursor(s, expectF) {
109
109
  return undefined;
110
110
  }
111
111
  }
112
- async function handleSessionList(res, lister, query, forceOwner, includeUnowned = false) {
113
- const owner = forceOwner != null ? forceOwner : (query.get("owner") ?? undefined);
112
+ async function handleSessionList(res, lister, query, filter) {
113
+ const kindRaw = query.get("sessionKind");
114
+ if (kindRaw !== null && !isSessionKind(kindRaw)) {
115
+ sendError(res, 400, "request.query_invalid", `sessionKind must be one of ${SESSION_KINDS.map((w) => JSON.stringify(w)).join(" | ")} when present (absent = the default view: top-level sessions only)`);
116
+ return;
117
+ }
118
+ const sessionKind = kindRaw ?? undefined;
119
+ const owner = listOwnerOf(filter, query.get("owner") ?? undefined);
114
120
  const limit = Math.min(100, Math.max(1, Number(query.get("limit") ?? 50) || 50));
115
121
  const qRaw = (query.get("q") ?? "").trim();
116
122
  const q = qRaw ? qRaw.slice(0, 256) : undefined;
117
- const f = filterFingerprint([owner, includeUnowned, q]);
123
+ const f = filterFingerprint(sessionKind === undefined ? [owner, filter.includeUnowned, q] : [owner, filter.includeUnowned, q, sessionKind]);
118
124
  const cursor = decodeSessionCursor(query.get("cursor"), f);
119
125
  if (cursor === "mismatch") {
120
126
  sendError(res, 400, "request.cursor_filter_mismatch", "cursor was issued under a different filter (owner/q) — restart from the first page without a cursor");
121
127
  return;
122
128
  }
123
- const rows = await lister({ ...(owner !== undefined ? { owner } : {}), ...(includeUnowned ? { includeUnowned: true } : {}), ...(cursor ? { cursor } : {}), limit: limit + 1, ...(q ? { q } : {}) });
129
+ const rows = await listVisibleSessions(lister, filter, query.get("owner") ?? undefined, { ...(cursor ? { cursor } : {}), limit: limit + 1, ...(q ? { q } : {}), ...(sessionKind !== undefined ? { sessionKind } : {}) });
124
130
  const hasMore = rows.length > limit;
125
131
  const page = hasMore ? rows.slice(0, limit) : rows;
126
132
  const last = page[page.length - 1];