@sema-agent/server 7.131.0 → 7.133.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 (509) hide show
  1. package/MIGRATION.md +575 -0
  2. package/README.md +12 -9
  3. package/README.zh-CN.md +9 -6
  4. package/USAGE.md +326 -98
  5. package/deploy/sema-up/README.md +19 -1
  6. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
  7. package/deploy/sema-up/chart/templates/server.yaml +5 -2
  8. package/deploy/sema-up/stack/compose.yaml +3 -0
  9. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  10. package/dist/adoption/plan.d.ts +3 -2
  11. package/dist/adoption/plan.js +7 -5
  12. package/dist/adoption/runner.js +3 -10
  13. package/dist/adoption/sql.d.ts +3 -2
  14. package/dist/adoption/sql.js +3 -5
  15. package/dist/adoption/wire.d.ts +4 -1
  16. package/dist/adoption/wire.js +1 -0
  17. package/dist/approval-ask-audit-store.d.ts +31 -13
  18. package/dist/approval-ask-audit-store.js +272 -74
  19. package/dist/approval-ask-machine.d.ts +15 -0
  20. package/dist/approval-ask-machine.js +6 -0
  21. package/dist/approval-ask-retention.d.ts +136 -0
  22. package/dist/approval-ask-retention.js +102 -0
  23. package/dist/approval-card.d.ts +82 -20
  24. package/dist/approval-card.js +46 -16
  25. package/dist/approval-deny-reasons.d.ts +1 -1
  26. package/dist/approval.d.ts +9 -0
  27. package/dist/approval.js +24 -3
  28. package/dist/audit.d.ts +33 -19
  29. package/dist/audit.js +12 -16
  30. package/dist/auth-bridge.d.ts +4 -0
  31. package/dist/auth-bridge.js +10 -11
  32. package/dist/bake-runner/main.js +3 -2
  33. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  34. package/dist/boot/deployment-mods.d.ts +31 -0
  35. package/dist/boot/deployment-mods.js +26 -0
  36. package/dist/boot/execution-env.d.ts +1 -1
  37. package/dist/boot/execution-env.js +27 -12
  38. package/dist/boot/execution-lane.js +11 -0
  39. package/dist/boot/leader.js +2 -0
  40. package/dist/boot/memory-boundary.d.ts +2 -2
  41. package/dist/boot/memory-boundary.js +2 -2
  42. package/dist/boot/memory-consolidation.d.ts +5 -4
  43. package/dist/boot/memory-consolidation.js +7 -6
  44. package/dist/boot/org-delivery.d.ts +28 -0
  45. package/dist/boot/org-delivery.js +20 -0
  46. package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
  47. package/dist/boot/read-deny-anchor-audit.js +36 -0
  48. package/dist/boot/reapers.d.ts +3 -0
  49. package/dist/boot/reapers.js +21 -1
  50. package/dist/boot/resolve-spec.d.ts +4 -5
  51. package/dist/boot/resolve-spec.js +74 -123
  52. package/dist/boot/runner-deps.d.ts +19 -8
  53. package/dist/boot/runner-deps.js +15 -2
  54. package/dist/boot/session-faces.d.ts +2 -7
  55. package/dist/boot/session-faces.js +4 -2
  56. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  57. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  58. package/dist/boot/stage-03-store-backend.js +2 -2
  59. package/dist/boot/stage-04-stores.d.ts +1 -1
  60. package/dist/boot/stage-05-execution-env.d.ts +4 -4
  61. package/dist/boot/stage-05-execution-env.js +7 -10
  62. package/dist/boot/stage-06-runners.d.ts +4 -2
  63. package/dist/boot/stage-06-runners.js +11 -7
  64. package/dist/boot/stage-07-capability-layer.d.ts +4 -2
  65. package/dist/boot/stage-07-capability-layer.js +27 -6
  66. package/dist/boot/stage-08-reapers.d.ts +4 -2
  67. package/dist/boot/stage-08-reapers.js +2 -2
  68. package/dist/boot/stage-09-leader.d.ts +6 -9
  69. package/dist/boot/stage-10-http-server.d.ts +6 -9
  70. package/dist/boot/stage-10-http-server.js +7 -9
  71. package/dist/boot/stores.d.ts +1 -1
  72. package/dist/boot/stores.js +7 -8
  73. package/dist/boot/web-admin.d.ts +4 -3
  74. package/dist/boot/web-admin.js +186 -98
  75. package/dist/boot/workflow-orchestration.d.ts +2 -0
  76. package/dist/boot/workflow-orchestration.js +2 -1
  77. package/dist/brain.js +25 -25
  78. package/dist/breaker-key.d.ts +6 -0
  79. package/dist/breaker-key.js +29 -0
  80. package/dist/budget.js +5 -4
  81. package/dist/caller-text-echo.d.ts +23 -0
  82. package/dist/caller-text-echo.js +21 -0
  83. package/dist/capabilities/brand-identity.d.ts +26 -0
  84. package/dist/capabilities/brand-identity.js +27 -0
  85. package/dist/capabilities/center-plugins.d.ts +7 -0
  86. package/dist/capabilities/center-plugins.js +1 -1
  87. package/dist/capabilities/center-prompts.d.ts +32 -59
  88. package/dist/capabilities/center-prompts.js +18 -32
  89. package/dist/capabilities/composite-members.d.ts +1 -1
  90. package/dist/capabilities/composite-members.js +1 -1
  91. package/dist/capabilities/engine-capabilities.js +2 -1
  92. package/dist/capabilities/execution-lane.js +2 -2
  93. package/dist/capabilities/hands-lane.d.ts +30 -6
  94. package/dist/capabilities/hands-lane.js +11 -1
  95. package/dist/capabilities/mcp-probe.d.ts +48 -3
  96. package/dist/capabilities/mcp-probe.js +47 -135
  97. package/dist/capabilities/scenarios.d.ts +95 -45
  98. package/dist/capabilities/scenarios.js +53 -38
  99. package/dist/capabilities/skills.d.ts +19 -4
  100. package/dist/capabilities/skills.js +30 -10
  101. package/dist/capability-facts.d.ts +34 -4
  102. package/dist/capability-facts.js +28 -2
  103. package/dist/center-config-tier.d.ts +69 -0
  104. package/dist/center-config-tier.js +42 -0
  105. package/dist/checkpoint-identity.d.ts +16 -0
  106. package/dist/checkpoint-identity.js +19 -0
  107. package/dist/config-catalog.d.ts +17 -10
  108. package/dist/config-catalog.js +47 -32
  109. package/dist/config-d-migration.d.ts +3 -1
  110. package/dist/config-d-migration.js +2 -2
  111. package/dist/config-dir-trust.d.ts +114 -0
  112. package/dist/config-dir-trust.js +388 -0
  113. package/dist/config-invariants.d.ts +18 -5
  114. package/dist/config-invariants.js +35 -3
  115. package/dist/config-lkg.d.ts +9 -9
  116. package/dist/config-lkg.js +20 -4
  117. package/dist/config-provider.d.ts +9 -2
  118. package/dist/config-provider.js +18 -6
  119. package/dist/config-types.d.ts +75 -20
  120. package/dist/config-types.js +8 -0
  121. package/dist/config.d.ts +13 -0
  122. package/dist/config.js +137 -62
  123. package/dist/delegated-session-owner.d.ts +185 -0
  124. package/dist/delegated-session-owner.js +119 -0
  125. package/dist/device-protocol.d.ts +5 -3
  126. package/dist/device-protocol.js +1 -1
  127. package/dist/device-ws-hub.js +21 -2
  128. package/dist/device-ws-protocol.d.ts +70 -6
  129. package/dist/device-ws-protocol.js +50 -22
  130. package/dist/elicitation.js +3 -2
  131. package/dist/entry-problems.d.ts +34 -0
  132. package/dist/entry-problems.js +14 -0
  133. package/dist/env-name-allowlist-knobs.d.ts +12 -2
  134. package/dist/env-name-allowlist-knobs.js +5 -4
  135. package/dist/exec-bounds.d.ts +15 -3
  136. package/dist/exec-bounds.js +4 -0
  137. package/dist/execution-lane-caps.d.ts +56 -10
  138. package/dist/execution-lane-caps.js +50 -0
  139. package/dist/field-conflict.d.ts +43 -0
  140. package/dist/field-conflict.js +20 -0
  141. package/dist/fleet/fleet-bus.d.ts +80 -6
  142. package/dist/fleet/fleet-bus.js +41 -9
  143. package/dist/hooks/classic-stations.d.ts +91 -0
  144. package/dist/hooks/classic-stations.js +27 -0
  145. package/dist/hooks/command-spawn.d.ts +57 -0
  146. package/dist/hooks/command-spawn.js +139 -0
  147. package/dist/hooks/hook-llm.d.ts +8 -5
  148. package/dist/hooks/hook-llm.js +79 -36
  149. package/dist/hooks/hook-runner.d.ts +349 -95
  150. package/dist/hooks/hook-runner.js +855 -568
  151. package/dist/hooks/hook-source.d.ts +44 -0
  152. package/dist/hooks/hook-source.js +40 -0
  153. package/dist/http/active-run-conflict.d.ts +5 -13
  154. package/dist/http/active-run-conflict.js +17 -27
  155. package/dist/http/admission.d.ts +8 -2
  156. package/dist/http/admission.js +188 -101
  157. package/dist/http/approval-sweeps.js +99 -21
  158. package/dist/http/caller-trust.d.ts +77 -0
  159. package/dist/http/caller-trust.js +143 -0
  160. package/dist/http/checkpoint-ctx.d.ts +41 -24
  161. package/dist/http/checkpoint-ctx.js +23 -16
  162. package/dist/http/claimed-run.d.ts +14 -0
  163. package/dist/http/claimed-run.js +15 -0
  164. package/dist/http/device-placement.d.ts +2 -4
  165. package/dist/http/device-placement.js +7 -11
  166. package/dist/http/dispatch.d.ts +0 -4
  167. package/dist/http/dispatch.js +15 -13
  168. package/dist/http/durable-run-leg.d.ts +6 -33
  169. package/dist/http/durable-run-leg.js +36 -10
  170. package/dist/http/health-self-report.d.ts +7 -5
  171. package/dist/http/health-self-report.js +4 -18
  172. package/dist/http/owner-access.d.ts +56 -0
  173. package/dist/http/owner-access.js +42 -0
  174. package/dist/http/principal-gate.d.ts +70 -28
  175. package/dist/http/principal-gate.js +61 -15
  176. package/dist/http/readiness.d.ts +11 -5
  177. package/dist/http/readiness.js +10 -3
  178. package/dist/http/refusal-body.d.ts +21 -0
  179. package/dist/http/refusal-body.js +4 -0
  180. package/dist/http/request-guards.d.ts +43 -23
  181. package/dist/http/request-guards.js +53 -17
  182. package/dist/http/resume-ctx-read.d.ts +2 -5
  183. package/dist/http/resume-ctx-read.js +7 -4
  184. package/dist/http/resume-legs.d.ts +28 -4
  185. package/dist/http/resume-legs.js +169 -91
  186. package/dist/http/retired-service-deps.d.ts +43 -0
  187. package/dist/http/retired-service-deps.js +18 -0
  188. package/dist/http/route-ctx.d.ts +44 -28
  189. package/dist/http/route-ctx.js +4 -0
  190. package/dist/http/route-table.js +2 -0
  191. package/dist/http/routes/a2a-serve.js +3 -4
  192. package/dist/http/routes/admin-config-refresh.js +1 -1
  193. package/dist/http/routes/admin-drain.js +1 -1
  194. package/dist/http/routes/admin-memory-optout.js +5 -1
  195. package/dist/http/routes/adoption.js +2 -9
  196. package/dist/http/routes/approvals-assistant.js +49 -48
  197. package/dist/http/routes/background.js +3 -2
  198. package/dist/http/routes/capabilities.js +21 -5
  199. package/dist/http/routes/config-catalog.d.ts +3 -3
  200. package/dist/http/routes/config-catalog.js +1 -1
  201. package/dist/http/routes/devices.js +3 -17
  202. package/dist/http/routes/diagnostics.js +6 -2
  203. package/dist/http/routes/images.js +6 -7
  204. package/dist/http/routes/leader.js +1 -8
  205. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  206. package/dist/http/routes/mcp-reconnect.js +3 -2
  207. package/dist/http/routes/memory-bundle.js +1 -1
  208. package/dist/http/routes/memory-compliance.js +1 -1
  209. package/dist/http/routes/memory-consolidation.js +1 -1
  210. package/dist/http/routes/memory-origin.js +1 -1
  211. package/dist/http/routes/memory-policy.d.ts +1 -1
  212. package/dist/http/routes/memory-policy.js +3 -2
  213. package/dist/http/routes/notify-wake.js +8 -21
  214. package/dist/http/routes/observability.js +2 -2
  215. package/dist/http/routes/principal-inbox.d.ts +39 -0
  216. package/dist/http/routes/principal-inbox.js +76 -0
  217. package/dist/http/routes/retention-ops.js +2 -9
  218. package/dist/http/routes/rules.js +5 -18
  219. package/dist/http/routes/runs.d.ts +5 -0
  220. package/dist/http/routes/runs.js +34 -107
  221. package/dist/http/routes/session-sync.js +15 -26
  222. package/dist/http/routes/sessions.js +30 -40
  223. package/dist/http/routes/shared-memory.js +2 -13
  224. package/dist/http/routes/side-query.js +8 -7
  225. package/dist/http/routes/tasks.js +67 -21
  226. package/dist/http/routes/workflows.d.ts +351 -0
  227. package/dist/http/routes/workflows.js +153 -119
  228. package/dist/http/send.d.ts +33 -10
  229. package/dist/http/send.js +21 -4
  230. package/dist/http/server.d.ts +27 -18
  231. package/dist/http/server.js +34 -6
  232. package/dist/http/stored-body-replay.js +17 -4
  233. package/dist/http/submit-ctx.d.ts +25 -0
  234. package/dist/http/submit-ctx.js +40 -0
  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 +11 -8
  238. package/dist/index.d.ts +2 -2
  239. package/dist/index.js +1 -2
  240. package/dist/lane-home-probe.d.ts +112 -0
  241. package/dist/lane-home-probe.js +101 -0
  242. package/dist/leader/endpoint.d.ts +4 -1
  243. package/dist/leader/endpoint.js +11 -10
  244. package/dist/limit-refusal.d.ts +59 -0
  245. package/dist/limit-refusal.js +15 -0
  246. package/dist/main.js +1 -1
  247. package/dist/mcp-assertion-header.d.ts +32 -19
  248. package/dist/mcp-assertion-header.js +10 -9
  249. package/dist/mcp-tool-faces.d.ts +5 -0
  250. package/dist/mcp-tool-faces.js +6 -4
  251. package/dist/memory-project-layer.d.ts +37 -0
  252. package/dist/memory-project-layer.js +46 -0
  253. package/dist/memory-scope.d.ts +24 -17
  254. package/dist/memory-scope.js +24 -8
  255. package/dist/memory-sync-client.d.ts +27 -13
  256. package/dist/memory-sync-client.js +107 -18
  257. package/dist/model-entry-refusal.d.ts +9 -1
  258. package/dist/model-entry-refusal.js +6 -1
  259. package/dist/model-plane-face.d.ts +51 -0
  260. package/dist/model-plane-face.js +24 -0
  261. package/dist/model-provider.d.ts +44 -12
  262. package/dist/model-provider.js +21 -2
  263. package/dist/model-route-endpoint.d.ts +9 -12
  264. package/dist/model-route-endpoint.js +8 -11
  265. package/dist/model-route-env.d.ts +22 -0
  266. package/dist/model-route-env.js +2 -0
  267. package/dist/model-route-gap.d.ts +60 -30
  268. package/dist/model-route-gap.js +21 -15
  269. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  270. package/dist/observability/corrupt-read-seat.js +9 -0
  271. package/dist/observability/cost-taxonomy.d.ts +7 -7
  272. package/dist/observability/err-text.d.ts +6 -0
  273. package/dist/observability/err-text.js +18 -4
  274. package/dist/observability/fail-open.d.ts +76 -14
  275. package/dist/observability/fail-open.js +76 -14
  276. package/dist/observability/metrics.js +4 -1
  277. package/dist/observability/prompt-manifest.d.ts +33 -82
  278. package/dist/observability/prompt-manifest.js +122 -17
  279. package/dist/observability/run-terminal.js +14 -6
  280. package/dist/observability/secret-env-scrub.d.ts +13 -1
  281. package/dist/observability/secret-env-scrub.js +13 -1
  282. package/dist/observability/tool-trace.d.ts +16 -21
  283. package/dist/observability/tool-trace.js +58 -49
  284. package/dist/operator-ask.d.ts +10 -0
  285. package/dist/operator-ask.js +3 -0
  286. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  287. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  288. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  289. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  290. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  291. package/dist/orchestration/workflow-notify-journal.js +27 -34
  292. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  293. package/dist/orchestration/workflow-park-decision.js +118 -0
  294. package/dist/org-delivery-gate.d.ts +81 -0
  295. package/dist/org-delivery-gate.js +59 -0
  296. package/dist/panel-tool-names.d.ts +23 -0
  297. package/dist/panel-tool-names.js +8 -0
  298. package/dist/parked-decide.d.ts +39 -6
  299. package/dist/parked-decide.js +98 -51
  300. package/dist/parked-revive-surface.d.ts +9 -2
  301. package/dist/parked-revive-surface.js +11 -8
  302. package/dist/per-task-image.d.ts +7 -1
  303. package/dist/per-task-image.js +3 -3
  304. package/dist/permission-rule-list.d.ts +1 -1
  305. package/dist/permission-rule-list.js +2 -2
  306. package/dist/plain-string-record.d.ts +25 -0
  307. package/dist/plain-string-record.js +32 -0
  308. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  309. package/dist/plugins/approval-ask-store-file.js +21 -0
  310. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  311. package/dist/plugins/approval-ask-store-memory.js +34 -2
  312. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  313. package/dist/plugins/approval-ask-store-sql.js +37 -1
  314. package/dist/plugins/blob-backend.d.ts +83 -15
  315. package/dist/plugins/blob-backend.js +68 -15
  316. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  317. package/dist/plugins/breaker-state-sql.js +4 -4
  318. package/dist/plugins/caching-session-store.d.ts +3 -0
  319. package/dist/plugins/caching-session-store.js +3 -0
  320. package/dist/plugins/checkpoint-store-sql.d.ts +28 -4
  321. package/dist/plugins/checkpoint-store-sql.js +59 -28
  322. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  323. package/dist/plugins/file-history-store-sql.js +3 -1
  324. package/dist/plugins/file-run-store.d.ts +5 -13
  325. package/dist/plugins/file-run-store.js +9 -0
  326. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  327. package/dist/plugins/fork-routing-session-store.js +12 -1
  328. package/dist/plugins/host-platform.d.ts +2 -0
  329. package/dist/plugins/host-platform.js +2 -1
  330. package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
  331. package/dist/plugins/k8s-bg-scripts.js +22 -0
  332. package/dist/plugins/local-checkpoint-store.d.ts +2 -0
  333. package/dist/plugins/local-checkpoint-store.js +11 -3
  334. package/dist/plugins/local-session-store.d.ts +1 -1
  335. package/dist/plugins/local-session-store.js +1 -1
  336. package/dist/plugins/local-session-window.d.ts +39 -0
  337. package/dist/plugins/local-session-window.js +54 -0
  338. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  339. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  340. package/dist/plugins/mailbox-store-sql.js +77 -52
  341. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  342. package/dist/plugins/memory-run-store.d.ts +5 -13
  343. package/dist/plugins/memory-run-store.js +8 -0
  344. package/dist/plugins/one-time-migrations.d.ts +245 -93
  345. package/dist/plugins/one-time-migrations.js +668 -207
  346. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  347. package/dist/plugins/org-delivery-quota-store.js +228 -0
  348. package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
  349. package/dist/plugins/permission-rule-store-sql.js +4 -18
  350. package/dist/plugins/pg-pool.js +39 -7
  351. package/dist/plugins/pg-session-storage.d.ts +20 -8
  352. package/dist/plugins/pg-session-storage.js +34 -21
  353. package/dist/plugins/remote-env-adb.d.ts +12 -12
  354. package/dist/plugins/remote-env-adb.js +21 -6
  355. package/dist/plugins/remote-env-device.js +3 -0
  356. package/dist/plugins/remote-env-e2b.d.ts +1 -1
  357. package/dist/plugins/remote-env-e2b.js +21 -9
  358. package/dist/plugins/remote-env-host.d.ts +9 -9
  359. package/dist/plugins/remote-env-host.js +10 -32
  360. package/dist/plugins/remote-env-k8s.d.ts +103 -38
  361. package/dist/plugins/remote-env-k8s.js +288 -95
  362. package/dist/plugins/remote-env-local-docker.d.ts +27 -13
  363. package/dist/plugins/remote-env-local-docker.js +82 -11
  364. package/dist/plugins/remote-env-ssh.d.ts +21 -12
  365. package/dist/plugins/remote-env-ssh.js +117 -5
  366. package/dist/plugins/remote-shell.d.ts +0 -1
  367. package/dist/plugins/remote-shell.js +1 -2
  368. package/dist/plugins/retention-store-sql.js +6 -2
  369. package/dist/plugins/run-store-sql.d.ts +16 -14
  370. package/dist/plugins/run-store-sql.js +22 -2
  371. package/dist/plugins/schema-consistency.d.ts +54 -0
  372. package/dist/plugins/schema-consistency.js +52 -0
  373. package/dist/plugins/schema-indexes.js +2 -0
  374. package/dist/plugins/send-user-file.js +2 -2
  375. package/dist/plugins/session-epoch-anchor.d.ts +39 -0
  376. package/dist/plugins/session-epoch-anchor.js +22 -0
  377. package/dist/plugins/session-store.d.ts +18 -8
  378. package/dist/plugins/session-store.js +15 -4
  379. package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
  380. package/dist/plugins/shared-memory-store-sql.js +5 -16
  381. package/dist/plugins/sql-driver.d.ts +205 -1
  382. package/dist/plugins/sql-driver.js +325 -13
  383. package/dist/plugins/sql-errors.d.ts +64 -0
  384. package/dist/plugins/sql-errors.js +57 -0
  385. package/dist/plugins/store-backend.d.ts +36 -1
  386. package/dist/plugins/store-backend.js +42 -15
  387. package/dist/plugins/store-contracts.d.ts +42 -0
  388. package/dist/plugins/store-contracts.js +1 -0
  389. package/dist/plugins/tidb-pool.d.ts +6 -1
  390. package/dist/plugins/tidb-pool.js +44 -10
  391. package/dist/plugins/tidb-session-storage.d.ts +8 -11
  392. package/dist/plugins/tidb-session-storage.js +6 -16
  393. package/dist/plugins/tidb-session-store.d.ts +24 -4
  394. package/dist/plugins/tidb-session-store.js +29 -5
  395. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  396. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  397. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  398. package/dist/plugins/workflow-run-store-sql.js +50 -9
  399. package/dist/posture-source.d.ts +18 -10
  400. package/dist/posture-source.js +4 -1
  401. package/dist/project-identity.d.ts +45 -6
  402. package/dist/project-identity.js +162 -8
  403. package/dist/project-layer-key.d.ts +28 -0
  404. package/dist/project-layer-key.js +29 -0
  405. package/dist/prompts-domain-validate.d.ts +17 -61
  406. package/dist/prompts-domain-validate.js +9 -119
  407. package/dist/question.js +3 -2
  408. package/dist/read-deny-entry.d.ts +25 -0
  409. package/dist/read-deny-entry.js +12 -0
  410. package/dist/read-face-posture.d.ts +37 -11
  411. package/dist/read-face-posture.js +32 -3
  412. package/dist/request-key-closure.d.ts +9 -2
  413. package/dist/request-key-closure.js +11 -5
  414. package/dist/request-value-closure.d.ts +5 -0
  415. package/dist/request-value-closure.js +11 -3
  416. package/dist/rule-entry-list.d.ts +38 -11
  417. package/dist/rule-entry-list.js +106 -30
  418. package/dist/rules-consent.js +3 -4
  419. package/dist/run-acceptance.d.ts +19 -3
  420. package/dist/run-acceptance.js +13 -1
  421. package/dist/run-local.js +54 -24
  422. package/dist/runs.d.ts +15 -8
  423. package/dist/runs.js +35 -1
  424. package/dist/runtime-caps-resolver.d.ts +16 -6
  425. package/dist/runtime-caps-resolver.js +18 -5
  426. package/dist/sandbox-pkg-source.d.ts +19 -1
  427. package/dist/sandbox-pkg-source.js +29 -7
  428. package/dist/security.d.ts +87 -9
  429. package/dist/security.js +52 -9
  430. package/dist/server-secret-env.d.ts +44 -18
  431. package/dist/server-secret-env.js +49 -8
  432. package/dist/session-error-wire.d.ts +19 -2
  433. package/dist/session-error-wire.js +5 -1
  434. package/dist/session-incarnation.d.ts +15 -5
  435. package/dist/session-incarnation.js +16 -9
  436. package/dist/session-titled-frame.d.ts +33 -0
  437. package/dist/session-titled-frame.js +4 -0
  438. package/dist/session-titler.d.ts +9 -1
  439. package/dist/session-titler.js +27 -6
  440. package/dist/spec-fields.d.ts +28 -16
  441. package/dist/spec-fields.js +66 -54
  442. package/dist/sql-engine-posture.d.ts +31 -4
  443. package/dist/sql-engine-posture.js +36 -1
  444. package/dist/stored-request-tool-axes-m19.d.ts +19 -4
  445. package/dist/stored-request-tool-axes-m19.js +30 -2
  446. package/dist/task-a2a.d.ts +9 -1
  447. package/dist/task-a2a.js +73 -47
  448. package/dist/task-cwd.d.ts +1 -1
  449. package/dist/task-mcp.d.ts +46 -58
  450. package/dist/task-mcp.js +82 -107
  451. package/dist/task-settings.d.ts +95 -108
  452. package/dist/task-settings.js +77 -98
  453. package/dist/text-bidi.d.ts +1 -48
  454. package/dist/text-bidi.js +3 -5
  455. package/dist/tighten-only-seats.d.ts +150 -0
  456. package/dist/tighten-only-seats.js +196 -0
  457. package/dist/tool-approval.d.ts +304 -88
  458. package/dist/tool-approval.js +623 -239
  459. package/dist/trace/core-keyset-guard.d.ts +122 -20
  460. package/dist/trace/engine-notice-wire.d.ts +11 -3
  461. package/dist/trace/engine-notice-wire.js +8 -1
  462. package/dist/trace/exit-seat.d.ts +28 -0
  463. package/dist/trace/exit-seat.js +76 -0
  464. package/dist/trace/ledger-events.d.ts +6 -3
  465. package/dist/trace/ledger-sink.js +4 -1
  466. package/dist/trace/model-segment.js +1 -1
  467. package/dist/trace/project.d.ts +98 -17
  468. package/dist/trace/project.js +98 -50
  469. package/dist/trace/projection-table.d.ts +100 -0
  470. package/dist/trace/projection-table.js +130 -0
  471. package/dist/trace/redact.d.ts +54 -0
  472. package/dist/trace/redact.js +778 -152
  473. package/dist/trace/self-minted-wire.d.ts +345 -1
  474. package/dist/trace/self-minted-wire.js +117 -1
  475. package/dist/trace/wire-projection-faces.d.ts +377 -3
  476. package/dist/trace/wire-projection-faces.js +164 -1
  477. package/dist/url-refusal.js +2 -0
  478. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  479. package/dist/web-admin-client/apply-effective.js +56 -5
  480. package/dist/web-admin-client/candidate-gate.d.ts +6 -6
  481. package/dist/web-admin-client/candidate-gate.js +3 -3
  482. package/dist/web-admin-client/facade.d.ts +1 -1
  483. package/dist/web-admin-client/facade.js +1 -1
  484. package/dist/web-admin-client/http-client.js +0 -6
  485. package/dist/web-admin-client/read-face.js +5 -9
  486. package/dist/web-admin-client/read-warnings.d.ts +13 -0
  487. package/dist/web-admin-client/read-warnings.js +10 -0
  488. package/dist/web-admin-client/skills-mcp.d.ts +3 -0
  489. package/dist/web-admin-client/skills-mcp.js +11 -9
  490. package/dist/web-admin-client/types.d.ts +2 -3
  491. package/dist/workspace-cache.d.ts +35 -0
  492. package/dist/workspace-cache.js +36 -0
  493. package/dist/workspace-space.d.ts +3 -2
  494. package/dist/workspace-space.js +2 -0
  495. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +65 -10
  496. package/package.json +8 -4
  497. package/scripts/drain-check-local.mjs +34 -1
  498. package/scripts/drain-check.mysql.sql +30 -2
  499. package/scripts/drain-check.pg.sql +29 -2
  500. package/dist/capabilities/memory-notice.d.ts +0 -138
  501. package/dist/capabilities/memory-notice.js +0 -64
  502. package/dist/capabilities/prompt.d.ts +0 -17
  503. package/dist/capabilities/prompt.js +0 -6
  504. package/dist/mcp-content-origin.d.ts +0 -34
  505. package/dist/mcp-content-origin.js +0 -10
  506. package/dist/tool-axis-words.d.ts +0 -27
  507. package/dist/tool-axis-words.js +0 -9
  508. package/dist/wire-name-bound.d.ts +0 -14
  509. package/dist/wire-name-bound.js +0 -13
@@ -2,6 +2,8 @@ import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLev
2
2
  import { modelImageInput, modelReasoningDecl, isAtMentionable, selectableCatalog } from "../../model-select.js";
3
3
  import { buildDroppedEntriesWire } from "../../web-admin-client/read-warnings.js";
4
4
  import { buildCandidateRejectedWire } from "../../web-admin-client/candidate-gate.js";
5
+ import { buildModelPlaneFace } from "../../model-plane-face.js";
6
+ import { isRosterGateArmed } from "../../config.js";
5
7
  import { modelKeyPoisonOf, resolveModelApiKey } from "../../key-resolver.js";
6
8
  import { projectSealedKeyCapability } from "../../sealed-key.js";
7
9
  import { cwdHonored, deviceCwdHonored } from "../../task-cwd.js";
@@ -10,7 +12,7 @@ import { leaderEntryRefusal, leaderRunEntry } from "../../leader/run-entry.js";
10
12
  import { autonomyKeepsOpenWriteFace, autonomyModeFloor } from "../../runtime-governance.js";
11
13
  import { DEVICE_PROTOCOL_VERSION, DEVICE_WS_PATH } from "../../device-ws-protocol.js";
12
14
  import { a2aInjectionHonored } from "../../task-a2a.js";
13
- import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
15
+ import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, McpProbeMisaligned, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
14
16
  import { mcpForScenario } from "../../web-admin-client/facade.js";
15
17
  import { sendScenarioNotFound } from "../scenario-read-face.js";
16
18
  import { sendJson, sendError } from "../send.js";
@@ -21,6 +23,7 @@ import { projectWriteProtectionCapability } from "../../write-protection.js";
21
23
  import { projectStoreCapability } from "../../store-posture.js";
22
24
  import { projectWebSearchCapability } from "../../plugins/web-search.js";
23
25
  import { projectExecutionLaneCapability } from "../../capabilities/execution-lane.js";
26
+ import { MCP_ASSERTION_HEADER_SENT } from "../../mcp-assertion-header.js";
24
27
  import { gateCompositeMembers } from "../../capabilities/composite-members.js";
25
28
  import { projectApprovalsStreamLiveCapability } from "../../capabilities/approvals-push.js";
26
29
  import { workflowModelAllowlistFor } from "../../task-workflow.js";
@@ -29,6 +32,7 @@ import * as facts from "../../capability-facts.js";
29
32
  import { judgeAutoModeArming } from "../../auto-mode-face.js";
30
33
  import { coercePermissionModeStrict, PERMISSION_MODE_WORDS, taskHooksHonored } from "../../task-settings.js";
31
34
  import { gatedPrincipal, sendPrincipalRefusal } from "../principal-gate.js";
35
+ import { callerTrust } from "../caller-trust.js";
32
36
  function routePairingOf(deps, name, m) {
33
37
  if (modelKeyPoisonOf(name, deps.config.modelApiKeyEnv ?? {}, process.env, deps.config.modelApiKeys ?? {}) !== undefined)
34
38
  return "unknown";
@@ -72,12 +76,14 @@ export async function handleCapabilities(req, res, match, ctx) {
72
76
  if (autoModeFault !== undefined)
73
77
  deps.logger?.warn("auto_mode_face_resolver_fault", { fault: autoModeFault });
74
78
  const rulesLaneForCaller = facts.ruleLaneForCaller(deps, gatedPrincipal(req, deps.config)).available;
79
+ const streamApprovalFact = facts.streamApproval(deps);
75
80
  sendJson(res, 200, gateCompositeMembers({
76
81
  ...deps.capabilities,
77
82
  ...facts.engineCapabilityBits(),
78
83
  asyncRuns: facts.durableRuns(deps).available,
79
84
  artifacts: facts.durableRuns(deps).available,
80
85
  approvals: facts.checkpointPark(deps).available,
86
+ approvalReadRootGrant: facts.readRootGrant(deps).available,
81
87
  sessions: facts.sessionAuditView(deps).available,
82
88
  deviceExecutor: facts.deviceLane(deps).available
83
89
  ? { enabled: true, protocolVersion: DEVICE_PROTOCOL_VERSION, maxInflightPerDevice: deps.config.remoteExec?.provider === "device" ? (deps.config.remoteExec.maxInflightPerDevice ?? 4) : 4, wsPath: DEVICE_WS_PATH, management: facts.deviceManagement(deps).available }
@@ -92,7 +98,7 @@ export async function handleCapabilities(req, res, match, ctx) {
92
98
  memory: false,
93
99
  memoryWrite: false,
94
100
  memoryEngine: projectMemoryEngineCapability(deps.memoryPosture),
95
- store: projectStoreCapability(deps.storePosture ?? { declared: deps.config.dbBackend, backend: "memory" }, deps.sqlEngineFacts?.()),
101
+ store: projectStoreCapability(deps.storePosture ?? { declared: deps.config.dbBackend, backend: "memory" }, deps.sqlEngine?.facts),
96
102
  centerWiring: deps.centerWiring?.(gatedPrincipal(req, deps.config)),
97
103
  webSearch: projectWebSearchCapability(deps.webSearchProvider),
98
104
  sessionBackgroundable: facts.durableRuns(deps).available,
@@ -100,6 +106,7 @@ export async function handleCapabilities(req, res, match, ctx) {
100
106
  mcpReconnect: facts.mcpReconnect(deps).available,
101
107
  background: { listFace: facts.sessionOwnership(deps).available, exitFaces: facts.sessionOwnership(deps).available },
102
108
  sharedMemory: facts.sharedMemoryRead(deps).available,
109
+ principalInboxDelivery: facts.principalInboxDelivery(deps).available,
103
110
  adoption: facts.adoption(deps).available,
104
111
  memoryBundle: facts.memoryBundle(deps).available,
105
112
  memoryCompliance: facts.memoryCompliance(deps).available,
@@ -124,8 +131,8 @@ export async function handleCapabilities(req, res, match, ctx) {
124
131
  scratchpadDir: true,
125
132
  subagentSteer: facts.subagentSteer(deps).available,
126
133
  subagentResume: facts.subagentSteer(deps).available,
127
- taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: cwdHonored(deps.config) || deviceCwdHonored(deps.config), hooks: taskHooksHonored(deps.config) },
128
- settings: { permissions: { allowGrant: true, allowLayer: true } },
134
+ taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: cwdHonored(deps.config) || deviceCwdHonored(deps.config), hooks: taskHooksHonored(deps.config), pluginHooks: taskHooksHonored(deps.config), managedHookGroups: taskHooksHonored(deps.config), tightenOnlySeats: true },
135
+ settings: { permissions: { allowGrant: true, allowLayer: true, callerTrust: callerTrust(req, deps.config).trust } },
129
136
  permissionModeAuto: {
130
137
  accepted: true,
131
138
  classifierSeat: deps.autoModeFace?.seatMounted === true,
@@ -160,11 +167,13 @@ export async function handleCapabilities(req, res, match, ctx) {
160
167
  sessionInit: true,
161
168
  mcp: true,
162
169
  mcpProbe: true,
170
+ mcpAssertionHeaderSent: MCP_ASSERTION_HEADER_SENT,
163
171
  mcpElicitation: facts.elicitation(deps).available,
164
172
  askUserQuestion: facts.askUserQuestion(deps).available,
165
173
  toolApproval: facts.toolApproval(deps).available,
166
174
  approvalsStreamLive: projectApprovalsStreamLiveCapability(deps),
167
- streamApproval: facts.streamApproval(deps).available,
175
+ streamApproval: streamApprovalFact.available,
176
+ approvalFrameFamilies: [...facts.approvalFrameFamilies(streamApprovalFact)],
168
177
  approvalDecisionNote: true,
169
178
  approvalDecidedBy: true,
170
179
  permissionModes: [...PERMISSION_MODES],
@@ -273,6 +282,11 @@ export async function handleCapabilities(req, res, match, ctx) {
273
282
  defaultModel: { id: deps.config.model.id, ...(defaultName ? { name: defaultName } : {}) },
274
283
  droppedEntries: buildDroppedEntriesWire(deps.config.droppedCatalogEntries),
275
284
  ...(candidateRejection !== undefined ? { candidateRejected: buildCandidateRejectedWire(candidateRejection) } : {}),
285
+ modelPlane: buildModelPlaneFace(deps.config, {
286
+ envTableIsPlaceholder: isRosterGateArmed(deps.config.webAdmin),
287
+ candidateRejection,
288
+ modelRefusals: deps.modelRefusalsState?.(),
289
+ }),
276
290
  });
277
291
  return;
278
292
  }
@@ -330,6 +344,8 @@ async function answerMcpProbe(res, ctx, answer, outcome, declaredBy) {
330
344
  sendMcpProbeRefusal(res, ctx, buildMcpProbeIncompleteRefusal(err.boundMs), "failed", Math.ceil(err.boundMs / 1000));
331
345
  return;
332
346
  }
347
+ if (err instanceof McpProbeMisaligned)
348
+ throw err;
333
349
  if (declaredBy === "caller") {
334
350
  sendMcpProbeRefusal(res, ctx, buildMcpProbeDeclarationRefusal(), "failed");
335
351
  return;
@@ -9,9 +9,9 @@
9
9
  * 门序 = operator 面口径:身份 → 能力(事实 `configCatalog`,501)→ 授权 → 应答;billable=false,
10
10
  * 刻意不吃 drain / roster-pending 两道 503(排障读面在停机窗里恰恰要打得通)。
11
11
  *
12
- * 🔴 鉴权 = `explicitOperatorOk`(空名单=谁都不是)——设计稿 §0.5 点名**禁** `isOperator` 那个
13
- * 「空名单=人人都是」的 fail-open 谓词:本面是部署事实外泄口(env 在场性/后端形态/限额值),
14
- * 单用户形也不放宽。
12
+ * 🔴 鉴权 = `explicitOperatorOk`(「谁是 operator」的唯一读法:空名单 = 谁都不是)—— 设计稿 §0.5 点名禁「空名单 = 人人都是」的 fail-open 读法
13
+ * (S-1050 起整只删):本面是部署事实外泄口(env 在场性 / 后端形态 / 限额值)。单用户形只在部署方显式声明 `OPERATOR_SINGLE_USER=true`
14
+ * (每个调用方都是运维)时对调用方开。
15
15
  *
16
16
  * 🔴 旋钮 `CONFIG_CATALOG_ENABLED=false` / operator 名单空 ⇒ 501(事实 `configCatalog`,与能力位同一只函数):
17
17
  * 旋钮关 = `feature.config_catalog_disabled`(合规部署不想让部署事实上 wire 的表态;「去开旋钮」由码与句承担),
@@ -29,7 +29,7 @@ export async function handleConfigCatalog(req, res, match, ctx) {
29
29
  return assertNever(fact.why);
30
30
  }
31
31
  }
32
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
32
+ if (!explicitOperatorOk(principal, deps.config)) {
33
33
  sendError(res, 403, "auth.operator_only", OPERATOR_ONLY_MESSAGE);
34
34
  return;
35
35
  }
@@ -47,14 +47,7 @@ function bodyKeyIssue(body, accepted) {
47
47
  return `unknown key(s) in body: ${extra.join(", ")} — this endpoint accepts ${accepted.length === 0 ? "no body keys" : accepted.slice().sort().join(", ")} (a silently dropped key is a declaration that never existed)`;
48
48
  }
49
49
  async function readClosedBody(req, res, readJson, accepted) {
50
- let body;
51
- try {
52
- body = await readJson(req);
53
- }
54
- catch {
55
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
56
- return null;
57
- }
50
+ const body = await readJson(req);
58
51
  if (typeof body !== "object" || body === null || Array.isArray(body)) {
59
52
  sendError(res, 400, "request.body_shape", "body must be a JSON object");
60
53
  return null;
@@ -151,7 +144,7 @@ export async function handleDevices(req, res, match, ctx) {
151
144
  }
152
145
  }
153
146
  const { store, hub, enrollment, runStore } = lane;
154
- const operator = explicitOperatorOk(principal, deps.config.operatorPrincipals);
147
+ const operator = explicitOperatorOk(principal, deps.config);
155
148
  const domain = deviceOwnerDomainOf(req, deps.config);
156
149
  if (match.decl.id === "devices-list") {
157
150
  if (!operator && domain === undefined) {
@@ -277,14 +270,7 @@ export async function handleDevices(req, res, match, ctx) {
277
270
  sendDeviceNotFound(res);
278
271
  return;
279
272
  }
280
- let body;
281
- try {
282
- body = (await readJson(req));
283
- }
284
- catch {
285
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
286
- return;
287
- }
273
+ const body = (await readJson(req));
288
274
  if (typeof body !== "object" || body === null || typeof body.toDeviceId !== "string" || body.expectedRev === undefined) {
289
275
  sendError(res, 400, "request.body_shape", "body must be { toDeviceId: string, expectedRev: number } — expectedRev is the binding rev read from GET /v1/devices/sessions/{rootSessionId} (explicit prior state; two concurrent operators must not silently stomp each other)");
290
276
  return;
@@ -15,24 +15,28 @@ export function buildServerWiringGates(input) {
15
15
  parkFacility: input.checkpointStore !== undefined,
16
16
  });
17
17
  const noCenterArm = (knob) => `this knob has no web-admin arm on this deployment — it is set by ${knob} on this machine, or derived from the deployment posture`;
18
+ const noLaneArm = (knob) => `this knob has no execution-lane default — ${knob} does not depend on which execution lane this deployment runs`;
18
19
  return {
19
20
  streamApproval: gate.active ? "active" : gate.reason,
20
21
  durableApproval: buildPostureKnobReading(input.durableApproval, {
21
22
  knob: "DURABLE_APPROVAL",
22
23
  source: input.durableApprovalSource,
23
24
  centerMeaning: noCenterArm("DURABLE_APPROVAL"),
25
+ laneMeaning: noLaneArm("DURABLE_APPROVAL"),
24
26
  postureMeaning: "derived from the single-user turnkey posture (REQUIRE_PRINCIPAL is not set) composed with a durable store being present: park/resume and the /v1/approvals routes are on by default — set DURABLE_APPROVAL=false to pin them off",
25
27
  }),
26
28
  streamAskWindowMs: buildPostureKnobReading(input.streamAskWindowMs, {
27
29
  knob: "STREAM_ASK_WINDOW_MS",
28
30
  source: input.streamAskWindowMsSource,
29
31
  centerMeaning: noCenterArm("STREAM_ASK_WINDOW_MS"),
32
+ laneMeaning: noLaneArm("STREAM_ASK_WINDOW_MS"),
30
33
  postureMeaning: "derived from the single-user turnkey posture (REQUIRE_PRINCIPAL is not set): an approval card waits 24h instead of 5 minutes, so stepping away does not settle the run unattended — set STREAM_ASK_WINDOW_MS to pin your own window",
31
34
  }),
32
35
  sessionAutoTitle: buildPostureKnobReading(input.sessionAutoTitle, {
33
36
  knob: "SESSION_AUTO_TITLE",
34
37
  source: input.sessionAutoTitleSource,
35
38
  centerMeaning: noCenterArm("SESSION_AUTO_TITLE"),
39
+ laneMeaning: noLaneArm("SESSION_AUTO_TITLE"),
36
40
  postureMeaning: "this knob has no posture arm — its default is the same on every deployment shape",
37
41
  }),
38
42
  checkpointStore: input.checkpointStore !== undefined,
@@ -93,7 +97,7 @@ export async function handleDiagnostics(req, res, match, ctx) {
93
97
  return;
94
98
  }
95
99
  const principal = gatedPrincipal(req, deps.config);
96
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
100
+ if (!explicitOperatorOk(principal, deps.config)) {
97
101
  sendError(res, 403, "auth.operator_only", "wiring diagnostics are operator-only on a multi-tenant worker");
98
102
  return;
99
103
  }
@@ -109,7 +113,7 @@ export async function handleDiagnostics(req, res, match, ctx) {
109
113
  sendJson(res, 200, {
110
114
  static: deps.staticWiring,
111
115
  memoryPosture: deps.memoryPosture ?? null,
112
- sqlEngine: deps.sqlEngineFacts?.() ?? null,
116
+ sqlEngine: deps.sqlEngine?.facts ?? null,
113
117
  writeProtection: deps.writeProtection ?? null,
114
118
  readFace: buildReadFaceWiring(deps.config),
115
119
  executionLane: projectExecutionLaneCapability(deps.config),
@@ -49,8 +49,7 @@ export async function handleImages(req, res, match, ctx) {
49
49
  const bakes = deps.imageBakes;
50
50
  const idx = deps.imageIndex;
51
51
  const principal = gatedPrincipal(req, deps.config);
52
- const operators = deps.config.operatorPrincipals;
53
- const isExplicitOperator = explicitOperatorOk(principal, operators);
52
+ const isExplicitOperator = explicitOperatorOk(principal, deps.config);
54
53
  const operatorLane = facts.operatorLane(deps);
55
54
  const cfg = deps.config.imageBakes;
56
55
  const isRunner = source !== undefined && source !== null && source === cfg.runnerPrincipal;
@@ -239,12 +238,12 @@ export async function handleImages(req, res, match, ctx) {
239
238
  if (line.event === "heartbeat") {
240
239
  const fresh = await bakes.getBake(bakeId);
241
240
  if (!fresh || fresh.status !== "running") {
242
- sendJson(res, 409, { accepted: false, leaseValid: false, cancelRequested: fresh?.cancelRequested ?? false, errorCode: "conflict.bake_not_running" });
241
+ sendError(res, 409, "conflict.bake_not_running", "bake is not running", { accepted: false, leaseValid: false, cancelRequested: fresh?.cancelRequested ?? false });
243
242
  return;
244
243
  }
245
244
  const ok = bake.runnerId ? await bakes.heartbeatLease(bakeId, bake.runnerId, cfg.leaseMs) : false;
246
245
  if (!ok) {
247
- sendJson(res, 409, { accepted: false, leaseValid: false, cancelRequested: fresh.cancelRequested, errorCode: "conflict.bake_lease_lost" });
246
+ sendError(res, 409, "conflict.bake_lease_lost", "bake lease lost", { accepted: false, leaseValid: false, cancelRequested: fresh.cancelRequested });
248
247
  return;
249
248
  }
250
249
  sendJson(res, 200, { accepted: true, leaseValid: true, cancelRequested: fresh.cancelRequested });
@@ -252,7 +251,7 @@ export async function handleImages(req, res, match, ctx) {
252
251
  }
253
252
  const fresh = await bakes.getBake(bakeId);
254
253
  if (!fresh || fresh.status !== "running") {
255
- sendJson(res, 409, { accepted: false, leaseValid: false, cancelRequested: fresh?.cancelRequested ?? false, errorCode: "conflict.bake_not_running" });
254
+ sendError(res, 409, "conflict.bake_not_running", "bake is not running", { accepted: false, leaseValid: false, cancelRequested: fresh?.cancelRequested ?? false });
256
255
  return;
257
256
  }
258
257
  if (fresh.runnerId) {
@@ -291,7 +290,7 @@ export async function handleImages(req, res, match, ctx) {
291
290
  if (pool.available && isIndexRouteId(match.decl.id)) {
292
291
  const idx = pool.imageIndex;
293
292
  const principal = gatedPrincipal(req, deps.config);
294
- const operator = explicitOperatorOk(principal, deps.config.operatorPrincipals);
293
+ const operator = explicitOperatorOk(principal, deps.config);
295
294
  const viewer = { operator, tenantId: principal ?? null };
296
295
  const q = new URLSearchParams(match.search);
297
296
  if (match.decl.id === "images-index") {
@@ -345,7 +344,7 @@ export async function handleImages(req, res, match, ctx) {
345
344
  sendOperatorPrincipalsRequired(res);
346
345
  return;
347
346
  }
348
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
347
+ if (!explicitOperatorOk(principal, deps.config)) {
349
348
  sendError(res, 403, "auth.operator_only", "operator only");
350
349
  return;
351
350
  }
@@ -30,14 +30,7 @@ export async function handleLeader(req, res, match, ctx) {
30
30
  if (match.decl.id === "leader-submit") {
31
31
  if (rateLimited(req, res) || quotaExceeded(req, res) || (await leaseDenied(req, res)) || (await usageWindowDenied(req, res)))
32
32
  return;
33
- let body;
34
- try {
35
- body = await readJson(req);
36
- }
37
- catch {
38
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
39
- return;
40
- }
33
+ const body = await readJson(req);
41
34
  const laneRefusal = leaderEntryRefusal(leaderRunEntry(deps.config.autonomy));
42
35
  if (laneRefusal !== undefined) {
43
36
  sendError(res, 422, "request.autonomy_lane_refused", laneRefusal);
@@ -34,7 +34,7 @@
34
34
  * 404 无 oracle,与 `POST /v1/sessions/:id/notify` 逐字同形)→ `getActiveTaskId` 取本会话的活 run →
35
35
  * `steerableRuns` 取本副本活流。非 live 的四臂一码 409 `steering.not_running`,判据取词表属主
36
36
  * (`isParkedRunStatus` / `isTerminalRunStatus`)与 `runProvenElsewhere`(手抄已收编成一只谓词,S-430 起同住 `plugins/store-contracts.ts`)。
37
- * 显式 operator 可重拨任何租户的会话(监督动作,与 notify / steer 同臂;**不是** bare `isOperator`)。
37
+ * 显式 operator 可重拨任何租户的会话(监督动作,与 notify / steer 同臂;「谁是 operator」的唯一读法 `explicitOperatorOk`)。
38
38
  *
39
39
  * ── 应答期限(S-431)────────────────────────────────────────────────────────────────────────────
40
40
  * 修前这一口对 `live.reconnectMcpServer(server)` 是裸 `await`:server 侧没有期限,上界只来自 core 自己的启动期钟
@@ -7,6 +7,7 @@ import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal } from "../pri
7
7
  import {} from "../route-ctx.js";
8
8
  import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
9
9
  import * as facts from "../../capability-facts.js";
10
+ import { sessionOwnerCellOf } from "../../security.js";
10
11
  const BodySchema = z.object({ server: z.string().min(1).max(190) }).strict();
11
12
  const NEUTRALIZED_TEXT_MAX = 200;
12
13
  const humanText = (s) => redactSecrets(s).slice(0, NEUTRALIZED_TEXT_MAX);
@@ -93,8 +94,8 @@ export async function handleMcpReconnect(req, res, match, ctx) {
93
94
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
94
95
  return;
95
96
  }
96
- const isOperator = explicitOperatorOk(principal, deps.config.operatorPrincipals);
97
- if (!isOperator && !ctx.helpers.sessionOwnerOk(req, res, owner))
97
+ const operator = explicitOperatorOk(principal, deps.config);
98
+ if (!operator && !ctx.helpers.sessionOwnerOk(req, res, await sessionOwnerCellOf(sessionStorage, sessionId, owner)))
98
99
  return;
99
100
  const activeTaskId = await runStore.getActiveTaskId(sessionId);
100
101
  const live = activeTaskId === undefined ? undefined : ctx.registry.steerableRuns.get(activeTaskId);
@@ -73,7 +73,7 @@ export async function handleMemoryBundle(req, res, match, ctx) {
73
73
  sendOperatorPrincipalsRequired(res);
74
74
  return;
75
75
  }
76
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
76
+ if (!explicitOperatorOk(principal, deps.config)) {
77
77
  sendError(res, 403, "auth.operator_only", "memory governance bundles are an operator-only deployment action");
78
78
  return;
79
79
  }
@@ -29,7 +29,7 @@ export async function handleMemoryCompliance(req, res, match, ctx) {
29
29
  sendOperatorPrincipalsRequired(res);
30
30
  return;
31
31
  }
32
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
32
+ if (!explicitOperatorOk(principal, deps.config)) {
33
33
  sendError(res, 403, "auth.operator_only", "memory provenance and erasure are operator-only deployment actions");
34
34
  return;
35
35
  }
@@ -92,7 +92,7 @@ export async function handleMemoryConsolidation(req, res, match, ctx) {
92
92
  }
93
93
  }
94
94
  const faces = fact.valve;
95
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
95
+ if (!explicitOperatorOk(principal, deps.config)) {
96
96
  sendError(res, 403, "auth.operator_only", "memory consolidation is operator-only: the caller principal is not in OPERATOR_PRINCIPALS");
97
97
  return;
98
98
  }
@@ -122,7 +122,7 @@ export async function handleMemoryOrigin(req, res, match, ctx) {
122
122
  sendOperatorPrincipalsRequired(res);
123
123
  return;
124
124
  }
125
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
125
+ if (!explicitOperatorOk(principal, deps.config)) {
126
126
  sendError(res, 403, "auth.operator_only", "memory origin marking and clearance are operator-only deployment actions");
127
127
  return;
128
128
  }
@@ -2,7 +2,7 @@
2
2
  * [ref] A9 域模块 —— memory 导出/同步 + 只读策略面。
3
3
  *
4
4
  * 路由:`GET /v1/memory/export`、`POST /v1/memory/sync/:scope`、`GET /v1/policy`。
5
- * owner 门 = 「本人 user scope / 显式 operator / `org:` 键的目录成员」(见 {@link gateMemoryScope}),
5
+ * owner 门 = 「本人 user scope / 本人的项目层 / 显式 operator / `org:` 键的目录成员」(见 {@link gateMemoryScope}),
6
6
  * 越界一律 404(零存在性 oracle)。本域零可变状态。
7
7
  */
8
8
  import type { IncomingMessage, ServerResponse } from "node:http";
@@ -2,6 +2,7 @@ import { formatUserScope } from "@sema-agent/core";
2
2
  import { parseMemorySyncRequest } from "../../memory-sync.js";
3
3
  import { sendJson, sendError } from "../send.js";
4
4
  import { buildOriginFence, readOriginAware } from "../../memory-origin-fence.js";
5
+ import { parseProjectLayerKey } from "../../project-layer-key.js";
5
6
  import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sendUnauthorized } from "../principal-gate.js";
6
7
  import { assertNever } from "../route-ctx.js";
7
8
  const ORG_PREFIX = "org:";
@@ -33,9 +34,9 @@ function directoryDecidesThisFace(mode) {
33
34
  }
34
35
  }
35
36
  async function gateMemoryScope(deps, principal, scope, need) {
36
- if (scope === formatUserScope(principal))
37
+ if (scope === formatUserScope(principal) || parseProjectLayerKey(scope)?.owner === principal)
37
38
  return { kind: "allow" };
38
- if (explicitOperatorOk(principal, deps.config.operatorPrincipals))
39
+ if (explicitOperatorOk(principal, deps.config))
39
40
  return { kind: "allow" };
40
41
  const directory = deps.orgMemoryDirectory;
41
42
  if (!scope.startsWith(ORG_PREFIX) || directory === undefined || !directoryDecidesThisFace(deps.config.memoryOrgAdmissionMode)) {
@@ -1,6 +1,7 @@
1
- import { taskNotificationInboxEntry } from "../../orchestration/workflow-completion-inbox.js";
1
+ import { externalNotificationInboxEntry } from "../../orchestration/workflow-completion-inbox.js";
2
2
  import { sendJson, sendError } from "../send.js";
3
- import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal } from "../principal-gate.js";
3
+ import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sessionCallerOf } from "../principal-gate.js";
4
+ import { ownerlessRowOpen, sessionOwnerCellOf } from "../../security.js";
4
5
  import { sendResumeOutcome } from "../route-ctx.js";
5
6
  import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
6
7
  import * as facts from "../../capability-facts.js";
@@ -23,14 +24,7 @@ export async function handleNotifyWake(req, res, match, ctx) {
23
24
  sendError(res, 400, "request.path_malformed", "session id segment is not valid percent-encoding");
24
25
  return;
25
26
  }
26
- let nb;
27
- try {
28
- nb = (await readJson(req));
29
- }
30
- catch {
31
- sendError(res, 400, "request.body_shape", "body must be JSON: { task_id, status, summary, result?, seq?, source? }");
32
- return;
33
- }
27
+ const nb = (await readJson(req));
34
28
  if (typeof nb.task_id !== "string" || nb.task_id.trim().length === 0 || nb.task_id.length > 190) {
35
29
  sendError(res, 400, "request.field_invalid", "task_id must be a non-empty string of at most 190 characters");
36
30
  return;
@@ -68,8 +62,8 @@ export async function handleNotifyWake(req, res, match, ctx) {
68
62
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
69
63
  return;
70
64
  }
71
- const notifyOperator = explicitOperatorOk(principal, deps.config.operatorPrincipals);
72
- if (!notifyOperator && notifyOwner !== null && notifyOwner !== principal) {
65
+ const notifyOperator = explicitOperatorOk(principal, deps.config);
66
+ if (!notifyOperator && notifyOwner !== principal && !ownerlessRowOpen(await sessionOwnerCellOf(owned.sessionStorage, notifySession, notifyOwner), sessionCallerOf(req, deps))) {
73
67
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
74
68
  return;
75
69
  }
@@ -101,7 +95,7 @@ export async function handleNotifyWake(req, res, match, ctx) {
101
95
  sendError(res, 501, "capability.workflow_store_required", "external notify requires the workflow completion inbox (WORKFLOW_RUN_STORE)");
102
96
  return;
103
97
  }
104
- await deps.workflowCompletionInbox.enqueue(taskNotificationInboxEntry(notifySession, notifyOwner ?? principal ?? null, { task_id: payload.task_id, task_type: "external", status: payload.status, summary: payload.summary, ...(payload.result !== undefined ? { result: payload.result } : {}), ...(payload.seq !== undefined ? { seq: payload.seq } : {}), ...(payload.source !== undefined ? { source: payload.source } : {}) }, Date.now()));
98
+ await deps.workflowCompletionInbox.enqueue(externalNotificationInboxEntry(notifySession, notifyOwner ?? principal ?? null, { task_type: "external", ...payload }, Date.now()));
105
99
  sendJson(res, 202, { sessionId: notifySession, delivery: "parked", note: "no live stream — parked in the session inbox; drained as a task_notification on the next stream open" });
106
100
  return;
107
101
  }
@@ -122,14 +116,7 @@ export async function handleNotifyWake(req, res, match, ctx) {
122
116
  sendError(res, 400, "request.path_malformed", "session id segment is not valid percent-encoding");
123
117
  return;
124
118
  }
125
- let wakeBody;
126
- try {
127
- wakeBody = (await readJson(req));
128
- }
129
- catch {
130
- sendError(res, 400, "request.body_shape", "body must be JSON: { message?: string }");
131
- return;
132
- }
119
+ const wakeBody = (await readJson(req));
133
120
  if (wakeBody.message !== undefined && (typeof wakeBody.message !== "string" || wakeBody.message.length === 0)) {
134
121
  sendError(res, 400, "request.field_invalid", "message must be a non-empty string when present");
135
122
  return;
@@ -1,5 +1,5 @@
1
1
  import { sendJson, sendError } from "../send.js";
2
- import { gatedPrincipal, isOperator, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
2
+ import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
3
3
  import { assertNever } from "../route-ctx.js";
4
4
  import * as facts from "../../capability-facts.js";
5
5
  import { quotaWindowResetsAt } from "../../observability/cost-quota.js";
@@ -14,7 +14,7 @@ export async function handleObservability(req, res, match, ctx) {
14
14
  }
15
15
  if (deps.config.requirePrincipal) {
16
16
  const principal = gatedPrincipal(req, deps.config);
17
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
17
+ if (!explicitOperatorOk(principal, deps.config)) {
18
18
  sendError(res, 403, "auth.operator_only", "outcomes view is operator-only on a multi-tenant worker");
19
19
  return;
20
20
  }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 跨主体投递门的**受理口**:`POST /v1/principal-inbox/messages`。
3
+ *
4
+ * 本口只做三件事,其余全归门(`src/org-delivery-gate.ts`,规则全文在它的头注):
5
+ * ① 取发件人 —— **只**取自验过的身份面(`gatedPrincipal`),交给门的 `authedFrom` 就是 `{ scope: <那位主体> }`;
6
+ * 体里没有发件人这个键(写了 = 词表外键,400)。没有验过的身份 ⇒ 401(身份面那一句),不论部署是否要求 principal ——
7
+ * 门要一个发件人 scope,匿名者没有。无凭证部署上 principal 头只是调用方自报 ⇒ 本口在分派器的无凭证写门内
8
+ * (声明行 `credentialGated`,503 `auth.service_token_required`;本地开发显式 `ALLOW_UNAUTHED_WRITES=true` 才放行);
9
+ * ② 判体形 —— `{ to: 非空串, content: 非空串(≤ {@link PRINCIPAL_INBOX_CONTENT_MAX_CHARS} 字), urgent?: 布尔 }`,
10
+ * 键闭集与提交口同一只组句器(`principalInboxBodyKeyIssue`);
11
+ * ③ 调门、投影门的答案 —— 回执 ⇒ 200 `{ receiptId }`;拒绝 ⇒ core 的词原样做 `errorCode`、门的那一句原样做 `error`。
12
+ * 本口**不碰**任何店:一个店名、一个 `.append` 都没有(`test/org-delivery-gate-single-path.test.ts` 按源码钉)。
13
+ *
14
+ * 回执**不**带门回执里的 `seq`:那是收件人箱的序号,原样交给发件人就是把「收件人这只箱收过多少封」泄给 org 里的任何人。
15
+ *
16
+ * 拒绝词 → HTTP 状态(穷举 `switch`,core 加词 ⇒ 编译红):
17
+ * · `not_member` → 404:「不同 org」「查无此人」「目录答不上来」同一份字节(门保证),404 与本仓反枚举的既有形一致;
18
+ * · `rate_limited` → 429;
19
+ * · `inbox_full` → 409(收件人那一侧的状态,不是发件人的速率;与 `steering.queue_full` 同档);
20
+ * · `recipient_tombstoned` → 410(收件人正在被删除,这条路关了)。
21
+ * 门缺席(本部署没声明收件箱消费方)⇒ 501 `capability.unavailable`,能力位 `principalInboxDelivery` 读同一只事实。
22
+ */
23
+ import type { IncomingMessage, ServerResponse } from "node:http";
24
+ import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
25
+ /**
26
+ * 一封信正文的字符上界。全局请求体上界(8 MiB)对一只收件箱太宽:箱里最多 50 封,而读它的是收件人的助理 ——
27
+ * 一封信是一段话,不是一份附件(要转一份长文,发它的出处)。
28
+ */
29
+ export declare const PRINCIPAL_INBOX_CONTENT_MAX_CHARS = 32000;
30
+ export declare function handlePrincipalInbox(req: IncomingMessage, res: ServerResponse, match: RouteMatch<PrincipalInboxRouteId>, ctx: RouteCtx): Promise<void>;
31
+ export declare const PRINCIPAL_INBOX_ROUTES: readonly [{
32
+ readonly id: "principal-inbox-messages";
33
+ readonly path: "/v1/principal-inbox/messages";
34
+ readonly credentialGated: readonly ["POST"];
35
+ readonly methods: readonly ["POST"];
36
+ }];
37
+ /** 本域可分派行的 `id` 闭集 —— handler 的 `switch` 按它判穷尽。 */
38
+ export type PrincipalInboxRouteId = RouteIdsOf<typeof PRINCIPAL_INBOX_ROUTES>;
39
+ //# sourceMappingURL=principal-inbox.d.ts.map
@@ -0,0 +1,76 @@
1
+ import { sendJson, sendError } from "../send.js";
2
+ import { gatedPrincipal, sendUnauthorized } from "../principal-gate.js";
3
+ import { assertNever } from "../route-ctx.js";
4
+ import * as facts from "../../capability-facts.js";
5
+ import { principalInboxBodyKeyIssue } from "../../request-key-closure.js";
6
+ export const PRINCIPAL_INBOX_CONTENT_MAX_CHARS = 32_000;
7
+ function sendRefusal(res, outcome) {
8
+ switch (outcome.code) {
9
+ case "org_delivery.not_member":
10
+ sendError(res, 404, "org_delivery.not_member", outcome.message);
11
+ return;
12
+ case "org_delivery.rate_limited":
13
+ sendError(res, 429, "org_delivery.rate_limited", outcome.message);
14
+ return;
15
+ case "org_delivery.inbox_full":
16
+ sendError(res, 409, "org_delivery.inbox_full", outcome.message);
17
+ return;
18
+ case "org_delivery.recipient_tombstoned":
19
+ sendError(res, 410, "org_delivery.recipient_tombstoned", outcome.message);
20
+ return;
21
+ default:
22
+ return assertNever(outcome.code);
23
+ }
24
+ }
25
+ export async function handlePrincipalInbox(req, res, match, ctx) {
26
+ const { deps } = ctx;
27
+ const { readJson } = ctx.helpers;
28
+ switch (match.decl.id) {
29
+ case "principal-inbox-messages": {
30
+ const principal = gatedPrincipal(req, deps.config);
31
+ if (principal === undefined) {
32
+ sendUnauthorized(res, "identity");
33
+ return;
34
+ }
35
+ const fact = facts.principalInboxDelivery(deps);
36
+ if (!fact.available) {
37
+ sendError(res, 501, "capability.unavailable", "cross-principal delivery is not available on this deployment (it declares no principal-inbox consumer, so no organization delivery gate is mounted)");
38
+ return;
39
+ }
40
+ const raw = await readJson(req);
41
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
42
+ sendError(res, 400, "request.field_invalid", "body must be a JSON object { to: string, content: string, urgent?: boolean }");
43
+ return;
44
+ }
45
+ const keyIssue = principalInboxBodyKeyIssue(raw);
46
+ if (keyIssue) {
47
+ sendError(res, 400, "request.body_shape", keyIssue.message, { unknownKeys: keyIssue.unknownKeys, unsupportedKeys: keyIssue.unsupportedKeys });
48
+ return;
49
+ }
50
+ const body = raw;
51
+ if (typeof body.to !== "string" || body.to === "") {
52
+ sendError(res, 400, "request.field_invalid", "to must be a non-empty string naming the recipient principal");
53
+ return;
54
+ }
55
+ if (typeof body.content !== "string" || body.content === "" || body.content.length > PRINCIPAL_INBOX_CONTENT_MAX_CHARS) {
56
+ sendError(res, 400, "request.field_invalid", `content must be a non-empty string of at most ${PRINCIPAL_INBOX_CONTENT_MAX_CHARS} characters`);
57
+ return;
58
+ }
59
+ if (body.urgent !== undefined && typeof body.urgent !== "boolean") {
60
+ sendError(res, 400, "request.field_invalid", "urgent must be a boolean when present");
61
+ return;
62
+ }
63
+ const outcome = await fact.gate.deliverCrossPrincipal({ scope: principal }, body.to, { content: body.content, ...(body.urgent !== undefined ? { urgent: body.urgent } : {}) });
64
+ if (!outcome.ok) {
65
+ sendRefusal(res, outcome);
66
+ return;
67
+ }
68
+ sendJson(res, 200, { receiptId: outcome.receipt.receiptId });
69
+ return;
70
+ }
71
+ default:
72
+ return assertNever(match.decl.id);
73
+ }
74
+ }
75
+ export const PRINCIPAL_INBOX_ROUTES = [{ id: "principal-inbox-messages", path: "/v1/principal-inbox/messages", credentialGated: ["POST"], methods: ["POST"] }];
76
+ //# sourceMappingURL=principal-inbox.js.map
@@ -36,7 +36,7 @@ export async function handleRetention(req, res, match, ctx) {
36
36
  sendOperatorPrincipalsRequired(res);
37
37
  return;
38
38
  }
39
- if (!explicitOperatorOk(principal, deps.config.operatorPrincipals)) {
39
+ if (!explicitOperatorOk(principal, deps.config)) {
40
40
  sendError(res, 403, "auth.operator_only", OPERATOR_ONLY_MESSAGE);
41
41
  return;
42
42
  }
@@ -71,14 +71,7 @@ async function handleHold(req, res, ctx, store, rawDomain, principal, held) {
71
71
  }
72
72
  let note;
73
73
  if (held) {
74
- let raw;
75
- try {
76
- raw = await ctx.helpers.readJson(req);
77
- }
78
- catch {
79
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
80
- return;
81
- }
74
+ const raw = await ctx.helpers.readJson(req);
82
75
  if (raw !== undefined && raw !== null && raw !== "") {
83
76
  if (typeof raw !== "object" || Array.isArray(raw)) {
84
77
  sendError(res, 400, "request.body_shape", "invalid retention hold body — expected an object with an optional `note` string");