@sema-agent/server 7.132.0 → 7.134.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 (473) hide show
  1. package/MIGRATION.md +353 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +301 -64
  5. package/deploy/sema-up/README.md +35 -1
  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 +19 -2
  11. package/deploy/sema-up/chart/templates/server.yaml +19 -2
  12. package/deploy/sema-up/chart/values-full-single.yaml +5 -1
  13. package/deploy/sema-up/chart/values.yaml +34 -0
  14. package/deploy/sema-up/stack/compose.yaml +3 -0
  15. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  16. package/dist/adoption/plan.d.ts +3 -2
  17. package/dist/adoption/plan.js +7 -5
  18. package/dist/adoption/runner.js +3 -10
  19. package/dist/adoption/sql.d.ts +3 -2
  20. package/dist/adoption/sql.js +3 -5
  21. package/dist/adoption/wire.d.ts +4 -1
  22. package/dist/adoption/wire.js +1 -0
  23. package/dist/approval-ask-audit-store.d.ts +32 -14
  24. package/dist/approval-ask-audit-store.js +272 -74
  25. package/dist/approval-ask-machine.d.ts +15 -0
  26. package/dist/approval-ask-machine.js +6 -0
  27. package/dist/approval-ask-retention.d.ts +136 -0
  28. package/dist/approval-ask-retention.js +102 -0
  29. package/dist/approval-card.d.ts +83 -23
  30. package/dist/approval-card.js +45 -15
  31. package/dist/approval-content-kind.d.ts +5 -2
  32. package/dist/approval-content-kind.js +16 -3
  33. package/dist/approval-deny-reasons.d.ts +1 -1
  34. package/dist/approval-gate-currency.d.ts +72 -0
  35. package/dist/approval-gate-currency.js +94 -0
  36. package/dist/approval.d.ts +15 -0
  37. package/dist/approval.js +55 -17
  38. package/dist/audit.d.ts +27 -10
  39. package/dist/audit.js +12 -16
  40. package/dist/bake-runner/main.js +3 -2
  41. package/dist/boot/coordinators.d.ts +6 -1
  42. package/dist/boot/coordinators.js +6 -3
  43. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  44. package/dist/boot/execution-env.js +9 -7
  45. package/dist/boot/execution-lane.js +11 -0
  46. package/dist/boot/leader.d.ts +2 -0
  47. package/dist/boot/leader.js +4 -1
  48. package/dist/boot/memory-boundary.js +2 -2
  49. package/dist/boot/memory-consolidation.d.ts +5 -4
  50. package/dist/boot/memory-consolidation.js +7 -6
  51. package/dist/boot/org-delivery.d.ts +28 -0
  52. package/dist/boot/org-delivery.js +20 -0
  53. package/dist/boot/read-deny-anchor-audit.js +2 -2
  54. package/dist/boot/reapers.d.ts +3 -0
  55. package/dist/boot/reapers.js +21 -1
  56. package/dist/boot/resolve-spec.d.ts +3 -0
  57. package/dist/boot/resolve-spec.js +60 -81
  58. package/dist/boot/runner-deps.d.ts +18 -5
  59. package/dist/boot/runner-deps.js +10 -0
  60. package/dist/boot/session-faces.d.ts +1 -0
  61. package/dist/boot/session-faces.js +4 -2
  62. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  63. package/dist/boot/stage-06-runners.d.ts +6 -3
  64. package/dist/boot/stage-06-runners.js +20 -4
  65. package/dist/boot/stage-07-capability-layer.d.ts +4 -1
  66. package/dist/boot/stage-07-capability-layer.js +24 -3
  67. package/dist/boot/stage-08-reapers.d.ts +4 -1
  68. package/dist/boot/stage-08-reapers.js +2 -2
  69. package/dist/boot/stage-09-leader.d.ts +5 -1
  70. package/dist/boot/stage-09-leader.js +2 -2
  71. package/dist/boot/stage-10-http-server.d.ts +5 -1
  72. package/dist/boot/stage-10-http-server.js +6 -6
  73. package/dist/boot/stores.d.ts +8 -0
  74. package/dist/boot/stores.js +10 -14
  75. package/dist/boot/web-admin.d.ts +10 -0
  76. package/dist/boot/web-admin.js +162 -65
  77. package/dist/boot/workflow-orchestration.d.ts +2 -0
  78. package/dist/boot/workflow-orchestration.js +2 -1
  79. package/dist/brain.js +8 -3
  80. package/dist/breaker-key.d.ts +6 -0
  81. package/dist/breaker-key.js +29 -0
  82. package/dist/budget.js +5 -1
  83. package/dist/caller-text-echo.d.ts +11 -6
  84. package/dist/caller-text-echo.js +10 -12
  85. package/dist/canonical-json.d.ts +2 -41
  86. package/dist/canonical-json.js +2 -13
  87. package/dist/capabilities/center-plugins.d.ts +7 -0
  88. package/dist/capabilities/center-plugins.js +1 -1
  89. package/dist/capabilities/composite-members.d.ts +1 -1
  90. package/dist/capabilities/composite-members.js +1 -1
  91. package/dist/capabilities/execution-lane.js +2 -2
  92. package/dist/capabilities/hands-lane.d.ts +21 -0
  93. package/dist/capabilities/hands-lane.js +10 -0
  94. package/dist/capabilities/mcp-probe.d.ts +36 -4
  95. package/dist/capabilities/mcp-probe.js +29 -6
  96. package/dist/capabilities/scenarios.d.ts +63 -7
  97. package/dist/capabilities/scenarios.js +39 -7
  98. package/dist/capability-facts.d.ts +36 -4
  99. package/dist/capability-facts.js +30 -4
  100. package/dist/center-config-tier.d.ts +69 -0
  101. package/dist/center-config-tier.js +42 -0
  102. package/dist/checkpoint-ctx-seal-m28.d.ts +42 -0
  103. package/dist/checkpoint-ctx-seal-m28.js +19 -0
  104. package/dist/checkpoint-identity.d.ts +16 -0
  105. package/dist/checkpoint-identity.js +19 -0
  106. package/dist/config-catalog.d.ts +17 -10
  107. package/dist/config-catalog.js +43 -28
  108. package/dist/config-d-migration.d.ts +3 -1
  109. package/dist/config-d-migration.js +2 -2
  110. package/dist/config-dir-trust.d.ts +114 -0
  111. package/dist/config-dir-trust.js +388 -0
  112. package/dist/config-invariants.d.ts +18 -5
  113. package/dist/config-invariants.js +35 -3
  114. package/dist/config-provider.d.ts +6 -1
  115. package/dist/config-provider.js +6 -2
  116. package/dist/config-types.d.ts +71 -14
  117. package/dist/config-types.js +8 -0
  118. package/dist/config.d.ts +13 -0
  119. package/dist/config.js +121 -59
  120. package/dist/delegated-session-owner.d.ts +185 -0
  121. package/dist/delegated-session-owner.js +119 -0
  122. package/dist/device-protocol.d.ts +5 -3
  123. package/dist/device-protocol.js +1 -1
  124. package/dist/device-ws-hub.js +21 -2
  125. package/dist/device-ws-protocol.d.ts +70 -6
  126. package/dist/device-ws-protocol.js +50 -23
  127. package/dist/elicitation.js +3 -2
  128. package/dist/entry-problems.d.ts +34 -0
  129. package/dist/entry-problems.js +14 -0
  130. package/dist/execution-lane-caps.d.ts +49 -10
  131. package/dist/execution-lane-caps.js +43 -4
  132. package/dist/field-conflict.d.ts +44 -0
  133. package/dist/field-conflict.js +21 -0
  134. package/dist/file-history-disclosure.d.ts +34 -5
  135. package/dist/file-history-disclosure.js +2 -2
  136. package/dist/fleet/fleet-bus.d.ts +84 -6
  137. package/dist/fleet/fleet-bus.js +42 -9
  138. package/dist/hooks/classic-stations.d.ts +10 -5
  139. package/dist/hooks/classic-stations.js +4 -4
  140. package/dist/hooks/command-spawn.d.ts +57 -0
  141. package/dist/hooks/command-spawn.js +139 -0
  142. package/dist/hooks/hook-llm.js +2 -2
  143. package/dist/hooks/hook-runner.d.ts +127 -25
  144. package/dist/hooks/hook-runner.js +668 -287
  145. package/dist/hooks/hook-source.d.ts +44 -0
  146. package/dist/hooks/hook-source.js +40 -0
  147. package/dist/http/active-run-conflict.d.ts +5 -13
  148. package/dist/http/active-run-conflict.js +17 -27
  149. package/dist/http/admission.js +111 -60
  150. package/dist/http/approval-sweeps.js +58 -19
  151. package/dist/http/caller-trust.d.ts +77 -0
  152. package/dist/http/caller-trust.js +143 -0
  153. package/dist/http/checkpoint-ctx.d.ts +173 -18
  154. package/dist/http/checkpoint-ctx.js +171 -12
  155. package/dist/http/claimed-run.d.ts +4 -3
  156. package/dist/http/device-placement.d.ts +2 -4
  157. package/dist/http/device-placement.js +2 -1
  158. package/dist/http/dispatch.js +13 -7
  159. package/dist/http/durable-run-leg.d.ts +4 -32
  160. package/dist/http/durable-run-leg.js +37 -12
  161. package/dist/http/idempotency.d.ts +2 -2
  162. package/dist/http/idempotency.js +2 -2
  163. package/dist/http/owner-access.d.ts +56 -0
  164. package/dist/http/owner-access.js +42 -0
  165. package/dist/http/principal-gate.d.ts +78 -27
  166. package/dist/http/principal-gate.js +64 -14
  167. package/dist/http/readiness.d.ts +11 -5
  168. package/dist/http/readiness.js +10 -3
  169. package/dist/http/refusal-body.d.ts +12 -0
  170. package/dist/http/refusal-body.js +11 -0
  171. package/dist/http/request-guards.d.ts +16 -32
  172. package/dist/http/request-guards.js +31 -30
  173. package/dist/http/resume-ctx-read.d.ts +50 -6
  174. package/dist/http/resume-ctx-read.js +33 -7
  175. package/dist/http/resume-legs.d.ts +5 -5
  176. package/dist/http/resume-legs.js +163 -91
  177. package/dist/http/retired-service-deps.d.ts +43 -0
  178. package/dist/http/retired-service-deps.js +18 -0
  179. package/dist/http/route-ctx.d.ts +44 -37
  180. package/dist/http/route-ctx.js +4 -0
  181. package/dist/http/route-table.js +2 -0
  182. package/dist/http/routes/a2a-serve.js +3 -4
  183. package/dist/http/routes/admin-config-refresh.js +1 -1
  184. package/dist/http/routes/admin-drain.js +1 -1
  185. package/dist/http/routes/admin-memory-optout.js +5 -1
  186. package/dist/http/routes/adoption.js +2 -9
  187. package/dist/http/routes/agents-roster.js +2 -3
  188. package/dist/http/routes/approvals-assistant.js +91 -56
  189. package/dist/http/routes/background.js +3 -2
  190. package/dist/http/routes/capabilities.js +20 -4
  191. package/dist/http/routes/config-catalog.d.ts +3 -3
  192. package/dist/http/routes/config-catalog.js +1 -1
  193. package/dist/http/routes/devices.js +3 -17
  194. package/dist/http/routes/diagnostics.d.ts +3 -3
  195. package/dist/http/routes/diagnostics.js +6 -2
  196. package/dist/http/routes/fleet.js +4 -4
  197. package/dist/http/routes/images.js +6 -7
  198. package/dist/http/routes/leader.js +1 -8
  199. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  200. package/dist/http/routes/mcp-reconnect.js +3 -2
  201. package/dist/http/routes/memory-bundle.js +1 -1
  202. package/dist/http/routes/memory-compliance.js +1 -1
  203. package/dist/http/routes/memory-consolidation.js +1 -1
  204. package/dist/http/routes/memory-origin.d.ts +1 -1
  205. package/dist/http/routes/memory-origin.js +1 -1
  206. package/dist/http/routes/memory-policy.d.ts +1 -1
  207. package/dist/http/routes/memory-policy.js +3 -2
  208. package/dist/http/routes/notify-wake.js +8 -21
  209. package/dist/http/routes/observability.js +2 -2
  210. package/dist/http/routes/principal-inbox.d.ts +39 -0
  211. package/dist/http/routes/principal-inbox.js +76 -0
  212. package/dist/http/routes/retention-ops.js +2 -9
  213. package/dist/http/routes/rules.js +9 -22
  214. package/dist/http/routes/runs.d.ts +5 -0
  215. package/dist/http/routes/runs.js +63 -115
  216. package/dist/http/routes/session-sync.d.ts +3 -2
  217. package/dist/http/routes/session-sync.js +53 -48
  218. package/dist/http/routes/sessions-list.d.ts +1 -1
  219. package/dist/http/routes/sessions-list.js +3 -4
  220. package/dist/http/routes/sessions.js +33 -43
  221. package/dist/http/routes/side-query.js +6 -4
  222. package/dist/http/routes/tasks.js +71 -30
  223. package/dist/http/routes/trace-usage.js +7 -9
  224. package/dist/http/routes/workflows.d.ts +351 -0
  225. package/dist/http/routes/workflows.js +153 -119
  226. package/dist/http/run-declared-families.d.ts +16 -0
  227. package/dist/http/run-declared-families.js +12 -0
  228. package/dist/http/send.d.ts +24 -3
  229. package/dist/http/send.js +14 -2
  230. package/dist/http/server.d.ts +23 -18
  231. package/dist/http/server.js +20 -15
  232. package/dist/http/stored-body-replay.js +17 -4
  233. package/dist/http/submit-ctx.d.ts +4 -3
  234. package/dist/http/submit-ctx.js +23 -6
  235. package/dist/http/submit-replay.d.ts +4 -3
  236. package/dist/http/submit-replay.js +5 -4
  237. package/dist/http/wire-types.d.ts +17 -10
  238. package/dist/index.d.ts +3 -1
  239. package/dist/index.js +1 -1
  240. package/dist/lane-home-probe.d.ts +78 -9
  241. package/dist/lane-home-probe.js +78 -12
  242. package/dist/leader/endpoint.d.ts +4 -1
  243. package/dist/leader/endpoint.js +11 -10
  244. package/dist/leader/wire.d.ts +4 -0
  245. package/dist/leader/wire.js +8 -7
  246. package/dist/limit-refusal.d.ts +17 -5
  247. package/dist/limit-refusal.js +4 -1
  248. package/dist/main.js +1 -1
  249. package/dist/mcp-assertion-header.d.ts +31 -10
  250. package/dist/mcp-assertion-header.js +10 -3
  251. package/dist/memory-origin-fence.js +2 -2
  252. package/dist/memory-project-layer.d.ts +37 -0
  253. package/dist/memory-project-layer.js +46 -0
  254. package/dist/memory-scope.d.ts +23 -16
  255. package/dist/memory-scope.js +24 -8
  256. package/dist/memory-sync-client.d.ts +27 -13
  257. package/dist/memory-sync-client.js +107 -18
  258. package/dist/model-compat.d.ts +1 -1
  259. package/dist/model-entry-refusal.d.ts +9 -1
  260. package/dist/model-entry-refusal.js +6 -1
  261. package/dist/model-plane-face.d.ts +51 -0
  262. package/dist/model-plane-face.js +24 -0
  263. package/dist/model-provider.d.ts +5 -0
  264. package/dist/model-provider.js +4 -2
  265. package/dist/model-route-endpoint.d.ts +8 -11
  266. package/dist/model-route-endpoint.js +4 -7
  267. package/dist/model-route-env.d.ts +22 -0
  268. package/dist/model-route-env.js +2 -0
  269. package/dist/model-route-gap.d.ts +60 -30
  270. package/dist/model-route-gap.js +21 -15
  271. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  272. package/dist/observability/corrupt-read-seat.js +9 -0
  273. package/dist/observability/err-text.d.ts +6 -0
  274. package/dist/observability/err-text.js +18 -4
  275. package/dist/observability/fail-open.d.ts +35 -9
  276. package/dist/observability/fail-open.js +35 -9
  277. package/dist/observability/metrics.js +1 -0
  278. package/dist/observability/prompt-manifest.d.ts +22 -25
  279. package/dist/observability/prompt-manifest.js +54 -50
  280. package/dist/observability/tool-trace.js +9 -10
  281. package/dist/operator-ask.d.ts +10 -0
  282. package/dist/operator-ask.js +3 -0
  283. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  284. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  285. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  286. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  287. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  288. package/dist/orchestration/workflow-notify-journal.js +27 -34
  289. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  290. package/dist/orchestration/workflow-park-decision.js +119 -0
  291. package/dist/org-delivery-gate.d.ts +81 -0
  292. package/dist/org-delivery-gate.js +59 -0
  293. package/dist/panel-tool-names.d.ts +23 -0
  294. package/dist/panel-tool-names.js +8 -0
  295. package/dist/parked-decide.d.ts +43 -11
  296. package/dist/parked-decide.js +100 -51
  297. package/dist/parked-revive-surface.d.ts +9 -2
  298. package/dist/parked-revive-surface.js +11 -8
  299. package/dist/permission-rule-list.d.ts +1 -1
  300. package/dist/permission-rule-list.js +2 -2
  301. package/dist/permission-rule-vocab.d.ts +1 -23
  302. package/dist/permission-rule-vocab.js +0 -13
  303. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  304. package/dist/plugins/approval-ask-store-file.js +21 -0
  305. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  306. package/dist/plugins/approval-ask-store-memory.js +34 -2
  307. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  308. package/dist/plugins/approval-ask-store-sql.js +37 -1
  309. package/dist/plugins/approval-payload-fingerprint.d.ts +14 -6
  310. package/dist/plugins/approval-payload-fingerprint.js +1 -1
  311. package/dist/plugins/blob-backend.d.ts +38 -25
  312. package/dist/plugins/blob-backend.js +29 -19
  313. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  314. package/dist/plugins/breaker-state-sql.js +4 -4
  315. package/dist/plugins/caching-session-store.d.ts +4 -1
  316. package/dist/plugins/caching-session-store.js +7 -3
  317. package/dist/plugins/checkpoint-store-sql.d.ts +36 -1
  318. package/dist/plugins/checkpoint-store-sql.js +65 -3
  319. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  320. package/dist/plugins/file-history-store-sql.js +3 -1
  321. package/dist/plugins/file-run-store.d.ts +5 -13
  322. package/dist/plugins/file-run-store.js +9 -0
  323. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  324. package/dist/plugins/fork-routing-session-store.js +12 -1
  325. package/dist/plugins/host-platform.d.ts +2 -0
  326. package/dist/plugins/host-platform.js +2 -1
  327. package/dist/plugins/local-checkpoint-store.d.ts +15 -2
  328. package/dist/plugins/local-checkpoint-store.js +32 -1
  329. package/dist/plugins/local-session-store.d.ts +13 -10
  330. package/dist/plugins/local-session-store.js +23 -14
  331. package/dist/plugins/local-session-window.d.ts +45 -0
  332. package/dist/plugins/local-session-window.js +38 -0
  333. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  334. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  335. package/dist/plugins/mailbox-store-sql.js +77 -52
  336. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  337. package/dist/plugins/memory-run-store.d.ts +5 -13
  338. package/dist/plugins/memory-run-store.js +8 -0
  339. package/dist/plugins/one-time-migrations.d.ts +121 -5
  340. package/dist/plugins/one-time-migrations.js +332 -8
  341. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  342. package/dist/plugins/org-delivery-quota-store.js +228 -0
  343. package/dist/plugins/permission-rule-store-file.js +10 -6
  344. package/dist/plugins/permission-rule-store-sql.js +8 -8
  345. package/dist/plugins/pg-pool.js +39 -7
  346. package/dist/plugins/pg-session-storage.d.ts +18 -5
  347. package/dist/plugins/pg-session-storage.js +68 -23
  348. package/dist/plugins/remote-env-adb.d.ts +6 -12
  349. package/dist/plugins/remote-env-adb.js +12 -2
  350. package/dist/plugins/remote-env-device.d.ts +14 -7
  351. package/dist/plugins/remote-env-device.js +23 -15
  352. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  353. package/dist/plugins/remote-env-k8s.js +23 -5
  354. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  355. package/dist/plugins/remote-env-local-docker.js +12 -9
  356. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  357. package/dist/plugins/remote-env-ssh.js +17 -11
  358. package/dist/plugins/run-store-sql.d.ts +16 -14
  359. package/dist/plugins/run-store-sql.js +22 -2
  360. package/dist/plugins/schema-indexes.js +2 -0
  361. package/dist/plugins/send-user-file.js +2 -2
  362. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  363. package/dist/plugins/session-epoch-anchor.js +2 -3
  364. package/dist/plugins/session-ownership.d.ts +11 -0
  365. package/dist/plugins/session-ownership.js +11 -0
  366. package/dist/plugins/session-placement.d.ts +12 -14
  367. package/dist/plugins/session-placement.js +2 -15
  368. package/dist/plugins/session-store.d.ts +18 -8
  369. package/dist/plugins/session-store.js +15 -4
  370. package/dist/plugins/sql-driver.d.ts +74 -11
  371. package/dist/plugins/sql-driver.js +210 -12
  372. package/dist/plugins/sql-errors.d.ts +23 -0
  373. package/dist/plugins/sql-errors.js +21 -0
  374. package/dist/plugins/store-backend.d.ts +36 -1
  375. package/dist/plugins/store-backend.js +40 -14
  376. package/dist/plugins/store-contracts.d.ts +42 -0
  377. package/dist/plugins/store-contracts.js +1 -0
  378. package/dist/plugins/tidb-pool.d.ts +6 -1
  379. package/dist/plugins/tidb-pool.js +44 -10
  380. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  381. package/dist/plugins/tidb-session-storage.js +2 -2
  382. package/dist/plugins/tidb-session-store.d.ts +25 -5
  383. package/dist/plugins/tidb-session-store.js +67 -21
  384. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  385. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  386. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  387. package/dist/plugins/workflow-run-store-sql.js +50 -9
  388. package/dist/posture-source.d.ts +18 -10
  389. package/dist/posture-source.js +4 -1
  390. package/dist/project-identity.d.ts +45 -6
  391. package/dist/project-identity.js +162 -8
  392. package/dist/project-layer-key.d.ts +28 -0
  393. package/dist/project-layer-key.js +29 -0
  394. package/dist/question.js +3 -2
  395. package/dist/read-deny-entry.d.ts +25 -0
  396. package/dist/read-deny-entry.js +12 -0
  397. package/dist/read-face-posture.d.ts +37 -11
  398. package/dist/read-face-posture.js +32 -3
  399. package/dist/request-key-closure.d.ts +7 -0
  400. package/dist/request-key-closure.js +9 -1
  401. package/dist/request-tool-axes.d.ts +12 -0
  402. package/dist/request-tool-axes.js +20 -0
  403. package/dist/request-value-closure.d.ts +5 -0
  404. package/dist/request-value-closure.js +11 -3
  405. package/dist/rule-entry-list.d.ts +26 -2
  406. package/dist/rule-entry-list.js +72 -12
  407. package/dist/rules-consent.js +3 -4
  408. package/dist/run-acceptance.d.ts +19 -3
  409. package/dist/run-acceptance.js +13 -1
  410. package/dist/run-local.js +37 -6
  411. package/dist/runs.d.ts +12 -10
  412. package/dist/runs.js +25 -6
  413. package/dist/runtime-caps-resolver.d.ts +16 -6
  414. package/dist/runtime-caps-resolver.js +18 -5
  415. package/dist/sandbox-pkg-source.d.ts +19 -1
  416. package/dist/sandbox-pkg-source.js +29 -7
  417. package/dist/sealed-key.d.ts +32 -0
  418. package/dist/sealed-key.js +55 -1
  419. package/dist/security.d.ts +95 -15
  420. package/dist/security.js +52 -9
  421. package/dist/session-error-wire.d.ts +31 -7
  422. package/dist/session-error-wire.js +9 -2
  423. package/dist/session-sync-kernel.d.ts +37 -10
  424. package/dist/session-sync-kernel.js +10 -0
  425. package/dist/session-titled-frame.d.ts +33 -0
  426. package/dist/session-titled-frame.js +4 -0
  427. package/dist/session-titler.d.ts +9 -1
  428. package/dist/session-titler.js +15 -4
  429. package/dist/spec-fields.js +21 -2
  430. package/dist/sql-engine-posture.d.ts +3 -1
  431. package/dist/task-a2a.js +4 -3
  432. package/dist/task-cwd.d.ts +1 -1
  433. package/dist/task-mcp.d.ts +5 -5
  434. package/dist/task-mcp.js +27 -74
  435. package/dist/task-settings.d.ts +93 -88
  436. package/dist/task-settings.js +71 -63
  437. package/dist/text-bidi.d.ts +0 -4
  438. package/dist/text-bidi.js +1 -3
  439. package/dist/tighten-only-seats.d.ts +150 -0
  440. package/dist/tighten-only-seats.js +196 -0
  441. package/dist/tool-approval.d.ts +451 -136
  442. package/dist/tool-approval.js +733 -256
  443. package/dist/tool-rule-names.d.ts +6 -0
  444. package/dist/trace/core-keyset-guard.d.ts +108 -25
  445. package/dist/trace/exit-seat.d.ts +40 -0
  446. package/dist/trace/exit-seat.js +130 -0
  447. package/dist/trace/ledger-events.d.ts +6 -3
  448. package/dist/trace/project.d.ts +98 -13
  449. package/dist/trace/project.js +57 -32
  450. package/dist/trace/projection-table.d.ts +100 -0
  451. package/dist/trace/projection-table.js +130 -0
  452. package/dist/trace/redact.d.ts +57 -0
  453. package/dist/trace/redact.js +962 -168
  454. package/dist/trace/self-minted-wire.d.ts +349 -1
  455. package/dist/trace/self-minted-wire.js +118 -1
  456. package/dist/trace/wire-projection-faces.d.ts +304 -2
  457. package/dist/trace/wire-projection-faces.js +160 -13
  458. package/dist/url-refusal.js +2 -0
  459. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  460. package/dist/web-admin-client/apply-effective.js +56 -5
  461. package/dist/web-admin-client/facade.d.ts +1 -1
  462. package/dist/web-admin-client/facade.js +1 -1
  463. package/dist/web-admin-client/read-face.js +5 -9
  464. package/dist/web-admin-client/skills-mcp.d.ts +1 -1
  465. package/dist/web-admin-client/skills-mcp.js +6 -8
  466. package/dist/web-admin-client/types.d.ts +1 -1
  467. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  468. package/package.json +8 -4
  469. package/scripts/drain-check-local.mjs +34 -2
  470. package/scripts/drain-check.mysql.sql +20 -2
  471. package/scripts/drain-check.pg.sql +20 -2
  472. package/dist/mcp-tool-faces.d.ts +0 -69
  473. package/dist/mcp-tool-faces.js +0 -106
@@ -5,7 +5,7 @@ import { uuidv7, mintCheckpointToken, CheckpointError, policyCannotAnswer, valid
5
5
  import { isTerminalRunStatus, isParkedRunStatus, runProvenElsewhere } from "../../plugins/store-contracts.js";
6
6
  import { LIVE_RUN_GATE_KINDS, TERMINAL_PARK_GATE_KINDS } from "../../plugins/checkpoint-store-sql.js";
7
7
  import { redactSecrets } from "../../trace/redact.js";
8
- import { HttpError, isUuidV7, encodeCheckpointScope } from "../../security.js";
8
+ import { isUuidV7, encodeCheckpointScope } from "../../security.js";
9
9
  import { redactSteerIn, STEER_IN_MAX_CHARS, STEER_IN_MAX_REQUEST_CHARS } from "../../orchestration/workflow-agent-steer.js";
10
10
  import { defaultSubagentTailBus } from "../../fleet/subagent-tail-bus.js";
11
11
  import { idemCallerOf, idemKeyOf, inflightKeyOf, submissionIdemOf } from "../idempotency.js";
@@ -13,11 +13,12 @@ import { streamSseLog } from "../sse-log.js";
13
13
  import { bindSseLifecycle } from "../sse-lifecycle.js";
14
14
  import { buildApprovalPreamble, buildApprovalPreambleSseFrames, readClosedWordSeat, storedCardDemandsAPerson } from "../../approval-card.js";
15
15
  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 { MAX_DECISION_NOTE_CHARS } from "../../approval-ask-machine.js";
16
+ import { ASK_DECISION_CONSUMER_ABSENT, approvalPreambleReplays, outcomeOfDecidedRow, resolveStreamApprovalGate } from "../../tool-approval.js";
17
+ import { readRunDeclaredFamilies } from "../run-declared-families.js";
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";
20
- import { sendJson, sendError, sendHttpError, sseHeaders } from "../send.js";
21
+ import { invalidJsonError, sendJson, sendError, sendHttpError, sseHeaders } from "../send.js";
21
22
  import { mintCancelledResult } from "../../run-cancel-context.js";
22
23
  import { acceptedInputKindOf } from "../../user-input-ledger.js";
23
24
  import { INJECTION_TIERS } from "../../trace/injection-tier.js";
@@ -35,6 +36,7 @@ import { storedBodyReplayAnswer, storedBodyReplayLogFields } from "../checkpoint
35
36
  import { serviceVersion } from "../../service-version.js";
36
37
  import { storedBodyReplayRefusal } from "../stored-body-replay.js";
37
38
  import { steerBodyKeyIssue } from "../../request-key-closure.js";
39
+ import { fieldConflictFacts } from "../../field-conflict.js";
38
40
  const STEER_PRIORITY_WORDS = INJECTION_TIERS.map((tier) => `'${tier}'`);
39
41
  const STEER_PRIORITY_UNION = STEER_PRIORITY_WORDS.join(" | ");
40
42
  const STEER_PRIORITY_CHOICES = STEER_PRIORITY_WORDS.length <= 2 ? STEER_PRIORITY_WORDS.join(" or ") : `${STEER_PRIORITY_WORDS.slice(0, -1).join(", ")}, or ${STEER_PRIORITY_WORDS[STEER_PRIORITY_WORDS.length - 1]}`;
@@ -81,7 +83,7 @@ async function subagentReadGate(req, res, ctx, runId, search) {
81
83
  sendPrincipalRefusal(res, req, deps.config);
82
84
  return null;
83
85
  }
84
- const trusted = explicitOperatorOk(principal, deps.config.operatorPrincipals);
86
+ const trusted = explicitOperatorOk(principal, deps.config);
85
87
  const run = await deps.runStore.getRun(runId);
86
88
  if (!run) {
87
89
  sendError(res, 404, "not_found.run", RUN_NOT_FOUND_MESSAGE);
@@ -108,17 +110,26 @@ function sendHandleMiss(res, run, thisInstanceId) {
108
110
  }
109
111
  return false;
110
112
  }
111
- async function streamRunEvents(req, res, deps, runStore, taskId, staleMs) {
113
+ async function streamRunEvents(req, res, deps, runStore, taskId, sessionId, staleMs) {
112
114
  await streamSseLog(req, res, {
113
115
  preamble: async (signal) => {
114
116
  const gate = resolveStreamApprovalGate({
115
117
  toolApprovalEnabled: Boolean(deps.toolApproval),
116
118
  streamApprovalEnabled: deps.config.streamApproval?.enabled === true,
117
119
  backend: deps.backend,
118
- parkFacility: deps.checkpointStore !== undefined,
120
+ checkpointStore: deps.checkpointStore,
119
121
  });
120
122
  if (!gate.active)
121
123
  return [];
124
+ const declaredFamilies = await readRunDeclaredFamilies(gate.checkpointStore, sessionId, (where) => deps.logger?.warn?.("approval_preamble_declaration_unreadable", { taskId, where, face: "run.events" }));
125
+ if (!approvalPreambleReplays({
126
+ streamApprovalOn: gate.active,
127
+ windowMs: deps.config.streamApproval?.windowMs,
128
+ windowMarginMs: deps.config.streamAskWindowMarginMs,
129
+ declaredFamilies,
130
+ })) {
131
+ return [];
132
+ }
122
133
  const store = gate.askStore;
123
134
  const rows = await store.listPendingByTask(taskId, signal);
124
135
  const { frames, skipped, dropped } = buildApprovalPreamble(rows, Date.now(), deps.config.streamApproval.replayMax);
@@ -254,7 +265,7 @@ export async function handleRuns(req, res, match, ctx) {
254
265
  if (!runSessionAcceptOk(req, res, run, match.decl.id === "run-events" ? "run.events" : "run.poll"))
255
266
  return;
256
267
  if (match.decl.id === "run-events") {
257
- await streamRunEvents(req, res, deps, runStore, taskId, deps.config.runStaleSec * 1000);
268
+ await streamRunEvents(req, res, deps, runStore, taskId, run.sessionId, deps.config.runStaleSec * 1000);
258
269
  }
259
270
  else {
260
271
  sendJson(res, 200, await readRunFace(deps, runStore, run));
@@ -399,18 +410,7 @@ export async function handleRuns(req, res, match, ctx) {
399
410
  return;
400
411
  }
401
412
  const taskId = match.params.taskId;
402
- let body;
403
- try {
404
- body = ((await readJson(req)) ?? {});
405
- }
406
- catch (e) {
407
- if (e instanceof HttpError) {
408
- sendHttpError(res, e);
409
- return;
410
- }
411
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
412
- return;
413
- }
413
+ const body = ((await readJson(req)) ?? {});
414
414
  if (typeof body.text !== "string" || body.text.length === 0) {
415
415
  sendError(res, 400, "request.body_shape", `body must be { text: string (non-empty), mode?: 'all' | 'one-at-a-time', priority?: ${STEER_PRIORITY_UNION} }`);
416
416
  return;
@@ -435,7 +435,7 @@ export async function handleRuns(req, res, match, ctx) {
435
435
  const steerIdemRaw = headerStr(req.headers["idempotency-key"]);
436
436
  const steerInputId = steerIdemRaw ? `idem-${idemKeyOf(steerIdemRaw, idemCallerOf(req, ctx), "run").slice(0, 32)}` : undefined;
437
437
  const messageId = steerInputId ?? uuidv7();
438
- const trusted = explicitOperatorOk(principal, deps.config.operatorPrincipals);
438
+ const trusted = explicitOperatorOk(principal, deps.config);
439
439
  const steerInput = () => ({
440
440
  text,
441
441
  trusted,
@@ -623,11 +623,15 @@ export async function handleRuns(req, res, match, ctx) {
623
623
  const leafId = await Promise.resolve(deps.sessionStorage.getLeafId(run.sessionId)).catch(() => undefined);
624
624
  if (leafId === undefined || leafId === null)
625
625
  return;
626
- const resumeRead = await readResumeCtx(cs.getCtx(run.sessionId));
626
+ const resumeRead = await readResumeCtx(cs.getCtx(run.sessionId), { sessionId: run.sessionId, opener: deps.checkpointCtxSealing });
627
627
  if (resumeRead.kind === "corrupt") {
628
628
  mintResult.corruptCtxWhere = resumeRead.where;
629
629
  return;
630
630
  }
631
+ if (resumeRead.kind === "unsealable") {
632
+ mintResult.unsealableCtx = resumeRead;
633
+ return;
634
+ }
631
635
  if (resumeRead.kind === "absent") {
632
636
  mintResult.noResumeCtx = true;
633
637
  return;
@@ -651,10 +655,13 @@ export async function handleRuns(req, res, match, ctx) {
651
655
  createdAt: Date.now(),
652
656
  sourceTaskId: taskId,
653
657
  });
654
- const stillRead = await readResumeCtx(cs.getCtx(run.sessionId));
655
- if (stillRead.kind === "corrupt") {
656
- await withdrawWakeCard(wakeToken, cpScope, "resume_context_corrupt");
657
- mintResult.corruptCtxWhere = stillRead.where;
658
+ const stillRead = await readResumeCtx(cs.getCtx(run.sessionId), { sessionId: run.sessionId, opener: deps.checkpointCtxSealing });
659
+ if (stillRead.kind === "corrupt" || stillRead.kind === "unsealable") {
660
+ await withdrawWakeCard(wakeToken, cpScope, stillRead.kind === "corrupt" ? "resume_context_corrupt" : "resume_context_unsealable");
661
+ if (stillRead.kind === "corrupt")
662
+ mintResult.corruptCtxWhere = stillRead.where;
663
+ else
664
+ mintResult.unsealableCtx = stillRead;
658
665
  return;
659
666
  }
660
667
  if (stillRead.kind !== "ok") {
@@ -691,6 +698,10 @@ export async function handleRuns(req, res, match, ctx) {
691
698
  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 });
692
699
  return;
693
700
  }
701
+ if (mintResult.unsealableCtx !== undefined) {
702
+ 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 });
703
+ return;
704
+ }
694
705
  if (mintResult.unservable !== undefined) {
695
706
  deps.logger?.warn?.("steer_wake_park_refused_stored_body", { taskId, sessionId: run.sessionId, ...storedBodyReplayLogFields(mintResult.unservable) });
696
707
  const { status, body: { error, errorCode, ...rest } } = storedBodyReplayAnswer(mintResult.unservable, serviceVersion(), false);
@@ -724,18 +735,7 @@ export async function handleRuns(req, res, match, ctx) {
724
735
  return;
725
736
  }
726
737
  const taskId = match.params.taskId;
727
- let interruptRaw;
728
- try {
729
- interruptRaw = await readJson(req);
730
- }
731
- catch (e) {
732
- if (e instanceof HttpError) {
733
- sendHttpError(res, e);
734
- return;
735
- }
736
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
737
- return;
738
- }
738
+ const interruptRaw = await readJson(req);
739
739
  const interruptNormalized = interruptRaw === null || interruptRaw === undefined ? {} : interruptRaw;
740
740
  if (typeof interruptNormalized !== "object" || Array.isArray(interruptNormalized)) {
741
741
  sendError(res, 400, "request.body_shape", "body must be {} (bare halt: cut the in-flight turn and stop the run at this boundary) or { text: string (non-empty) } (cut + steer: the text reaches the model after the cut)");
@@ -759,7 +759,7 @@ export async function handleRuns(req, res, match, ctx) {
759
759
  const interruptIdemRaw = headerStr(req.headers["idempotency-key"]);
760
760
  const interruptInputId = interruptIdemRaw ? `idem-${idemKeyOf(interruptIdemRaw, idemCallerOf(req, ctx), "run").slice(0, 32)}` : uuidv7();
761
761
  const interruptMessageId = interruptInputId;
762
- const trusted = explicitOperatorOk(principal, deps.config.operatorPrincipals);
762
+ const trusted = explicitOperatorOk(principal, deps.config);
763
763
  if (!interruptBare) {
764
764
  try {
765
765
  validatePendingSteer({ text, trusted, inputId: interruptInputId });
@@ -877,28 +877,17 @@ export async function handleRuns(req, res, match, ctx) {
877
877
  sendError(res, 404, "not_found.run", RUN_NOT_FOUND_MESSAGE);
878
878
  return;
879
879
  }
880
- const operator = explicitOperatorOk(principal, deps.config.operatorPrincipals);
880
+ const operator = explicitOperatorOk(principal, deps.config);
881
881
  if (!operator && !runOwnerOk(req, res, run.owner))
882
882
  return;
883
883
  if (!runSessionAcceptOk(req, res, run, "run.compact"))
884
884
  return;
885
- let compactBody;
886
- try {
887
- const parsed = await readJson(req);
888
- if (parsed === null || typeof parsed !== "object") {
889
- sendError(res, 400, "request.invalid_json", "body must be a JSON object when present");
890
- return;
891
- }
892
- compactBody = parsed;
893
- }
894
- catch (e) {
895
- if (e instanceof HttpError) {
896
- sendHttpError(res, e);
897
- return;
898
- }
899
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
885
+ const parsed = await readJson(req);
886
+ if (parsed === null || typeof parsed !== "object") {
887
+ sendHttpError(res, invalidJsonError("not_object"));
900
888
  return;
901
889
  }
890
+ const compactBody = parsed;
902
891
  if (compactBody.instructions !== undefined && (typeof compactBody.instructions !== "string" || compactBody.instructions.length === 0 || [...compactBody.instructions].length > 2_048)) {
903
892
  sendError(res, 400, "request.field_invalid", "instructions must be a non-empty string of at most 2048 characters (code points) when present — the engine caps compaction instructions there");
904
893
  return;
@@ -938,18 +927,7 @@ export async function handleRuns(req, res, match, ctx) {
938
927
  return;
939
928
  }
940
929
  const taskId = match.params.taskId;
941
- let body;
942
- try {
943
- body = ((await readJson(req)) ?? {});
944
- }
945
- catch (e) {
946
- if (e instanceof HttpError) {
947
- sendHttpError(res, e);
948
- return;
949
- }
950
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
951
- return;
952
- }
930
+ const body = ((await readJson(req)) ?? {});
953
931
  if (typeof body.toolCallId !== "string" || body.toolCallId.length === 0 || body.toolCallId.length > 256) {
954
932
  sendError(res, 400, "request.body_shape", "body must be { toolCallId: string (non-empty, ≤256 chars) }");
955
933
  return;
@@ -959,7 +937,7 @@ export async function handleRuns(req, res, match, ctx) {
959
937
  sendError(res, 404, "not_found.run", RUN_NOT_FOUND_MESSAGE);
960
938
  return;
961
939
  }
962
- const operator = explicitOperatorOk(principal, deps.config.operatorPrincipals);
940
+ const operator = explicitOperatorOk(principal, deps.config);
963
941
  if (!operator && !runOwnerOk(req, res, run.owner))
964
942
  return;
965
943
  if (!runSessionAcceptOk(req, res, run, "run.detach"))
@@ -1164,18 +1142,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1164
1142
  sendError(res, 400, "request.path_malformed", "malformed subagent path (invalid percent-encoding)");
1165
1143
  return;
1166
1144
  }
1167
- let body;
1168
- try {
1169
- body = ((await readJson(req)) ?? {});
1170
- }
1171
- catch (e) {
1172
- if (e instanceof HttpError) {
1173
- sendHttpError(res, e);
1174
- return;
1175
- }
1176
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
1177
- return;
1178
- }
1145
+ const body = ((await readJson(req)) ?? {});
1179
1146
  if (typeof body.content !== "string" || body.content.length === 0) {
1180
1147
  sendError(res, 400, "request.body_shape", "body must be { content: string (non-empty) }");
1181
1148
  return;
@@ -1191,7 +1158,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1191
1158
  sendError(res, 413, "steer.content_too_large", `content exceeds ${STEER_IN_MAX_REQUEST_CHARS} characters (got ${body.content.length}); note only the first ${STEER_IN_MAX_CHARS} are delivered anyway`);
1192
1159
  return;
1193
1160
  }
1194
- const trusted = explicitOperatorOk(principal, deps.config.operatorPrincipals);
1161
+ const trusted = explicitOperatorOk(principal, deps.config);
1195
1162
  const run = await runStore.getRun(runId);
1196
1163
  if (!run) {
1197
1164
  sendError(res, 404, "not_found.run", RUN_NOT_FOUND_MESSAGE);
@@ -1274,14 +1241,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1274
1241
  return;
1275
1242
  }
1276
1243
  const id = match.params.id;
1277
- let body;
1278
- try {
1279
- body = await readJson(req);
1280
- }
1281
- catch {
1282
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
1283
- return;
1284
- }
1244
+ const body = await readJson(req);
1285
1245
  const { status, body: respBody } = elicitFact.coordinator.respond(id, principal, body);
1286
1246
  sendJson(res, status, respBody);
1287
1247
  return;
@@ -1300,19 +1260,12 @@ export async function handleRunVerbs(req, res, match, ctx) {
1300
1260
  return;
1301
1261
  }
1302
1262
  const id = match.params.id;
1303
- let body;
1304
- try {
1305
- body = await readJson(req);
1306
- }
1307
- catch {
1308
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
1309
- return;
1310
- }
1263
+ const body = await readJson(req);
1311
1264
  const { status, body: respBody } = questionFact.coordinator.respond(id, principal, body);
1312
1265
  sendJson(res, status, respBody);
1313
1266
  return;
1314
1267
  }
1315
- if (match.decl.id === "tool-approval-respond") {
1268
+ if (match.decl.id === "tool-approval-respond" || match.decl.id === "tool-approval-read") {
1316
1269
  if (rateLimited(req, res))
1317
1270
  return;
1318
1271
  const approvalFact = facts.toolApproval(deps);
@@ -1326,15 +1279,13 @@ export async function handleRunVerbs(req, res, match, ctx) {
1326
1279
  return;
1327
1280
  }
1328
1281
  const id = match.params.id;
1329
- let body;
1330
- try {
1331
- body = await readJson(req);
1332
- }
1333
- catch {
1334
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
1282
+ if (match.decl.id === "tool-approval-read") {
1283
+ const { status, body: respBody } = await approvalFact.coordinator.readApproval(id, principal);
1284
+ sendJson(res, status, respBody);
1335
1285
  return;
1336
1286
  }
1337
- const { status, body: respBody } = await approvalFact.coordinator.respond(id, principal, body, req);
1287
+ const body = await readJson(req);
1288
+ const { status, body: respBody } = await approvalFact.coordinator.respond(id, principal, body, req, { readRootGrantAccepted: facts.readRootGrant(deps).available });
1338
1289
  const retryAfterSec = respBody.retryAfterSec;
1339
1290
  if (typeof retryAfterSec === "number" && Number.isFinite(retryAfterSec) && retryAfterSec >= 0) {
1340
1291
  res.setHeader("retry-after", String(Math.ceil(retryAfterSec)));
@@ -1356,14 +1307,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1356
1307
  sendPrincipalRefusal(res, req, deps.config);
1357
1308
  return;
1358
1309
  }
1359
- let rawBody;
1360
- try {
1361
- rawBody = await readJson(req);
1362
- }
1363
- catch {
1364
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
1365
- return;
1366
- }
1310
+ const rawBody = await readJson(req);
1367
1311
  const parsedBody = AskDecisionBodySchema.safeParse(rawBody);
1368
1312
  if (!parsedBody.success) {
1369
1313
  const retired = retiredDecisionKeyFacts(rawBody);
@@ -1401,7 +1345,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1401
1345
  return;
1402
1346
  }
1403
1347
  const ownerOk = row0.owner === null || (principal !== undefined && row0.owner === principal);
1404
- const operatorOk = explicitOperatorOk(principal, deps.config.operatorPrincipals);
1348
+ const operatorOk = explicitOperatorOk(principal, deps.config);
1405
1349
  if (!ownerOk && !operatorOk) {
1406
1350
  askNotFound();
1407
1351
  return;
@@ -1440,6 +1384,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1440
1384
  return true;
1441
1385
  };
1442
1386
  const decisionNoteEcho = (row) => (row.decisionNote === null ? {} : { decisionNote: row.decisionNote });
1387
+ const noteReceipt = (row) => noteRecordedReceipt(body.note, noteLandedOnRow(body.note, row.decisionNote));
1443
1388
  const replayDecided = (row) => {
1444
1389
  const storedActor = projectDecisionActor(row.decisionActor);
1445
1390
  sendJson(res, 200, {
@@ -1449,6 +1394,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1449
1394
  decidedAtMs: row.decidedAtMs,
1450
1395
  ...(storedActor ? { actor: storedActor } : {}),
1451
1396
  ...decisionNoteEcho(row),
1397
+ ...noteReceipt(row),
1452
1398
  });
1453
1399
  };
1454
1400
  const sendTerminal = (row) => {
@@ -1519,7 +1465,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1519
1465
  return;
1520
1466
  }
1521
1467
  if (body.decision === "approve" && policyCannotAnswer(heldAskOf(storedCardDemandsAPerson(row0.cardJson)), decidedBy)) {
1522
- sendError(res, 400, "request.field_conflict", POLICY_CANNOT_ALLOW_PERSON_ASK);
1468
+ sendError(res, 400, "request.field_conflict", POLICY_CANNOT_ALLOW_PERSON_ASK, fieldConflictFacts("policy_person_ask", ["decidedBy", "decision"]));
1523
1469
  return;
1524
1470
  }
1525
1471
  let outcome;
@@ -1606,6 +1552,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
1606
1552
  ...(forwarded ? { updatedInputForwarded: true } : {}),
1607
1553
  ...(settled === 0 ? { consumerState: ASK_DECISION_CONSUMER_ABSENT } : {}),
1608
1554
  ...decisionNoteEcho(outcome.row),
1555
+ ...noteReceipt(outcome.row),
1609
1556
  });
1610
1557
  return;
1611
1558
  }
@@ -1675,6 +1622,7 @@ export const RUN_VERBS_ROUTES = [
1675
1622
  { id: "elicitation-respond", pattern: /^\/v1\/elicitations\/(?<id>[^/]+)\/respond$/, label: "/v1/elicitations/:id/respond", methods: ["POST"] },
1676
1623
  { id: "question-respond", pattern: /^\/v1\/questions\/(?<id>[^/]+)\/respond$/, label: "/v1/questions/:id/respond", methods: ["POST"] },
1677
1624
  { id: "tool-approval-respond", pattern: /^\/v1\/tool-approvals\/(?<id>[^/]+)\/respond$/, label: "/v1/tool-approvals/:id/respond", methods: ["POST"] },
1625
+ { id: "tool-approval-read", pattern: /^\/v1\/tool-approvals\/(?<id>[^/]+)$/, label: "/v1/tool-approvals/:id", methods: ["GET"] },
1678
1626
  { id: "task-ask-decision", pattern: /^\/v1\/tasks\/(?<taskId>[^/]+)\/asks\/(?<askId>[^/]+)\/decision$/, label: "/v1/tasks/:id/asks/:askId/decision", methods: ["POST"] },
1679
1627
  ];
1680
1628
  //# sourceMappingURL=runs.js.map
@@ -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 (`ownerOf` reading: `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 {
@@ -5,11 +5,10 @@ import { StringDecoder } from "node:string_decoder";
5
5
  import { exportSessionManifest, 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";
9
- import { sqlBlobCapRefusalText } from "../../plugins/blob-backend.js";
10
- import { sendJson, sendError, sendSessionError, sendSessionPolicyError, msg } from "../send.js";
8
+ import { isUuidShape, legacyUnownedSessionOk, sessionOwnerCellOf } from "../../security.js";
9
+ import { sendJson, sendError, sendSessionError, sendSessionPolicyError, logRequestError, msg } from "../send.js";
11
10
  import { buildDisplaySafeUrl } from "../../trace/redact.js";
12
- import { gatedPrincipal, explicitOperatorOk, sendUnauthorized } from "../principal-gate.js";
11
+ import { fleetViewOf, gatedPrincipal, explicitOperatorOk, sendUnauthorized, sessionCallerOf } from "../principal-gate.js";
13
12
  const SYNC_BLOB_MAX_BYTES = 64 * 1024 * 1024;
14
13
  const SYNC_NDJSON_LINE_MAX_BYTES = 8 * 1024 * 1024;
15
14
  const SYNC_IMPORT_BATCH = 500;
@@ -35,7 +34,7 @@ export function createSessionSyncLocal() {
35
34
  }
36
35
  export async function handleSessionSync(req, res, match, ctx) {
37
36
  const { deps } = ctx;
38
- const { readJson, readRawBody, safeDecode, sessionOwnerScopeForWrite, rateLimited } = ctx.helpers;
37
+ const { readJson, readRawBody, safeDecode, rateLimited } = ctx.helpers;
39
38
  const { pendingStagings, importLeases, touchImportLease, cleanupStaging } = ctx.local.sessionSync;
40
39
  {
41
40
  {
@@ -45,7 +44,7 @@ export async function handleSessionSync(req, res, match, ctx) {
45
44
  return;
46
45
  }
47
46
  const { backend, sessionStorage, historyStore } = sync;
48
- const scope = sessionOwnerScopeForWrite(req);
47
+ const scope = fleetViewOf(req, deps, "write");
49
48
  if (!scope.fleetWide && scope.gateOwner === null) {
50
49
  sendUnauthorized(res, "identity");
51
50
  return;
@@ -55,23 +54,25 @@ export async function handleSessionSync(req, res, match, ctx) {
55
54
  sendError(res, 400, "request.id_invalid", "invalid session id (must be a canonical uuid)");
56
55
  return;
57
56
  }
58
- const gateFace = await sessionStorage.sessionFaceOf(sessionId);
57
+ const judgeSessionGate = async () => {
58
+ const face = await sessionStorage.sessionFaceOf(sessionId);
59
+ const mayTouch = face !== undefined && (scope.fleetWide || face.owner === scope.gateOwner || legacyUnownedSessionOk(deps.config.requirePrincipal, sessionCallerOf(req, deps), await sessionOwnerCellOf(sessionStorage, sessionId, face.owner)));
60
+ return { face, mayPull: mayTouch, mayPush: face === undefined || mayTouch };
61
+ };
62
+ const gate = await judgeSessionGate();
63
+ const gateFace = gate.face;
59
64
  const owner = gateFace === undefined ? undefined : gateFace.owner;
60
- const ownsOrFleet = (o) => scope.fleetWide || o === scope.gateOwner;
65
+ const sendSessionAbsent = () => sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
61
66
  const pullGateOk = () => {
62
- if (owner === undefined) {
63
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
64
- return false;
65
- }
66
- if (!ownsOrFleet(owner)) {
67
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
67
+ if (!gate.mayPull) {
68
+ sendSessionAbsent();
68
69
  return false;
69
70
  }
70
71
  return true;
71
72
  };
72
73
  const pushGateOk = () => {
73
- if (owner !== undefined && !ownsOrFleet(owner)) {
74
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
74
+ if (!gate.mayPush) {
75
+ sendSessionAbsent();
75
76
  return false;
76
77
  }
77
78
  return true;
@@ -94,7 +95,7 @@ export async function handleSessionSync(req, res, match, ctx) {
94
95
  throw e;
95
96
  }
96
97
  if (out === null) {
97
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
98
+ sendSessionAbsent();
98
99
  return;
99
100
  }
100
101
  sendJson(res, 200, { manifest: out.manifest });
@@ -115,7 +116,7 @@ export async function handleSessionSync(req, res, match, ctx) {
115
116
  }
116
117
  const it = await sessionStorage.exportEntriesStream(sessionId, afterSeq === undefined ? undefined : { afterSeq });
117
118
  if (it === null) {
118
- sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
119
+ sendSessionAbsent();
119
120
  return;
120
121
  }
121
122
  res.writeHead(200, { "content-type": "application/x-ndjson", "transfer-encoding": "chunked" });
@@ -187,17 +188,16 @@ export async function handleSessionSync(req, res, match, ctx) {
187
188
  }
188
189
  const fs = blobs.historyStore;
189
190
  const body = await readRawBody(req, SYNC_BLOB_MAX_BYTES);
190
- const sqlCap = deps.snapshotBlobSqlCap?.();
191
- if (sqlCap !== undefined && body.byteLength > sqlCap.capBytes) {
192
- sendError(res, 413, "blob_too_large_for_sql", sqlBlobCapRefusalText(body.byteLength, sqlCap), { wallSource: sqlCap.source });
193
- return;
194
- }
195
191
  if (createHash("sha256").update(body).digest("hex") !== hash) {
196
192
  sendError(res, 400, "request.hash_mismatch", "blob hash mismatch");
197
193
  return;
198
194
  }
199
195
  const put = await fs.putBlob(hash, new Uint8Array(body));
200
196
  if (!put.ok) {
197
+ if (put.error.code === "blob_too_large_for_sql") {
198
+ sendError(res, 413, "blob_too_large_for_sql", put.error.message, { wallSource: put.error.wallSource });
199
+ return;
200
+ }
201
201
  sendError(res, 502, put.error.code, "blob store write failed");
202
202
  return;
203
203
  }
@@ -216,14 +216,7 @@ export async function handleSessionSync(req, res, match, ctx) {
216
216
  }
217
217
  }).catch(() => { });
218
218
  }
219
- let body;
220
- try {
221
- body = (await readJson(req));
222
- }
223
- catch {
224
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
225
- return;
226
- }
219
+ const body = (await readJson(req));
227
220
  if (!Array.isArray(body.entryIds) || !body.entryIds.every((x) => typeof x === "string")) {
228
221
  sendError(res, 400, "request.field_invalid", "entryIds must be an array of strings");
229
222
  return;
@@ -314,7 +307,7 @@ export async function handleSessionSync(req, res, match, ctx) {
314
307
  return;
315
308
  }
316
309
  }
317
- const opOk = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config.operatorPrincipals);
310
+ const opOk = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config);
318
311
  if (deps.sessionPolicyStore) {
319
312
  try {
320
313
  await replayPolicyRecords(deps.sessionPolicyStore, sessionId, policy, opOk);
@@ -389,14 +382,14 @@ export async function handleSessionSync(req, res, match, ctx) {
389
382
  }
390
383
  }
391
384
  const importingPrincipal = scope.fleetWide ? (owner ?? null) : scope.gateOwner;
392
- const operatorOk = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config.operatorPrincipals);
385
+ const operatorOk = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config);
393
386
  const token = randomBytes(8).toString("hex");
394
387
  const handle = sessionStorage.beginImportStaging(sessionId, token);
395
388
  const stagingId = handle.stagingId;
396
389
  importLeases.set(sessionId, { at: Date.now(), stagingId });
397
390
  pendingStagings.set(stagingId, {
398
391
  handle, realSessionId: sessionId, owner: importingPrincipal, ...(resolution ? { resolution } : {}), operatorOk,
399
- fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: scope.gateOwner, openedFleetWide: scope.fleetWide,
392
+ fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: scope.gateOwner, expectedOwner: owner,
400
393
  });
401
394
  sendJson(res, 200, { stagingId, relation: relA.relation });
402
395
  return;
@@ -412,7 +405,7 @@ export async function handleSessionSync(req, res, match, ctx) {
412
405
  sendError(res, 404, "not_found.staging", "staging not found");
413
406
  return;
414
407
  }
415
- if (!pending.openedFleetWide && !scope.fleetWide && pending.openedBy !== scope.gateOwner) {
408
+ if (!scope.fleetWide && pending.openedBy !== scope.gateOwner) {
416
409
  sendError(res, 404, "not_found.staging", "staging not found");
417
410
  return;
418
411
  }
@@ -494,7 +487,23 @@ export async function handleSessionSync(req, res, match, ctx) {
494
487
  return;
495
488
  throw e;
496
489
  }
497
- const activeAtCommit = await deps.runStore?.getActiveTaskId(sessionId);
490
+ let mayPushAtCommit;
491
+ let activeAtCommit;
492
+ try {
493
+ mayPushAtCommit = (await judgeSessionGate()).mayPush;
494
+ activeAtCommit = mayPushAtCommit ? await deps.runStore?.getActiveTaskId(sessionId) : undefined;
495
+ }
496
+ catch (e) {
497
+ await pending.handle.abort().catch(() => undefined);
498
+ cleanupStaging(stagingId);
499
+ throw e;
500
+ }
501
+ if (!mayPushAtCommit) {
502
+ await pending.handle.abort().catch(() => undefined);
503
+ cleanupStaging(stagingId);
504
+ sendSessionAbsent();
505
+ return;
506
+ }
498
507
  if (activeAtCommit) {
499
508
  await pending.handle.abort().catch(() => undefined);
500
509
  cleanupStaging(stagingId);
@@ -502,7 +511,7 @@ export async function handleSessionSync(req, res, match, ctx) {
502
511
  return;
503
512
  }
504
513
  try {
505
- const committed = await pending.handle.commit(pending.owner, pending.resolution ? { resolution: pending.resolution } : undefined);
514
+ const committed = await pending.handle.commit(pending.owner, { expectedOwner: pending.expectedOwner, ...(pending.resolution ? { resolution: pending.resolution } : {}) });
506
515
  if (pending.resolution === "overwrite-dst" && (committed.relation === "fork" || committed.relation === "stale")) {
507
516
  await wipeSessionAttendants({ fileHistoryStore: historyStore, sessionPolicyStore: deps.sessionPolicyStore, resumeAnchorStore: deps.resumeAnchorStore }, sessionId);
508
517
  }
@@ -532,15 +541,18 @@ export async function handleSessionSync(req, res, match, ctx) {
532
541
  sendJson(res, 200, { relation: committed.relation });
533
542
  }
534
543
  catch (e) {
544
+ await pending.handle.abort().catch(() => undefined);
545
+ cleanupStaging(stagingId);
535
546
  if (e instanceof SyncConflictError) {
536
- await pending.handle.abort().catch(() => undefined);
537
- cleanupStaging(stagingId);
538
547
  sendError(res, 409, "conflict", "sync conflict", { relation: e.relation });
539
548
  return;
540
549
  }
541
- cleanupStaging(stagingId);
542
550
  if (sendSessionPolicyError(res, e))
543
551
  return;
552
+ if (sendSessionError(res, e, "import")) {
553
+ logRequestError(deps.logger, req, e);
554
+ return;
555
+ }
544
556
  throw e;
545
557
  }
546
558
  return;
@@ -548,14 +560,7 @@ export async function handleSessionSync(req, res, match, ctx) {
548
560
  if (match.decl.id === "session-sync-plan") {
549
561
  if (!pushGateOk())
550
562
  return;
551
- let body;
552
- try {
553
- body = (await readJson(req));
554
- }
555
- catch {
556
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
557
- return;
558
- }
563
+ const body = (await readJson(req));
559
564
  if (!Array.isArray(body.entryIds) || !body.entryIds.every((x) => typeof x === "string")) {
560
565
  sendError(res, 400, "request.field_invalid", "entryIds must be an array of strings");
561
566
  return;
@@ -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";