@sema-agent/server 7.132.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 (402) hide show
  1. package/MIGRATION.md +266 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +174 -55
  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 +79 -19
  24. package/dist/approval-card.js +44 -13
  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 +27 -10
  29. package/dist/audit.js +12 -16
  30. package/dist/bake-runner/main.js +3 -2
  31. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  32. package/dist/boot/execution-env.js +9 -7
  33. package/dist/boot/execution-lane.js +11 -0
  34. package/dist/boot/leader.js +2 -0
  35. package/dist/boot/memory-boundary.js +2 -2
  36. package/dist/boot/memory-consolidation.d.ts +5 -4
  37. package/dist/boot/memory-consolidation.js +7 -6
  38. package/dist/boot/org-delivery.d.ts +28 -0
  39. package/dist/boot/org-delivery.js +20 -0
  40. package/dist/boot/reapers.d.ts +3 -0
  41. package/dist/boot/reapers.js +21 -1
  42. package/dist/boot/resolve-spec.d.ts +3 -0
  43. package/dist/boot/resolve-spec.js +60 -81
  44. package/dist/boot/runner-deps.js +1 -0
  45. package/dist/boot/session-faces.d.ts +1 -0
  46. package/dist/boot/session-faces.js +4 -2
  47. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  48. package/dist/boot/stage-06-runners.d.ts +2 -0
  49. package/dist/boot/stage-06-runners.js +6 -3
  50. package/dist/boot/stage-07-capability-layer.d.ts +2 -0
  51. package/dist/boot/stage-07-capability-layer.js +24 -3
  52. package/dist/boot/stage-08-reapers.d.ts +2 -0
  53. package/dist/boot/stage-08-reapers.js +2 -2
  54. package/dist/boot/stage-09-leader.d.ts +3 -0
  55. package/dist/boot/stage-10-http-server.d.ts +3 -0
  56. package/dist/boot/stage-10-http-server.js +5 -6
  57. package/dist/boot/stores.js +2 -2
  58. package/dist/boot/web-admin.d.ts +4 -0
  59. package/dist/boot/web-admin.js +151 -63
  60. package/dist/boot/workflow-orchestration.d.ts +2 -0
  61. package/dist/boot/workflow-orchestration.js +2 -1
  62. package/dist/brain.js +8 -3
  63. package/dist/breaker-key.d.ts +6 -0
  64. package/dist/breaker-key.js +29 -0
  65. package/dist/caller-text-echo.d.ts +9 -6
  66. package/dist/caller-text-echo.js +8 -11
  67. package/dist/capabilities/center-plugins.d.ts +7 -0
  68. package/dist/capabilities/center-plugins.js +1 -1
  69. package/dist/capabilities/composite-members.d.ts +1 -1
  70. package/dist/capabilities/composite-members.js +1 -1
  71. package/dist/capabilities/execution-lane.js +2 -2
  72. package/dist/capabilities/hands-lane.d.ts +21 -0
  73. package/dist/capabilities/hands-lane.js +10 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -4
  75. package/dist/capabilities/mcp-probe.js +27 -4
  76. package/dist/capabilities/scenarios.d.ts +63 -7
  77. package/dist/capabilities/scenarios.js +39 -7
  78. package/dist/capability-facts.d.ts +34 -4
  79. package/dist/capability-facts.js +28 -2
  80. package/dist/center-config-tier.d.ts +69 -0
  81. package/dist/center-config-tier.js +42 -0
  82. package/dist/checkpoint-identity.d.ts +16 -0
  83. package/dist/checkpoint-identity.js +19 -0
  84. package/dist/config-catalog.d.ts +17 -10
  85. package/dist/config-catalog.js +43 -28
  86. package/dist/config-d-migration.d.ts +3 -1
  87. package/dist/config-d-migration.js +2 -2
  88. package/dist/config-dir-trust.d.ts +114 -0
  89. package/dist/config-dir-trust.js +388 -0
  90. package/dist/config-invariants.d.ts +18 -5
  91. package/dist/config-invariants.js +35 -3
  92. package/dist/config-provider.d.ts +6 -1
  93. package/dist/config-provider.js +6 -2
  94. package/dist/config-types.d.ts +71 -14
  95. package/dist/config-types.js +8 -0
  96. package/dist/config.d.ts +13 -0
  97. package/dist/config.js +121 -59
  98. package/dist/delegated-session-owner.d.ts +185 -0
  99. package/dist/delegated-session-owner.js +119 -0
  100. package/dist/device-protocol.d.ts +5 -3
  101. package/dist/device-protocol.js +1 -1
  102. package/dist/device-ws-hub.js +21 -2
  103. package/dist/device-ws-protocol.d.ts +70 -6
  104. package/dist/device-ws-protocol.js +50 -23
  105. package/dist/elicitation.js +3 -2
  106. package/dist/entry-problems.d.ts +34 -0
  107. package/dist/entry-problems.js +14 -0
  108. package/dist/execution-lane-caps.d.ts +49 -10
  109. package/dist/execution-lane-caps.js +43 -4
  110. package/dist/field-conflict.d.ts +43 -0
  111. package/dist/field-conflict.js +20 -0
  112. package/dist/fleet/fleet-bus.d.ts +80 -6
  113. package/dist/fleet/fleet-bus.js +41 -9
  114. package/dist/hooks/classic-stations.d.ts +10 -5
  115. package/dist/hooks/classic-stations.js +4 -4
  116. package/dist/hooks/command-spawn.d.ts +57 -0
  117. package/dist/hooks/command-spawn.js +139 -0
  118. package/dist/hooks/hook-llm.js +2 -2
  119. package/dist/hooks/hook-runner.d.ts +127 -25
  120. package/dist/hooks/hook-runner.js +668 -287
  121. package/dist/hooks/hook-source.d.ts +44 -0
  122. package/dist/hooks/hook-source.js +40 -0
  123. package/dist/http/active-run-conflict.d.ts +5 -13
  124. package/dist/http/active-run-conflict.js +17 -27
  125. package/dist/http/admission.js +103 -60
  126. package/dist/http/approval-sweeps.js +55 -18
  127. package/dist/http/caller-trust.d.ts +77 -0
  128. package/dist/http/caller-trust.js +143 -0
  129. package/dist/http/checkpoint-ctx.d.ts +16 -16
  130. package/dist/http/checkpoint-ctx.js +13 -10
  131. package/dist/http/claimed-run.d.ts +4 -3
  132. package/dist/http/device-placement.d.ts +2 -4
  133. package/dist/http/device-placement.js +2 -1
  134. package/dist/http/dispatch.js +10 -4
  135. package/dist/http/durable-run-leg.d.ts +4 -32
  136. package/dist/http/durable-run-leg.js +34 -10
  137. package/dist/http/owner-access.d.ts +56 -0
  138. package/dist/http/owner-access.js +42 -0
  139. package/dist/http/principal-gate.d.ts +48 -23
  140. package/dist/http/principal-gate.js +39 -12
  141. package/dist/http/readiness.d.ts +11 -5
  142. package/dist/http/readiness.js +10 -3
  143. package/dist/http/request-guards.d.ts +16 -23
  144. package/dist/http/request-guards.js +30 -15
  145. package/dist/http/resume-ctx-read.d.ts +2 -5
  146. package/dist/http/resume-ctx-read.js +7 -4
  147. package/dist/http/resume-legs.d.ts +3 -4
  148. package/dist/http/resume-legs.js +126 -69
  149. package/dist/http/retired-service-deps.d.ts +43 -0
  150. package/dist/http/retired-service-deps.js +18 -0
  151. package/dist/http/route-ctx.d.ts +44 -28
  152. package/dist/http/route-ctx.js +4 -0
  153. package/dist/http/route-table.js +2 -0
  154. package/dist/http/routes/a2a-serve.js +3 -4
  155. package/dist/http/routes/admin-config-refresh.js +1 -1
  156. package/dist/http/routes/admin-drain.js +1 -1
  157. package/dist/http/routes/admin-memory-optout.js +5 -1
  158. package/dist/http/routes/adoption.js +2 -9
  159. package/dist/http/routes/approvals-assistant.js +49 -48
  160. package/dist/http/routes/background.js +3 -2
  161. package/dist/http/routes/capabilities.js +20 -4
  162. package/dist/http/routes/config-catalog.d.ts +3 -3
  163. package/dist/http/routes/config-catalog.js +1 -1
  164. package/dist/http/routes/devices.js +3 -17
  165. package/dist/http/routes/diagnostics.js +5 -1
  166. package/dist/http/routes/images.js +6 -7
  167. package/dist/http/routes/leader.js +1 -8
  168. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  169. package/dist/http/routes/mcp-reconnect.js +3 -2
  170. package/dist/http/routes/memory-bundle.js +1 -1
  171. package/dist/http/routes/memory-compliance.js +1 -1
  172. package/dist/http/routes/memory-consolidation.js +1 -1
  173. package/dist/http/routes/memory-origin.js +1 -1
  174. package/dist/http/routes/memory-policy.d.ts +1 -1
  175. package/dist/http/routes/memory-policy.js +3 -2
  176. package/dist/http/routes/notify-wake.js +8 -21
  177. package/dist/http/routes/observability.js +2 -2
  178. package/dist/http/routes/principal-inbox.d.ts +39 -0
  179. package/dist/http/routes/principal-inbox.js +76 -0
  180. package/dist/http/routes/retention-ops.js +2 -9
  181. package/dist/http/routes/rules.js +5 -18
  182. package/dist/http/routes/runs.d.ts +5 -0
  183. package/dist/http/routes/runs.js +33 -106
  184. package/dist/http/routes/session-sync.js +15 -28
  185. package/dist/http/routes/sessions.js +30 -40
  186. package/dist/http/routes/side-query.js +6 -4
  187. package/dist/http/routes/tasks.js +50 -14
  188. package/dist/http/routes/workflows.d.ts +351 -0
  189. package/dist/http/routes/workflows.js +153 -119
  190. package/dist/http/send.d.ts +24 -3
  191. package/dist/http/send.js +14 -2
  192. package/dist/http/server.d.ts +17 -18
  193. package/dist/http/server.js +15 -13
  194. package/dist/http/stored-body-replay.js +17 -4
  195. package/dist/http/submit-ctx.js +4 -3
  196. package/dist/http/submit-replay.d.ts +4 -3
  197. package/dist/http/submit-replay.js +5 -4
  198. package/dist/http/wire-types.d.ts +10 -7
  199. package/dist/index.d.ts +1 -1
  200. package/dist/index.js +0 -1
  201. package/dist/lane-home-probe.d.ts +78 -9
  202. package/dist/lane-home-probe.js +78 -12
  203. package/dist/leader/endpoint.d.ts +4 -1
  204. package/dist/leader/endpoint.js +11 -10
  205. package/dist/limit-refusal.d.ts +17 -5
  206. package/dist/limit-refusal.js +4 -1
  207. package/dist/mcp-assertion-header.d.ts +31 -10
  208. package/dist/mcp-assertion-header.js +10 -3
  209. package/dist/mcp-tool-faces.js +1 -3
  210. package/dist/memory-project-layer.d.ts +37 -0
  211. package/dist/memory-project-layer.js +46 -0
  212. package/dist/memory-scope.d.ts +23 -16
  213. package/dist/memory-scope.js +24 -8
  214. package/dist/memory-sync-client.d.ts +27 -13
  215. package/dist/memory-sync-client.js +107 -18
  216. package/dist/model-entry-refusal.d.ts +9 -1
  217. package/dist/model-entry-refusal.js +6 -1
  218. package/dist/model-plane-face.d.ts +51 -0
  219. package/dist/model-plane-face.js +24 -0
  220. package/dist/model-provider.d.ts +5 -0
  221. package/dist/model-provider.js +4 -2
  222. package/dist/model-route-endpoint.d.ts +8 -11
  223. package/dist/model-route-endpoint.js +4 -7
  224. package/dist/model-route-env.d.ts +22 -0
  225. package/dist/model-route-env.js +2 -0
  226. package/dist/model-route-gap.d.ts +60 -30
  227. package/dist/model-route-gap.js +21 -15
  228. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  229. package/dist/observability/corrupt-read-seat.js +9 -0
  230. package/dist/observability/err-text.d.ts +6 -0
  231. package/dist/observability/err-text.js +18 -4
  232. package/dist/observability/fail-open.d.ts +35 -9
  233. package/dist/observability/fail-open.js +35 -9
  234. package/dist/observability/metrics.js +1 -0
  235. package/dist/observability/prompt-manifest.d.ts +3 -17
  236. package/dist/observability/prompt-manifest.js +45 -42
  237. package/dist/observability/tool-trace.js +9 -9
  238. package/dist/operator-ask.d.ts +10 -0
  239. package/dist/operator-ask.js +3 -0
  240. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  241. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  242. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  243. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  244. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  245. package/dist/orchestration/workflow-notify-journal.js +27 -34
  246. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  247. package/dist/orchestration/workflow-park-decision.js +118 -0
  248. package/dist/org-delivery-gate.d.ts +81 -0
  249. package/dist/org-delivery-gate.js +59 -0
  250. package/dist/panel-tool-names.d.ts +23 -0
  251. package/dist/panel-tool-names.js +8 -0
  252. package/dist/parked-decide.d.ts +39 -6
  253. package/dist/parked-decide.js +98 -51
  254. package/dist/parked-revive-surface.d.ts +9 -2
  255. package/dist/parked-revive-surface.js +11 -8
  256. package/dist/permission-rule-list.d.ts +1 -1
  257. package/dist/permission-rule-list.js +2 -2
  258. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  259. package/dist/plugins/approval-ask-store-file.js +21 -0
  260. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  261. package/dist/plugins/approval-ask-store-memory.js +34 -2
  262. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  263. package/dist/plugins/approval-ask-store-sql.js +37 -1
  264. package/dist/plugins/blob-backend.d.ts +38 -25
  265. package/dist/plugins/blob-backend.js +29 -19
  266. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  267. package/dist/plugins/breaker-state-sql.js +4 -4
  268. package/dist/plugins/caching-session-store.d.ts +3 -0
  269. package/dist/plugins/caching-session-store.js +3 -0
  270. package/dist/plugins/checkpoint-store-sql.d.ts +14 -0
  271. package/dist/plugins/checkpoint-store-sql.js +20 -2
  272. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  273. package/dist/plugins/file-history-store-sql.js +3 -1
  274. package/dist/plugins/file-run-store.d.ts +5 -13
  275. package/dist/plugins/file-run-store.js +9 -0
  276. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  277. package/dist/plugins/fork-routing-session-store.js +12 -1
  278. package/dist/plugins/host-platform.d.ts +2 -0
  279. package/dist/plugins/host-platform.js +2 -1
  280. package/dist/plugins/local-checkpoint-store.d.ts +2 -0
  281. package/dist/plugins/local-checkpoint-store.js +6 -1
  282. package/dist/plugins/local-session-store.d.ts +1 -1
  283. package/dist/plugins/local-session-window.d.ts +39 -0
  284. package/dist/plugins/local-session-window.js +54 -0
  285. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  286. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  287. package/dist/plugins/mailbox-store-sql.js +77 -52
  288. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  289. package/dist/plugins/memory-run-store.d.ts +5 -13
  290. package/dist/plugins/memory-run-store.js +8 -0
  291. package/dist/plugins/one-time-migrations.d.ts +110 -5
  292. package/dist/plugins/one-time-migrations.js +320 -8
  293. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  294. package/dist/plugins/org-delivery-quota-store.js +228 -0
  295. package/dist/plugins/pg-pool.js +39 -7
  296. package/dist/plugins/pg-session-storage.d.ts +17 -4
  297. package/dist/plugins/pg-session-storage.js +29 -6
  298. package/dist/plugins/remote-env-adb.d.ts +6 -12
  299. package/dist/plugins/remote-env-adb.js +12 -2
  300. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  301. package/dist/plugins/remote-env-k8s.js +23 -5
  302. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  303. package/dist/plugins/remote-env-local-docker.js +12 -9
  304. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  305. package/dist/plugins/remote-env-ssh.js +17 -11
  306. package/dist/plugins/run-store-sql.d.ts +16 -14
  307. package/dist/plugins/run-store-sql.js +22 -2
  308. package/dist/plugins/schema-indexes.js +2 -0
  309. package/dist/plugins/send-user-file.js +2 -2
  310. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  311. package/dist/plugins/session-epoch-anchor.js +2 -3
  312. package/dist/plugins/session-store.d.ts +18 -8
  313. package/dist/plugins/session-store.js +15 -4
  314. package/dist/plugins/sql-driver.d.ts +74 -11
  315. package/dist/plugins/sql-driver.js +210 -12
  316. package/dist/plugins/sql-errors.d.ts +23 -0
  317. package/dist/plugins/sql-errors.js +21 -0
  318. package/dist/plugins/store-backend.d.ts +36 -1
  319. package/dist/plugins/store-backend.js +40 -14
  320. package/dist/plugins/store-contracts.d.ts +42 -0
  321. package/dist/plugins/store-contracts.js +1 -0
  322. package/dist/plugins/tidb-pool.d.ts +6 -1
  323. package/dist/plugins/tidb-pool.js +44 -10
  324. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  325. package/dist/plugins/tidb-session-storage.js +2 -2
  326. package/dist/plugins/tidb-session-store.d.ts +24 -4
  327. package/dist/plugins/tidb-session-store.js +28 -4
  328. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  329. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  330. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  331. package/dist/plugins/workflow-run-store-sql.js +50 -9
  332. package/dist/posture-source.d.ts +18 -10
  333. package/dist/posture-source.js +4 -1
  334. package/dist/project-identity.d.ts +45 -6
  335. package/dist/project-identity.js +162 -8
  336. package/dist/project-layer-key.d.ts +28 -0
  337. package/dist/project-layer-key.js +29 -0
  338. package/dist/question.js +3 -2
  339. package/dist/read-deny-entry.d.ts +25 -0
  340. package/dist/read-deny-entry.js +12 -0
  341. package/dist/read-face-posture.d.ts +37 -11
  342. package/dist/read-face-posture.js +32 -3
  343. package/dist/request-key-closure.d.ts +7 -0
  344. package/dist/request-key-closure.js +9 -1
  345. package/dist/request-value-closure.d.ts +5 -0
  346. package/dist/request-value-closure.js +11 -3
  347. package/dist/rule-entry-list.d.ts +26 -2
  348. package/dist/rule-entry-list.js +72 -12
  349. package/dist/rules-consent.js +3 -4
  350. package/dist/run-acceptance.d.ts +19 -3
  351. package/dist/run-acceptance.js +13 -1
  352. package/dist/run-local.js +36 -6
  353. package/dist/runs.d.ts +10 -9
  354. package/dist/runs.js +21 -3
  355. package/dist/runtime-caps-resolver.d.ts +16 -6
  356. package/dist/runtime-caps-resolver.js +18 -5
  357. package/dist/sandbox-pkg-source.d.ts +19 -1
  358. package/dist/sandbox-pkg-source.js +29 -7
  359. package/dist/security.d.ts +87 -9
  360. package/dist/security.js +52 -9
  361. package/dist/session-error-wire.d.ts +19 -2
  362. package/dist/session-error-wire.js +5 -1
  363. package/dist/session-titled-frame.d.ts +33 -0
  364. package/dist/session-titled-frame.js +4 -0
  365. package/dist/session-titler.d.ts +9 -1
  366. package/dist/session-titler.js +15 -4
  367. package/dist/spec-fields.js +21 -2
  368. package/dist/sql-engine-posture.d.ts +3 -1
  369. package/dist/task-cwd.d.ts +1 -1
  370. package/dist/task-mcp.d.ts +3 -3
  371. package/dist/task-mcp.js +7 -66
  372. package/dist/task-settings.d.ts +89 -88
  373. package/dist/task-settings.js +71 -63
  374. package/dist/text-bidi.d.ts +0 -4
  375. package/dist/text-bidi.js +1 -3
  376. package/dist/tighten-only-seats.d.ts +150 -0
  377. package/dist/tighten-only-seats.js +196 -0
  378. package/dist/tool-approval.d.ts +303 -87
  379. package/dist/tool-approval.js +623 -239
  380. package/dist/trace/core-keyset-guard.d.ts +104 -22
  381. package/dist/trace/exit-seat.d.ts +28 -0
  382. package/dist/trace/exit-seat.js +76 -0
  383. package/dist/trace/ledger-events.d.ts +3 -2
  384. package/dist/trace/project.d.ts +80 -12
  385. package/dist/trace/project.js +41 -28
  386. package/dist/trace/projection-table.d.ts +100 -0
  387. package/dist/trace/projection-table.js +130 -0
  388. package/dist/trace/redact.d.ts +54 -0
  389. package/dist/trace/redact.js +778 -152
  390. package/dist/trace/self-minted-wire.d.ts +345 -1
  391. package/dist/trace/self-minted-wire.js +117 -1
  392. package/dist/trace/wire-projection-faces.d.ts +298 -2
  393. package/dist/trace/wire-projection-faces.js +154 -13
  394. package/dist/url-refusal.js +2 -0
  395. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  396. package/dist/web-admin-client/apply-effective.js +56 -5
  397. package/dist/web-admin-client/facade.d.ts +1 -1
  398. package/dist/web-admin-client/facade.js +1 -1
  399. package/dist/web-admin-client/read-face.js +5 -9
  400. package/dist/web-admin-client/skills-mcp.js +4 -5
  401. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  402. package/package.json +7 -3
package/dist/config.js CHANGED
@@ -3,27 +3,29 @@ import { DEFAULT_AT_MENTION, DEFAULT_MODEL_REF, mintCapabilityKeys } from "./mod
3
3
  import { homedir } from "node:os";
4
4
  import { join, posix as posixPath } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { compileAllowList, inheritEnvPolicyProblem, BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, CROSS_SESSION_INBOUND_SETTINGS, CROSS_SESSION_DIALOG_EXPIRY_VALUES, compileReadDeny, resolveReadDenyBuiltins, CODE_AGENT_PROMPT, isModelPriced, PROTOCOL_TABLE, RECOMMENDED_SENSITIVE_PATTERNS, judgeRuleToolName, resolveFileHistoryRetention, resolveLockedKeys, validatePermissionRules, WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable } from "@sema-agent/core";
7
- import { ROSTER_PRIMARY_ROLES, ROSTER_CHEAP_ROLES, WEB_ADMIN_ENV, retiredEnvRefusal } from "@sema-agent/settings-schema";
6
+ import { compileAllowList, inheritEnvPolicyProblem, BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, CROSS_SESSION_INBOUND_SETTINGS, CROSS_SESSION_DIALOG_EXPIRY_VALUES, compileReadDeny, resolveReadDenyBuiltins, CODE_AGENT_PROMPT, isModelPriced, PROTOCOL_TABLE, RECOMMENDED_SENSITIVE_PATTERNS, judgeRuleToolName, resolveFileHistoryRetention, resolveLockedKeys, validatePermissionRules, WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, principalInboxConsumerOf } from "@sema-agent/core";
7
+ import { ROSTER_PRIMARY_ROLES, ROSTER_CHEAP_ROLES, WEB_ADMIN_ENV, retiredEnvRefusal, stripControlAndBidi } from "@sema-agent/settings-schema";
8
8
  import { parseApprovalHmacKeys, parsePrincipalJwks } from "./auth-keys.js";
9
9
  import { DEFAULT_ELICITATION_THROTTLE } from "./elicitation.js";
10
- import { isV2ScopeKey, memoryReplicationCoverage, replicationCovers } from "./memory-scope.js";
10
+ import { isV2ScopeKey, memoryReplicationCoverage, replicatesProjectLayersOf } from "./memory-scope.js";
11
+ import { assertProjectLayerOwnable } from "./project-identity.js";
12
+ import { projectLayerOwnerOf } from "./project-layer-key.js";
11
13
  import { DEFAULT_QUESTION_THROTTLE } from "./question.js";
12
14
  import { GIT_API_KINDS, isGitApiKind } from "./git-api-kind.js";
13
- import { CONFIG_PROVIDER_WORDS, RETENTION_MODES, MEMORY_CONSOLIDATION_MIN_INTERVAL_SEC, RESILIENCE_DEFAULTS, TASK_WRITE_FACE_ESCALATIONS, MAX_TIMER_DELAY_MS, AUTO_MODE_CLASSIFIER_TIMEOUT_BOUNDS, DRAIN_GRACE_FLOOR_MS, DRAIN_SECOND_SIGNAL_MIN_GAP_BOUNDS, DRAIN_SECOND_SIGNAL_MIN_GAP_DEFAULT_MS, FIRST_BYTE_TIMEOUT_BOUNDS, FLEET_LEASE_OUTAGE_MAX_DEFAULT_MS, fleetScopeOf } from "./config-types.js";
15
+ import { CONFIG_PROVIDER_WORDS, RETENTION_MODES, MEMORY_CONSOLIDATION_MIN_INTERVAL_SEC, RESILIENCE_DEFAULTS, TASK_WRITE_FACE_ESCALATIONS, MAX_TIMER_DELAY_MS, AUTO_MODE_CLASSIFIER_TIMEOUT_BOUNDS, DRAIN_GRACE_FLOOR_MS, DRAIN_SECOND_SIGNAL_MIN_GAP_BOUNDS, DRAIN_SECOND_SIGNAL_MIN_GAP_DEFAULT_MS, FIRST_BYTE_TIMEOUT_BOUNDS, FLEET_LEASE_OUTAGE_MAX_DEFAULT_MS, fleetScopeOf, DEVICE_DELIVERY_TIMEOUT_BOUNDS, DEVICE_EXEC_TIMEOUT_BOUNDS, inWholeNumberBounds, wholeNumberBoundsRule } from "./config-types.js";
16
+ import { DEVICE_HELLO_ACK_BOUNDS } from "./device-ws-protocol.js";
14
17
  import { FLEET_GENERATION_ENV, FLEET_SCOPE_ENV, SERVING_LEASE_TTL_FLOOR_MS, isCanonicalGeneration } from "@sema-agent/settings-schema/fleet";
15
18
  import { ScopeId } from "@sema-agent/settings-schema/api/scopes";
16
19
  import { centerLaneConfigured, pathBaseUrlRefusal } from "./web-admin-client/center-request.js";
17
20
  import { resolveLocalDataRoot } from "./local-data-root.js";
18
21
  import { buildWriteProtectionPosture } from "./write-protection.js";
19
22
  import { normalizeSshFingerprint } from "./ssh-host-key.js";
20
- import { buildReadFacePostureNotice, readFaceForPosture } from "./read-face-posture.js";
23
+ import { buildReadFacePostureNotice, settleDerivedReadFace } from "./read-face-posture.js";
21
24
  import { THINKING_LEVELS, THINKING_FORMATS, buildModelCompat, isThinkingFormat, isThinkingTier } from "./model-compat.js";
22
25
  import {} from "./posture-source.js";
23
26
  import { COST_QUOTA_WINDOW_SEC_RANGE, costQuotaWindowSecInRange } from "./observability/cost-quota.js";
24
- import { CONTROL_AND_BIDI_STRIP_RE } from "./text-bidi.js";
25
27
  import { TOOL_NAME_ROSTER, describeUnmatchableRuleName, ruleEntryToolName, unmatchableRuleNameOf } from "./namespaced-rule-name.js";
26
- import { bakeOperatorPrincipalsRefusal, bakeRunnerCredentialRefusal, centerIdentityRefusal, halfOpenDirectDoorRefusal, leaderDurableStoreRefusal, operatorPrincipalsRequiredRefusal } from "./config-invariants.js";
28
+ import { bakeOperatorPrincipalsRefusal, bakeRunnerCredentialRefusal, centerIdentityRefusal, halfOpenDirectDoorRefusal, leaderDurableStoreRefusal, operatorPrincipalsRequiredRefusal, operatorSingleUserRefusal, workflowParkDecisionDomainRefusal } from "./config-invariants.js";
27
29
  import { declaredSemaConfigDir } from "./sema-config-dir.js";
28
30
  import { lkgPathOverrideOf } from "./config-lkg.js";
29
31
  import { K8S_WORKSPACE_MOUNT_DEFAULT, WORKSPACE_PERSIST_DEFAULT, WORKSPACE_PERSIST_WORDS, WORKSPACE_SNAPSHOT_KEEP_DEFAULT, WORKSPACE_SNAPSHOT_KEEP_RANGE, WORKSPACE_SNAPSHOT_TIMEOUT_MS_DEFAULT, WORKSPACE_SNAPSHOT_TIMEOUT_MS_RANGE, parseWorkspaceSnapshotExclude } from "./workspace-space.js";
@@ -34,17 +36,22 @@ import { REMOTE_EXEC_PROVIDER_WORDS, executionLaneOf, executionLaneRequiredRefus
34
36
  import { MEMORY_ENGINE_BACKENDS, SESSION_BACKENDS, STORE_BACKENDS } from "@sema-agent/settings-schema/execution-lanes";
35
37
  import { AUTONOMY_MODES } from "./runtime-governance.js";
36
38
  import { MAX_NAMED_INERT_ENTRIES, allowLayerEntryCountIssue, describeInertRuleEntries, inertRuleEntriesOf, inertRuleEntryGuidance, ruleEntryListShapeOk } from "./rule-entry-list.js";
39
+ import { readReadDenyEntry } from "./read-deny-entry.js";
37
40
  import { createCenterCredentialSource, readCenterCredentialDeclaration } from "./center-credential.js";
38
41
  import { parseCenterCredentialRenewLeadMs } from "./center-credential-renewer.js";
39
42
  import { modelProviderRefusal } from "./model-provider.js";
40
43
  import { modelRouteUrlRefusal } from "./model-route-url.js";
41
44
  import { httpUrlFlaws } from "@sema-agent/settings-schema";
42
45
  import { buildHttpUrlRefusal } from "./url-refusal.js";
46
+ import { customPkgSourceFromEnv } from "./sandbox-pkg-source.js";
43
47
  import { csvOf, envLaneTable, mintedCheapId, readModelRouteEnv } from "./model-route-gap.js";
44
48
  import { displayListEntry } from "./list-entry-display.js";
49
+ import { echoCallerText } from "./caller-text-echo.js";
45
50
  import { buildDisplaySafeUrl, redactSecrets } from "./trace/redact.js";
51
+ import { parseConfigLocalOwnerUid } from "./config-dir-trust.js";
46
52
  import { allowlistedEnv } from "./server-secret-env.js";
47
53
  import { ENV_NAME_ALLOWLIST_KNOBS, ENV_NAME_ALLOWLIST_KNOB_NAMES, describeAllowlistPostures } from "./env-name-allowlist-knobs.js";
54
+ import { APPROVAL_ASK_RETENTION_DEFAULT_MS, APPROVAL_ASK_RETENTION_FLOOR_MS } from "./approval-ask-retention.js";
48
55
  export { RETENTION_MODES, MEMORY_CONSOLIDATION_MIN_INTERVAL_SEC } from "./config-types.js";
49
56
  function csv(name) {
50
57
  return csvOf(process.env[name]);
@@ -183,13 +190,14 @@ function buildExecLaneNotice(remoteExec) {
183
190
  source: lane === "in-process" ? "default-unset" : isSingleMachineDefaultLane(remoteExec) ? "default-local-provider" : "explicit-env",
184
191
  };
185
192
  }
193
+ const ENV_VALUE_ECHO_CHARS = 120;
186
194
  function parseConfigProvider() {
187
195
  const raw = process.env.CONFIG_PROVIDER;
188
196
  if (raw === undefined || raw === "")
189
197
  return undefined;
190
198
  const word = CONFIG_PROVIDER_WORDS.find((w) => w === raw);
191
199
  if (word === undefined) {
192
- throw new Error(`env CONFIG_PROVIDER="${raw.slice(0, 120)}" must be one of: ${CONFIG_PROVIDER_WORDS.join(", ")} — or leave it unset (then ${WEB_ADMIN_ENV.url}, if set, selects the center as the config source; otherwise this worker is env-only). ` +
200
+ throw new Error(`env CONFIG_PROVIDER="${echoCallerText(raw, { maxChars: ENV_VALUE_ECHO_CHARS })}" must be one of: ${CONFIG_PROVIDER_WORDS.join(", ")} — or leave it unset (then ${WEB_ADMIN_ENV.url}, if set, selects the center as the config source; otherwise this worker is env-only). ` +
193
201
  `The word is matched exactly (no trimming, no case folding). Refusing to boot rather than guessing: the config source, the execution-lane default and the local config root all key on this one word.`);
194
202
  }
195
203
  return word;
@@ -338,6 +346,17 @@ function livenessMsEnv(name) {
338
346
  const n = optNumEnvStrict(name);
339
347
  return n === undefined ? undefined : laneLivenessOf(n, name).ms;
340
348
  }
349
+ function parseDeviceBoundedIntEnv(name, raw, bounds) {
350
+ if (raw === undefined || raw === "")
351
+ return undefined;
352
+ const n = /^(0|[1-9]\d*)$/.test(raw) ? Number(raw) : Number.NaN;
353
+ if (!inWholeNumberBounds(bounds, n)) {
354
+ const shown = raw.length > 40 ? `${raw.slice(0, 40)}…(${raw.length} chars)` : raw;
355
+ throw new Error(`env ${name}=${JSON.stringify(shown)} must be ${wholeNumberBoundsRule(bounds)} (canonical decimal digits only — no sign, leading zero, fraction, exponent, hex, whitespace or unit; unset = the device lane's own default). ` +
356
+ `Refusing to boot rather than sending an out-of-range value to every executor, or running the default while the operator believes their value is in force.`);
357
+ }
358
+ return n;
359
+ }
341
360
  function parseDeviceEnrollTokenTtlEnv() {
342
361
  const raw = process.env.DEVICE_ENROLL_TOKEN_TTL_SEC;
343
362
  if (raw === undefined || raw === "")
@@ -440,15 +459,10 @@ function parseReadDenyPatternsEnv(raw) {
440
459
  if (!Array.isArray(arr))
441
460
  throw new Error('READ_DENY_PATTERNS must be a JSON array of "pattern" strings or {pattern, caseSensitive?} objects');
442
461
  const entries = arr.map((it, i) => {
443
- if (typeof it === "string")
444
- return { pattern: it, caseSensitive: false };
445
- if (typeof it !== "object" || it === null || typeof it.pattern !== "string") {
446
- throw new Error(`READ_DENY_PATTERNS[${i}] must be a string or an object with a string 'pattern'`);
447
- }
448
- const cs = it.caseSensitive;
449
- if (cs !== undefined && typeof cs !== "boolean")
450
- throw new Error(`READ_DENY_PATTERNS[${i}].caseSensitive must be boolean when present`);
451
- return { pattern: it.pattern, caseSensitive: cs === true };
462
+ const read = readReadDenyEntry(it);
463
+ if (!read.ok)
464
+ throw new Error(`READ_DENY_PATTERNS[${i}]${read.after}`);
465
+ return read.entry;
452
466
  });
453
467
  compileReadDeny(entries);
454
468
  return entries;
@@ -645,11 +659,22 @@ function optionalEnumKey(key, envName, raw, allowed) {
645
659
  if (raw === undefined || raw === "")
646
660
  return {};
647
661
  if (!allowed.includes(raw)) {
648
- throw new Error(`env ${envName}="${raw.slice(0, 120)}" must be one of: ${allowed.join(", ")} — or leave it UNSET to say nothing on this layer. ` +
662
+ throw new Error(`env ${envName}="${echoCallerText(raw, { maxChars: ENV_VALUE_ECHO_CHARS })}" must be one of: ${allowed.join(", ")} — or leave it UNSET to say nothing on this layer. ` +
649
663
  `Refusing to boot rather than reading a misspelled value as "unset": that runs the deployment with NO policy on this axis while the operator believes one is configured`);
650
664
  }
651
665
  return { [key]: raw };
652
666
  }
667
+ function principalInboxAssistantKey(raw) {
668
+ if (raw === undefined || raw === "")
669
+ return {};
670
+ try {
671
+ principalInboxConsumerOf({ principalInboxConsumer: { assistant: raw } });
672
+ }
673
+ catch (err) {
674
+ throw new Error(`env PRINCIPAL_INBOX_ASSISTANT must name the agent handle that consumes the principal inbox (or stay UNSET for no cross-principal delivery): ${err instanceof Error ? err.message : String(err)}`);
675
+ }
676
+ return { principalInboxAssistant: raw };
677
+ }
653
678
  function parseAutoModeClassifierTimeoutMs(raw) {
654
679
  if (raw === undefined || raw === "")
655
680
  return {};
@@ -1034,7 +1059,7 @@ function parseModelDomain() {
1034
1059
  noticeAutoCompactAboveWindow("cheap", "MODEL_CHEAP_AUTO_COMPACT_TOKENS", cheapModel);
1035
1060
  }
1036
1061
  const models = envLaneTable(modelId, model, cheapModel);
1037
- const gatewayApiKey = process.env.MODEL_API_KEY;
1062
+ const gatewayApiKey = route.gatewayApiKey;
1038
1063
  if (gatewayBaseUrl === undefined && gatewayApiKey !== undefined && gatewayApiKey !== "") {
1039
1064
  CONFIG_NOTICES.push({
1040
1065
  level: "warn",
@@ -1167,7 +1192,7 @@ function uncompilableRuleGuidance(name, behavior, pathBases) {
1167
1192
  const issue = issues[0];
1168
1193
  if (issue === undefined)
1169
1194
  return undefined;
1170
- return `${issue.code} — core's rule grammar cannot compile this entry: ${issue.message}`;
1195
+ return { code: issue.code, guidance: `${issue.code} — core's rule grammar cannot compile this entry: ${issue.message}` };
1171
1196
  }
1172
1197
  function findUnmatchableToolNames(names, opts) {
1173
1198
  const out = [];
@@ -1175,42 +1200,46 @@ function findUnmatchableToolNames(names, opts) {
1175
1200
  if (opts.consumer === "tool-name-table") {
1176
1201
  const ccGuidance = ccRuleFormGuidance(name);
1177
1202
  if (ccGuidance !== undefined) {
1178
- out.push({ name, guidance: ccGuidance });
1203
+ out.push({ name, guidance: ccGuidance, reason: "cc_rule_form" });
1179
1204
  continue;
1180
1205
  }
1181
1206
  }
1182
1207
  const subject = opts.consumer === "tool-name-table" ? name : ruleEntryToolName(name);
1183
1208
  const verdict = unmatchableRuleNameOf(subject);
1184
1209
  if (verdict?.kind === "retired") {
1185
- out.push({ name, guidance: describeUnmatchableRuleName(verdict, subject) });
1210
+ out.push({ name, guidance: describeUnmatchableRuleName(verdict, subject), reason: verdict.kind });
1186
1211
  continue;
1187
1212
  }
1188
1213
  const uncompilable = uncompilableRuleGuidance(name, opts.behavior, opts.pathBases);
1189
1214
  if (uncompilable !== undefined) {
1190
- out.push({ name, guidance: uncompilable });
1215
+ out.push({ name, guidance: uncompilable.guidance, reason: uncompilable.code });
1191
1216
  continue;
1192
1217
  }
1193
1218
  if (verdict !== undefined) {
1194
- out.push({ name, guidance: describeUnmatchableRuleName(verdict, subject) });
1219
+ out.push({ name, guidance: describeUnmatchableRuleName(verdict, subject), reason: verdict.kind });
1195
1220
  continue;
1196
1221
  }
1197
1222
  const nearMiss = compileAllowList([subject], "deny", TOOL_NAME_ROSTER).inert.find((i) => i.reason === "near_miss");
1198
1223
  if (nearMiss?.currentName !== undefined) {
1199
1224
  const rest = name.startsWith(subject) ? name.slice(subject.length) : "";
1200
- out.push({ name, guidance: inertRuleEntryGuidance({ ...nearMiss, currentName: `${nearMiss.currentName}${rest}` }) });
1225
+ out.push({ name, guidance: inertRuleEntryGuidance({ ...nearMiss, currentName: `${nearMiss.currentName}${rest}` }), reason: nearMiss.reason });
1201
1226
  }
1202
1227
  }
1203
1228
  return out;
1204
1229
  }
1205
1230
  export function unmatchableToolNamesRefusal(source, names, judgment) {
1231
+ const judged = judgeUnmatchableToolNames(source, names, judgment);
1232
+ return judged === undefined ? undefined : { message: judged.message, names: judged.bad.map((b) => b.name) };
1233
+ }
1234
+ export function judgeUnmatchableToolNames(source, names, judgment) {
1206
1235
  const bad = findUnmatchableToolNames(names, judgment);
1207
1236
  if (bad.length === 0)
1208
1237
  return undefined;
1209
1238
  const named = bad.slice(0, MAX_NAMED_INERT_ENTRIES).map((b) => `${displayListEntry(b.name)} → ${b.guidance}`).join("; ");
1210
- const message = (`${source} has ${bad.length === 1 ? "an entry" : "entries"} that can never take effect — ${bad.length === 1 ? "it" : "each"} would never match a live tool or cannot be compiled into a rule ` +
1239
+ const message = stripControlAndBidi(`${source} has ${bad.length === 1 ? "an entry" : "entries"} that can never take effect — ${bad.length === 1 ? "it" : "each"} would never match a live tool or cannot be compiled into a rule ` +
1211
1240
  `(names are read exactly as written: no alias folding, no protocol prefix added): ` +
1212
- (bad.length > MAX_NAMED_INERT_ENTRIES ? `${named}; and ${bad.length - MAX_NAMED_INERT_ENTRIES} more` : named)).replace(CONTROL_AND_BIDI_STRIP_RE, "");
1213
- return { message, names: bad.map((b) => b.name) };
1241
+ (bad.length > MAX_NAMED_INERT_ENTRIES ? `${named}; and ${bad.length - MAX_NAMED_INERT_ENTRIES} more` : named));
1242
+ return { message, bad };
1214
1243
  }
1215
1244
  const APPROVAL_GRANT_ENV = "APPROVAL_GRANT";
1216
1245
  export function approvalGrantRefusal(names) {
@@ -1265,7 +1294,7 @@ function unattendedApprovalPolicyEnv() {
1265
1294
  return "park";
1266
1295
  if (raw === "park" || raw === "deny")
1267
1296
  return raw;
1268
- throw new Error(`env UNATTENDED_APPROVAL_POLICY="${raw.slice(0, 120)}" is not a recognized value — use "park" (default: an ask nobody can answer becomes a durable park, the run suspends and waits for a human) ` +
1297
+ throw new Error(`env UNATTENDED_APPROVAL_POLICY="${echoCallerText(raw, { maxChars: ENV_VALUE_ECHO_CHARS })}" is not a recognized value — use "park" (default: an ask nobody can answer becomes a durable park, the run suspends and waits for a human) ` +
1269
1298
  `or "deny" (an unattended/headless deployment declaring that NOBODY will ever answer: such asks are denied on the spot instead of piling up parked runs). ` +
1270
1299
  `The words are matched EXACTLY (lowercase, surrounding whitespace trimmed) and there is no "off" — both values are real postures, and unset simply means the documented default "park". ` +
1271
1300
  `Refusing to boot rather than treating a misspelled value as "unset": that runs the deployment on a policy the operator did not choose, with no trace anywhere`);
@@ -1347,7 +1376,7 @@ function parseApprovalDomain(ctx) {
1347
1376
  `Use "always" to keep EVERY shell call behind an approval under every mode (bypassPermissions included), or unset it / "off" to rely on the engine's mode arbitration. ` +
1348
1377
  `Refusing to boot rather than accepting it as a no-op: that would silently drop the half the operator configured it for`);
1349
1378
  }
1350
- throw new Error(`env MANUAL_MODE_SHELL_GATE="${trimmed.slice(0, 120)}" is not a recognized value — use "always" (every shell call is gated) or "off"/unset (this knob contributes nothing). ` +
1379
+ throw new Error(`env MANUAL_MODE_SHELL_GATE="${echoCallerText(trimmed, { maxChars: ENV_VALUE_ECHO_CHARS })}" is not a recognized value — use "always" (every shell call is gated) or "off"/unset (this knob contributes nothing). ` +
1351
1380
  `The words are matched EXACTLY (lowercase, surrounding whitespace trimmed): "OFF"/"Always" land here too, deliberately — a closed word table with no case-folding is what keeps "it looked accepted" from meaning "it did nothing". ` +
1352
1381
  `Refusing to boot rather than treating a misspelled value as "unset": that silently ran the deployment with NO shell gate while the operator believed one was configured`);
1353
1382
  })(process.env.MANUAL_MODE_SHELL_GATE),
@@ -1356,6 +1385,7 @@ function parseApprovalDomain(ctx) {
1356
1385
  ...parseAutoModeClassifierTimeoutMs(process.env.AUTO_MODE_CLASSIFIER_TIMEOUT_MS),
1357
1386
  ...optionalEnumKey("crossSessionInbound", "CROSS_SESSION_INBOUND", process.env.CROSS_SESSION_INBOUND, CROSS_SESSION_INBOUND_SETTINGS),
1358
1387
  ...optionalEnumKey("crossSessionDialogExpiry", "CROSS_SESSION_DIALOG_EXPIRY", process.env.CROSS_SESSION_DIALOG_EXPIRY, CROSS_SESSION_DIALOG_EXPIRY_VALUES),
1388
+ ...principalInboxAssistantKey(process.env.PRINCIPAL_INBOX_ASSISTANT),
1359
1389
  mcpElicitation: {
1360
1390
  enabled: boolEnv("MCP_ELICITATION_ENABLED", false),
1361
1391
  throttle: {
@@ -1380,8 +1410,20 @@ function parseApprovalDomain(ctx) {
1380
1410
  durableApprovalSource: postureSourceOfKnob("DURABLE_APPROVAL"),
1381
1411
  unattendedApprovalPolicy: unattendedPolicy,
1382
1412
  approvalTimeoutSec: numEnv("APPROVAL_TIMEOUT_SEC", "0"),
1413
+ approvalAskRetentionMs: approvalAskRetentionEnv(),
1383
1414
  };
1384
1415
  }
1416
+ function approvalAskRetentionEnv() {
1417
+ const n = numEnv("APPROVAL_ASK_RETENTION_MS", String(APPROVAL_ASK_RETENTION_DEFAULT_MS));
1418
+ const raw = env("APPROVAL_ASK_RETENTION_MS", "");
1419
+ if (n < 0 || !Number.isSafeInteger(n)) {
1420
+ throw new Error(`env APPROVAL_ASK_RETENTION_MS="${raw}" must be 0 (keep the approval ledgers forever) or a whole number of milliseconds (the retention window)`);
1421
+ }
1422
+ if (n === 0 || n >= APPROVAL_ASK_RETENTION_FLOOR_MS)
1423
+ return n;
1424
+ CONFIG_WARNINGS.push({ env: "APPROVAL_ASK_RETENTION_MS", raw, used: String(APPROVAL_ASK_RETENTION_FLOOR_MS), kind: "clamped" });
1425
+ return APPROVAL_ASK_RETENTION_FLOOR_MS;
1426
+ }
1385
1427
  const MEMORY_ENGINE_ON_WORDS = ["on", "true", "1", "yes", "enabled"];
1386
1428
  const MEMORY_ENGINE_OFF_WORDS = ["off", "false", "0", "no", "disabled"];
1387
1429
  function parseMemoryEngineWord(word) {
@@ -1431,6 +1473,13 @@ function pkgSourceEnv() {
1431
1473
  }
1432
1474
  return v;
1433
1475
  }
1476
+ function pkgSourceFields() {
1477
+ if (process.env.SANDBOX_PKG_SOURCE === "none")
1478
+ return {};
1479
+ const sandboxPkgSource = pkgSourceEnv();
1480
+ const custom = sandboxPkgSource === "custom" ? customPkgSourceFromEnv() : {};
1481
+ return { sandboxPkgSource, ...(Object.keys(custom).length > 0 ? { sandboxPkgSourceCustom: custom } : {}) };
1482
+ }
1434
1483
  function syncEntryCap(name, field) {
1435
1484
  const raw = process.env[name];
1436
1485
  if (raw === undefined || raw === "")
@@ -1593,6 +1642,8 @@ function parseMemoryDomain(ctx) {
1593
1642
  const memoryEngineEnabled = parseMemoryEngineWord(env("MEMORY_ENGINE", "on"));
1594
1643
  const memoryEngineBackend = enumEnv("MEMORY_ENGINE_BACKEND", "file", MEMORY_ENGINE_BACKENDS);
1595
1644
  const memoryScope = process.env.MEMORY_SCOPE ?? (memoryEngineEnabled && !requirePrincipal ? "local" : undefined);
1645
+ if (memoryScope !== undefined && memoryEngineEnabled && !requirePrincipal)
1646
+ assertProjectLayerOwnable(memoryScope, "MEMORY_SCOPE");
1596
1647
  const memorySyncUrl = process.env.MEMORY_SYNC_URL || undefined;
1597
1648
  const memorySyncToken = process.env.MEMORY_SYNC_TOKEN || undefined;
1598
1649
  const memorySyncScopeRaw = process.env.MEMORY_SYNC_SCOPE || undefined;
@@ -1618,6 +1669,7 @@ function parseMemoryDomain(ctx) {
1618
1669
  if (scope === undefined) {
1619
1670
  throw new Error("MEMORY_SYNC_URL is set but no sync scope is derivable (memory engine off or multi-tenant without an explicit scope) — set MEMORY_SYNC_SCOPE, or run the single-user file memory engine with a typed MEMORY_SCOPE (e.g. user:<tenant>) so it provides one");
1620
1671
  }
1672
+ assertProjectLayerOwnable(scope, memorySyncScopeRaw !== undefined ? "MEMORY_SYNC_SCOPE" : "MEMORY_SCOPE");
1621
1673
  memorySync = {
1622
1674
  url: memorySyncUrl,
1623
1675
  token: memorySyncToken,
@@ -1627,23 +1679,17 @@ function parseMemoryDomain(ctx) {
1627
1679
  };
1628
1680
  }
1629
1681
  const replication = memoryReplicationCoverage(memorySync !== undefined ? { memorySync } : {});
1630
- if (replication.kind === "scopes" && memoryEngineEnabled && !requirePrincipal && memoryScope !== undefined) {
1631
- const YIELD_HINT = {
1632
- in: "memory sync (MEMORY_SYNC_*) replicates only the scope(s) listed in replicatedScopes — the per-project memory layer (S-512, repo:<key>) is not replicated, " +
1633
- "so sessions do NOT write project-keyed memory here: new memory lands in the global layer (writeScope = MEMORY_SCOPE), which IS replicated, and every " +
1634
- "project reads it. Project-layer replication is a separate change; unset MEMORY_SYNC_URL to get per-project memory without sync.",
1635
- out: "memory sync (MEMORY_SYNC_*) replicates only the scope(s) listed in replicatedScopes — the per-project memory layer (S-512, repo:<key>) is not replicated, " +
1636
- "so sessions do NOT write project-keyed memory here: new memory lands in the global layer (writeScope = MEMORY_SCOPE), every project reads it, " +
1637
- "and that write scope is not among the replicated scopes either — NONE of the memory this deployment writes is synced. " +
1638
- "Point MEMORY_SYNC_SCOPE at the write scope (sync replicates one scope), or unset MEMORY_SYNC_URL to stop expecting sync.",
1639
- };
1682
+ if (replication.kind === "layers" && memoryEngineEnabled && !requirePrincipal && memoryScope !== undefined && !replicatesProjectLayersOf(replication, projectLayerOwnerOf(memoryScope))) {
1640
1683
  CONFIG_NOTICES.push({
1641
1684
  level: "warn",
1642
1685
  event: "memory_project_scope_yields_to_sync",
1643
1686
  fields: {
1644
- replicatedScopes: replication.scopes.join(","),
1687
+ replicatedScopes: replication.layers.join(","),
1645
1688
  writeScope: memoryScope,
1646
- hint: YIELD_HINT[replicationCovers(replication, memoryScope) ? "in" : "out"],
1689
+ hint: "memory sync (MEMORY_SYNC_*) replicates the scope(s) listed in replicatedScopes and the per-project memory layers of the same owner; " +
1690
+ "this deployment's project layers belong to MEMORY_SCOPE, which has a different owner, so sessions do NOT write project-keyed memory here: " +
1691
+ "new memory lands in the global layer (writeScope = MEMORY_SCOPE), every project reads it, and NONE of the memory this deployment writes is synced. " +
1692
+ "Set MEMORY_SCOPE to the replicated user key (the same value as MEMORY_SYNC_SCOPE) to sync the global and per-project layers, or unset MEMORY_SYNC_URL to stop expecting sync.",
1647
1693
  },
1648
1694
  });
1649
1695
  }
@@ -1776,6 +1822,7 @@ function parseAuthDomain(ctx) {
1776
1822
  autonomy: parseAutonomy(process.env.AUTONOMY),
1777
1823
  ...parseGovernanceDeclarations(),
1778
1824
  operatorPrincipals: csv("OPERATOR_PRINCIPALS"),
1825
+ operatorSingleUser: boolEnv("OPERATOR_SINGLE_USER", false),
1779
1826
  configCatalogEnabled: boolEnv("CONFIG_CATALOG_ENABLED", true),
1780
1827
  principalJwtPubkeys,
1781
1828
  principalJwtIss,
@@ -1820,10 +1867,7 @@ function parseOrchestrationDomain(ctx) {
1820
1867
  }
1821
1868
  const readFaceFacts = process.env.READ_FACE !== undefined
1822
1869
  ? { readFace: enumEnv("READ_FACE", "roots", ["open", "roots"]), readFaceSource: "env" }
1823
- : readFaceForPosture(singleUserTurnkey);
1824
- const readFaceNotice = buildReadFacePostureNotice(readFaceFacts);
1825
- if (readFaceNotice !== undefined)
1826
- CONFIG_NOTICES.push({ level: "info", ...readFaceNotice });
1870
+ : { readFaceSource: "engine-default" };
1827
1871
  return {
1828
1872
  requireExecutionLane: boolEnv("REQUIRE_EXECUTION_LANE", false),
1829
1873
  ...readFaceFacts,
@@ -1931,10 +1975,10 @@ function parseOrchestrationDomain(ctx) {
1931
1975
  process.env.REMOTE_EXEC === "device"
1932
1976
  ? {
1933
1977
  provider: "device",
1934
- ...((n) => (n !== undefined ? { deliveryTimeoutMs: n } : {}))(optNumEnvStrict("DEVICE_DELIVERY_TIMEOUT_MS")),
1935
- ...((n) => (n !== undefined ? { reconnectGraceMs: n } : {}))(optNumEnvStrict("DEVICE_RECONNECT_GRACE_MS")),
1936
- ...((n) => (n !== undefined ? { execTimeoutMs: n } : {}))(optNumEnvStrict("DEVICE_EXEC_TIMEOUT_MS")),
1937
- ...((n) => (n !== undefined ? { maxInflightPerDevice: n } : {}))(optNumEnvStrict("DEVICE_MAX_INFLIGHT_PER_DEVICE")),
1978
+ ...((n) => (n !== undefined ? { deliveryTimeoutMs: n } : {}))(parseDeviceBoundedIntEnv("DEVICE_DELIVERY_TIMEOUT_MS", process.env.DEVICE_DELIVERY_TIMEOUT_MS, DEVICE_DELIVERY_TIMEOUT_BOUNDS)),
1979
+ ...((n) => (n !== undefined ? { reconnectGraceMs: n } : {}))(parseDeviceBoundedIntEnv("DEVICE_RECONNECT_GRACE_MS", process.env.DEVICE_RECONNECT_GRACE_MS, DEVICE_HELLO_ACK_BOUNDS.reconnectGraceMs)),
1980
+ ...((n) => (n !== undefined ? { execTimeoutMs: n } : {}))(parseDeviceBoundedIntEnv("DEVICE_EXEC_TIMEOUT_MS", process.env.DEVICE_EXEC_TIMEOUT_MS, DEVICE_EXEC_TIMEOUT_BOUNDS)),
1981
+ ...((n) => (n !== undefined ? { maxInflightPerDevice: n } : {}))(parseDeviceBoundedIntEnv("DEVICE_MAX_INFLIGHT_PER_DEVICE", process.env.DEVICE_MAX_INFLIGHT_PER_DEVICE, DEVICE_HELLO_ACK_BOUNDS.maxInflight)),
1938
1982
  ...((n) => (n !== undefined ? { maxPreAuthPerRemote: n } : {}))(parseDevicePreAuthPerRemoteEnv()),
1939
1983
  ...((n) => (n !== undefined ? { enrollTokenTtlSec: n } : {}))(parseDeviceEnrollTokenTtlEnv()),
1940
1984
  ...(process.env.DEVICE_SUPERSEDE ? { supersede: enumEnv("DEVICE_SUPERSEDE", "stale_only", ["stale_only", "deny"]) } : {}),
@@ -1986,9 +2030,7 @@ function parseOrchestrationDomain(ctx) {
1986
2030
  }
1987
2031
  return n;
1988
2032
  })(numEnv("SCRATCHPAD_SWEEP_TTL_MS", String(7 * 24 * 60 * 60 * 1000)), env("SCRATCHPAD_SWEEP_TTL_MS", String(7 * 24 * 60 * 60 * 1000))),
1989
- ...(process.env.SANDBOX_PKG_SOURCE !== "none"
1990
- ? { sandboxPkgSource: pkgSourceEnv() }
1991
- : {}),
2033
+ ...pkgSourceFields(),
1992
2034
  sessionAutoTitle: boolEnv("SESSION_AUTO_TITLE", true),
1993
2035
  sessionAutoTitleSource: postureSourceOfKnob("SESSION_AUTO_TITLE"),
1994
2036
  selectEnvironmentTool: boolEnv("SELECT_ENVIRONMENT_TOOL", true),
@@ -2125,6 +2167,7 @@ function parseGitApiKind(raw, baseUrl) {
2125
2167
  }
2126
2168
  function parseIntegrationsDomain(ctx) {
2127
2169
  const { requirePrincipal, configProvider } = ctx;
2170
+ const configLocalOwnerUid = parseConfigLocalOwnerUid(process.env.CONFIG_LOCAL_OWNER_UID);
2128
2171
  const baseUrl = parseCenterBaseUrl(WEB_ADMIN_ENV.url, process.env[WEB_ADMIN_ENV.url], `It is the center base every config pull, fleet and lease request is sent to; setting it selects the center as the config source.`);
2129
2172
  const liveBaseUrl = parseCenterBaseUrl(WEB_ADMIN_ENV.liveUrl, process.env[WEB_ADMIN_ENV.liveUrl], `It is the center base the fleet liveness endpoints (heartbeat, serving lease) are sent to; unset it to send them to ${WEB_ADMIN_ENV.url}.`);
2130
2173
  const webBaseUrl = parseCenterBaseUrl(WEB_ADMIN_ENV.webUrl, process.env[WEB_ADMIN_ENV.webUrl], `It is the center's web console base this engine reports on GET /health (center.webBaseUrl); unset it if the center has no web console to link to.`);
@@ -2149,6 +2192,7 @@ function parseIntegrationsDomain(ctx) {
2149
2192
  fleetLeaseOutageMaxMs: parseFleetLeaseOutageMaxMs(process.env.FLEET_LEASE_OUTAGE_MAX_MS),
2150
2193
  ...(configProvider !== undefined ? { configProvider } : {}),
2151
2194
  configLocalDir: process.env.CONFIG_LOCAL_DIR || undefined,
2195
+ ...(configLocalOwnerUid !== undefined ? { configLocalOwnerUid } : {}),
2152
2196
  a2aServe: parseA2aServe(),
2153
2197
  };
2154
2198
  }
@@ -2334,10 +2378,10 @@ const MODEL_PLANE_GROUP_KEYS = [
2334
2378
  "modelApiKeyEnv", "modelApiKeys", "modelRefusals", "droppedCatalogEntries", "modelQuotaWeights", "tiers", "projects", "roles", "atMention", "cascadeLadder", "degrade",
2335
2379
  ];
2336
2380
  const APPROVAL_GROUP_KEYS = [
2337
- "approvalRequire", "approvalDeny", "approvalTimeoutSec", "approvalAutoBudget", "approvalNeverAuto", "approvalGrant",
2381
+ "approvalRequire", "approvalDeny", "approvalTimeoutSec", "approvalAskRetentionMs", "approvalAutoBudget", "approvalNeverAuto", "approvalGrant",
2338
2382
  "approvalHmacKeys", "durableApproval", "durableApprovalSource", "streamAskWindowMsSource", "directApprovalDoor", "directDoorActive", "resourceSuspend",
2339
2383
  "resourceSuspendTtlSec", "resourceSuspendTotalTokens", "resourceSuspendTotalBudgetUsd", "resourceSuspendMaxSlices", "askQuestionEnabled", "questionThrottle", "toolApprovalEnabled", "permissionRulesEnabled", "permissionRulesEnabledExplicit", "streamAskWindowMarginMs", "streamApproval", "unattendedApprovalPolicy", "mcpElicitation",
2340
- "sensitiveWritePatterns", "writeProtectedPaths", "manualModeShellGate", "permissionsDisableAutoMode", "autoModeClassifierFallback", "autoModeClassifierTimeoutMs", "crossSessionInbound", "crossSessionDialogExpiry",
2384
+ "sensitiveWritePatterns", "writeProtectedPaths", "manualModeShellGate", "permissionsDisableAutoMode", "autoModeClassifierFallback", "autoModeClassifierTimeoutMs", "crossSessionInbound", "crossSessionDialogExpiry", "principalInboxAssistant",
2341
2385
  ];
2342
2386
  const MEMORY_GROUP_KEYS = [
2343
2387
  "memoryEngineEnabled", "memoryEngineDir", "memoryEngineRemoteLaneAllowed", "memoryEngineBackend", "memoryScope",
@@ -2347,7 +2391,7 @@ const MEMORY_GROUP_KEYS = [
2347
2391
  const AUTH_GROUP_KEYS = [
2348
2392
  "authToken", "authTokens", "allowUnauthedWrites", "corsOrigins", "principalHeader", "requirePrincipal", "autonomy",
2349
2393
  "commandPolicy", "compliancePosture", "lockedConfigKeys", "retentionPolicy", "retentionSweep",
2350
- "operatorPrincipals", "configCatalogEnabled", "principalJwtPubkeys", "principalJwtIss", "principalJwtAud",
2394
+ "operatorPrincipals", "operatorSingleUser", "configCatalogEnabled", "principalJwtPubkeys", "principalJwtIss", "principalJwtAud",
2351
2395
  "principalJwtMaxTtlSec", "authBridgeIssuer", "bindHost", "bindHostSource",
2352
2396
  ];
2353
2397
  const ORCHESTRATION_GROUP_KEYS = [
@@ -2356,7 +2400,7 @@ const ORCHESTRATION_GROUP_KEYS = [
2356
2400
  "schedulerEnabled", "schedulerSessionWakeup", "schedulerSessionLifetime", "schedulerStorePath", "planModeEnabled", "hooksTimeoutMs", "workflowRunStoreBackend",
2357
2401
  "workflowOrphanGraceMs", "workflowJournalRetentionMs", "workflowRunRetentionMs", "usageWindows", "workflowAgentsReadOnly",
2358
2402
  "workflowSizeGuideline", "backgroundAgentRetentionMs", "backgroundAgentStaleRunningMs",
2359
- "backgroundAgentParkClaimStaleMs", "delegationEntryCaps", "rosterRetentionMs", "leaderRunStaleMs", "scratchpadSweepTtlMs", "sandboxPkgSource",
2403
+ "backgroundAgentParkClaimStaleMs", "delegationEntryCaps", "rosterRetentionMs", "leaderRunStaleMs", "scratchpadSweepTtlMs", "sandboxPkgSource", "sandboxPkgSourceCustom",
2360
2404
  "sessionAutoTitle", "sessionAutoTitleSource", "selectEnvironmentTool", "envFactsEnabled", "toolDeferLongtail", "lspEnabled", "lspHostEnabled", "lspEnvAllow",
2361
2405
  "imageBakes", "readFace", "readFaceSource", "taskWriteFaceEscalation", "readDenyPatterns", "readDenyBuiltinTiers", "readDenyBuiltinExclude",
2362
2406
  "agentConfigDir", "configLkgPath", "configLkgEnabled",
@@ -2371,7 +2415,7 @@ const LIMITS_HTTP_GROUP_KEYS = [
2371
2415
  const OBSERVABILITY_GROUP_KEYS = ["metricsToken", "traceToken", "toolTrace", "traceThinking", "logLevel", "otel"];
2372
2416
  const INTEGRATIONS_GROUP_KEYS = [
2373
2417
  "pluginsAllowHosts", "mcpServers", "a2aPeers", "a2aServe", "configBootFetchBudgetMs", "gitApiBaseUrl", "gitApiToken", "gitApiKind", "defaultScenario",
2374
- "skillsDir", "centerCredentialRenewLeadMs", "webAdmin", "fleetLeaseFailClosed", "fleetGeneration", "fleetScope", "fleetAdvertiseAddress", "fleetLeaseOutageMaxMs", "configProvider", "configLocalDir",
2418
+ "skillsDir", "centerCredentialRenewLeadMs", "webAdmin", "fleetLeaseFailClosed", "fleetGeneration", "fleetScope", "fleetAdvertiseAddress", "fleetLeaseOutageMaxMs", "configProvider", "configLocalDir", "configLocalOwnerUid",
2375
2419
  ];
2376
2420
  export const CONFIG_GROUP_KEYS = {
2377
2421
  store: STORE_GROUP_KEYS,
@@ -2498,6 +2542,10 @@ export function loadConfig() {
2498
2542
  const memory = parseMemoryDomain({ requirePrincipal });
2499
2543
  const auth = parseAuthDomain({ requirePrincipal });
2500
2544
  const orchestration = parseOrchestrationDomain({ postureOn, singleUserTurnkey, configProvider });
2545
+ settleDerivedReadFace(orchestration, singleUserTurnkey);
2546
+ const readFaceNotice = buildReadFacePostureNotice(orchestration);
2547
+ if (readFaceNotice !== undefined)
2548
+ CONFIG_NOTICES.push({ level: "info", ...readFaceNotice });
2501
2549
  const limitsHttp = parseLimitsHttpDomain();
2502
2550
  const observability = parseObservabilityDomain();
2503
2551
  const integrations = parseIntegrationsDomain({ requirePrincipal, configProvider });
@@ -2506,7 +2554,7 @@ export function loadConfig() {
2506
2554
  throw new Error(centerIdentity);
2507
2555
  }
2508
2556
  const { directApprovalDoor, durableApproval: dgDurable, approvalHmacKeys: dgHmacKeys } = approval;
2509
- const { principalJwtPubkeys, principalJwtIss, principalJwtAud, operatorPrincipals: dgOperators, authTokens } = auth;
2557
+ const { principalJwtPubkeys, principalJwtIss, principalJwtAud, operatorPrincipals: dgOperators, operatorSingleUser, authTokens } = auth;
2510
2558
  const directDoorActive = directApprovalDoor && dgDurable && dgHmacKeys.length > 0 && principalJwtPubkeys.length > 0 && !!principalJwtIss && !!principalJwtAud;
2511
2559
  const doorRefusal = halfOpenDirectDoorRefusal({
2512
2560
  directApprovalDoor,
@@ -2525,6 +2573,10 @@ export function loadConfig() {
2525
2573
  if (operatorsRefusal !== undefined) {
2526
2574
  throw new Error(operatorsRefusal);
2527
2575
  }
2576
+ const singleUserOperatorRefusal = operatorSingleUserRefusal({ operatorSingleUser, requirePrincipal, operatorPrincipals: dgOperators });
2577
+ if (singleUserOperatorRefusal !== undefined) {
2578
+ throw new Error(singleUserOperatorRefusal);
2579
+ }
2528
2580
  const bakeOperatorsRefusal = bakeOperatorPrincipalsRefusal({ imageBakes: orchestration.imageBakes, operatorPrincipals: dgOperators });
2529
2581
  if (bakeOperatorsRefusal !== undefined) {
2530
2582
  throw new Error(bakeOperatorsRefusal);
@@ -2537,6 +2589,16 @@ export function loadConfig() {
2537
2589
  if (leaderStoreRefusal !== undefined) {
2538
2590
  throw new Error(leaderStoreRefusal);
2539
2591
  }
2592
+ const parkDecisionDomainRefusal = workflowParkDecisionDomainRefusal({
2593
+ selfOrchestrationEnabled: orchestration.selfOrchestrationEnabled,
2594
+ workflowRunStoreBackend: orchestration.workflowRunStoreBackend,
2595
+ dbBackend: store.dbBackend,
2596
+ tidb: store.tidb,
2597
+ pg: store.pg,
2598
+ });
2599
+ if (parkDecisionDomainRefusal !== undefined) {
2600
+ throw new Error(parkDecisionDomainRefusal);
2601
+ }
2540
2602
  const laneRequiredRefusal = executionLaneRequiredRefusal(orchestration);
2541
2603
  if (laneRequiredRefusal !== undefined) {
2542
2604
  throw new Error(laneRequiredRefusal);