@sema-agent/server 7.133.0 → 7.135.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 (526) hide show
  1. package/MIGRATION.md +221 -0
  2. package/README.md +2 -2
  3. package/README.zh-CN.md +2 -2
  4. package/USAGE.md +222 -36
  5. package/deploy/sema-up/README.md +16 -0
  6. package/deploy/sema-up/chart/Chart.yaml +1 -1
  7. package/deploy/sema-up/chart/templates/NOTES.txt +15 -0
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +129 -0
  9. package/deploy/sema-up/chart/templates/sealed-key.yaml +24 -0
  10. package/deploy/sema-up/chart/templates/server-v4pro.yaml +14 -0
  11. package/deploy/sema-up/chart/templates/server.yaml +14 -0
  12. package/deploy/sema-up/chart/values-full-single.yaml +5 -1
  13. package/deploy/sema-up/chart/values.yaml +34 -0
  14. package/dist/adoption/plan.d.ts +1 -1
  15. package/dist/approval-ask-audit-store.d.ts +25 -25
  16. package/dist/approval-ask-machine.d.ts +2 -2
  17. package/dist/approval-card.d.ts +66 -154
  18. package/dist/approval-card.js +33 -52
  19. package/dist/approval-content-kind.d.ts +26 -6
  20. package/dist/approval-content-kind.js +23 -3
  21. package/dist/approval-deny-reasons.d.ts +1 -1
  22. package/dist/approval-gate-currency.d.ts +91 -0
  23. package/dist/approval-gate-currency.js +120 -0
  24. package/dist/approval-hmac.d.ts +7 -7
  25. package/dist/approval-policy-settlement.d.ts +2 -2
  26. package/dist/approval-reconciler.d.ts +3 -3
  27. package/dist/approval.d.ts +14 -8
  28. package/dist/approval.js +35 -16
  29. package/dist/auth-bridge.d.ts +1 -1
  30. package/dist/auto-mode-face.d.ts +4 -4
  31. package/dist/background-session-reap.d.ts +2 -2
  32. package/dist/bake-runner/main.d.ts +2 -2
  33. package/dist/bake-runner/runner.d.ts +4 -4
  34. package/dist/bench/s1/live-deps.d.ts +1 -1
  35. package/dist/bench/s1/run-firm.d.ts +1 -1
  36. package/dist/boot/coordinators.d.ts +7 -2
  37. package/dist/boot/coordinators.js +8 -5
  38. package/dist/boot/deferred-sandbox-path-env.d.ts +0 -6
  39. package/dist/boot/deferred-sandbox-path-env.js +0 -5
  40. package/dist/boot/engine-lease.d.ts +5 -5
  41. package/dist/boot/execution-env.d.ts +16 -15
  42. package/dist/boot/execution-env.js +19 -21
  43. package/dist/boot/fatal-exit.d.ts +2 -2
  44. package/dist/boot/late-binds.d.ts +1 -1
  45. package/dist/boot/leader.d.ts +2 -0
  46. package/dist/boot/leader.js +2 -1
  47. package/dist/boot/memory-boundary.d.ts +2 -2
  48. package/dist/boot/memory-consolidation.d.ts +15 -15
  49. package/dist/boot/parked-revive-gate.d.ts +3 -3
  50. package/dist/boot/parked-revive-gate.js +3 -2
  51. package/dist/boot/read-deny-anchor-audit.js +2 -2
  52. package/dist/boot/reapers.d.ts +4 -4
  53. package/dist/boot/resolve-spec.d.ts +1 -1
  54. package/dist/boot/resolve-spec.js +28 -24
  55. package/dist/boot/runner-deps.d.ts +29 -16
  56. package/dist/boot/runner-deps.js +12 -2
  57. package/dist/boot/session-faces.d.ts +3 -3
  58. package/dist/boot/session-faces.js +11 -30
  59. package/dist/boot/shutdown.d.ts +5 -5
  60. package/dist/boot/side-query-lane.d.ts +2 -2
  61. package/dist/boot/stage-05-execution-env.js +4 -4
  62. package/dist/boot/stage-06-runners.d.ts +4 -3
  63. package/dist/boot/stage-06-runners.js +15 -4
  64. package/dist/boot/stage-07-capability-layer.d.ts +2 -1
  65. package/dist/boot/stage-08-reapers.d.ts +2 -1
  66. package/dist/boot/stage-09-leader.d.ts +2 -1
  67. package/dist/boot/stage-09-leader.js +2 -2
  68. package/dist/boot/stage-10-http-server.d.ts +2 -1
  69. package/dist/boot/stage-10-http-server.js +2 -1
  70. package/dist/boot/stores.d.ts +8 -0
  71. package/dist/boot/stores.js +10 -13
  72. package/dist/boot/web-admin.d.ts +21 -15
  73. package/dist/boot/web-admin.js +16 -12
  74. package/dist/boot/workflow-orchestration.js +2 -9
  75. package/dist/brain.d.ts +11 -11
  76. package/dist/budget.d.ts +4 -4
  77. package/dist/budget.js +5 -1
  78. package/dist/caller-text-echo.d.ts +2 -0
  79. package/dist/caller-text-echo.js +2 -1
  80. package/dist/canonical-json.d.ts +2 -41
  81. package/dist/canonical-json.js +2 -13
  82. package/dist/capabilities/approvals-push.d.ts +4 -4
  83. package/dist/capabilities/builtin-tools.d.ts +5 -5
  84. package/dist/capabilities/center-plugins.d.ts +5 -5
  85. package/dist/capabilities/center-plugins.js +1 -1
  86. package/dist/capabilities/center-prompts.d.ts +1 -1
  87. package/dist/capabilities/center-wiring.d.ts +1 -1
  88. package/dist/capabilities/composite-members.d.ts +2 -2
  89. package/dist/capabilities/composite-members.js +1 -1
  90. package/dist/capabilities/execution-lane.d.ts +5 -5
  91. package/dist/capabilities/execution-lane.js +2 -2
  92. package/dist/capabilities/hands-lane.d.ts +5 -5
  93. package/dist/capabilities/mcp-probe.d.ts +10 -7
  94. package/dist/capabilities/mcp-probe.js +2 -2
  95. package/dist/capabilities/sandbox-file-send.d.ts +1 -18
  96. package/dist/capabilities/sandbox-file-send.js +0 -7
  97. package/dist/capabilities/scenarios.d.ts +28 -10
  98. package/dist/capabilities/scenarios.js +15 -5
  99. package/dist/capabilities/send-user-file-tool.d.ts +1 -1
  100. package/dist/capabilities/skills.d.ts +31 -12
  101. package/dist/capabilities/skills.js +23 -17
  102. package/dist/capabilities/tool-defer.d.ts +1 -1
  103. package/dist/capability-facts.d.ts +27 -24
  104. package/dist/capability-facts.js +18 -20
  105. package/dist/center-config-tier.d.ts +1 -1
  106. package/dist/center-credential.d.ts +4 -4
  107. package/dist/checkpoint-ctx-seal-m28.d.ts +42 -0
  108. package/dist/checkpoint-ctx-seal-m28.js +19 -0
  109. package/dist/checkpoint-identity.d.ts +5 -0
  110. package/dist/checkpoint-identity.js +14 -0
  111. package/dist/config-catalog.d.ts +12 -12
  112. package/dist/config-invariants.d.ts +4 -4
  113. package/dist/config-invariants.js +3 -2
  114. package/dist/config-lkg.d.ts +1 -1
  115. package/dist/config-provider.d.ts +13 -13
  116. package/dist/config-provider.js +2 -1
  117. package/dist/config-types.d.ts +83 -83
  118. package/dist/config.d.ts +26 -24
  119. package/dist/config.js +12 -10
  120. package/dist/cross-session-settings.d.ts +1 -1
  121. package/dist/delegated-session-owner.d.ts +16 -13
  122. package/dist/delegated-session-owner.js +9 -10
  123. package/dist/deployment-governance.d.ts +16 -16
  124. package/dist/deployment-shape.d.ts +127 -0
  125. package/dist/deployment-shape.js +72 -0
  126. package/dist/device-store.d.ts +1 -1
  127. package/dist/device-ws-hub.d.ts +1 -1
  128. package/dist/egress-redirect.d.ts +1 -1
  129. package/dist/entry-mode-clamp-notice.d.ts +2 -2
  130. package/dist/env-facts.d.ts +10 -9
  131. package/dist/env-facts.js +1 -1
  132. package/dist/env-name-allowlist-knobs.d.ts +5 -5
  133. package/dist/exec-bounds.d.ts +2 -2
  134. package/dist/execution-lane-caps.d.ts +31 -43
  135. package/dist/execution-lane-caps.js +0 -13
  136. package/dist/field-conflict.d.ts +2 -1
  137. package/dist/field-conflict.js +1 -0
  138. package/dist/file-history-capture.d.ts +9 -9
  139. package/dist/file-history-disclosure.d.ts +50 -9
  140. package/dist/file-history-disclosure.js +8 -13
  141. package/dist/fleet/drain-entry.d.ts +2 -2
  142. package/dist/fleet/fleet-bus.d.ts +26 -14
  143. package/dist/fleet/fleet-bus.js +6 -5
  144. package/dist/fleet/fleet-reconciler.d.ts +9 -9
  145. package/dist/fleet/subagent-tail-bus.d.ts +4 -4
  146. package/dist/fleet-client.d.ts +13 -13
  147. package/dist/fleet-lease.d.ts +16 -16
  148. package/dist/governance-http-status.d.ts +2 -2
  149. package/dist/hooks/hook-llm.d.ts +7 -7
  150. package/dist/hooks/hook-runner.d.ts +57 -30
  151. package/dist/hooks/hook-runner.js +38 -20
  152. package/dist/host-decision.d.ts +5 -5
  153. package/dist/host-lsp-manager.d.ts +5 -5
  154. package/dist/hosted-posture.d.ts +23 -13
  155. package/dist/hosted-posture.js +4 -9
  156. package/dist/http/admission.d.ts +2 -2
  157. package/dist/http/admission.js +28 -5
  158. package/dist/http/approval-sweeps.d.ts +1 -1
  159. package/dist/http/approval-sweeps.js +5 -2
  160. package/dist/http/checkpoint-ctx.d.ts +183 -2
  161. package/dist/http/checkpoint-ctx.js +197 -2
  162. package/dist/http/dispatch.d.ts +3 -3
  163. package/dist/http/dispatch.js +3 -3
  164. package/dist/http/durable-run-leg.js +7 -5
  165. package/dist/http/idempotency.d.ts +4 -4
  166. package/dist/http/idempotency.js +2 -2
  167. package/dist/http/mcp-dial-deadline.d.ts +7 -5
  168. package/dist/http/memory-compliance-failure-reply.d.ts +4 -4
  169. package/dist/http/owner-access.d.ts +4 -6
  170. package/dist/http/owner-access.js +1 -1
  171. package/dist/http/principal-gate.d.ts +39 -13
  172. package/dist/http/principal-gate.js +30 -6
  173. package/dist/http/readiness.d.ts +1 -1
  174. package/dist/http/refusal-body.d.ts +12 -0
  175. package/dist/http/refusal-body.js +11 -0
  176. package/dist/http/request-guards.d.ts +4 -13
  177. package/dist/http/request-guards.js +4 -17
  178. package/dist/http/resume-ctx-read.d.ts +53 -6
  179. package/dist/http/resume-ctx-read.js +26 -3
  180. package/dist/http/resume-legs.d.ts +5 -4
  181. package/dist/http/resume-legs.js +47 -29
  182. package/dist/http/route-ctx.d.ts +29 -38
  183. package/dist/http/route-table.d.ts +9 -9
  184. package/dist/http/routes/agents-roster.d.ts +1 -1
  185. package/dist/http/routes/agents-roster.js +2 -3
  186. package/dist/http/routes/approvals-assistant.d.ts +5 -5
  187. package/dist/http/routes/approvals-assistant.js +91 -17
  188. package/dist/http/routes/background.d.ts +3 -3
  189. package/dist/http/routes/background.js +2 -2
  190. package/dist/http/routes/capabilities.d.ts +1 -1
  191. package/dist/http/routes/capabilities.js +16 -8
  192. package/dist/http/routes/config-catalog.d.ts +1 -1
  193. package/dist/http/routes/devices.d.ts +1 -1
  194. package/dist/http/routes/diagnostics.d.ts +6 -6
  195. package/dist/http/routes/diagnostics.js +1 -1
  196. package/dist/http/routes/fleet.d.ts +1 -1
  197. package/dist/http/routes/fleet.js +5 -4
  198. package/dist/http/routes/mcp-reconnect.d.ts +4 -4
  199. package/dist/http/routes/mcp-reconnect.js +3 -3
  200. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  201. package/dist/http/routes/memory-origin.d.ts +1 -1
  202. package/dist/http/routes/notify-wake.d.ts +1 -1
  203. package/dist/http/routes/notify-wake.js +2 -2
  204. package/dist/http/routes/rules.d.ts +1 -1
  205. package/dist/http/routes/rules.js +4 -4
  206. package/dist/http/routes/runs.js +44 -11
  207. package/dist/http/routes/session-sync.d.ts +3 -2
  208. package/dist/http/routes/session-sync.js +109 -62
  209. package/dist/http/routes/sessions-list.d.ts +1 -1
  210. package/dist/http/routes/sessions-list.js +4 -5
  211. package/dist/http/routes/sessions.js +34 -48
  212. package/dist/http/routes/tasks.d.ts +1 -1
  213. package/dist/http/routes/tasks.js +21 -16
  214. package/dist/http/routes/trace-usage.d.ts +1 -1
  215. package/dist/http/routes/trace-usage.js +7 -9
  216. package/dist/http/routes/workflows.d.ts +3 -0
  217. package/dist/http/routes/workflows.js +31 -28
  218. package/dist/http/send.d.ts +5 -5
  219. package/dist/http/server.d.ts +39 -33
  220. package/dist/http/server.js +5 -2
  221. package/dist/http/session-inherit-env.d.ts +3 -3
  222. package/dist/http/sse-lifecycle.d.ts +1 -1
  223. package/dist/http/sse-log.d.ts +2 -2
  224. package/dist/http/submit-ctx.d.ts +4 -3
  225. package/dist/http/submit-ctx.js +19 -3
  226. package/dist/http/sync-submit-body.d.ts +1 -1
  227. package/dist/http/verify-rounds.d.ts +1 -1
  228. package/dist/http/wire-types.d.ts +35 -24
  229. package/dist/index.d.ts +2 -0
  230. package/dist/index.js +1 -0
  231. package/dist/instruction-source-notice.d.ts +2 -2
  232. package/dist/key-resolver.d.ts +3 -3
  233. package/dist/lane-home-probe.d.ts +1 -1
  234. package/dist/leader/diffout.d.ts +1 -1
  235. package/dist/leader/diffup.d.ts +2 -2
  236. package/dist/leader/endpoint.d.ts +1 -1
  237. package/dist/leader/fanout.d.ts +1 -1
  238. package/dist/leader/leader.d.ts +4 -4
  239. package/dist/leader/merge.d.ts +3 -3
  240. package/dist/leader/repair-wire.d.ts +1 -1
  241. package/dist/leader/wire.d.ts +9 -5
  242. package/dist/leader/wire.js +8 -7
  243. package/dist/list-entry-display.d.ts +1 -1
  244. package/dist/lsp-evict.d.ts +1 -1
  245. package/dist/main.js +1 -1
  246. package/dist/mcp-assertion-header.d.ts +1 -1
  247. package/dist/memory-layer-legacy-lock.d.ts +1 -1
  248. package/dist/memory-operator-faces.d.ts +1 -1
  249. package/dist/memory-origin-fence.js +2 -2
  250. package/dist/memory-posture.js +4 -2
  251. package/dist/memory-project-layer.d.ts +1 -1
  252. package/dist/memory-scope.d.ts +19 -19
  253. package/dist/memory-store-refusal.d.ts +4 -4
  254. package/dist/model-compat.d.ts +1 -1
  255. package/dist/model-entry-headers.d.ts +2 -2
  256. package/dist/model-entry-refusal.d.ts +17 -17
  257. package/dist/model-provider.d.ts +10 -10
  258. package/dist/model-reach-scope.d.ts +1 -1
  259. package/dist/model-route-endpoint.d.ts +6 -6
  260. package/dist/model-route-url.d.ts +5 -5
  261. package/dist/model-select.d.ts +15 -6
  262. package/dist/model-select.js +5 -0
  263. package/dist/model-unreachable-notice.d.ts +3 -3
  264. package/dist/namespaced-rule-name.d.ts +15 -5
  265. package/dist/namespaced-rule-name.js +3 -2
  266. package/dist/observability/corrupt-read-seat.d.ts +9 -9
  267. package/dist/observability/cost-taxonomy.d.ts +1 -1
  268. package/dist/observability/err-text.d.ts +1 -1
  269. package/dist/observability/fail-open.d.ts +12 -8
  270. package/dist/observability/fail-open.js +12 -8
  271. package/dist/observability/metrics.d.ts +3 -3
  272. package/dist/observability/prompt-manifest.d.ts +19 -8
  273. package/dist/observability/prompt-manifest.js +9 -8
  274. package/dist/observability/run-terminal.d.ts +36 -36
  275. package/dist/observability/secret-env-scrub.d.ts +3 -3
  276. package/dist/observability/tool-trace.d.ts +1 -1
  277. package/dist/observability/tool-trace.js +8 -9
  278. package/dist/operator-ask.d.ts +4 -4
  279. package/dist/orchestration/workflow-agent-session-index.d.ts +3 -3
  280. package/dist/orchestration/workflow-completion-inbox.d.ts +20 -5
  281. package/dist/orchestration/workflow-completion-inbox.js +29 -7
  282. package/dist/orchestration/workflow-notify-journal.d.ts +43 -19
  283. package/dist/orchestration/workflow-notify-journal.js +17 -0
  284. package/dist/orchestration/workflow-park-decision.d.ts +1 -1
  285. package/dist/orchestration/workflow-park-decision.js +1 -0
  286. package/dist/outbound-dispatcher.d.ts +4 -4
  287. package/dist/parent-watch.d.ts +4 -4
  288. package/dist/parked-decide.d.ts +20 -20
  289. package/dist/parked-decide.js +8 -5
  290. package/dist/parked-revive-surface.d.ts +7 -7
  291. package/dist/parked-revive-surface.js +2 -3
  292. package/dist/peer-directory.d.ts +3 -3
  293. package/dist/peer-directory.js +1 -1
  294. package/dist/permission-rule-list.d.ts +10 -1
  295. package/dist/permission-rule-list.js +7 -5
  296. package/dist/permission-rule-vocab.d.ts +3 -25
  297. package/dist/permission-rule-vocab.js +0 -13
  298. package/dist/plugins/adoption-log-sql.d.ts +1 -1
  299. package/dist/plugins/approval-ask-store-file.d.ts +8 -1
  300. package/dist/plugins/approval-ask-store-file.js +6 -3
  301. package/dist/plugins/approval-ask-store-memory.d.ts +11 -7
  302. package/dist/plugins/approval-ask-store-memory.js +11 -7
  303. package/dist/plugins/approval-ask-store-sql.d.ts +34 -15
  304. package/dist/plugins/approval-ask-store-sql.js +18 -5
  305. package/dist/plugins/approval-exemption-store.d.ts +3 -3
  306. package/dist/plugins/approval-nonce-store.d.ts +3 -3
  307. package/dist/plugins/approval-payload-fingerprint.d.ts +14 -6
  308. package/dist/plugins/approval-payload-fingerprint.js +1 -1
  309. package/dist/plugins/background-agent-store-sql.d.ts +1 -1
  310. package/dist/plugins/background-shell-support.d.ts +2 -2
  311. package/dist/plugins/blob-backend.d.ts +1 -1
  312. package/dist/plugins/caching-session-store.d.ts +24 -33
  313. package/dist/plugins/caching-session-store.js +8 -19
  314. package/dist/plugins/checkpoint-index-columns.d.ts +81 -0
  315. package/dist/plugins/checkpoint-index-columns.js +62 -0
  316. package/dist/plugins/checkpoint-store-sql.d.ts +66 -67
  317. package/dist/plugins/checkpoint-store-sql.js +100 -103
  318. package/dist/plugins/device-store-sql.d.ts +7 -6
  319. package/dist/plugins/e2b-orphan-reclaim.d.ts +1 -1
  320. package/dist/plugins/ensure-schema-lock-policy.d.ts +1 -1
  321. package/dist/plugins/file-history-store-sql.d.ts +9 -7
  322. package/dist/plugins/file-history-store-sql.js +27 -15
  323. package/dist/plugins/file-run-store.d.ts +8 -8
  324. package/dist/plugins/fork-routing-session-store.d.ts +2 -2
  325. package/dist/plugins/fork-routing-session-store.js +1 -1
  326. package/dist/plugins/host-platform.d.ts +10 -10
  327. package/dist/plugins/image-bake-store-sql.d.ts +1 -1
  328. package/dist/plugins/image-index-sql.d.ts +1 -1
  329. package/dist/plugins/leader-run-store-sql.d.ts +1 -1
  330. package/dist/plugins/local-checkpoint-store.d.ts +23 -12
  331. package/dist/plugins/local-checkpoint-store.js +29 -4
  332. package/dist/plugins/local-session-store.d.ts +44 -45
  333. package/dist/plugins/local-session-store.js +42 -52
  334. package/dist/plugins/local-session-window.d.ts +12 -6
  335. package/dist/plugins/local-session-window.js +1 -17
  336. package/dist/plugins/mailbox-store-sql.d.ts +2 -2
  337. package/dist/plugins/memory-engine-pg.d.ts +1 -1
  338. package/dist/plugins/memory-run-store.d.ts +4 -4
  339. package/dist/plugins/memory-sync-store-pg.d.ts +3 -3
  340. package/dist/plugins/one-time-migrations.d.ts +76 -39
  341. package/dist/plugins/one-time-migrations.js +127 -34
  342. package/dist/plugins/outcome-ledger-sql.d.ts +1 -1
  343. package/dist/plugins/park-commit-watch.d.ts +3 -3
  344. package/dist/plugins/permission-rule-store-file.d.ts +5 -5
  345. package/dist/plugins/permission-rule-store-file.js +16 -19
  346. package/dist/plugins/permission-rule-store-sql.d.ts +38 -4
  347. package/dist/plugins/permission-rule-store-sql.js +74 -31
  348. package/dist/plugins/pg-cost-quota.d.ts +1 -1
  349. package/dist/plugins/pg-pool.d.ts +2 -2
  350. package/dist/plugins/pg-pool.js +5 -2
  351. package/dist/plugins/pg-rate-limiter.d.ts +1 -1
  352. package/dist/plugins/pg-session-storage.d.ts +9 -21
  353. package/dist/plugins/pg-session-storage.js +51 -42
  354. package/dist/plugins/remote-env-adb.d.ts +10 -10
  355. package/dist/plugins/remote-env-device.d.ts +22 -14
  356. package/dist/plugins/remote-env-device.js +28 -16
  357. package/dist/plugins/remote-env-e2b.d.ts +3 -3
  358. package/dist/plugins/remote-env-host.d.ts +16 -16
  359. package/dist/plugins/remote-env-k8s.d.ts +8 -8
  360. package/dist/plugins/remote-env-local-docker.d.ts +2 -2
  361. package/dist/plugins/remote-env-ssh.d.ts +4 -4
  362. package/dist/plugins/remote-scratchpad.d.ts +2 -3
  363. package/dist/plugins/remote-scratchpad.js +0 -4
  364. package/dist/plugins/remote-shell.d.ts +6 -6
  365. package/dist/plugins/retention-lane-store-sql.d.ts +4 -4
  366. package/dist/plugins/retention-store-sql.d.ts +4 -4
  367. package/dist/plugins/roster-store-sql.d.ts +1 -1
  368. package/dist/plugins/run-store-sql.d.ts +8 -8
  369. package/dist/plugins/schema-consistency.d.ts +2 -2
  370. package/dist/plugins/schema-ensure-legs.d.ts +3 -3
  371. package/dist/plugins/schema-indexes.d.ts +1 -1
  372. package/dist/plugins/schema-live-columns.d.ts +1 -1
  373. package/dist/plugins/session-event-payload.d.ts +4 -4
  374. package/dist/plugins/session-fork.d.ts +34 -0
  375. package/dist/plugins/session-fork.js +29 -0
  376. package/dist/plugins/session-ownership.d.ts +11 -0
  377. package/dist/plugins/session-ownership.js +11 -0
  378. package/dist/plugins/session-placement.d.ts +12 -14
  379. package/dist/plugins/session-placement.js +2 -15
  380. package/dist/plugins/session-policy-store-sql.d.ts +12 -12
  381. package/dist/plugins/session-store.d.ts +2 -2
  382. package/dist/plugins/session-store.js +2 -2
  383. package/dist/plugins/shared-memory-store-sql.d.ts +2 -2
  384. package/dist/plugins/sql-driver.d.ts +8 -8
  385. package/dist/plugins/sql-errors.d.ts +1 -1
  386. package/dist/plugins/sql-json-column.d.ts +21 -21
  387. package/dist/plugins/sql-row-helpers.d.ts +2 -2
  388. package/dist/plugins/store-backend.d.ts +17 -16
  389. package/dist/plugins/store-backend.js +3 -3
  390. package/dist/plugins/store-contracts.d.ts +21 -21
  391. package/dist/plugins/task-attachment-store.d.ts +2 -2
  392. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  393. package/dist/plugins/tidb-pool.d.ts +2 -2
  394. package/dist/plugins/tidb-pool.js +9 -2
  395. package/dist/plugins/tidb-session-store.d.ts +17 -27
  396. package/dist/plugins/tidb-session-store.js +52 -42
  397. package/dist/plugins/tool-result-store-sql.d.ts +1 -1
  398. package/dist/plugins/usage-window-store-sql.d.ts +3 -3
  399. package/dist/plugins/user-input-ledger-file.d.ts +1 -1
  400. package/dist/plugins/user-input-ledger-sql.d.ts +3 -3
  401. package/dist/plugins/web-search.d.ts +19 -5
  402. package/dist/plugins/web-search.js +19 -4
  403. package/dist/{orchestration/workflow-journal-entry.d.ts → plugins/workflow-journal-payload.d.ts} +23 -32
  404. package/dist/plugins/workflow-journal-payload.js +32 -0
  405. package/dist/plugins/workflow-journal-store-sql.d.ts +28 -14
  406. package/dist/plugins/workflow-journal-store-sql.js +34 -15
  407. package/dist/plugins/workflow-run-store-sql.d.ts +4 -4
  408. package/dist/posture-source.d.ts +11 -11
  409. package/dist/principal-jwt.d.ts +6 -6
  410. package/dist/project-identity.d.ts +3 -3
  411. package/dist/project-memory.d.ts +4 -4
  412. package/dist/read-face-posture.d.ts +7 -7
  413. package/dist/request-key-closure.d.ts +1 -1
  414. package/dist/request-key-closure.js +1 -1
  415. package/dist/request-tool-axes.d.ts +12 -0
  416. package/dist/request-tool-axes.js +20 -0
  417. package/dist/request-value-closure.d.ts +15 -8
  418. package/dist/request-value-closure.js +2 -0
  419. package/dist/router/route-orchestration.d.ts +11 -16
  420. package/dist/router/route-orchestration.js +2 -12
  421. package/dist/rule-entry-list.d.ts +8 -7
  422. package/dist/rule-entry-list.js +2 -9
  423. package/dist/rules-consent.d.ts +6 -6
  424. package/dist/rules-consent.js +2 -0
  425. package/dist/run-cancel-context.d.ts +5 -5
  426. package/dist/run-local.d.ts +10 -10
  427. package/dist/run-local.js +1 -0
  428. package/dist/runs.d.ts +15 -12
  429. package/dist/runs.js +19 -4
  430. package/dist/runtime-caps-resolver.d.ts +6 -6
  431. package/dist/runtime-governance.d.ts +9 -9
  432. package/dist/sandbox-pkg-source.d.ts +9 -31
  433. package/dist/sandbox-pkg-source.js +14 -8
  434. package/dist/sealed-key.d.ts +34 -2
  435. package/dist/sealed-key.js +55 -1
  436. package/dist/security.d.ts +31 -32
  437. package/dist/security.js +12 -9
  438. package/dist/server-secret-env.d.ts +10 -10
  439. package/dist/session-children-retire.d.ts +1 -1
  440. package/dist/session-error-wire.d.ts +19 -12
  441. package/dist/session-error-wire.js +4 -1
  442. package/dist/session-incarnation.d.ts +52 -35
  443. package/dist/session-incarnation.js +23 -8
  444. package/dist/session-policy-wire.d.ts +27 -5
  445. package/dist/session-policy-wire.js +15 -1
  446. package/dist/session-records-skipped-notice.d.ts +1 -1
  447. package/dist/session-sync-kernel.d.ts +38 -11
  448. package/dist/session-sync-kernel.js +10 -0
  449. package/dist/session-sync.d.ts +49 -6
  450. package/dist/session-sync.js +52 -10
  451. package/dist/session-titler.d.ts +7 -6
  452. package/dist/session-titler.js +8 -13
  453. package/dist/session-watch.d.ts +3 -3
  454. package/dist/session-watch.js +4 -4
  455. package/dist/sighup-idle.d.ts +2 -2
  456. package/dist/spec-fields.d.ts +4 -4
  457. package/dist/sql-engine-posture.d.ts +3 -3
  458. package/dist/store-posture.d.ts +2 -2
  459. package/dist/stored-request-tool-axes-m19.d.ts +1 -1
  460. package/dist/task-a2a.d.ts +3 -1
  461. package/dist/task-a2a.js +38 -5
  462. package/dist/task-cwd.d.ts +7 -88
  463. package/dist/task-cwd.js +2 -15
  464. package/dist/task-mcp.d.ts +14 -10
  465. package/dist/task-mcp.js +39 -12
  466. package/dist/task-settings.d.ts +34 -18
  467. package/dist/task-settings.js +34 -4
  468. package/dist/task-workflow.d.ts +0 -24
  469. package/dist/task-workflow.js +2 -1
  470. package/dist/terminal.d.ts +5 -5
  471. package/dist/tighten-only-seats.d.ts +7 -6
  472. package/dist/tighten-only-seats.js +1 -1
  473. package/dist/tool-approval.d.ts +273 -228
  474. package/dist/tool-approval.js +125 -47
  475. package/dist/tool-rule-names.d.ts +7 -1
  476. package/dist/trace/core-keyset-guard.d.ts +15 -9
  477. package/dist/trace/engine-notice-wire.d.ts +5 -5
  478. package/dist/trace/engine-notice-wire.js +1 -0
  479. package/dist/trace/exit-seat.d.ts +40 -1
  480. package/dist/trace/exit-seat.js +46 -14
  481. package/dist/trace/ledger-events.d.ts +6 -4
  482. package/dist/trace/ledger-sink.d.ts +1 -1
  483. package/dist/trace/model-segment.d.ts +3 -3
  484. package/dist/trace/project.d.ts +65 -46
  485. package/dist/trace/project.js +49 -5
  486. package/dist/trace/redact.d.ts +44 -27
  487. package/dist/trace/redact.js +343 -73
  488. package/dist/trace/self-minted-wire.d.ts +39 -14
  489. package/dist/trace/self-minted-wire.js +9 -0
  490. package/dist/trace/sema-provenance.d.ts +1 -1
  491. package/dist/trace/task-notification-facets.d.ts +4 -4
  492. package/dist/trace/wire-projection-faces.d.ts +9 -3
  493. package/dist/trace/wire-projection-faces.js +7 -1
  494. package/dist/unattended-permission-mode.d.ts +5 -5
  495. package/dist/url-credential.d.ts +52 -0
  496. package/dist/url-credential.js +49 -0
  497. package/dist/url-refusal.d.ts +6 -2
  498. package/dist/url-refusal.js +8 -1
  499. package/dist/usage-analytics.d.ts +2 -2
  500. package/dist/user-input-ledger.d.ts +23 -23
  501. package/dist/web-admin-client/apply-effective.d.ts +5 -5
  502. package/dist/web-admin-client/apply-effective.js +2 -1
  503. package/dist/web-admin-client/apply-ledger.d.ts +2 -2
  504. package/dist/web-admin-client/center-request.d.ts +2 -2
  505. package/dist/web-admin-client/facade.d.ts +5 -5
  506. package/dist/web-admin-client/facade.js +1 -1
  507. package/dist/web-admin-client/hot-keys-registry.d.ts +2 -2
  508. package/dist/web-admin-client/http-client.d.ts +4 -4
  509. package/dist/web-admin-client/mcp-revocation.d.ts +1 -1
  510. package/dist/web-admin-client/pull-state.d.ts +1 -1
  511. package/dist/web-admin-client/read-face.d.ts +2 -2
  512. package/dist/web-admin-client/read-warnings.d.ts +5 -5
  513. package/dist/web-admin-client/restart-signal.d.ts +6 -6
  514. package/dist/web-admin-client/skills-mcp.d.ts +29 -4
  515. package/dist/web-admin-client/skills-mcp.js +31 -4
  516. package/dist/web-admin-client/types.d.ts +17 -10
  517. package/dist/workspace-space.d.ts +5 -3
  518. package/dist/write-protection.d.ts +2 -2
  519. package/package.json +4 -3
  520. package/scripts/drain-check-local.mjs +35 -2
  521. package/scripts/drain-check.mysql.sql +22 -2
  522. package/scripts/drain-check.pg.sql +22 -2
  523. package/skills/loop.md +1 -1
  524. package/dist/mcp-tool-faces.d.ts +0 -69
  525. package/dist/mcp-tool-faces.js +0 -104
  526. package/dist/orchestration/workflow-journal-entry.js +0 -27
@@ -12,7 +12,7 @@
12
12
  * 因此**导入两口**只认已验明的 principal,连 `explicitOperatorOk` 的旁路都不给:一个 operator 想给
13
13
  * 自己导规则,用他自己的 principal 走同一条路即可(那时他就是租户)。
14
14
  *
15
- * 🔴 **`POST /v1/rules` 是撤销口的对偶,不是导入口的简写**(S-511):它写的只有**收紧**方向
15
+ * 🔴 **`POST /v1/rules` 是撤销口的对偶,不是导入口的简写**([ref]):它写的只有**收紧**方向
16
16
  * (deny/ask),而收紧不需要同意仪式 —— 与撤销为什么不需要是同一条理由(core `removePersistedRule`
17
17
  * 头注逐字:「a host may narrow on a user's behalf, it may not widen」)。放宽(allow)仍然只有两条路:
18
18
  * 一张卡上的人点头,或一次显式的 settings 导入。方向表在 `permission-rule-vocab.ts`,不在本文件。
@@ -6,8 +6,8 @@ import * as facts from "../../capability-facts.js";
6
6
  import { createLogger } from "../../observability/logger.js";
7
7
  import { RULE_IMPORT_RETRY_AFTER_SEC, RULE_SCOPE_REFUSAL_SENTENCE, MAX_RULE_SCOPE_CHARS, buildCcImportLayerRootRefusal, parseRuleScope, serializeRuleScope } from "../../rules-consent.js";
8
8
  import { hasControlOrBidi } from "@sema-agent/settings-schema";
9
- import { MAX_RULE_TEXT_CHARS, RULE_BEHAVIORS, isValidDurableScope } from "@sema-agent/core";
10
- import { PERSISTED_RULE_MATCHES, isPersistedRuleTool, isDirectWritableRuleBehavior } from "../../permission-rule-vocab.js";
9
+ import { IMPORTED_SETTINGS_LAYERS, MAX_RULE_TEXT_CHARS, PERSISTED_RULE_MATCHES, RULE_ADD_ORIGINS, RULE_BEHAVIORS, isValidDurableScope } from "@sema-agent/core";
10
+ import { isPersistedRuleTool, isDirectWritableRuleBehavior } from "../../permission-rule-vocab.js";
11
11
  const logger = createLogger();
12
12
  export const RULES_CC_IMPORT_PREPARE_PATH = "/v1/rules/cc-import/prepare";
13
13
  export const RULES_CC_IMPORT_REDEEM_PATH = "/v1/rules/cc-import/redeem";
@@ -23,7 +23,7 @@ const CcImportPrepareBodySchema = z
23
23
  layers: z
24
24
  .array(z
25
25
  .object({
26
- layer: z.enum(["userSettings", "projectSettings", "localSettings"]),
26
+ layer: z.enum(IMPORTED_SETTINGS_LAYERS),
27
27
  path: z.string().min(1).max(1024),
28
28
  root: z.string().max(1024),
29
29
  content: z.string().max(MAX_LAYER_CONTENT_CHARS),
@@ -41,7 +41,7 @@ const CcImportRedeemBodySchema = z.object({ ticket: TicketStringSchema }).strict
41
41
  const LocalImportAddSchema = z
42
42
  .object({
43
43
  dot: z.object({ actor: z.string().min(1).max(190), counter: z.number().int().nonnegative().safe() }).strict(),
44
- origin: z.enum(["user", "imported-cc", "starter"]),
44
+ origin: z.enum(RULE_ADD_ORIGINS),
45
45
  createdAt: z.string().min(1).max(64),
46
46
  })
47
47
  .strict();
@@ -3,6 +3,7 @@ import { redactHead, redactLedgerEventForRead } from "../../observability/run-te
3
3
  import { z } from "zod";
4
4
  import { uuidv7, mintCheckpointToken, CheckpointError, policyCannotAnswer, validatePendingSteer, TASK_OUTPUT_REPLAY_KINDS, isSystemInjectionPriority } from "@sema-agent/core";
5
5
  import { isTerminalRunStatus, isParkedRunStatus, runProvenElsewhere } from "../../plugins/store-contracts.js";
6
+ import { askRowCarriesOwner } from "../../plugins/approval-ask-store-sql.js";
6
7
  import { LIVE_RUN_GATE_KINDS, TERMINAL_PARK_GATE_KINDS } from "../../plugins/checkpoint-store-sql.js";
7
8
  import { redactSecrets } from "../../trace/redact.js";
8
9
  import { isUuidV7, encodeCheckpointScope } from "../../security.js";
@@ -13,7 +14,7 @@ import { streamSseLog } from "../sse-log.js";
13
14
  import { bindSseLifecycle } from "../sse-lifecycle.js";
14
15
  import { buildApprovalPreamble, buildApprovalPreambleSseFrames, readClosedWordSeat, storedCardDemandsAPerson } from "../../approval-card.js";
15
16
  import { heldAskOf, liveSettledBy, readDecidedBy, retiredDecisionKeyFacts, DECIDED_BY_NOT_IN_PROOF, DECIDED_BY_OUTSIDE_CLOSED_SET, POLICY_CANNOT_ALLOW_PERSON_ASK } from "../../host-decision.js";
16
- import { ASK_DECISION_CONSUMER_ABSENT, outcomeOfDecidedRow, resolveStreamApprovalGate } from "../../tool-approval.js";
17
+ import { ASK_DECISION_CONSUMER_ABSENT, approvalPreambleReplays, outcomeOfDecidedRow, presentedApprovalFrameFamily, resolveStreamApprovalGate } from "../../tool-approval.js";
17
18
  import { MAX_DECISION_NOTE_CHARS, noteLandedOnRow, noteRecordedReceipt } from "../../approval-ask-machine.js";
18
19
  import { causeOfAskRow } from "../../approval-deny-reasons.js";
19
20
  import { normalizeRunEventType, screenedStoredEventData } from "../../trace/project.js";
@@ -32,6 +33,7 @@ import { RUN_NOT_FOUND_MESSAGE, runNotFoundMessage } from "../route-ctx.js";
32
33
  import { withPrincipal } from "../../observability/principal-context.js";
33
34
  import { readResumeCtx } from "../resume-ctx-read.js";
34
35
  import { storedBodyReplayAnswer, storedBodyReplayLogFields } from "../checkpoint-ctx.js";
36
+ import { headReadOf } from "../../session-incarnation.js";
35
37
  import { serviceVersion } from "../../service-version.js";
36
38
  import { storedBodyReplayRefusal } from "../stored-body-replay.js";
37
39
  import { steerBodyKeyIssue } from "../../request-key-closure.js";
@@ -116,10 +118,18 @@ async function streamRunEvents(req, res, deps, runStore, taskId, staleMs) {
116
118
  toolApprovalEnabled: Boolean(deps.toolApproval),
117
119
  streamApprovalEnabled: deps.config.streamApproval?.enabled === true,
118
120
  backend: deps.backend,
119
- parkFacility: deps.checkpointStore !== undefined,
121
+ checkpointStore: deps.checkpointStore,
120
122
  });
121
123
  if (!gate.active)
122
124
  return [];
125
+ if (!approvalPreambleReplays({
126
+ streamApprovalOn: gate.active,
127
+ windowMs: deps.config.streamApproval?.windowMs,
128
+ windowMarginMs: deps.config.streamAskWindowMarginMs,
129
+ declaredFamilies: new Set([presentedApprovalFrameFamily(gate.active)]),
130
+ })) {
131
+ return [];
132
+ }
123
133
  const store = gate.askStore;
124
134
  const rows = await store.listPendingByTask(taskId, signal);
125
135
  const { frames, skipped, dropped } = buildApprovalPreamble(rows, Date.now(), deps.config.streamApproval.replayMax);
@@ -560,7 +570,8 @@ export async function handleRuns(req, res, match, ctx) {
560
570
  }
561
571
  return;
562
572
  }
563
- if (deps.checkpointStore && deps.sessionStorage?.getLeafId) {
573
+ const sessionHeadOf = headReadOf(deps.sessionStorage);
574
+ if (deps.checkpointStore && sessionHeadOf) {
564
575
  const activeTaskId = await runStore.getActiveTaskId?.(run.sessionId).catch(() => undefined);
565
576
  if (activeTaskId !== undefined && activeTaskId !== null && activeTaskId !== taskId) {
566
577
  sendNotRunning(`run is ${run.status} and its session has an ACTIVE run (${activeTaskId}) — steer that run instead`);
@@ -610,14 +621,18 @@ export async function handleRuns(req, res, match, ctx) {
610
621
  mintResult.duplicateKey = true;
611
622
  return;
612
623
  }
613
- const leafId = await Promise.resolve(deps.sessionStorage.getLeafId(run.sessionId)).catch(() => undefined);
624
+ const leafId = await sessionHeadOf(run.sessionId).then((h) => h?.leafId).catch(() => undefined);
614
625
  if (leafId === undefined || leafId === null)
615
626
  return;
616
- const resumeRead = await readResumeCtx(cs.getCtx(run.sessionId));
627
+ const resumeRead = await readResumeCtx(cs.getCtx(run.sessionId), { sessionId: run.sessionId, opener: deps.checkpointCtxSealing });
617
628
  if (resumeRead.kind === "corrupt") {
618
629
  mintResult.corruptCtxWhere = resumeRead.where;
619
630
  return;
620
631
  }
632
+ if (resumeRead.kind === "unsealable") {
633
+ mintResult.unsealableCtx = resumeRead;
634
+ return;
635
+ }
621
636
  if (resumeRead.kind === "absent") {
622
637
  mintResult.noResumeCtx = true;
623
638
  return;
@@ -641,10 +656,13 @@ export async function handleRuns(req, res, match, ctx) {
641
656
  createdAt: Date.now(),
642
657
  sourceTaskId: taskId,
643
658
  });
644
- const stillRead = await readResumeCtx(cs.getCtx(run.sessionId));
645
- if (stillRead.kind === "corrupt") {
646
- await withdrawWakeCard(wakeToken, cpScope, "resume_context_corrupt");
647
- mintResult.corruptCtxWhere = stillRead.where;
659
+ const stillRead = await readResumeCtx(cs.getCtx(run.sessionId), { sessionId: run.sessionId, opener: deps.checkpointCtxSealing });
660
+ if (stillRead.kind === "corrupt" || stillRead.kind === "unsealable") {
661
+ await withdrawWakeCard(wakeToken, cpScope, stillRead.kind === "corrupt" ? "resume_context_corrupt" : "resume_context_unsealable");
662
+ if (stillRead.kind === "corrupt")
663
+ mintResult.corruptCtxWhere = stillRead.where;
664
+ else
665
+ mintResult.unsealableCtx = stillRead;
648
666
  return;
649
667
  }
650
668
  if (stillRead.kind !== "ok") {
@@ -681,6 +699,10 @@ export async function handleRuns(req, res, match, ctx) {
681
699
  sendError(res, 500, "corrupt", "run already ended and this session's stored resume context cannot be read — nothing was queued. Ask whoever operates this deployment to repair or remove the row named in `where` before steering this session again.", { where: mintResult.corruptCtxWhere });
682
700
  return;
683
701
  }
702
+ if (mintResult.unsealableCtx !== undefined) {
703
+ sendError(res, 409, "conflict.checkpoint_ctx_unsealable", "run already ended and this session's stored resume context holds credentials this server cannot unseal (reason says why) — nothing was queued, because POST /v1/sessions/:id/wake could not resume it; restore the sealed-key directory that sealed them, restart this server (it reads its keys only at startup) and steer again, or submit a new task instead", { field: mintResult.unsealableCtx.field, reason: mintResult.unsealableCtx.reason });
704
+ return;
705
+ }
684
706
  if (mintResult.unservable !== undefined) {
685
707
  deps.logger?.warn?.("steer_wake_park_refused_stored_body", { taskId, sessionId: run.sessionId, ...storedBodyReplayLogFields(mintResult.unservable) });
686
708
  const { status, body: { error, errorCode, ...rest } } = storedBodyReplayAnswer(mintResult.unservable, serviceVersion(), false);
@@ -1432,6 +1454,10 @@ export async function handleRunVerbs(req, res, match, ctx) {
1432
1454
  });
1433
1455
  return;
1434
1456
  }
1457
+ if (hit && !askRowCarriesOwner(hit, row0.owner)) {
1458
+ askNotFound();
1459
+ return;
1460
+ }
1435
1461
  if (hit && hit.state === "DECIDED") {
1436
1462
  if (!syncLiveFromDecidedRow(hit))
1437
1463
  return;
@@ -1450,7 +1476,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1450
1476
  let outcome;
1451
1477
  const releaseEditMark = body.decision === "approve" && hasUpdatedInput ? deps.toolApproval?.markEditedDecisionInFlight(askId) : undefined;
1452
1478
  try {
1453
- outcome = await askStore.decideAsk(askId, row0.batchId, {
1479
+ outcome = await askStore.decideAsk(askId, row0.batchId, row0.owner, {
1454
1480
  decision: body.decision,
1455
1481
  decisionActor: actor,
1456
1482
  decisionNote: body.note ?? null,
@@ -1466,13 +1492,16 @@ export async function handleRunVerbs(req, res, match, ctx) {
1466
1492
  hadIdempotencyKey: body.idempotencyKey !== undefined,
1467
1493
  error: err instanceof Error ? err.message : String(err ?? ""),
1468
1494
  });
1495
+ let confirmedOutOfScope = false;
1469
1496
  if (releaseEditMark !== undefined &&
1470
1497
  body.idempotencyKey !== undefined &&
1471
1498
  deps.toolApproval &&
1472
1499
  deps.toolApproval.editedDecisionInFlightCount(askId) === 1) {
1473
1500
  try {
1474
1501
  const confirmed = await withDeadline(askStore.getAsk(askId), ASK_DECISION_CONFIRM_TIMEOUT_MS, "getAsk(ambiguous-commit-confirm)");
1475
- if (confirmed !== null &&
1502
+ if (confirmed !== null && !askRowCarriesOwner(confirmed, row0.owner))
1503
+ confirmedOutOfScope = true;
1504
+ else if (confirmed !== null &&
1476
1505
  confirmed.state === "DECIDED" &&
1477
1506
  confirmed.decision === body.decision &&
1478
1507
  confirmed.idempotencyKey === body.idempotencyKey &&
@@ -1485,6 +1514,10 @@ export async function handleRunVerbs(req, res, match, ctx) {
1485
1514
  deps.logger?.warn?.("ask_decision_edit_confirm_failed", { taskId, askId, error: confirmErr instanceof Error ? confirmErr.message : String(confirmErr ?? "") });
1486
1515
  }
1487
1516
  }
1517
+ if (confirmedOutOfScope) {
1518
+ askNotFound();
1519
+ return;
1520
+ }
1488
1521
  if (body.idempotencyKey !== undefined) {
1489
1522
  sendError(res, 500, "internal.error", "the ask decision store failed around commit — the decision MAY already be persisted; retry with the same idempotencyKey to replay it instead of colliding with it");
1490
1523
  }
@@ -34,8 +34,9 @@ export type PendingStaging = {
34
34
  declaredEntryIds: string[];
35
35
  /** The principal that opened this staging — a different caller may not drive it (404, no oracle). */
36
36
  openedBy: string | null;
37
- /** Fleet-wide caller (ops on-behalf) — bypasses the openedBy identity check (like the route's owner gates). */
38
- openedFleetWide: boolean;
37
+ /** The owner cell the gate judged when it opened this staging (head-read reading `headOf(id)?.owner`: `undefined` = no such session) — the commit lands only on
38
+ * this same cell (`StagedCommitOptions.expectedOwner`, `session-sync-kernel.ts`); `owner` above (the re-stamped importing principal) is derived from it for a fleet caller. */
39
+ expectedOwner: string | null | undefined;
39
40
  };
40
41
  /** 单域独占状态 + 它的两个操作。每个 server 实例一份。 */
41
42
  export interface SessionSyncLocal {
@@ -2,13 +2,13 @@ import { once } from "node:events";
2
2
  import { randomBytes, createHash } from "node:crypto";
3
3
  import { sessionLogDigest, sessionLogDigestsComparable, StreamingImportValidator, validateFileHistoryExport } from "@sema-agent/core";
4
4
  import { StringDecoder } from "node:string_decoder";
5
- import { exportSessionManifest, fileHistoryImportFace, replayFileHistory, replayPolicyRecords, wipeSessionAttendants } from "../../session-sync.js";
5
+ import { FileHistoryUnreadableError, blobGetterOf, exportSessionManifest, exportedFileHistory, fileHistoryImportFace, replayFileHistory, replayPolicyRecords, wipeSessionAttendants } from "../../session-sync.js";
6
6
  import * as facts from "../../capability-facts.js";
7
7
  import { classifySyncRelationshipByIds, SyncConflictError } from "../../session-sync-kernel.js";
8
- import { isUuidShape } from "../../security.js";
8
+ import { isUuidShape, legacyUnownedSessionOk, sessionOwnerCellOf } from "../../security.js";
9
9
  import { sendJson, sendError, sendSessionError, sendSessionPolicyError, logRequestError, msg } from "../send.js";
10
10
  import { buildDisplaySafeUrl } from "../../trace/redact.js";
11
- import { gatedPrincipal, explicitOperatorOk, sendUnauthorized } from "../principal-gate.js";
11
+ import { fleetViewOf, gatedPrincipal, explicitOperatorOk, sendUnauthorized, sessionCallerOf } from "../principal-gate.js";
12
12
  const SYNC_BLOB_MAX_BYTES = 64 * 1024 * 1024;
13
13
  const SYNC_NDJSON_LINE_MAX_BYTES = 8 * 1024 * 1024;
14
14
  const SYNC_IMPORT_BATCH = 500;
@@ -16,6 +16,7 @@ import { SHA256_HEX_RE } from "../../digest-form.js";
16
16
  import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
17
17
  import { readSessionRulesRecords, describeSessionRulesRecordProblem } from "../../session-policy-wire.js";
18
18
  import { readSessionPinned, readSessionTitle } from "../../session-row.js";
19
+ import { sessionFaceOfHead } from "../../session-incarnation.js";
19
20
  export function createSessionSyncLocal() {
20
21
  const pendingStagings = new Map();
21
22
  const importLeases = new Map();
@@ -34,7 +35,7 @@ export function createSessionSyncLocal() {
34
35
  }
35
36
  export async function handleSessionSync(req, res, match, ctx) {
36
37
  const { deps } = ctx;
37
- const { readJson, readRawBody, safeDecode, sessionOwnerScopeForWrite, rateLimited } = ctx.helpers;
38
+ const { readJson, readRawBody, safeDecode, rateLimited } = ctx.helpers;
38
39
  const { pendingStagings, importLeases, touchImportLease, cleanupStaging } = ctx.local.sessionSync;
39
40
  {
40
41
  {
@@ -44,7 +45,7 @@ export async function handleSessionSync(req, res, match, ctx) {
44
45
  return;
45
46
  }
46
47
  const { backend, sessionStorage, historyStore } = sync;
47
- const scope = sessionOwnerScopeForWrite(req);
48
+ const scope = fleetViewOf(req, deps, "write");
48
49
  if (!scope.fleetWide && scope.gateOwner === null) {
49
50
  sendUnauthorized(res, "identity");
50
51
  return;
@@ -54,23 +55,25 @@ export async function handleSessionSync(req, res, match, ctx) {
54
55
  sendError(res, 400, "request.id_invalid", "invalid session id (must be a canonical uuid)");
55
56
  return;
56
57
  }
57
- const gateFace = await sessionStorage.sessionFaceOf(sessionId);
58
+ const judgeSessionGate = async () => {
59
+ const face = sessionFaceOfHead(sessionId, await sessionStorage.headOf(sessionId));
60
+ const mayTouch = face !== undefined && (scope.fleetWide || face.owner === scope.gateOwner || legacyUnownedSessionOk(deps.config, sessionCallerOf(req, deps), await sessionOwnerCellOf(sessionStorage, sessionId, face.owner)));
61
+ return { face, mayPull: mayTouch, mayPush: face === undefined || mayTouch };
62
+ };
63
+ const gate = await judgeSessionGate();
64
+ const gateFace = gate.face;
58
65
  const owner = gateFace === undefined ? undefined : gateFace.owner;
59
- const ownsOrFleet = (o) => scope.fleetWide || o === scope.gateOwner;
66
+ const sendSessionAbsent = () => sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
60
67
  const pullGateOk = () => {
61
- if (owner === undefined) {
62
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
63
- return false;
64
- }
65
- if (!ownsOrFleet(owner)) {
66
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
68
+ if (!gate.mayPull) {
69
+ sendSessionAbsent();
67
70
  return false;
68
71
  }
69
72
  return true;
70
73
  };
71
74
  const pushGateOk = () => {
72
- if (owner !== undefined && !ownsOrFleet(owner)) {
73
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
75
+ if (!gate.mayPush) {
76
+ sendSessionAbsent();
74
77
  return false;
75
78
  }
76
79
  return true;
@@ -80,6 +83,11 @@ export async function handleSessionSync(req, res, match, ctx) {
80
83
  return true;
81
84
  return face !== undefined && (await sessionStorage.patchSessionMeta(sessionId, row, face)) !== undefined;
82
85
  };
86
+ const canReplayHistory = fileHistoryImportFace(historyStore) !== undefined;
87
+ const replayHistory = async (envelope, allowReplace) => {
88
+ const r = await replayFileHistory(historyStore, sessionId, envelope, blobGetterOf(historyStore), { allowReplace });
89
+ return r.ok ? undefined : r;
90
+ };
83
91
  if (match.decl.id === "session-sync-manifest") {
84
92
  if (!pullGateOk())
85
93
  return;
@@ -88,12 +96,12 @@ export async function handleSessionSync(req, res, match, ctx) {
88
96
  out = await exportSessionManifest(sessionId, backend, historyStore);
89
97
  }
90
98
  catch (e) {
91
- if (sendSessionPolicyError(res, e))
99
+ if (sendSessionPolicyError(res, e) || sendFileHistoryUnreadable(res, e))
92
100
  return;
93
101
  throw e;
94
102
  }
95
103
  if (out === null) {
96
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
104
+ sendSessionAbsent();
97
105
  return;
98
106
  }
99
107
  sendJson(res, 200, { manifest: out.manifest });
@@ -114,7 +122,7 @@ export async function handleSessionSync(req, res, match, ctx) {
114
122
  }
115
123
  const it = await sessionStorage.exportEntriesStream(sessionId, afterSeq === undefined ? undefined : { afterSeq });
116
124
  if (it === null) {
117
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
125
+ sendSessionAbsent();
118
126
  return;
119
127
  }
120
128
  res.writeHead(200, { "content-type": "application/x-ndjson", "transfer-encoding": "chunked" });
@@ -154,8 +162,16 @@ export async function handleSessionSync(req, res, match, ctx) {
154
162
  return;
155
163
  }
156
164
  const fs = blobs.historyStore;
157
- const envelope = typeof fs.exportHistory === "function" ? await fs.exportHistory(sessionId) : null;
158
- const referenced = envelope !== null && envelope !== undefined && envelope.tracked.some((t) => t.versions.some((v) => v.blobHash === hash));
165
+ let envelope;
166
+ try {
167
+ envelope = await exportedFileHistory(fs, sessionId);
168
+ }
169
+ catch (e) {
170
+ if (sendFileHistoryUnreadable(res, e))
171
+ return;
172
+ throw e;
173
+ }
174
+ const referenced = envelope !== null && envelope.tracked.some((t) => t.versions.some((v) => v.blobHash === hash));
159
175
  if (!referenced) {
160
176
  sendError(res, 404, "not_found.blob", "blob not found");
161
177
  return;
@@ -273,6 +289,17 @@ export async function handleSessionSync(req, res, match, ctx) {
273
289
  sendError(res, 409, "conflict", "sync conflict", { relation: relA });
274
290
  return;
275
291
  }
292
+ if (fileHistory !== null) {
293
+ const distinct = new Set();
294
+ for (const t of fileHistory.tracked)
295
+ for (const v of t.versions)
296
+ if (v.blobHash !== null)
297
+ distinct.add(v.blobHash);
298
+ if (await firstMissingBlob(facts.sessionSyncFileHistory(deps), [...distinct]) !== undefined) {
299
+ sendMissingBlob(res);
300
+ return;
301
+ }
302
+ }
276
303
  let payloadVerified = false;
277
304
  let digestSaysDiffer = false;
278
305
  if (relA.relation === "identical" && srcLogDigest !== undefined) {
@@ -288,8 +315,7 @@ export async function handleSessionSync(req, res, match, ctx) {
288
315
  digestSaysDiffer = true;
289
316
  }
290
317
  if (relA.relation === "identical" && !digestSaysDiffer) {
291
- const blobFaces = facts.sessionSyncFileHistory(deps);
292
- if (fileHistory !== null && blobFaces.available && fileHistoryImportFace(blobFaces.historyStore)) {
318
+ if (fileHistory !== null && canReplayHistory) {
293
319
  if (resolution === "overwrite-dst") {
294
320
  const activeNow = await deps.runStore?.getActiveTaskId(sessionId);
295
321
  if (activeNow) {
@@ -297,11 +323,9 @@ export async function handleSessionSync(req, res, match, ctx) {
297
323
  return;
298
324
  }
299
325
  }
300
- const getBlobA = (h) => blobFaces.historyStore.getBlob(h);
301
- const r = await replayFileHistory(blobFaces.historyStore, sessionId, fileHistory, getBlobA, { allowReplace: resolution === "overwrite-dst" });
302
- const failCode = r.ok ? undefined : r.error.code === "not_found" ? "missing_blob" : r.error.code;
303
- if (!r.ok) {
304
- sendError(res, 422, failCode, `file history import failed (${r.error.code})`);
326
+ const failed = await replayHistory(fileHistory, resolution === "overwrite-dst");
327
+ if (failed !== undefined) {
328
+ sendFileHistoryReplayFailure(res, failed);
305
329
  return;
306
330
  }
307
331
  }
@@ -354,31 +378,6 @@ export async function handleSessionSync(req, res, match, ctx) {
354
378
  return;
355
379
  }
356
380
  }
357
- const fss = historyStore;
358
- if (fileHistory !== null && fileHistoryImportFace(fss) !== undefined) {
359
- const distinct = new Set();
360
- for (const t of fileHistory.tracked)
361
- for (const v of t.versions)
362
- if (v.blobHash !== null)
363
- distinct.add(v.blobHash);
364
- const all = [...distinct];
365
- if (typeof fss.hasBlobs === "function") {
366
- const present = await fss.hasBlobs(all);
367
- const missing = all.find((h) => !present.has(h));
368
- if (missing !== undefined) {
369
- sendError(res, 422, "missing_blob", "missing blob; PUT all referenced blobs before import");
370
- return;
371
- }
372
- }
373
- else if (typeof fss.getBlob === "function") {
374
- for (const hash of all) {
375
- if (!(await fss.getBlob(hash))) {
376
- sendError(res, 422, "missing_blob", "missing blob; PUT all referenced blobs before import");
377
- return;
378
- }
379
- }
380
- }
381
- }
382
381
  const importingPrincipal = scope.fleetWide ? (owner ?? null) : scope.gateOwner;
383
382
  const operatorOk = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config);
384
383
  const token = randomBytes(8).toString("hex");
@@ -387,7 +386,7 @@ export async function handleSessionSync(req, res, match, ctx) {
387
386
  importLeases.set(sessionId, { at: Date.now(), stagingId });
388
387
  pendingStagings.set(stagingId, {
389
388
  handle, realSessionId: sessionId, owner: importingPrincipal, ...(resolution ? { resolution } : {}), operatorOk,
390
- fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: scope.gateOwner, openedFleetWide: scope.fleetWide,
389
+ fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: scope.gateOwner, expectedOwner: owner,
391
390
  });
392
391
  sendJson(res, 200, { stagingId, relation: relA.relation });
393
392
  return;
@@ -403,11 +402,10 @@ export async function handleSessionSync(req, res, match, ctx) {
403
402
  sendError(res, 404, "not_found.staging", "staging not found");
404
403
  return;
405
404
  }
406
- if (!pending.openedFleetWide && !scope.fleetWide && pending.openedBy !== scope.gateOwner) {
405
+ if (!scope.fleetWide && pending.openedBy !== scope.gateOwner) {
407
406
  sendError(res, 404, "not_found.staging", "staging not found");
408
407
  return;
409
408
  }
410
- const getBlob = (h) => historyStore.getBlob ? historyStore.getBlob(h) : Promise.resolve(undefined);
411
409
  const validator = new StreamingImportValidator();
412
410
  let lineBuf = "";
413
411
  let pendingBatch = [];
@@ -485,7 +483,23 @@ export async function handleSessionSync(req, res, match, ctx) {
485
483
  return;
486
484
  throw e;
487
485
  }
488
- const activeAtCommit = await deps.runStore?.getActiveTaskId(sessionId);
486
+ let mayPushAtCommit;
487
+ let activeAtCommit;
488
+ try {
489
+ mayPushAtCommit = (await judgeSessionGate()).mayPush;
490
+ activeAtCommit = mayPushAtCommit ? await deps.runStore?.getActiveTaskId(sessionId) : undefined;
491
+ }
492
+ catch (e) {
493
+ await pending.handle.abort().catch(() => undefined);
494
+ cleanupStaging(stagingId);
495
+ throw e;
496
+ }
497
+ if (!mayPushAtCommit) {
498
+ await pending.handle.abort().catch(() => undefined);
499
+ cleanupStaging(stagingId);
500
+ sendSessionAbsent();
501
+ return;
502
+ }
489
503
  if (activeAtCommit) {
490
504
  await pending.handle.abort().catch(() => undefined);
491
505
  cleanupStaging(stagingId);
@@ -493,15 +507,14 @@ export async function handleSessionSync(req, res, match, ctx) {
493
507
  return;
494
508
  }
495
509
  try {
496
- const committed = await pending.handle.commit(pending.owner, pending.resolution ? { resolution: pending.resolution } : undefined);
510
+ const committed = await pending.handle.commit(pending.owner, { expectedOwner: pending.expectedOwner, ...(pending.resolution ? { resolution: pending.resolution } : {}) });
497
511
  if (pending.resolution === "overwrite-dst" && (committed.relation === "fork" || committed.relation === "stale")) {
498
512
  await wipeSessionAttendants({ fileHistoryStore: historyStore, sessionPolicyStore: deps.sessionPolicyStore, resumeAnchorStore: deps.resumeAnchorStore }, sessionId);
499
513
  }
500
- if (pending.fileHistory !== null && fileHistoryImportFace(historyStore)) {
501
- const r = await replayFileHistory(historyStore, sessionId, pending.fileHistory, getBlob, { allowReplace: pending.resolution === "overwrite-dst" });
502
- const failCode = r.ok ? undefined : r.error.code === "not_found" ? "missing_blob" : r.error.code;
503
- if (!r.ok) {
504
- sendError(res, 422, failCode, `file history import failed (${r.error.code})`);
514
+ if (pending.fileHistory !== null && canReplayHistory) {
515
+ const failed = await replayHistory(pending.fileHistory, pending.resolution === "overwrite-dst");
516
+ if (failed !== undefined) {
517
+ sendFileHistoryReplayFailure(res, failed);
505
518
  cleanupStaging(stagingId);
506
519
  return;
507
520
  }
@@ -556,6 +569,40 @@ export async function handleSessionSync(req, res, match, ctx) {
556
569
  }
557
570
  }
558
571
  }
572
+ function sendFileHistoryUnreadable(res, e) {
573
+ if (!(e instanceof FileHistoryUnreadableError))
574
+ return false;
575
+ const permanence = e.failure.permanence;
576
+ const advice = permanence === "transient" ? "the history store judged the fault transient: retry later" : permanence === "terminal" ? "the history store judged the fault permanent: retrying will not help until the store is repaired" : "the history store did not judge whether retrying can help";
577
+ sendError(res, 503, "state.file_history_unreadable", `this session's file history cannot be read whole (${e.failure.code}), so nothing was exported — ${advice}`, permanence === undefined ? undefined : { permanence });
578
+ return true;
579
+ }
580
+ function sendMissingBlob(res) {
581
+ sendError(res, 422, "missing_blob", "missing blob; PUT all referenced blobs before import");
582
+ }
583
+ function sendFileHistoryReplayFailure(res, failure) {
584
+ if (failure.missingBlob !== undefined) {
585
+ sendMissingBlob(res);
586
+ return;
587
+ }
588
+ const { code, permanence } = failure.error;
589
+ sendError(res, 422, code, `file history import failed (${code})`, permanence === undefined ? undefined : { permanence });
590
+ }
591
+ async function firstMissingBlob(blobFaces, referenced) {
592
+ if (referenced.length === 0)
593
+ return undefined;
594
+ if (!blobFaces.available)
595
+ return referenced[0];
596
+ const store = blobFaces.historyStore;
597
+ if (typeof store.hasBlobs === "function") {
598
+ const present = await store.hasBlobs([...referenced]);
599
+ return referenced.find((h) => !present.has(h));
600
+ }
601
+ for (const hash of referenced)
602
+ if (!(await store.getBlob(hash)))
603
+ return hash;
604
+ return undefined;
605
+ }
559
606
  function sendSessionSyncUnavailable(res, why) {
560
607
  switch (why) {
561
608
  case "store_backend_absent":
@@ -2,7 +2,7 @@
2
2
  * [ref] A9 域模块 —— 会话列表 / 发件链接列表。
3
3
  *
4
4
  * 路由:`GET /v1/sessions`(CC /resume picker,keyset 分页)、`GET /v1/sendfile-links`。
5
- * owner-scope 与 trace 列表同一权威模型(system/traceToken=fleet-wide,principal=钉住本人)。本域零可变状态。
5
+ * owner-scope 与 trace 列表同一权威模型(`fleetViewOf` 读档:service 凭据不报主体 / 只读 trace 凭据 / dev-open = fleet-wide;带验过的主体 = 钉住那位主体)。本域零可变状态。
6
6
  */
7
7
  import type { IncomingMessage, ServerResponse } from "node:http";
8
8
  import { type SessionListItem } from "../../security.js";
@@ -1,16 +1,15 @@
1
1
  import { isUuidV7, legacyUnownedAmnestyOpen } from "../../security.js";
2
2
  import { sendJson, sendError } from "../send.js";
3
- import { sendUnauthorized } from "../principal-gate.js";
3
+ import { fleetViewOf, sendUnauthorized } from "../principal-gate.js";
4
4
  import { filterFingerprint } from "../cursor-fingerprint.js";
5
5
  import { sessionTempoOfRunStatus } from "../../plugins/store-contracts.js";
6
6
  import { assertNever } from "../route-ctx.js";
7
7
  import * as facts from "../../capability-facts.js";
8
8
  export async function handleSessionsList(req, res, match, ctx) {
9
9
  const { deps } = ctx;
10
- const { isFleetWide, sessionOwnerScope } = ctx.helpers;
11
10
  switch (match.decl.id) {
12
11
  case "sessions-list": {
13
- const { fleetWide, gateOwner } = sessionOwnerScope(req);
12
+ const { fleetWide, gateOwner } = fleetViewOf(req, deps, "read");
14
13
  if (!fleetWide && gateOwner === null) {
15
14
  sendUnauthorized(res, "identity");
16
15
  return;
@@ -21,12 +20,12 @@ export async function handleSessionsList(req, res, match, ctx) {
21
20
  return;
22
21
  }
23
22
  const lister = listing.lister;
24
- const includeUnowned = !fleetWide && legacyUnownedAmnestyOpen(deps.config.requirePrincipal, gateOwner);
23
+ const includeUnowned = !fleetWide && legacyUnownedAmnestyOpen(deps.config, gateOwner);
25
24
  await handleSessionList(res, lister, new URLSearchParams(match.search), gateOwner, includeUnowned);
26
25
  return;
27
26
  }
28
27
  case "sendfile-links": {
29
- const { fleetWide, gateOwner } = sessionOwnerScope(req);
28
+ const { fleetWide, gateOwner } = fleetViewOf(req, deps, "read");
30
29
  if (!fleetWide && gateOwner === null) {
31
30
  sendUnauthorized(res, "identity");
32
31
  return;