@sema-agent/server 7.149.0 → 7.151.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 (441) hide show
  1. package/MIGRATION.md +307 -9
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +92 -40
  5. package/deploy/sema-up/README.md +7 -1
  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 +1 -0
  14. package/deploy/sema-up/kube-up.sh +1 -1
  15. package/deploy/sema-up/lib/flagshape.sh +1 -1
  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/dist/adoption/import.js +3 -3
  19. package/dist/approval-ask-machine.d.ts +1 -1
  20. package/dist/approval-card.d.ts +3 -3
  21. package/dist/approval-gate-currency.d.ts +2 -2
  22. package/dist/audit.d.ts +1 -1
  23. package/dist/audit.js +2 -2
  24. package/dist/auth-bridge.d.ts +20 -0
  25. package/dist/auth-bridge.js +9 -0
  26. package/dist/background-session-reap.d.ts +2 -2
  27. package/dist/bake-runner/main.d.ts +4 -2
  28. package/dist/bind-host.d.ts +2 -3
  29. package/dist/bind-host.js +2 -4
  30. package/dist/boot/budget-tracing.js +1 -1
  31. package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
  32. package/dist/boot/deferred-sandbox-path-env.js +1 -2
  33. package/dist/boot/engine-lease.d.ts +5 -0
  34. package/dist/boot/engine-lease.js +1 -0
  35. package/dist/boot/execution-env.d.ts +8 -14
  36. package/dist/boot/execution-env.js +54 -17
  37. package/dist/boot/execution-lane.js +32 -5
  38. package/dist/boot/late-binds.d.ts +8 -4
  39. package/dist/boot/late-binds.js +7 -1
  40. package/dist/boot/memory-consolidation.d.ts +3 -2
  41. package/dist/boot/memory-consolidation.js +6 -6
  42. package/dist/boot/parked-revive-gate.d.ts +5 -5
  43. package/dist/boot/parked-revive-gate.js +2 -3
  44. package/dist/boot/reapers.d.ts +5 -0
  45. package/dist/boot/reapers.js +12 -1
  46. package/dist/boot/resolve-spec.d.ts +7 -8
  47. package/dist/boot/resolve-spec.js +80 -35
  48. package/dist/boot/retention-lane.d.ts +1 -1
  49. package/dist/boot/runner-deps.d.ts +9 -2
  50. package/dist/boot/runner-deps.js +3 -3
  51. package/dist/boot/session-age-out.d.ts +36 -0
  52. package/dist/boot/session-age-out.js +101 -0
  53. package/dist/boot/session-faces.d.ts +5 -14
  54. package/dist/boot/session-faces.js +28 -24
  55. package/dist/boot/stage-01-config.js +2 -0
  56. package/dist/boot/stage-03-store-backend.js +2 -2
  57. package/dist/boot/stage-05-execution-env.d.ts +5 -3
  58. package/dist/boot/stage-05-execution-env.js +2 -2
  59. package/dist/boot/stage-06-runners.d.ts +7 -4
  60. package/dist/boot/stage-06-runners.js +16 -8
  61. package/dist/boot/stage-07-capability-layer.d.ts +7 -4
  62. package/dist/boot/stage-07-capability-layer.js +3 -2
  63. package/dist/boot/stage-08-reapers.d.ts +7 -4
  64. package/dist/boot/stage-08-reapers.js +4 -2
  65. package/dist/boot/stage-09-leader.d.ts +11 -5
  66. package/dist/boot/stage-09-leader.js +12 -3
  67. package/dist/boot/stage-10-http-server.d.ts +44 -6
  68. package/dist/boot/stage-10-http-server.js +12 -10
  69. package/dist/boot/web-admin.d.ts +1 -1
  70. package/dist/boot/web-admin.js +3 -1
  71. package/dist/boot/workflow-orchestration.d.ts +7 -2
  72. package/dist/boot/workflow-orchestration.js +24 -7
  73. package/dist/bounded-rotation.d.ts +29 -0
  74. package/dist/bounded-rotation.js +24 -0
  75. package/dist/capability-facts.d.ts +84 -66
  76. package/dist/capability-facts.js +58 -41
  77. package/dist/center-credential.d.ts +25 -6
  78. package/dist/center-credential.js +25 -5
  79. package/dist/config-catalog.d.ts +26 -7
  80. package/dist/config-catalog.js +15 -12
  81. package/dist/config-invariants.d.ts +2 -1
  82. package/dist/config-invariants.js +4 -4
  83. package/dist/config-types.d.ts +22 -15
  84. package/dist/config.d.ts +51 -2
  85. package/dist/config.js +35 -24
  86. package/dist/deployment-governance.d.ts +7 -28
  87. package/dist/deployment-governance.js +1 -14
  88. package/dist/deployment-shape.d.ts +9 -1
  89. package/dist/deployment-shape.js +2 -1
  90. package/dist/device-protocol.d.ts +5 -4
  91. package/dist/device-protocol.js +1 -1
  92. package/dist/device-ws-hub.d.ts +1 -0
  93. package/dist/device-ws-hub.js +66 -29
  94. package/dist/device-ws-protocol.d.ts +79 -12
  95. package/dist/device-ws-protocol.js +64 -26
  96. package/dist/engine-identity.d.ts +23 -5
  97. package/dist/engine-identity.js +13 -0
  98. package/dist/entry-mode-clamp-notice.d.ts +2 -1
  99. package/dist/execution-env-refusal.d.ts +23 -0
  100. package/dist/execution-env-refusal.js +5 -0
  101. package/dist/execution-lane-caps.d.ts +3 -1
  102. package/dist/field-conflict.d.ts +3 -3
  103. package/dist/file-history-capture.d.ts +11 -4
  104. package/dist/file-history-capture.js +9 -6
  105. package/dist/file-history-disclosure.d.ts +7 -5
  106. package/dist/file-history-disclosure.js +7 -5
  107. package/dist/fleet/drain-entry.d.ts +4 -0
  108. package/dist/fleet/engine-signal.d.ts +14 -1
  109. package/dist/fleet/engine-signal.js +5 -1
  110. package/dist/fleet/fleet-reconciler.d.ts +1 -1
  111. package/dist/fleet/serving-lease.d.ts +18 -3
  112. package/dist/fleet/serving-lease.js +81 -35
  113. package/dist/fleet-client.d.ts +13 -11
  114. package/dist/fleet-client.js +53 -33
  115. package/dist/history-anchor.js +1 -1
  116. package/dist/hitl-delivery.d.ts +1 -3
  117. package/dist/hitl-delivery.js +1 -1
  118. package/dist/hooks/hook-runner.js +2 -2
  119. package/dist/host-lsp-manager.d.ts +2 -2
  120. package/dist/http/active-run-conflict.d.ts +3 -7
  121. package/dist/http/active-run-conflict.js +2 -2
  122. package/dist/http/admission.js +19 -4
  123. package/dist/http/approval-sweeps.js +7 -6
  124. package/dist/http/caller-trust.d.ts +2 -2
  125. package/dist/http/caller-trust.js +3 -3
  126. package/dist/http/checkpoint-ctx.d.ts +20 -63
  127. package/dist/http/checkpoint-ctx.js +2 -24
  128. package/dist/http/claim-heartbeat.d.ts +4 -4
  129. package/dist/http/claim-heartbeat.js +3 -3
  130. package/dist/http/dispatch.d.ts +2 -1
  131. package/dist/http/dispatch.js +36 -29
  132. package/dist/http/durable-run-leg.js +17 -17
  133. package/dist/http/health-self-report.d.ts +9 -1
  134. package/dist/http/health-self-report.js +2 -0
  135. package/dist/http/owner-access.d.ts +264 -20
  136. package/dist/http/owner-access.js +215 -5
  137. package/dist/http/readiness.d.ts +4 -2
  138. package/dist/http/resume-ctx-read.js +38 -1
  139. package/dist/http/resume-legs.d.ts +2 -1
  140. package/dist/http/resume-legs.js +273 -89
  141. package/dist/http/route-ctx.d.ts +41 -19
  142. package/dist/http/route-table.d.ts +1 -1
  143. package/dist/http/routes/a2a-serve.js +15 -14
  144. package/dist/http/routes/admin-memory-optout.d.ts +1 -1
  145. package/dist/http/routes/agents-roster.js +2 -3
  146. package/dist/http/routes/approvals-assistant.d.ts +3 -2
  147. package/dist/http/routes/approvals-assistant.js +12 -12
  148. package/dist/http/routes/background.d.ts +3 -3
  149. package/dist/http/routes/capabilities.js +10 -6
  150. package/dist/http/routes/config-catalog.d.ts +1 -1
  151. package/dist/http/routes/fleet.js +10 -8
  152. package/dist/http/routes/mcp-reconnect.js +2 -2
  153. package/dist/http/routes/memory-origin.d.ts +1 -1
  154. package/dist/http/routes/notify-wake.js +2 -3
  155. package/dist/http/routes/projects.d.ts +4 -2
  156. package/dist/http/routes/projects.js +7 -6
  157. package/dist/http/routes/retention-ops.d.ts +1 -1
  158. package/dist/http/routes/run-permission-mode.d.ts +1 -1
  159. package/dist/http/routes/run-permission-mode.js +2 -2
  160. package/dist/http/routes/runs.d.ts +1 -1
  161. package/dist/http/routes/runs.js +125 -66
  162. package/dist/http/routes/session-memory-sync.js +4 -5
  163. package/dist/http/routes/session-sync.d.ts +4 -3
  164. package/dist/http/routes/session-sync.js +174 -83
  165. package/dist/http/routes/sessions-list.js +13 -7
  166. package/dist/http/routes/sessions.d.ts +1 -1
  167. package/dist/http/routes/sessions.js +26 -48
  168. package/dist/http/routes/tasks.js +38 -23
  169. package/dist/http/routes/trace-usage.js +14 -14
  170. package/dist/http/routes/workflows.d.ts +1 -0
  171. package/dist/http/routes/workflows.js +20 -38
  172. package/dist/http/server.d.ts +28 -30
  173. package/dist/http/server.js +7 -3
  174. package/dist/http/stored-body-replay.d.ts +3 -24
  175. package/dist/http/stored-body-replay.js +2 -12
  176. package/dist/http/submit-ctx.d.ts +1 -2
  177. package/dist/http/submit-ctx.js +8 -6
  178. package/dist/http/submit-replay.d.ts +15 -2
  179. package/dist/http/submit-replay.js +10 -4
  180. package/dist/http/wire-types.d.ts +19 -6
  181. package/dist/identity-source.d.ts +20 -3
  182. package/dist/identity-source.js +14 -0
  183. package/dist/index.d.ts +4 -0
  184. package/dist/lane-home-probe.d.ts +3 -7
  185. package/dist/lane-home-probe.js +0 -1
  186. package/dist/leader/endpoint.js +9 -8
  187. package/dist/leader/leader.d.ts +2 -1
  188. package/dist/leg-facts.d.ts +19 -5
  189. package/dist/leg-facts.js +3 -1
  190. package/dist/mcp-authorization-face.d.ts +18 -14
  191. package/dist/mcp-authorization-face.js +3 -2
  192. package/dist/memory-scope.d.ts +5 -4
  193. package/dist/memory-scope.js +4 -4
  194. package/dist/memory-store-refusal.d.ts +1 -1
  195. package/dist/memory-sync-client.d.ts +30 -2
  196. package/dist/memory-sync-client.js +16 -9
  197. package/dist/observability/corrupt-read-seat.d.ts +1 -1
  198. package/dist/observability/err-text.d.ts +7 -0
  199. package/dist/observability/err-text.js +5 -0
  200. package/dist/observability/fail-open.d.ts +12 -8
  201. package/dist/observability/fail-open.js +12 -8
  202. package/dist/observability/logger.d.ts +7 -0
  203. package/dist/observability/logger.js +3 -1
  204. package/dist/observability/metrics.js +1 -0
  205. package/dist/observability/run-terminal.d.ts +1 -1
  206. package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
  207. package/dist/orchestration/workflow-notify-journal.js +12 -1
  208. package/dist/orchestration/workflow-park-decision.d.ts +70 -18
  209. package/dist/orchestration/workflow-park-decision.js +49 -10
  210. package/dist/orchestration/workflow-park-holder.d.ts +65 -0
  211. package/dist/orchestration/workflow-park-holder.js +98 -0
  212. package/dist/orchestration/workflow-record-fence.d.ts +36 -0
  213. package/dist/orchestration/workflow-record-fence.js +42 -0
  214. package/dist/owner-faces.d.ts +28 -4
  215. package/dist/owner-faces.js +2 -0
  216. package/dist/parked-decide.d.ts +104 -53
  217. package/dist/parked-decide.js +153 -117
  218. package/dist/peer-directory.d.ts +2 -2
  219. package/dist/peer-inbound-face.d.ts +2 -6
  220. package/dist/peer-inbound-face.js +0 -3
  221. package/dist/peer-seat.d.ts +1 -1
  222. package/dist/peer-seat.js +52 -59
  223. package/dist/permission-mode-admission.d.ts +41 -5
  224. package/dist/permission-mode-admission.js +29 -3
  225. package/dist/plugins/adoption-log-sql.d.ts +3 -1
  226. package/dist/plugins/adoption-log-sql.js +7 -1
  227. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  228. package/dist/plugins/approval-ask-store-file.js +8 -0
  229. package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
  230. package/dist/plugins/approval-ask-store-memory.js +28 -9
  231. package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
  232. package/dist/plugins/approval-ask-store-sql.js +34 -5
  233. package/dist/plugins/approval-exemption-store.js +3 -0
  234. package/dist/plugins/approval-nonce-store.js +2 -0
  235. package/dist/plugins/breaker-state-sql.js +2 -0
  236. package/dist/plugins/caching-session-store.d.ts +9 -15
  237. package/dist/plugins/caching-session-store.js +6 -0
  238. package/dist/plugins/device-store-sql.js +6 -0
  239. package/dist/plugins/error-origin.d.ts +18 -0
  240. package/dist/plugins/error-origin.js +10 -0
  241. package/dist/plugins/exec-path-law.d.ts +34 -0
  242. package/dist/plugins/exec-path-law.js +13 -0
  243. package/dist/plugins/execution-placement-sql.js +6 -6
  244. package/dist/plugins/file-run-store.js +1 -1
  245. package/dist/plugins/image-bake-store-sql.js +6 -0
  246. package/dist/plugins/image-index-sql.js +4 -0
  247. package/dist/plugins/landed-attendants.d.ts +212 -0
  248. package/dist/plugins/landed-attendants.js +161 -0
  249. package/dist/plugins/leader-run-store-sql.js +4 -0
  250. package/dist/plugins/local-checkpoint-store.d.ts +4 -1
  251. package/dist/plugins/local-checkpoint-store.js +3 -0
  252. package/dist/plugins/local-session-live-reference.d.ts +40 -0
  253. package/dist/plugins/local-session-live-reference.js +39 -0
  254. package/dist/plugins/local-session-store.d.ts +71 -33
  255. package/dist/plugins/local-session-store.js +129 -27
  256. package/dist/plugins/memory-engine-pg.js +4 -0
  257. package/dist/plugins/memory-engine-sql-apply.js +5 -2
  258. package/dist/plugins/memory-engine-tidb.js +4 -0
  259. package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
  260. package/dist/plugins/memory-run-store.js +1 -1
  261. package/dist/plugins/memory-sync-store-pg.js +5 -0
  262. package/dist/plugins/memory-sync-store-tidb.js +5 -0
  263. package/dist/plugins/one-time-migrations.d.ts +80 -61
  264. package/dist/plugins/one-time-migrations.js +241 -104
  265. package/dist/plugins/org-delivery-quota-store.js +4 -1
  266. package/dist/plugins/outcome-ledger-sql.js +2 -0
  267. package/dist/plugins/permission-rule-store-sql.js +11 -4
  268. package/dist/plugins/pg-cost-quota.js +4 -0
  269. package/dist/plugins/pg-pool.js +28 -1
  270. package/dist/plugins/pg-rate-limiter.js +2 -0
  271. package/dist/plugins/posix-shell-fs.d.ts +6 -1
  272. package/dist/plugins/posix-shell-fs.js +8 -3
  273. package/dist/plugins/remote-env-adb.d.ts +19 -15
  274. package/dist/plugins/remote-env-adb.js +44 -17
  275. package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
  276. package/dist/plugins/remote-env-connect-seat.js +72 -0
  277. package/dist/plugins/remote-env-device.d.ts +22 -5
  278. package/dist/plugins/remote-env-device.js +114 -14
  279. package/dist/plugins/remote-env-e2b.d.ts +18 -7
  280. package/dist/plugins/remote-env-e2b.js +53 -40
  281. package/dist/plugins/remote-env-file-error.js +6 -2
  282. package/dist/plugins/remote-env-host.d.ts +18 -1
  283. package/dist/plugins/remote-env-host.js +48 -47
  284. package/dist/plugins/remote-env-k8s.d.ts +41 -39
  285. package/dist/plugins/remote-env-k8s.js +56 -32
  286. package/dist/plugins/remote-env-local-docker.d.ts +13 -8
  287. package/dist/plugins/remote-env-local-docker.js +37 -43
  288. package/dist/plugins/remote-env-ssh.d.ts +18 -12
  289. package/dist/plugins/remote-env-ssh.js +64 -62
  290. package/dist/plugins/remote-shell.d.ts +101 -2
  291. package/dist/plugins/remote-shell.js +221 -3
  292. package/dist/plugins/replica-registration.d.ts +35 -0
  293. package/dist/plugins/replica-registration.js +48 -0
  294. package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
  295. package/dist/plugins/resume-anchor-store-sql.js +12 -5
  296. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  297. package/dist/plugins/retention-lane-store-sql.js +4 -0
  298. package/dist/plugins/retention-sql.d.ts +20 -2
  299. package/dist/plugins/retention-sql.js +11 -0
  300. package/dist/plugins/run-store-sql.d.ts +22 -3
  301. package/dist/plugins/run-store-sql.js +33 -9
  302. package/dist/plugins/scenario-prefix-switch-m42.d.ts +6 -12
  303. package/dist/plugins/scenario-prefix-switch-m42.js +7 -5
  304. package/dist/plugins/schema-consistency.d.ts +9 -5
  305. package/dist/plugins/schema-consistency.js +48 -18
  306. package/dist/plugins/schema-drift-sentence.js +1 -1
  307. package/dist/plugins/send-file-ledger.js +3 -0
  308. package/dist/plugins/serving-requirement.d.ts +68 -0
  309. package/dist/plugins/serving-requirement.js +60 -0
  310. package/dist/plugins/session-birth.d.ts +6 -2
  311. package/dist/plugins/session-capture-record-store-sql.js +2 -0
  312. package/dist/plugins/session-ext-table.d.ts +14 -1
  313. package/dist/plugins/session-ext-table.js +5 -1
  314. package/dist/plugins/session-row-sql.d.ts +49 -2
  315. package/dist/plugins/session-row-sql.js +56 -13
  316. package/dist/plugins/session-store-sql.d.ts +34 -18
  317. package/dist/plugins/session-store-sql.js +98 -17
  318. package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
  319. package/dist/plugins/shared-memory-store-sql.js +6 -2
  320. package/dist/plugins/sql-driver.d.ts +2 -1
  321. package/dist/plugins/sql-driver.js +18 -3
  322. package/dist/plugins/sql-errors.d.ts +11 -6
  323. package/dist/plugins/sql-errors.js +5 -6
  324. package/dist/plugins/stop-then-start-sentence.d.ts +48 -3
  325. package/dist/plugins/stop-then-start-sentence.js +48 -0
  326. package/dist/plugins/stop-then-start.d.ts +109 -0
  327. package/dist/plugins/stop-then-start.js +104 -0
  328. package/dist/plugins/store-backend.d.ts +40 -13
  329. package/dist/plugins/store-backend.js +169 -27
  330. package/dist/plugins/store-boundary.d.ts +57 -0
  331. package/dist/plugins/store-boundary.js +139 -0
  332. package/dist/plugins/store-contracts.d.ts +29 -2
  333. package/dist/plugins/store-contracts.js +3 -0
  334. package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
  335. package/dist/plugins/store-fault-sentence-m53.js +25 -0
  336. package/dist/plugins/store-fault.d.ts +26 -7
  337. package/dist/plugins/store-fault.js +18 -2
  338. package/dist/plugins/task-attachment-store.js +9 -0
  339. package/dist/plugins/task-list-store-sql.d.ts +2 -2
  340. package/dist/plugins/task-list-store-sql.js +10 -8
  341. package/dist/plugins/tidb-cost-quota.js +4 -0
  342. package/dist/plugins/tidb-pool.js +6 -1
  343. package/dist/plugins/tidb-rate-limiter.js +4 -0
  344. package/dist/plugins/user-input-ledger-sql.js +4 -0
  345. package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
  346. package/dist/plugins/workflow-run-store-sql.js +64 -4
  347. package/dist/plugins/workspace-fill.d.ts +4 -7
  348. package/dist/plugins/workspace-fill.js +2 -1
  349. package/dist/plugins/write-behind-counter.js +5 -0
  350. package/dist/process-instance.d.ts +3 -0
  351. package/dist/process-instance.js +7 -0
  352. package/dist/project-context.d.ts +64 -0
  353. package/dist/project-context.js +66 -0
  354. package/dist/project-registry.d.ts +46 -0
  355. package/dist/project-registry.js +44 -0
  356. package/dist/question.d.ts +9 -21
  357. package/dist/question.js +28 -19
  358. package/dist/request-key-closure.js +1 -1
  359. package/dist/request-value-closure.d.ts +4 -0
  360. package/dist/request-value-closure.js +10 -0
  361. package/dist/run-acceptance.d.ts +3 -2
  362. package/dist/run-acceptance.js +4 -6
  363. package/dist/run-cancel-card.d.ts +1 -1
  364. package/dist/run-cancel-card.js +2 -1
  365. package/dist/run-local.js +1 -0
  366. package/dist/runs.d.ts +37 -8
  367. package/dist/runs.js +53 -12
  368. package/dist/runtime-governance.d.ts +5 -4
  369. package/dist/security.d.ts +31 -33
  370. package/dist/security.js +41 -7
  371. package/dist/server-secret-env.d.ts +12 -10
  372. package/dist/server-secret-env.js +24 -15
  373. package/dist/session-agent.d.ts +1 -10
  374. package/dist/session-agent.js +0 -6
  375. package/dist/session-bindings.d.ts +82 -0
  376. package/dist/session-bindings.js +18 -0
  377. package/dist/session-children-retire.d.ts +2 -2
  378. package/dist/session-children-retire.js +2 -6
  379. package/dist/session-deletion.d.ts +16 -1
  380. package/dist/session-error-wire.d.ts +3 -3
  381. package/dist/session-error-wire.js +3 -3
  382. package/dist/session-incarnation.d.ts +28 -4
  383. package/dist/session-incarnation.js +14 -2
  384. package/dist/session-kind.d.ts +57 -0
  385. package/dist/session-kind.js +22 -0
  386. package/dist/session-notify-door.d.ts +4 -4
  387. package/dist/session-notify-door.js +5 -6
  388. package/dist/session-row.d.ts +21 -1
  389. package/dist/session-row.js +7 -1
  390. package/dist/session-rules-seat.d.ts +4 -3
  391. package/dist/session-rules-seat.js +3 -11
  392. package/dist/session-sync-kernel.d.ts +24 -14
  393. package/dist/session-sync-kernel.js +3 -6
  394. package/dist/session-sync.d.ts +4 -98
  395. package/dist/session-sync.js +4 -74
  396. package/dist/session-titler.d.ts +10 -3
  397. package/dist/session-titler.js +19 -6
  398. package/dist/ssh-host-key.d.ts +5 -0
  399. package/dist/ssh-host-key.js +3 -0
  400. package/dist/stores-sql/checkpoint-store-sql.d.ts +21 -2
  401. package/dist/stores-sql/checkpoint-store-sql.js +106 -18
  402. package/dist/stores-sql/file-history-store-sql.d.ts +52 -2
  403. package/dist/stores-sql/file-history-store-sql.js +108 -70
  404. package/dist/stores-sql/pg-session-storage.d.ts +34 -7
  405. package/dist/stores-sql/pg-session-storage.js +37 -13
  406. package/dist/stores-sql/retention-store-sql.d.ts +2 -10
  407. package/dist/stores-sql/retention-store-sql.js +2 -10
  408. package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
  409. package/dist/stores-sql/session-policy-store-sql.js +61 -44
  410. package/dist/stores-sql/session-write-hooks.d.ts +11 -0
  411. package/dist/stores-sql/tidb-session-store.d.ts +58 -7
  412. package/dist/stores-sql/tidb-session-store.js +37 -13
  413. package/dist/submission-exit.d.ts +3 -2
  414. package/dist/submission-exit.js +9 -1
  415. package/dist/task-cwd.d.ts +6 -5
  416. package/dist/task-settings.d.ts +19 -5
  417. package/dist/task-settings.js +13 -7
  418. package/dist/terminal.d.ts +33 -2
  419. package/dist/terminal.js +139 -9
  420. package/dist/tool-approval.d.ts +147 -12
  421. package/dist/tool-approval.js +206 -109
  422. package/dist/trace/engine-notice-wire.d.ts +14 -0
  423. package/dist/trace/engine-notice-wire.js +18 -1
  424. package/dist/trace/project.d.ts +4 -3
  425. package/dist/trace/project.js +3 -2
  426. package/dist/trace/projection-table.d.ts +33 -2
  427. package/dist/trace/self-minted-wire.d.ts +422 -26
  428. package/dist/trace/self-minted-wire.js +149 -23
  429. package/dist/trace/tool-card.d.ts +3 -0
  430. package/dist/trace/tool-card.js +24 -0
  431. package/dist/trace/tool-output-media.d.ts +2 -1
  432. package/dist/unattended-permission-mode.d.ts +1 -1
  433. package/dist/web-admin-client/apply-effective.d.ts +1 -1
  434. package/dist/web-admin-client/effective-keys.d.ts +1 -1
  435. package/dist/web-admin-client/skills-mcp.d.ts +1 -1
  436. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +120 -41
  437. package/package.json +3 -3
  438. package/wire-changes/server@7.150.0.json +335 -0
  439. package/wire-changes/server@7.151.0.json +762 -0
  440. package/dist/http/session-inherit-env.d.ts +0 -36
  441. package/dist/http/session-inherit-env.js +0 -6
@@ -1,16 +1,16 @@
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, blobGetterOf, exportSessionManifest, exportedFileHistory } 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";
8
9
  import { sendJson, sendError, sendSessionError, sendSessionPolicyError, logRequestError, msg } from "../send.js";
9
10
  import { StampedSessionArchiveError } from "../../session-error-wire.js";
10
- import { readSessionAgent } from "../../session-agent.js";
11
11
  import { buildDisplaySafeUrl } from "../../trace/redact.js";
12
12
  import { storeFaultClassOf } from "../../plugins/store-fault.js";
13
- import { enter, judgeSession, refuse } from "../owner-access.js";
13
+ import { enter, readSessionAgent, readSyncGate, recheckSyncGate, refuse } from "../owner-access.js";
14
14
  import { listFilterOf, ownerKeyOf, sameKey } from "../../owner-faces.js";
15
15
  const SYNC_BLOB_MAX_BYTES = 64 * 1024 * 1024;
16
16
  const SYNC_NDJSON_LINE_MAX_BYTES = 8 * 1024 * 1024;
@@ -18,7 +18,7 @@ import { SHA256_HEX_RE } from "../../digest-form.js";
18
18
  import { assertNever } from "../route-ctx.js";
19
19
  import { readSessionRulesRecords, describeSessionRulesRecordProblem } from "../../session-policy-wire.js";
20
20
  import { readSessionPinned, readSessionTitle } from "../../session-row.js";
21
- import { deletionHeadReadOf, sessionFaceOfHead } from "../../session-incarnation.js";
21
+ import { incarnationLogPrefix, SessionOccupantChangedError } from "../../session-incarnation.js";
22
22
  import { defaultTaskRegistry } from "@sema-agent/core";
23
23
  import { SessionActiveRunError, SessionForkInProgressError, SessionWriterPresentError } from "../../execution-placement.js";
24
24
  import { probeSessionChildren, sessionTenantScope } from "../../session-children-retire.js";
@@ -94,10 +94,8 @@ export async function handleSessionSync(req, res, match, ctx) {
94
94
  return;
95
95
  }
96
96
  const judgeSessionGate = async () => {
97
- const face = sessionFaceOfHead(sessionId, await sessionStorage.headOf(sessionId));
98
- const held = face ?? sessionFaceOfHead(sessionId, await deletionHeadReadOf(sessionStorage)?.(sessionId));
99
- const mayTouch = held !== undefined && (await judgeSession(syncEntry, sessionStorage, sessionId, held)) !== undefined;
100
- return { face, occupant: held, mayPull: face !== undefined && mayTouch, mayPush: held === undefined || mayTouch };
97
+ const { face, occupant, mayTouch } = await readSyncGate(syncEntry, sessionStorage, sessionId);
98
+ return { face, occupant, mayPull: face !== undefined && mayTouch, mayPush: occupant === undefined || mayTouch };
101
99
  };
102
100
  let gate;
103
101
  try {
@@ -125,6 +123,33 @@ export async function handleSessionSync(req, res, match, ctx) {
125
123
  }
126
124
  return true;
127
125
  };
126
+ const stillAdmitted = async (port) => {
127
+ const admitted = port === "pull" ? gate.face : gate.occupant;
128
+ return admitted === undefined || (await recheckSyncGate(sessionStorage, sessionId, admitted, port));
129
+ };
130
+ const pullAnswer = async (send) => {
131
+ let same;
132
+ try {
133
+ same = await stillAdmitted("pull");
134
+ }
135
+ catch (e) {
136
+ if (sendPullUnreadable(req, res, deps.logger, e))
137
+ return;
138
+ throw e;
139
+ }
140
+ if (!same) {
141
+ sendSessionAbsent("missing");
142
+ return;
143
+ }
144
+ send();
145
+ };
146
+ const pushAnswer = async (send) => {
147
+ if (!(await stillAdmitted("push"))) {
148
+ sendError(res, 409, "conflict", "sync conflict");
149
+ return;
150
+ }
151
+ send();
152
+ };
128
153
  const replaySessionRow = async (row, face) => {
129
154
  if (Object.keys(row).length === 0)
130
155
  return true;
@@ -170,9 +195,28 @@ export async function handleSessionSync(req, res, match, ctx) {
170
195
  }
171
196
  };
172
197
  const canReplayHistory = fileHistoryImportFace(historyStore) !== undefined;
173
- const replayHistory = async (envelope, allowReplace) => {
174
- const r = await replayFileHistory(historyStore, sessionId, envelope, blobGetterOf(historyStore), { allowReplace });
175
- return r.ok ? undefined : r;
198
+ const landAttendants = async (attendants, landed, plan) => {
199
+ if (plan.wipe && !(await attendants.wipe(sessionId, landed)).landed)
200
+ return { kind: "gone", leg: "wipe" };
201
+ if (plan.fileHistory !== null && canReplayHistory) {
202
+ const h = await attendants.replayHistory(sessionId, landed, plan.fileHistory, blobGetterOf(historyStore), { allowReplace: plan.allowReplace });
203
+ if (!h.landed)
204
+ return { kind: "gone", leg: "file_history" };
205
+ if (!h.value.ok)
206
+ return { kind: "history_failed", failure: h.value };
207
+ }
208
+ if (plan.policy.length > 0 && !(await attendants.replayPolicy(sessionId, landed, plan.policy, plan.operator)).landed)
209
+ return { kind: "gone", leg: "policy" };
210
+ if (plan.anchors.length > 0 && !(await attendants.putAnchors(sessionId, landed, plan.anchors, plan.owner)).landed)
211
+ return { kind: "gone", leg: "anchors" };
212
+ if (!(await replaySessionRow(plan.row, landed)))
213
+ return { kind: "gone", leg: "row" };
214
+ return { kind: "landed" };
215
+ };
216
+ const sendLandedOccupantGone = (arm, leg, landed) => {
217
+ deps.logger?.warn?.("session_sync_landed_occupant_gone", { sessionId, arm, leg, landed: incarnationLogPrefix(landed.incarnation) });
218
+ deps.metrics?.inc("session_sync_landed_occupant_gone_total", { arm, leg }, 1);
219
+ sendError(res, 409, "conflict", "sync conflict");
176
220
  };
177
221
  if (match.decl.id === "session-sync-manifest") {
178
222
  if (!pullGateOk())
@@ -190,7 +234,7 @@ export async function handleSessionSync(req, res, match, ctx) {
190
234
  sendSessionAbsent("missing");
191
235
  return;
192
236
  }
193
- sendJson(res, 200, { manifest: out.manifest });
237
+ await pullAnswer(() => sendJson(res, 200, { manifest: out.manifest }));
194
238
  return;
195
239
  }
196
240
  if (match.decl.id === "session-sync-entries") {
@@ -206,9 +250,11 @@ export async function handleSessionSync(req, res, match, ctx) {
206
250
  }
207
251
  afterSeq = n;
208
252
  }
253
+ const recheck = async () => { if (!(await stillAdmitted("pull")))
254
+ throw new SessionOccupantChangedError(sessionId); };
209
255
  let it;
210
256
  try {
211
- it = await sessionStorage.exportEntriesStream(sessionId, afterSeq === undefined ? undefined : { afterSeq });
257
+ it = await sessionStorage.exportEntriesStream(sessionId, { ...(afterSeq === undefined ? {} : { afterSeq }), recheck });
212
258
  }
213
259
  catch (e) {
214
260
  if (sendPullUnreadable(req, res, deps.logger, e))
@@ -219,6 +265,19 @@ export async function handleSessionSync(req, res, match, ctx) {
219
265
  sendSessionAbsent("missing");
220
266
  return;
221
267
  }
268
+ let openSame;
269
+ try {
270
+ openSame = await stillAdmitted("pull");
271
+ }
272
+ catch (e) {
273
+ if (sendPullUnreadable(req, res, deps.logger, e))
274
+ return;
275
+ throw e;
276
+ }
277
+ if (!openSame) {
278
+ sendSessionAbsent("missing");
279
+ return;
280
+ }
222
281
  res.writeHead(200, { "content-type": "application/x-ndjson", "transfer-encoding": "chunked" });
223
282
  const write = async (line) => { if (!res.write(line))
224
283
  await once(res, "drain"); };
@@ -233,7 +292,10 @@ export async function handleSessionSync(req, res, match, ctx) {
233
292
  res.end();
234
293
  }
235
294
  catch (e) {
236
- deps.logger?.error?.("sync entries stream failed", { sessionId, count, error: msg(e) });
295
+ if (e instanceof SessionOccupantChangedError)
296
+ deps.logger?.info?.("session_sync_pull_occupant_changed", { sessionId, count });
297
+ else
298
+ deps.logger?.error?.("sync entries stream failed", { sessionId, count, error: msg(e) });
237
299
  res.end();
238
300
  }
239
301
  return;
@@ -268,7 +330,7 @@ export async function handleSessionSync(req, res, match, ctx) {
268
330
  }
269
331
  const referenced = envelope !== null && envelope.tracked.some((t) => t.versions.some((v) => v.blobHash === hash));
270
332
  if (!referenced) {
271
- sendError(res, 404, "not_found.blob", "blob not found");
333
+ await pullAnswer(() => sendError(res, 404, "not_found.blob", "blob not found"));
272
334
  return;
273
335
  }
274
336
  let bytes;
@@ -280,12 +342,15 @@ export async function handleSessionSync(req, res, match, ctx) {
280
342
  return;
281
343
  throw e;
282
344
  }
283
- if (!bytes) {
284
- sendError(res, 404, "not_found.blob", "blob not found");
345
+ const found = bytes;
346
+ if (!found) {
347
+ await pullAnswer(() => sendError(res, 404, "not_found.blob", "blob not found"));
285
348
  return;
286
349
  }
287
- res.writeHead(200, { "content-type": "application/octet-stream" });
288
- res.end(Buffer.from(bytes));
350
+ await pullAnswer(() => {
351
+ res.writeHead(200, { "content-type": "application/octet-stream" });
352
+ res.end(Buffer.from(found));
353
+ });
289
354
  return;
290
355
  }
291
356
  if (match.decl.id === "session-sync-blob-put") {
@@ -390,10 +455,14 @@ export async function handleSessionSync(req, res, match, ctx) {
390
455
  const entryIds = body.entryIds;
391
456
  const policy = policyRead.records;
392
457
  const anchors = anchorsRead.anchors;
393
- const dstIds = (await sessionStorage.listEntryIds?.(sessionId)) ?? null;
458
+ const dstIds = gate.occupant === undefined ? null : ((await sessionStorage.listEntryIds?.(sessionId)) ?? null);
394
459
  const relA = classifySyncRelationshipByIds(entryIds, dstIds);
395
460
  const refusalA = await firstPhaseRefusal(sessionStorage, sessionId, relA.relation, resolution === "overwrite-dst");
396
461
  if (refusalA !== undefined) {
462
+ if (!(await stillAdmitted("push"))) {
463
+ sendError(res, 409, "conflict", "sync conflict");
464
+ return;
465
+ }
397
466
  if (refusalA.kind === "stamped") {
398
467
  if (sendSessionError(res, refusalA.error, "import"))
399
468
  return;
@@ -409,7 +478,7 @@ export async function handleSessionSync(req, res, match, ctx) {
409
478
  if (v.blobHash !== null)
410
479
  distinct.add(v.blobHash);
411
480
  if (await firstMissingBlob(facts.sessionSyncFileHistory(deps), [...distinct]) !== undefined) {
412
- sendMissingBlob(res);
481
+ await pushAnswer(() => sendMissingBlob(res));
413
482
  return;
414
483
  }
415
484
  }
@@ -436,10 +505,10 @@ export async function handleSessionSync(req, res, match, ctx) {
436
505
  case "mirror":
437
506
  break;
438
507
  case "writer":
439
- sendSessionWriter(res);
508
+ await pushAnswer(() => sendSessionWriter(res));
440
509
  return;
441
510
  case "forking":
442
- sendError(res, 409, "conflict.fork_in_progress", new SessionForkInProgressError(sessionId).message);
511
+ await pushAnswer(() => sendError(res, 409, "conflict.fork_in_progress", new SessionForkInProgressError(sessionId).message));
443
512
  return;
444
513
  default: {
445
514
  const unknownRole = placed.cell;
@@ -447,12 +516,13 @@ export async function handleSessionSync(req, res, match, ctx) {
447
516
  }
448
517
  }
449
518
  }
450
- const activeNow = await activityOf(gateFace);
519
+ const activeNow = gate.occupant === undefined ? undefined : await activityOf(gateFace);
451
520
  if (activeNow !== undefined) {
452
- sendActivity(activeNow, "open");
521
+ await pushAnswer(() => sendActivity(activeNow, "open"));
453
522
  return;
454
523
  }
455
524
  if (relA.relation === "identical" && !digestSaysDiffer) {
525
+ const attendantsA = backend.landedAttendants();
456
526
  const seat = sessionStorage.executionPlacement;
457
527
  if (seat !== undefined) {
458
528
  if (gateFace === undefined) {
@@ -478,35 +548,38 @@ export async function handleSessionSync(req, res, match, ctx) {
478
548
  }
479
549
  }
480
550
  }
481
- if (fileHistory !== null && canReplayHistory) {
482
- const failed = await replayHistory(fileHistory, resolution === "overwrite-dst");
483
- if (failed !== undefined) {
484
- sendFileHistoryReplayFailure(res, failed);
551
+ if (gateFace === undefined) {
552
+ sendError(res, 409, "conflict", "sync conflict");
553
+ return;
554
+ }
555
+ let landedA;
556
+ try {
557
+ landedA = await landAttendants(attendantsA, gateFace, { wipe: false, fileHistory, allowReplace: resolution === "overwrite-dst", policy, operator: operatorOk, anchors, owner: importingPrincipal, row });
558
+ }
559
+ catch (e) {
560
+ if (sendSessionPolicyError(res, e))
485
561
  return;
486
- }
562
+ throw e;
487
563
  }
488
- if (deps.sessionPolicyStore) {
489
- try {
490
- await replayPolicyRecords(deps.sessionPolicyStore, sessionId, policy, operatorOk);
491
- }
492
- catch (e) {
493
- if (sendSessionPolicyError(res, e))
494
- return;
495
- throw e;
564
+ switch (landedA.kind) {
565
+ case "landed":
566
+ break;
567
+ case "gone":
568
+ sendLandedOccupantGone("identical", landedA.leg, gateFace);
569
+ return;
570
+ case "history_failed":
571
+ sendFileHistoryReplayFailure(res, landedA.failure);
572
+ return;
573
+ default: {
574
+ const unhandled = landedA;
575
+ throw new Error(`session sync: unknown landing answer ${JSON.stringify(unhandled)}`);
496
576
  }
497
577
  }
498
- if (deps.resumeAnchorStore)
499
- for (const a of anchors)
500
- await deps.resumeAnchorStore.put(sessionId, a.eventId, a.entryId, importingPrincipal);
501
- if (!(await replaySessionRow(row, gateFace))) {
502
- sendError(res, 409, "conflict", "sync conflict");
503
- return;
504
- }
505
- sendJson(res, 200, {
578
+ await pushAnswer(() => sendJson(res, 200, {
506
579
  relation: "identical",
507
580
  basis: payloadVerified ? "entry-ids+digest" : "entry-ids",
508
581
  payloadVerified,
509
- });
582
+ }));
510
583
  return;
511
584
  }
512
585
  const leaseKey = importLeaseKey(gate.occupant !== undefined ? gate.occupant.owner : importingPrincipal, sessionId);
@@ -518,8 +591,12 @@ export async function handleSessionSync(req, res, match, ctx) {
518
591
  const heldLease = importLeases.get(leaseKey);
519
592
  if (heldLease) {
520
593
  const retryAfterSec = staleMs > 0 ? Math.max(1, Math.ceil((staleMs - (Date.now() - heldLease.at)) / 1000)) : undefined;
521
- sendError(res, 409, "import_in_flight", "an import is already in flight for this session"
522
- + (retryAfterSec !== undefined ? ` (a stalled holder is taken over after ${staleSec}s of inactivity; retry in ~${retryAfterSec}s)` : ""), retryAfterSec !== undefined ? { retryAfterSec } : undefined);
594
+ await pushAnswer(() => sendError(res, 409, "import_in_flight", "an import is already in flight for this session"
595
+ + (retryAfterSec !== undefined ? ` (a stalled holder is taken over after ${staleSec}s of inactivity; retry in ~${retryAfterSec}s)` : ""), retryAfterSec !== undefined ? { retryAfterSec } : undefined));
596
+ return;
597
+ }
598
+ if (!(await stillAdmitted("push"))) {
599
+ sendError(res, 409, "conflict", "sync conflict");
523
600
  return;
524
601
  }
525
602
  const token = newStagingToken();
@@ -528,7 +605,7 @@ export async function handleSessionSync(req, res, match, ctx) {
528
605
  importLeases.set(leaseKey, { at: Date.now(), stagingId, sessionId });
529
606
  pendingStagings.set(stagingId, {
530
607
  handle, realSessionId: sessionId, owner: importingPrincipal, ...(resolution ? { resolution } : {}), operatorOk,
531
- fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: ownerKeyOf(scope.gateOwner), expectedOwner: owner, leaseKey,
608
+ fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: ownerKeyOf(scope.gateOwner), expectedOccupant: gateFace, leaseKey,
532
609
  });
533
610
  sendJson(res, 200, { stagingId, relation: relA.relation });
534
611
  return;
@@ -614,19 +691,22 @@ export async function handleSessionSync(req, res, match, ctx) {
614
691
  return;
615
692
  throw e;
616
693
  }
617
- let mayPushAtCommit;
694
+ let gateAtCommit;
618
695
  let activeAtCommit;
696
+ let activeStillAdmitted = true;
619
697
  try {
620
- const gateAtCommit = await judgeSessionGate();
621
- mayPushAtCommit = gateAtCommit.mayPush;
622
- activeAtCommit = mayPushAtCommit ? await activityOf(gateAtCommit.face) : undefined;
698
+ gateAtCommit = await judgeSessionGate();
699
+ const atCommit = gateAtCommit.occupant;
700
+ activeAtCommit = gateAtCommit.mayPush && atCommit !== undefined ? await activityOf(gateAtCommit.face) : undefined;
701
+ if (activeAtCommit !== undefined && atCommit !== undefined)
702
+ activeStillAdmitted = await recheckSyncGate(sessionStorage, sessionId, atCommit, "push");
623
703
  }
624
704
  catch (e) {
625
705
  await pending.handle.abort().catch(() => undefined);
626
706
  cleanupStaging(stagingId);
627
707
  throw e;
628
708
  }
629
- if (!mayPushAtCommit) {
709
+ if (!gateAtCommit.mayPush) {
630
710
  await pending.handle.abort().catch(() => undefined);
631
711
  cleanupStaging(stagingId);
632
712
  sendSessionAbsent("not_visible");
@@ -635,37 +715,43 @@ export async function handleSessionSync(req, res, match, ctx) {
635
715
  if (activeAtCommit !== undefined) {
636
716
  await pending.handle.abort().catch(() => undefined);
637
717
  cleanupStaging(stagingId);
718
+ if (!activeStillAdmitted) {
719
+ sendError(res, 409, "conflict", "sync conflict");
720
+ return;
721
+ }
638
722
  sendActivity(activeAtCommit, "streamed");
639
723
  return;
640
724
  }
641
725
  try {
642
- const committed = await pending.handle.commit(pending.owner, { expectedOwner: pending.expectedOwner, ...(pending.resolution ? { resolution: pending.resolution } : {}) });
643
- if (pending.resolution === "overwrite-dst" && (committed.relation === "fork" || committed.relation === "stale")) {
644
- await wipeSessionAttendants({ fileHistoryStore: historyStore, sessionPolicyStore: deps.sessionPolicyStore, resumeAnchorStore: deps.resumeAnchorStore }, sessionId);
645
- }
646
- if (pending.fileHistory !== null && canReplayHistory) {
647
- const failed = await replayHistory(pending.fileHistory, pending.resolution === "overwrite-dst");
648
- if (failed !== undefined) {
649
- sendFileHistoryReplayFailure(res, failed);
650
- cleanupStaging(stagingId);
651
- return;
652
- }
653
- }
654
- const policyStore = deps.sessionPolicyStore;
655
- if (policyStore)
656
- await replayPolicyRecords(policyStore, sessionId, pending.policy, pending.operatorOk);
657
- const anchorStore = deps.resumeAnchorStore;
658
- if (anchorStore)
659
- for (const a of pending.anchors)
660
- await anchorStore.put(sessionId, a.eventId, a.entryId, pending.owner);
661
- const rowLanded = await replaySessionRow(pending.row, committed.face);
726
+ const attendantsB = backend.landedAttendants();
727
+ const committed = await pending.handle.commit(pending.owner, { expectedOccupant: pending.expectedOccupant, ...(pending.resolution ? { resolution: pending.resolution } : {}) });
662
728
  sessionStorage.evict?.(sessionId);
729
+ const landedB = await landAttendants(attendantsB, committed.face, {
730
+ wipe: pending.resolution === "overwrite-dst" && (committed.relation === "fork" || committed.relation === "stale"),
731
+ fileHistory: pending.fileHistory,
732
+ allowReplace: pending.resolution === "overwrite-dst",
733
+ policy: pending.policy,
734
+ operator: pending.operatorOk,
735
+ anchors: pending.anchors,
736
+ owner: pending.owner,
737
+ row: pending.row,
738
+ });
663
739
  cleanupStaging(stagingId);
664
- if (!rowLanded) {
665
- sendError(res, 409, "conflict", "sync conflict");
666
- return;
740
+ switch (landedB.kind) {
741
+ case "landed":
742
+ sendJson(res, 200, { relation: committed.relation });
743
+ return;
744
+ case "gone":
745
+ sendLandedOccupantGone("commit", landedB.leg, committed.face);
746
+ return;
747
+ case "history_failed":
748
+ sendFileHistoryReplayFailure(res, landedB.failure);
749
+ return;
750
+ default: {
751
+ const unhandled = landedB;
752
+ throw new Error(`session sync: unknown landing answer ${JSON.stringify(unhandled)}`);
753
+ }
667
754
  }
668
- sendJson(res, 200, { relation: committed.relation });
669
755
  }
670
756
  catch (e) {
671
757
  await pending.handle.abort().catch(() => undefined);
@@ -704,9 +790,17 @@ export async function handleSessionSync(req, res, match, ctx) {
704
790
  sendError(res, 400, "request.field_invalid", "entryIds must be an array of strings");
705
791
  return;
706
792
  }
707
- const dst = await sessionStorage.exportEntries(sessionId);
793
+ const dst = gate.occupant === undefined ? null : await sessionStorage.exportEntries(sessionId);
708
794
  const relation = classifySyncRelationshipByIds(body.entryIds, dst ? dst.map((e) => e.id) : null);
795
+ if (gate.occupant === undefined) {
796
+ sendJson(res, 200, relation);
797
+ return;
798
+ }
709
799
  const refusal = await firstPhaseRefusal(sessionStorage, sessionId, relation.relation, false);
800
+ if (!(await stillAdmitted("push"))) {
801
+ sendError(res, 409, "conflict", "sync conflict");
802
+ return;
803
+ }
710
804
  if (refusal?.kind === "stamped") {
711
805
  if (sendSessionError(res, refusal.error, "import"))
712
806
  return;
@@ -795,9 +889,6 @@ function sendSessionSyncUnavailable(res, why) {
795
889
  case "session_import_staging_absent":
796
890
  sendError(res, 501, "capability.session_store_required", "staged session import requires a durable session store");
797
891
  return;
798
- case "file_history_store_absent":
799
- 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");
800
- return;
801
892
  case "policy_purge_absent":
802
893
  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");
803
894
  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];
@@ -26,7 +26,7 @@ export interface SessionsLocal {
26
26
  degraded?: boolean;
27
27
  }>;
28
28
  }>;
29
- /** DESIGN-269 件4:`/a2a` 面板的短 TTL single-flight 缓存。与 `mcpStatusCache` **分开一张表**而不是
29
+ /** [ref] 件4:`/a2a` 面板的短 TTL single-flight 缓存。与 `mcpStatusCache` **分开一张表**而不是
30
30
  * 共用带前缀的键:两张面板的体不同形(`peers` vs `servers`),塞进一张表就得靠 unknown 兜住两形,
31
31
  * 于是「取到的是哪一形」变成运行期约定 —— 两张表让它回到类型上。 */
32
32
  a2aStatusCache: Map<string, {