@sema-agent/server 7.150.0 → 7.152.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 (514) hide show
  1. package/MIGRATION.md +451 -0
  2. package/README.md +15 -3
  3. package/README.zh-CN.md +10 -2
  4. package/USAGE.md +144 -87
  5. package/deploy/sema-up/README.md +11 -4
  6. package/deploy/sema-up/chart/Chart.yaml +1 -1
  7. package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
  9. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
  10. package/deploy/sema-up/chart/templates/server.yaml +5 -3
  11. package/deploy/sema-up/chart/values-full-single.yaml +3 -1
  12. package/deploy/sema-up/chart/values.yaml +8 -1
  13. package/deploy/sema-up/cluster-up.sh +7 -6
  14. package/deploy/sema-up/kube-up.sh +6 -6
  15. package/deploy/sema-up/lib/flagshape.sh +36 -8
  16. package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
  17. package/deploy/sema-up/lib/helm-values-kube.py +2 -0
  18. package/deploy/sema-up/machines.example.yaml +3 -1
  19. package/deploy/sema-up/sema-up.sh +22 -16
  20. package/dist/adoption/import.js +3 -3
  21. package/dist/approval-ask-audit-store.d.ts +1 -1
  22. package/dist/approval-ask-machine.d.ts +4 -10
  23. package/dist/approval-ask-retention.d.ts +1 -1
  24. package/dist/approval-card.d.ts +12 -14
  25. package/dist/approval-gate-currency.d.ts +9 -9
  26. package/dist/approval-gate-currency.js +3 -4
  27. package/dist/approval-hmac.d.ts +17 -1
  28. package/dist/approval-hmac.js +7 -1
  29. package/dist/approval-queue-kind.d.ts +1 -1
  30. package/dist/approval.d.ts +2 -2
  31. package/dist/approval.js +2 -2
  32. package/dist/auth-bridge.d.ts +20 -0
  33. package/dist/auth-bridge.js +9 -0
  34. package/dist/background-session-reap.d.ts +1 -1
  35. package/dist/bake-runner/main.d.ts +4 -2
  36. package/dist/bind-host.d.ts +3 -6
  37. package/dist/bind-host.js +4 -7
  38. package/dist/boot/budget-tracing.js +1 -1
  39. package/dist/boot/coordinators.d.ts +1 -1
  40. package/dist/boot/coordinators.js +9 -10
  41. package/dist/boot/device-lane.js +2 -0
  42. package/dist/boot/engine-lease.d.ts +5 -0
  43. package/dist/boot/engine-lease.js +1 -0
  44. package/dist/boot/execution-env.d.ts +9 -14
  45. package/dist/boot/execution-env.js +85 -22
  46. package/dist/boot/execution-lane.js +32 -5
  47. package/dist/boot/late-binds.d.ts +8 -4
  48. package/dist/boot/late-binds.js +7 -1
  49. package/dist/boot/leader.d.ts +31 -30
  50. package/dist/boot/leader.js +38 -28
  51. package/dist/boot/leg-path-adjudication.d.ts +40 -0
  52. package/dist/boot/leg-path-adjudication.js +18 -0
  53. package/dist/boot/memory-consolidation.d.ts +3 -2
  54. package/dist/boot/memory-consolidation.js +6 -6
  55. package/dist/boot/parked-revive-gate.js +3 -15
  56. package/dist/boot/reapers.d.ts +6 -1
  57. package/dist/boot/reapers.js +13 -2
  58. package/dist/boot/resolve-spec.d.ts +3 -3
  59. package/dist/boot/resolve-spec.js +43 -48
  60. package/dist/boot/runner-deps.d.ts +46 -35
  61. package/dist/boot/runner-deps.js +94 -91
  62. package/dist/boot/session-age-out.d.ts +36 -0
  63. package/dist/boot/session-age-out.js +101 -0
  64. package/dist/boot/session-faces.d.ts +5 -14
  65. package/dist/boot/session-faces.js +9 -5
  66. package/dist/boot/shutdown.d.ts +6 -0
  67. package/dist/boot/shutdown.js +10 -4
  68. package/dist/boot/stage-01-config.js +2 -0
  69. package/dist/boot/stage-02-web-admin-pull.js +4 -5
  70. package/dist/boot/stage-05-execution-env.d.ts +5 -3
  71. package/dist/boot/stage-05-execution-env.js +3 -2
  72. package/dist/boot/stage-06-runners.d.ts +9 -4
  73. package/dist/boot/stage-06-runners.js +24 -9
  74. package/dist/boot/stage-07-capability-layer.d.ts +8 -4
  75. package/dist/boot/stage-07-capability-layer.js +3 -2
  76. package/dist/boot/stage-08-reapers.d.ts +8 -4
  77. package/dist/boot/stage-08-reapers.js +4 -2
  78. package/dist/boot/stage-09-leader.d.ts +12 -5
  79. package/dist/boot/stage-09-leader.js +14 -5
  80. package/dist/boot/stage-10-http-server.d.ts +19 -5
  81. package/dist/boot/stage-10-http-server.js +14 -21
  82. package/dist/boot/stores.js +7 -4
  83. package/dist/boot/web-admin.js +5 -8
  84. package/dist/boot/workflow-orchestration.d.ts +7 -2
  85. package/dist/boot/workflow-orchestration.js +24 -7
  86. package/dist/bounded-rotation.d.ts +29 -0
  87. package/dist/bounded-rotation.js +24 -0
  88. package/dist/capabilities/approvals-push.d.ts +3 -3
  89. package/dist/capabilities/scenarios.d.ts +28 -13
  90. package/dist/capabilities/scenarios.js +2 -2
  91. package/dist/capability-facts.d.ts +43 -32
  92. package/dist/capability-facts.js +45 -51
  93. package/dist/card-rule-offers.d.ts +32 -0
  94. package/dist/card-rule-offers.js +130 -0
  95. package/dist/center-credential.d.ts +25 -6
  96. package/dist/center-credential.js +25 -5
  97. package/dist/config-catalog.d.ts +26 -7
  98. package/dist/config-catalog.js +26 -22
  99. package/dist/config-dir-trust.js +4 -2
  100. package/dist/config-invariants.d.ts +20 -8
  101. package/dist/config-invariants.js +55 -12
  102. package/dist/config-lkg.d.ts +5 -19
  103. package/dist/config-lkg.js +8 -62
  104. package/dist/config-provider.d.ts +1 -1
  105. package/dist/config-root-migration.d.ts +2 -2
  106. package/dist/config-types.d.ts +38 -42
  107. package/dist/config.d.ts +58 -7
  108. package/dist/config.js +90 -40
  109. package/dist/control-socket.d.ts +51 -0
  110. package/dist/control-socket.js +115 -0
  111. package/dist/deployment-governance.d.ts +2 -1
  112. package/dist/deployment-shape.d.ts +9 -1
  113. package/dist/deployment-shape.js +2 -1
  114. package/dist/device-protocol.d.ts +5 -4
  115. package/dist/device-protocol.js +1 -1
  116. package/dist/device-ws-hub.d.ts +7 -0
  117. package/dist/device-ws-hub.js +10 -3
  118. package/dist/device-ws-protocol.d.ts +63 -10
  119. package/dist/device-ws-protocol.js +56 -25
  120. package/dist/elicitation.js +2 -2
  121. package/dist/engine-identity.d.ts +19 -7
  122. package/dist/engine-identity.js +10 -2
  123. package/dist/entry-mode-clamp-notice.d.ts +2 -1
  124. package/dist/entry-problems.d.ts +40 -3
  125. package/dist/entry-problems.js +3 -1
  126. package/dist/execution-env-refusal.d.ts +29 -0
  127. package/dist/execution-env-refusal.js +8 -0
  128. package/dist/execution-lane-caps.d.ts +3 -1
  129. package/dist/field-conflict.d.ts +1 -1
  130. package/dist/file-history-capture.d.ts +11 -4
  131. package/dist/file-history-capture.js +9 -6
  132. package/dist/file-history-disclosure.d.ts +7 -5
  133. package/dist/file-history-disclosure.js +7 -5
  134. package/dist/fleet/drain-entry.d.ts +4 -0
  135. package/dist/fleet/engine-signal.d.ts +12 -29
  136. package/dist/fleet/engine-signal.js +1 -7
  137. package/dist/fleet-client.js +2 -5
  138. package/dist/gate-settlement.d.ts +1 -8
  139. package/dist/gate-settlement.js +0 -4
  140. package/dist/history-anchor.js +1 -1
  141. package/dist/hitl-delivery.d.ts +2 -3
  142. package/dist/hitl-delivery.js +0 -2
  143. package/dist/hooks/hook-llm.js +4 -2
  144. package/dist/hooks/hook-runner.d.ts +3 -2
  145. package/dist/hooks/hook-runner.js +18 -3
  146. package/dist/host-decision.d.ts +11 -11
  147. package/dist/host-lsp-manager.d.ts +2 -2
  148. package/dist/http/active-run-conflict.d.ts +35 -2
  149. package/dist/http/active-run-conflict.js +48 -19
  150. package/dist/http/admission.js +17 -2
  151. package/dist/http/approval-sweeps.d.ts +1 -1
  152. package/dist/http/approval-sweeps.js +10 -7
  153. package/dist/http/checkpoint-ctx.d.ts +4 -0
  154. package/dist/http/checkpoint-ctx.js +2 -0
  155. package/dist/http/dispatch.d.ts +8 -3
  156. package/dist/http/dispatch.js +59 -32
  157. package/dist/http/durable-run-leg.js +16 -17
  158. package/dist/http/health-reader.d.ts +16 -9
  159. package/dist/http/health-reader.js +2 -1
  160. package/dist/http/health-self-report.d.ts +9 -1
  161. package/dist/http/health-self-report.js +3 -1
  162. package/dist/http/owner-access.d.ts +33 -14
  163. package/dist/http/owner-access.js +40 -10
  164. package/dist/http/principal-gate.d.ts +49 -21
  165. package/dist/http/principal-gate.js +61 -11
  166. package/dist/http/request-channel.d.ts +23 -0
  167. package/dist/http/request-channel.js +9 -0
  168. package/dist/http/request-guards.js +17 -2
  169. package/dist/http/resume-ctx-read.js +42 -3
  170. package/dist/http/resume-legs.d.ts +4 -3
  171. package/dist/http/resume-legs.js +367 -117
  172. package/dist/http/route-ctx.d.ts +91 -15
  173. package/dist/http/route-ctx.js +17 -0
  174. package/dist/http/route-table.d.ts +5 -1
  175. package/dist/http/route-table.js +4 -0
  176. package/dist/http/routes/admin-config-refresh.js +3 -3
  177. package/dist/http/routes/admin-drain.d.ts +3 -0
  178. package/dist/http/routes/admin-drain.js +7 -7
  179. package/dist/http/routes/admin-memory-optout.d.ts +1 -1
  180. package/dist/http/routes/admin-memory-optout.js +3 -3
  181. package/dist/http/routes/adoption.js +3 -5
  182. package/dist/http/routes/agents-roster.js +2 -3
  183. package/dist/http/routes/approvals-assistant.d.ts +2 -1
  184. package/dist/http/routes/approvals-assistant.js +99 -51
  185. package/dist/http/routes/background.d.ts +3 -3
  186. package/dist/http/routes/capabilities.d.ts +4 -0
  187. package/dist/http/routes/capabilities.js +38 -10
  188. package/dist/http/routes/config-catalog.js +2 -2
  189. package/dist/http/routes/devices.js +1 -1
  190. package/dist/http/routes/diagnostics.d.ts +3 -3
  191. package/dist/http/routes/diagnostics.js +19 -7
  192. package/dist/http/routes/fleet.js +10 -8
  193. package/dist/http/routes/images.js +10 -10
  194. package/dist/http/routes/memory-bundle.js +3 -3
  195. package/dist/http/routes/memory-compliance.js +3 -3
  196. package/dist/http/routes/memory-consolidation.js +2 -2
  197. package/dist/http/routes/memory-origin.js +3 -3
  198. package/dist/http/routes/memory-policy.js +2 -2
  199. package/dist/http/routes/observability.js +3 -3
  200. package/dist/http/routes/projects.d.ts +3 -2
  201. package/dist/http/routes/projects.js +4 -5
  202. package/dist/http/routes/retention-ops.js +3 -3
  203. package/dist/http/routes/rules.js +5 -5
  204. package/dist/http/routes/run-permission-mode.d.ts +2 -1
  205. package/dist/http/routes/run-permission-mode.js +2 -2
  206. package/dist/http/routes/runs.d.ts +4 -9
  207. package/dist/http/routes/runs.js +171 -65
  208. package/dist/http/routes/session-sync.d.ts +22 -9
  209. package/dist/http/routes/session-sync.js +204 -107
  210. package/dist/http/routes/sessions-list.js +13 -7
  211. package/dist/http/routes/sessions.js +30 -15
  212. package/dist/http/routes/tasks.js +46 -41
  213. package/dist/http/routes/trace-usage.js +2 -2
  214. package/dist/http/routes/workflows.js +1 -1
  215. package/dist/http/server.d.ts +30 -30
  216. package/dist/http/server.js +16 -4
  217. package/dist/http/submit-ctx.d.ts +1 -1
  218. package/dist/http/submit-ctx.js +7 -4
  219. package/dist/http/wire-types.d.ts +14 -4
  220. package/dist/human-facing-args.d.ts +33 -0
  221. package/dist/human-facing-args.js +33 -0
  222. package/dist/identity-source.d.ts +20 -3
  223. package/dist/identity-source.js +14 -0
  224. package/dist/index.d.ts +5 -1
  225. package/dist/k8s-api-credentials.d.ts +29 -0
  226. package/dist/k8s-api-credentials.js +25 -0
  227. package/dist/lane-home-probe.d.ts +3 -7
  228. package/dist/lane-home-probe.js +2 -2
  229. package/dist/leader/diffup.d.ts +19 -0
  230. package/dist/leader/diffup.js +7 -0
  231. package/dist/leader/leader.d.ts +116 -11
  232. package/dist/leader/leader.js +69 -5
  233. package/dist/leader/repair-wire.js +2 -2
  234. package/dist/leader/run-entry.d.ts +2 -1
  235. package/dist/leader/run-entry.js +1 -1
  236. package/dist/leader/wire.d.ts +42 -132
  237. package/dist/leader/wire.js +81 -67
  238. package/dist/leg-facts.d.ts +13 -5
  239. package/dist/leg-facts.js +2 -1
  240. package/dist/memory-scope.d.ts +23 -11
  241. package/dist/memory-scope.js +18 -6
  242. package/dist/memory-sync-client.d.ts +30 -2
  243. package/dist/memory-sync-client.js +16 -9
  244. package/dist/model-entry-headers.d.ts +9 -10
  245. package/dist/model-entry-headers.js +0 -4
  246. package/dist/model-entry-refusal.d.ts +7 -4
  247. package/dist/model-entry-refusal.js +11 -5
  248. package/dist/model-plane-face.d.ts +1 -1
  249. package/dist/model-plane-face.js +3 -1
  250. package/dist/model-route-endpoint.d.ts +13 -7
  251. package/dist/model-route-endpoint.js +14 -11
  252. package/dist/model-select.d.ts +22 -0
  253. package/dist/model-select.js +9 -0
  254. package/dist/model-unreachable-notice.d.ts +11 -0
  255. package/dist/model-unreachable-notice.js +4 -4
  256. package/dist/object-store-buckets.d.ts +640 -6
  257. package/dist/object-store-buckets.js +166 -0
  258. package/dist/observability/err-text.d.ts +7 -0
  259. package/dist/observability/err-text.js +5 -0
  260. package/dist/observability/fail-open.d.ts +25 -17
  261. package/dist/observability/fail-open.js +25 -17
  262. package/dist/observability/logger.js +3 -1
  263. package/dist/observability/metrics.js +1 -0
  264. package/dist/operator-roster.d.ts +68 -0
  265. package/dist/operator-roster.js +32 -0
  266. package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
  267. package/dist/orchestration/workflow-notify-journal.js +12 -1
  268. package/dist/orchestration/workflow-park-decision.d.ts +70 -18
  269. package/dist/orchestration/workflow-park-decision.js +49 -10
  270. package/dist/orchestration/workflow-park-holder.d.ts +65 -0
  271. package/dist/orchestration/workflow-park-holder.js +98 -0
  272. package/dist/orchestration/workflow-record-fence.d.ts +36 -0
  273. package/dist/orchestration/workflow-record-fence.js +42 -0
  274. package/dist/outbound-dispatcher.d.ts +71 -8
  275. package/dist/outbound-dispatcher.js +48 -7
  276. package/dist/owner-faces.d.ts +2 -2
  277. package/dist/parked-decide.d.ts +106 -55
  278. package/dist/parked-decide.js +153 -117
  279. package/dist/peer-directory.d.ts +2 -2
  280. package/dist/peer-inbound-face.d.ts +2 -6
  281. package/dist/peer-inbound-face.js +0 -3
  282. package/dist/permission-mode-admission.d.ts +74 -5
  283. package/dist/permission-mode-admission.js +56 -3
  284. package/dist/plugins/adoption-log-sql.d.ts +3 -1
  285. package/dist/plugins/adoption-log-sql.js +7 -1
  286. package/dist/plugins/approval-ask-store-file.d.ts +14 -2
  287. package/dist/plugins/approval-ask-store-file.js +11 -0
  288. package/dist/plugins/approval-ask-store-memory.d.ts +10 -1
  289. package/dist/plugins/approval-ask-store-memory.js +35 -10
  290. package/dist/plugins/approval-ask-store-sql.d.ts +69 -4
  291. package/dist/plugins/approval-ask-store-sql.js +45 -5
  292. package/dist/plugins/approval-exemption-store.js +3 -0
  293. package/dist/plugins/approval-nonce-store.js +2 -0
  294. package/dist/plugins/blob-backend.d.ts +83 -7
  295. package/dist/plugins/blob-backend.js +57 -6
  296. package/dist/plugins/breaker-state-sql.js +2 -0
  297. package/dist/plugins/caching-session-store.d.ts +9 -15
  298. package/dist/plugins/caching-session-store.js +6 -0
  299. package/dist/plugins/checkpoint-index-columns.d.ts +20 -16
  300. package/dist/plugins/checkpoint-index-columns.js +3 -6
  301. package/dist/plugins/checkpoint-store-face.d.ts +119 -61
  302. package/dist/plugins/checkpoint-store-face.js +134 -55
  303. package/dist/plugins/device-store-sql.js +6 -0
  304. package/dist/plugins/error-origin.d.ts +18 -0
  305. package/dist/plugins/error-origin.js +10 -0
  306. package/dist/plugins/execution-placement-sql.js +6 -6
  307. package/dist/plugins/image-bake-store-sql.js +6 -0
  308. package/dist/plugins/image-index-sql.js +4 -0
  309. package/dist/plugins/landed-attendants.d.ts +212 -0
  310. package/dist/plugins/landed-attendants.js +161 -0
  311. package/dist/plugins/leader-run-store-sql.js +4 -0
  312. package/dist/plugins/local-checkpoint-store.d.ts +13 -3
  313. package/dist/plugins/local-checkpoint-store.js +38 -49
  314. package/dist/plugins/local-session-live-reference.d.ts +40 -0
  315. package/dist/plugins/local-session-live-reference.js +39 -0
  316. package/dist/plugins/local-session-store.d.ts +71 -33
  317. package/dist/plugins/local-session-store.js +129 -27
  318. package/dist/plugins/memory-engine-pg.js +4 -0
  319. package/dist/plugins/memory-engine-sql-apply.js +5 -2
  320. package/dist/plugins/memory-engine-tidb.js +4 -0
  321. package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
  322. package/dist/plugins/memory-sync-store-pg.js +5 -0
  323. package/dist/plugins/memory-sync-store-tidb.js +5 -0
  324. package/dist/plugins/one-time-migrations.d.ts +104 -80
  325. package/dist/plugins/one-time-migrations.js +226 -132
  326. package/dist/plugins/org-delivery-quota-store.js +4 -1
  327. package/dist/plugins/outcome-ledger-sql.js +2 -0
  328. package/dist/plugins/permission-rule-store-sql.js +11 -4
  329. package/dist/plugins/pg-cost-quota.js +4 -0
  330. package/dist/plugins/pg-pool.js +35 -10
  331. package/dist/plugins/pg-rate-limiter.js +2 -0
  332. package/dist/plugins/posix-shell-fs.d.ts +6 -1
  333. package/dist/plugins/posix-shell-fs.js +4 -1
  334. package/dist/plugins/remote-env-adb.d.ts +19 -15
  335. package/dist/plugins/remote-env-adb.js +41 -15
  336. package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
  337. package/dist/plugins/remote-env-connect-seat.js +72 -0
  338. package/dist/plugins/remote-env-device.d.ts +22 -5
  339. package/dist/plugins/remote-env-device.js +106 -8
  340. package/dist/plugins/remote-env-e2b.d.ts +15 -6
  341. package/dist/plugins/remote-env-e2b.js +42 -32
  342. package/dist/plugins/remote-env-file-error.js +6 -2
  343. package/dist/plugins/remote-env-host.d.ts +46 -10
  344. package/dist/plugins/remote-env-host.js +124 -52
  345. package/dist/plugins/remote-env-k8s.d.ts +109 -41
  346. package/dist/plugins/remote-env-k8s.js +160 -54
  347. package/dist/plugins/remote-env-local-docker.d.ts +13 -8
  348. package/dist/plugins/remote-env-local-docker.js +34 -41
  349. package/dist/plugins/remote-env-ssh.d.ts +18 -12
  350. package/dist/plugins/remote-env-ssh.js +60 -59
  351. package/dist/plugins/remote-shell.d.ts +98 -1
  352. package/dist/plugins/remote-shell.js +218 -0
  353. package/dist/plugins/replica-registration.d.ts +1 -1
  354. package/dist/plugins/replica-registration.js +1 -1
  355. package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
  356. package/dist/plugins/resume-anchor-store-sql.js +12 -5
  357. package/dist/plugins/retention-lane-store-sql.js +4 -0
  358. package/dist/plugins/retention-sql.d.ts +20 -2
  359. package/dist/plugins/retention-sql.js +11 -0
  360. package/dist/plugins/run-store-sql.d.ts +21 -2
  361. package/dist/plugins/run-store-sql.js +31 -7
  362. package/dist/plugins/s3-presign.d.ts +23 -0
  363. package/dist/plugins/s3-presign.js +37 -3
  364. package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
  365. package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
  366. package/dist/plugins/scheduler-support.d.ts +2 -2
  367. package/dist/plugins/scheduler-support.js +0 -3
  368. package/dist/plugins/schema-consistency.d.ts +4 -2
  369. package/dist/plugins/schema-consistency.js +19 -2
  370. package/dist/plugins/schema-indexes.js +2 -0
  371. package/dist/plugins/send-file-ledger.d.ts +2 -2
  372. package/dist/plugins/send-file-ledger.js +5 -2
  373. package/dist/plugins/send-user-file.d.ts +3 -4
  374. package/dist/plugins/send-user-file.js +56 -52
  375. package/dist/plugins/serving-requirement.d.ts +26 -7
  376. package/dist/plugins/serving-requirement.js +11 -4
  377. package/dist/plugins/session-birth.d.ts +6 -2
  378. package/dist/plugins/session-blob-claim-token.d.ts +15 -0
  379. package/dist/plugins/session-blob-claim-token.js +20 -0
  380. package/dist/plugins/session-blob-namespace.d.ts +46 -0
  381. package/dist/plugins/session-blob-namespace.js +116 -0
  382. package/dist/plugins/session-capture-record-store-sql.js +2 -0
  383. package/dist/plugins/session-ext-table.d.ts +14 -1
  384. package/dist/plugins/session-ext-table.js +5 -1
  385. package/dist/plugins/session-row-sql.d.ts +49 -2
  386. package/dist/plugins/session-row-sql.js +56 -13
  387. package/dist/plugins/session-store-sql.d.ts +34 -18
  388. package/dist/plugins/session-store-sql.js +98 -17
  389. package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
  390. package/dist/plugins/shared-memory-store-sql.js +6 -2
  391. package/dist/plugins/snapshot-bucket-presence.d.ts +25 -2
  392. package/dist/plugins/snapshot-bucket-presence.js +8 -2
  393. package/dist/plugins/sql-driver.d.ts +2 -1
  394. package/dist/plugins/sql-driver.js +18 -3
  395. package/dist/plugins/sql-errors.d.ts +11 -6
  396. package/dist/plugins/sql-errors.js +5 -6
  397. package/dist/plugins/sql-json-column.d.ts +1 -1
  398. package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
  399. package/dist/plugins/stop-then-start-sentence.js +14 -10
  400. package/dist/plugins/stop-then-start.d.ts +109 -0
  401. package/dist/plugins/stop-then-start.js +104 -0
  402. package/dist/plugins/store-backend.d.ts +84 -15
  403. package/dist/plugins/store-backend.js +236 -72
  404. package/dist/plugins/store-boundary.d.ts +57 -0
  405. package/dist/plugins/store-boundary.js +139 -0
  406. package/dist/plugins/store-contracts.d.ts +17 -0
  407. package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
  408. package/dist/plugins/store-fault-sentence-m53.js +25 -0
  409. package/dist/plugins/store-fault.d.ts +26 -7
  410. package/dist/plugins/store-fault.js +18 -2
  411. package/dist/plugins/task-attachment-store.d.ts +2 -1
  412. package/dist/plugins/task-attachment-store.js +14 -1
  413. package/dist/plugins/task-list-store-sql.d.ts +2 -2
  414. package/dist/plugins/task-list-store-sql.js +10 -8
  415. package/dist/plugins/tidb-cost-quota.js +4 -0
  416. package/dist/plugins/tidb-pool.js +21 -25
  417. package/dist/plugins/tidb-rate-limiter.js +4 -0
  418. package/dist/plugins/user-input-ledger-sql.js +4 -0
  419. package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
  420. package/dist/plugins/workflow-run-store-sql.js +64 -4
  421. package/dist/plugins/workspace-custody.d.ts +4 -3
  422. package/dist/plugins/workspace-fill.d.ts +4 -7
  423. package/dist/plugins/workspace-fill.js +2 -1
  424. package/dist/plugins/write-behind-counter.js +5 -0
  425. package/dist/project-context.d.ts +0 -2
  426. package/dist/project-context.js +4 -8
  427. package/dist/project-registry.d.ts +46 -0
  428. package/dist/project-registry.js +44 -0
  429. package/dist/question.d.ts +2 -1
  430. package/dist/question.js +5 -13
  431. package/dist/request-form.d.ts +6 -1
  432. package/dist/request-form.js +4 -1
  433. package/dist/request-key-closure.js +1 -1
  434. package/dist/request-value-closure.d.ts +4 -0
  435. package/dist/request-value-closure.js +10 -0
  436. package/dist/rule-issue-reading.d.ts +1 -1
  437. package/dist/rules-consent.d.ts +1 -1
  438. package/dist/run-acceptance.d.ts +3 -2
  439. package/dist/run-acceptance.js +4 -6
  440. package/dist/run-local.js +9 -9
  441. package/dist/runs.d.ts +54 -16
  442. package/dist/runs.js +67 -13
  443. package/dist/runtime-governance.d.ts +5 -4
  444. package/dist/security.d.ts +30 -32
  445. package/dist/security.js +41 -7
  446. package/dist/sema-config-dir.d.ts +2 -1
  447. package/dist/server-secret-env.d.ts +12 -10
  448. package/dist/server-secret-env.js +24 -15
  449. package/dist/session-bindings.d.ts +82 -0
  450. package/dist/session-bindings.js +18 -0
  451. package/dist/session-children-retire.d.ts +2 -2
  452. package/dist/session-children-retire.js +2 -6
  453. package/dist/session-deletion.d.ts +16 -1
  454. package/dist/session-error-wire.d.ts +3 -3
  455. package/dist/session-error-wire.js +3 -3
  456. package/dist/session-incarnation.d.ts +10 -0
  457. package/dist/session-incarnation.js +10 -1
  458. package/dist/session-kind.d.ts +57 -0
  459. package/dist/session-kind.js +22 -0
  460. package/dist/session-row.d.ts +21 -1
  461. package/dist/session-row.js +7 -1
  462. package/dist/session-sync-kernel.d.ts +24 -14
  463. package/dist/session-sync-kernel.js +3 -6
  464. package/dist/session-sync.d.ts +25 -103
  465. package/dist/session-sync.js +14 -76
  466. package/dist/session-titler.d.ts +10 -3
  467. package/dist/session-titler.js +19 -6
  468. package/dist/ssh-host-key.d.ts +5 -0
  469. package/dist/ssh-host-key.js +3 -0
  470. package/dist/stores-sql/blob-index-sql.d.ts +30 -9
  471. package/dist/stores-sql/blob-index-sql.js +40 -21
  472. package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
  473. package/dist/stores-sql/checkpoint-store-sql.js +70 -146
  474. package/dist/stores-sql/file-history-store-sql.d.ts +113 -15
  475. package/dist/stores-sql/file-history-store-sql.js +205 -95
  476. package/dist/stores-sql/pg-session-storage.d.ts +34 -7
  477. package/dist/stores-sql/pg-session-storage.js +37 -13
  478. package/dist/stores-sql/retention-store-sql.d.ts +1 -9
  479. package/dist/stores-sql/retention-store-sql.js +5 -19
  480. package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
  481. package/dist/stores-sql/session-policy-store-sql.js +61 -44
  482. package/dist/stores-sql/session-write-hooks.d.ts +11 -0
  483. package/dist/stores-sql/tidb-session-store.d.ts +58 -7
  484. package/dist/stores-sql/tidb-session-store.js +37 -13
  485. package/dist/submission-exit.d.ts +3 -2
  486. package/dist/submission-exit.js +9 -1
  487. package/dist/task-cwd.d.ts +2 -2
  488. package/dist/task-settings.d.ts +7 -5
  489. package/dist/task-settings.js +3 -3
  490. package/dist/terminal.d.ts +33 -2
  491. package/dist/terminal.js +139 -9
  492. package/dist/tool-approval.d.ts +465 -507
  493. package/dist/tool-approval.js +606 -1222
  494. package/dist/trace/core-keyset-guard.d.ts +1 -1
  495. package/dist/trace/ledger-events.d.ts +3 -3
  496. package/dist/trace/project.d.ts +2 -3
  497. package/dist/trace/redact.js +3 -2
  498. package/dist/trace/self-minted-wire.d.ts +571 -178
  499. package/dist/trace/self-minted-wire.js +189 -56
  500. package/dist/web-admin-client/apply-effective.js +2 -2
  501. package/dist/web-admin-client/read-warnings.d.ts +2 -2
  502. package/dist/web-admin-client/read-warnings.js +1 -1
  503. package/dist/web-admin-client/types.d.ts +1 -1
  504. package/dist/workspace-space.d.ts +10 -4
  505. package/dist/workspace-space.js +4 -1
  506. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +79 -28
  507. package/package.json +7 -3
  508. package/scripts/embed-minimal.mjs +3 -3
  509. package/wire-changes/server@7.151.0.json +762 -0
  510. package/wire-changes/server@7.152.0.json +900 -0
  511. package/dist/config-d-migration.d.ts +0 -37
  512. package/dist/config-d-migration.js +0 -60
  513. package/dist/http/session-inherit-env.d.ts +0 -36
  514. package/dist/http/session-inherit-env.js +0 -6
package/dist/config.js CHANGED
@@ -32,11 +32,11 @@ import { MODEL_THINKING_LEVELS, THINKING_LEVELS, THINKING_FORMATS, buildModelCom
32
32
  import {} from "./posture-source.js";
33
33
  import { COST_QUOTA_WINDOW_SEC_RANGE, costQuotaWindowSecInRange } from "./observability/cost-quota.js";
34
34
  import { NAME_TABLE_BEHAVIOR, TOOL_NAME_ROSTER, describeUnmatchableRuleName, isRetiredLeftOut, retiredLeftOutEntries, ruleEntryToolName, unmatchableRuleNameOf } from "./namespaced-rule-name.js";
35
- import { bakeOperatorPrincipalsRefusal, bakeRunnerCredentialRefusal, centerIdentityRefusal, halfOpenDirectDoorRefusal, leaderDurableStoreRefusal, operatorPrincipalsRequiredRefusal, operatorSingleUserRefusal, remoteConfigProviderUrlRefusal, retentionLaneRefusal, workflowParkDecisionDomainRefusal } from "./config-invariants.js";
35
+ import { bakeOperatorPrincipalsRefusal, bakeRunnerCredentialRefusal, centerIdentityRefusal, halfOpenDirectDoorRefusal, leaderDurableStoreRefusal, operatorPrincipalsRequiredRefusal, operatorSingleUserRefusal, operatorRosterWellFormedRefusal, remoteConfigProviderUrlRefusal, retentionLaneRefusal, workflowParkDecisionDomainRefusal } from "./config-invariants.js";
36
36
  import { declaredSemaConfigDir } from "./sema-config-dir.js";
37
37
  import { lkgPathOverrideOf } from "./config-lkg.js";
38
38
  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, parseWorkspaceSnapshotPrefix } from "./workspace-space.js";
39
- import { SESSION_SNAPSHOT_BUCKET_DEFAULT, WORKSPACE_SNAPSHOT_BUCKET_DEFAULT } from "./object-store-buckets.js";
39
+ import { S3_PUBLIC_BUCKET_DEFAULT, SENDFILE_PRIVATE_PREFIX, SESSION_SNAPSHOT_BUCKET_DEFAULT, SIGV4_PRESIGN_MAX_SEC, WORKSPACE_SNAPSHOT_BUCKET_DEFAULT, sessionSnapshotPrefixProblem } from "./object-store-buckets.js";
40
40
  import { laneLivenessOf } from "./exec-bounds.js";
41
41
  import { SANDBOX_IPV6_DEFAULT, SANDBOX_IPV6_WORDS } from "./sandbox-egress-policy.js";
42
42
  import { WORKSPACE_CACHE_DEFAULT, WORKSPACE_CACHE_MOUNT_DEFAULT, WORKSPACE_CACHE_MOUNT_RESERVED, WORKSPACE_CACHE_SIZE_DEFAULT, WORKSPACE_CACHE_WORDS, isK8sQuantity, mountsOverlap, reservedMountCollision } from "./workspace-cache.js";
@@ -46,10 +46,11 @@ import { sandboxForwardedEnvOf } from "./execution-config-root.js";
46
46
  import { SANDBOX_READ_FLOOR_DEFAULT, SANDBOX_READ_FLOOR_WORDS, laneMissingEnv, readDeclaredLaneTable } from "./execution-lane-caps.js";
47
47
  import { MEMORY_ENGINE_BACKENDS, SESSION_BACKENDS, STORE_BACKENDS } from "@sema-agent/settings-schema/execution-lanes";
48
48
  import { AUTONOMY_MODES } from "./runtime-governance.js";
49
+ import { CC_RULE_FORM } from "./entry-problems.js";
49
50
  import { deploymentRuleRefusal } from "./rule-issue-reading.js";
50
51
  import { MAX_NAMED_INERT_ENTRIES, allowLayerEntryCountIssue, describeInertRuleEntries, inertRuleEntriesOf, inertRuleEntryGuidance, ruleEntryListShapeOk } from "./rule-entry-list.js";
51
52
  import { readReadDenyEntry } from "./read-deny-entry.js";
52
- import { createCenterCredentialSource, readCenterCredentialDeclaration } from "./center-credential.js";
53
+ import { createCenterCredentialSource, credentialOriginOf, readWebAdminCredentialDeclaration } from "./center-credential.js";
53
54
  import { parseCenterCredentialRenewLeadMs } from "./center-credential-renewer.js";
54
55
  import { catalogBrainLane, modelProviderRefusal } from "./model-provider.js";
55
56
  import { modelRouteUrlRefusal } from "./model-route-url.js";
@@ -408,15 +409,39 @@ function parseDeviceRelayUrlEnv(raw) {
408
409
  export function entryDeclarableRemoteExec(lane) {
409
410
  switch (lane) {
410
411
  case "host":
411
- return {
412
- provider: "host",
413
- ...(process.env.HOST_WORKSPACE_BASE ? { workspaceBase: process.env.HOST_WORKSPACE_BASE } : {}),
414
- ...((n) => (n !== undefined ? { commandTimeoutMs: n } : {}))(optNumEnvStrict("HOST_COMMAND_TIMEOUT_MS")),
415
- };
412
+ return { provider: "host", ...parseHostLaneEnv() };
416
413
  case "none":
417
414
  return { provider: "none" };
418
415
  }
419
416
  }
417
+ export function parseHostLaneEnv() {
418
+ return {
419
+ ...(process.env.HOST_WORKSPACE_BASE ? { workspaceBase: process.env.HOST_WORKSPACE_BASE } : {}),
420
+ ...((n) => (n !== undefined ? { commandTimeoutMs: n } : {}))(optNumEnvStrict("HOST_COMMAND_TIMEOUT_MS")),
421
+ };
422
+ }
423
+ export function parseLocalDockerLaneEnv(singleUserTurnkey) {
424
+ return {
425
+ ...(process.env.DOCKER_IMAGE ? { image: process.env.DOCKER_IMAGE } : {}),
426
+ ...(process.env.DOCKER_MOUNT_PATH ? { mountPath: process.env.DOCKER_MOUNT_PATH } : {}),
427
+ ...(process.env.DOCKER_PATH ? { dockerPath: process.env.DOCKER_PATH } : {}),
428
+ ...(process.env.DOCKER_HOST ? { dockerHost: process.env.DOCKER_HOST } : {}),
429
+ ...(process.env.DOCKER_MEMORY ? { memory: process.env.DOCKER_MEMORY } : {}),
430
+ ...((n) => (n !== undefined ? { cpus: n } : {}))(optNumEnvStrict("DOCKER_CPUS")),
431
+ ...((n) => (n !== undefined ? { pidsLimit: n } : {}))(optFinitePositiveEnv("DOCKER_PIDS_LIMIT")),
432
+ ...(boolEnv("DOCKER_DROP_CAPS", false) ? { dropAllCaps: true } : {}),
433
+ ...(process.env.DOCKER_NETWORK
434
+ ? { network: enumEnv("DOCKER_NETWORK", "bridge", ["none", "bridge", "host"]) }
435
+ : {}),
436
+ ...((n) => (n !== undefined ? { commandTimeoutMs: n } : {}))(optNumEnvStrict("DOCKER_COMMAND_TIMEOUT_MS")),
437
+ ...((names) => (names !== undefined ? { env: allowlistedEnv(names, process.env) } : {}))(parseEnvNameAllowlist("DOCKER_SANDBOX_ENV", singleUserTurnkey)),
438
+ ...((capacity) => (capacity !== undefined ? { capacity } : {}))(parseLocalDockerCapacityEnv()),
439
+ };
440
+ }
441
+ export const FILE_LANE_CELL_ENV = {
442
+ host: { workspaceBase: "HOST_WORKSPACE_BASE", commandTimeoutMs: "HOST_COMMAND_TIMEOUT_MS" },
443
+ "local-docker": { image: "DOCKER_IMAGE", mountPath: "DOCKER_MOUNT_PATH", memory: "DOCKER_MEMORY", cpus: "DOCKER_CPUS", network: "DOCKER_NETWORK" },
444
+ };
420
445
  const envNamesNoLane = (raw) => raw === undefined || raw === "";
421
446
  function declaredExecutionLane(raw) {
422
447
  if (envNamesNoLane(raw))
@@ -470,6 +495,41 @@ function parseDeviceTrustedProxyCidrsEnv(raw) {
470
495
  `(e.g. 10.0.0.0/8,fd00::/8); unset it to read no proxy header at all (the cap is then keyed on the socket peer).`);
471
496
  });
472
497
  }
498
+ function sessionSnapshotPrefixKnob(prefix) {
499
+ const problem = sessionSnapshotPrefixProblem(prefix);
500
+ if (problem !== undefined)
501
+ throw new Error(`SESSION_SNAPSHOT_PREFIX=${JSON.stringify(prefix)} is refused: ${problem} — give each engine on the bucket a prefix that does not end in a domain segment (e.g. "engine-a/")`);
502
+ return prefix;
503
+ }
504
+ function presignLifetimeKnob(knob, sec, alternative) {
505
+ if (sec > SIGV4_PRESIGN_MAX_SEC) {
506
+ throw new Error(`${knob}=${sec} is longer than a presigned URL can live (at most ${SIGV4_PRESIGN_MAX_SEC} s (7 days)) — set ${knob} to at most ${SIGV4_PRESIGN_MAX_SEC}${alternative ? `, ${alternative}` : ""}`);
507
+ }
508
+ return sec;
509
+ }
510
+ function presignLifetimeSpelled(knob, raw, legal, alternative) {
511
+ const spelled = raw?.trim() ?? "";
512
+ if (spelled === "")
513
+ return undefined;
514
+ if (!/^(0|[1-9]\d*)$/.test(spelled)) {
515
+ const shown = raw.length > 40 ? `${raw.slice(0, 40)}…` : raw;
516
+ throw new Error(`${knob}=${JSON.stringify(shown)} is not ${legal}`);
517
+ }
518
+ return presignLifetimeKnob(knob, Number(spelled), alternative);
519
+ }
520
+ function sendUserFileUrlTtlKnob(raw) {
521
+ return (presignLifetimeSpelled("SEND_USER_FILE_URL_TTL", raw, `a link lifetime — set 0 (or leave it unset) for a permanent public link, or a whole number of seconds from 1 to ${SIGV4_PRESIGN_MAX_SEC} (7 days) for a private presigned link that expires`, "or 0 for a permanent link") ?? 0);
522
+ }
523
+ function sessionSnapshotTtlKnob(raw) {
524
+ const sec = presignLifetimeSpelled("SESSION_SNAPSHOT_TTL_SEC", raw, `a presigned-URL lifetime — leave it unset for the default, or set a whole number of seconds from 1 to ${SIGV4_PRESIGN_MAX_SEC} (7 days) in decimal digits`);
525
+ if (sec !== 0)
526
+ return sec;
527
+ CONFIG_WARNINGS.push({ env: "SESSION_SNAPSHOT_TTL_SEC", raw: raw });
528
+ return undefined;
529
+ }
530
+ function workspaceSnapshotTtlKnob(raw) {
531
+ return presignLifetimeSpelled("WORKSPACE_SNAPSHOT_TTL_SEC", raw, `a presigned-URL lifetime — leave it unset (or 0) for the default, or set a whole number of seconds from 1 to ${SIGV4_PRESIGN_MAX_SEC} (7 days) in decimal digits`);
532
+ }
473
533
  function parseFileHistoryRetention() {
474
534
  const raw = process.env.FILE_HISTORY_RETENTION_KEEP;
475
535
  if (raw === undefined || raw === "")
@@ -1012,8 +1072,8 @@ function parseStoreDomain(ctx) {
1012
1072
  accessKey: process.env.MINIO_ACCESS_KEY,
1013
1073
  secretKey: process.env.MINIO_SECRET_KEY,
1014
1074
  ...(process.env.MINIO_REGION ? { region: process.env.MINIO_REGION } : {}),
1015
- ...(process.env.SESSION_SNAPSHOT_PREFIX ? { keyPrefix: process.env.SESSION_SNAPSHOT_PREFIX } : {}),
1016
- ...((ttl) => (ttl !== undefined ? { presignTtlSec: ttl } : {}))(optFinitePositiveEnv("SESSION_SNAPSHOT_TTL_SEC")),
1075
+ ...(process.env.SESSION_SNAPSHOT_PREFIX ? { keyPrefix: sessionSnapshotPrefixKnob(process.env.SESSION_SNAPSHOT_PREFIX) } : {}),
1076
+ ...((ttl) => (ttl !== undefined ? { presignTtlSec: ttl } : {}))(sessionSnapshotTtlKnob(process.env.SESSION_SNAPSHOT_TTL_SEC)),
1017
1077
  }
1018
1078
  : undefined,
1019
1079
  snapshotBlobSqlMaxBytes: optFinitePositiveEnv("SNAPSHOT_BLOB_SQL_MAX_BYTES"),
@@ -1026,14 +1086,14 @@ function parseStoreDomain(ctx) {
1026
1086
  ...(process.env.S3_PUBLIC_ENDPOINT || process.env.S3_ENDPOINT
1027
1087
  ? { publicEndpoint: (process.env.S3_PUBLIC_ENDPOINT || process.env.S3_ENDPOINT) }
1028
1088
  : {}),
1029
- publicBucket: process.env.S3_PUBLIC_BUCKET ?? "sema-public",
1089
+ publicBucket: process.env.S3_PUBLIC_BUCKET ?? S3_PUBLIC_BUCKET_DEFAULT,
1030
1090
  privateBucket: process.env.SESSION_SNAPSHOT_BUCKET ?? SESSION_SNAPSHOT_BUCKET_DEFAULT,
1031
- privateKeyPrefix: "sendfile/",
1091
+ privateKeyPrefix: SENDFILE_PRIVATE_PREFIX,
1032
1092
  ...(process.env.SEND_USER_FILE_SANDBOX_PUT_ENDPOINT ? { sandboxPutEndpoint: process.env.SEND_USER_FILE_SANDBOX_PUT_ENDPOINT } : {}),
1033
1093
  accessKey: process.env.MINIO_ACCESS_KEY,
1034
1094
  secretKey: process.env.MINIO_SECRET_KEY,
1035
1095
  ...(process.env.MINIO_REGION ? { region: process.env.MINIO_REGION } : {}),
1036
- defaultTtlSec: ((v) => (v !== undefined && Number.isInteger(v) && v >= 0 ? v : 0))(process.env.SEND_USER_FILE_URL_TTL !== undefined ? Number(process.env.SEND_USER_FILE_URL_TTL) : undefined),
1096
+ defaultTtlSec: sendUserFileUrlTtlKnob(process.env.SEND_USER_FILE_URL_TTL),
1037
1097
  }
1038
1098
  : undefined,
1039
1099
  };
@@ -1339,7 +1399,7 @@ function findUnmatchableToolNames(names, opts) {
1339
1399
  if (opts.consumer === "tool-name-table") {
1340
1400
  const ccGuidance = ccRuleFormGuidance(name);
1341
1401
  if (ccGuidance !== undefined) {
1342
- out.push({ name, guidance: ccGuidance, reason: "cc_rule_form" });
1402
+ out.push({ name, guidance: ccGuidance, reason: CC_RULE_FORM });
1343
1403
  continue;
1344
1404
  }
1345
1405
  }
@@ -1395,7 +1455,6 @@ export function approvalGrantRefusal(names) {
1395
1455
  }
1396
1456
  function streamApprovalConfig(gates) {
1397
1457
  const cfg = {
1398
- enabled: boolEnv("STREAM_APPROVAL_ENABLED", true),
1399
1458
  windowMs: numEnv("STREAM_ASK_WINDOW_MS", gates.windowMsSource === "posture" ? "86400000" : "300000"),
1400
1459
  replayMax: numEnv("STREAM_APPROVAL_REPLAY_MAX", "50"),
1401
1460
  admitMaxPerTask: numEnv("STREAM_APPROVAL_ADMIT_MAX_PER_TASK", "32"),
@@ -1419,7 +1478,7 @@ function streamApprovalConfig(gates) {
1419
1478
  if (cfg.windowMs + cfg.adhocGraceMs >= cfg.orphanTtlMs) {
1420
1479
  throw new Error(`env STREAM_ASK_WINDOW_MS=${cfg.windowMs} + STREAM_APPROVAL_ADHOC_GRACE_MS=${cfg.adhocGraceMs} must be STRICTLY LESS than STREAM_APPROVAL_ORPHAN_TTL_MS=${cfg.orphanTtlMs} — the adhoc arm fires at (createdAt + window + grace) while the orphan backstop fires at (createdAt + ttl); if the backstop wins, every adhoc-leg row is attributed "orphan_ttl_exceeded" instead of "adhoc_leg_no_durable_domain" (attribution honesty, design/172 §6.1)`);
1421
1480
  }
1422
- const suspendedRowsPossible = cfg.enabled && gates.toolApprovalEnabled && gates.unattendedPolicy !== "deny";
1481
+ const suspendedRowsPossible = gates.toolApprovalEnabled && gates.unattendedPolicy !== "deny";
1423
1482
  if (suspendedRowsPossible && cfg.unreachedTtlMs + cfg.adhocGraceMs >= cfg.orphanTtlMs) {
1424
1483
  throw new Error(`env UNREACHED_ASK_TTL_MS=${cfg.unreachedTtlMs} + STREAM_APPROVAL_ADHOC_GRACE_MS=${cfg.adhocGraceMs} must be STRICTLY LESS than STREAM_APPROVAL_ORPHAN_TTL_MS=${cfg.orphanTtlMs} — an ask minted with NO live stream (case A: a workflow child ask) waits UNREACHED_ASK_TTL_MS, so its row expires at (createdAt + that window); the orphan backstop fires at (createdAt + ttl). If the backstop wins, every suspended row is attributed "orphan_ttl_exceeded" instead of its real cause (attribution honesty, same rule as the STREAM_ASK_WINDOW_MS line above)`);
1425
1484
  }
@@ -1997,7 +2056,6 @@ function parseAuthDomain(ctx) {
1997
2056
  const authTokens = parseServiceAuthTokens(process.env.SERVICE_AUTH_TOKENS);
1998
2057
  return {
1999
2058
  bindHost: process.env.BIND_HOST || undefined,
2000
- bindHostSource: process.env.BIND_HOST ? "BIND_HOST" : undefined,
2001
2059
  authToken: process.env.SERVICE_AUTH_TOKEN,
2002
2060
  authTokens,
2003
2061
  allowUnauthedWrites: boolEnv("ALLOW_UNAUTHED_WRITES", false),
@@ -2007,6 +2065,7 @@ function parseAuthDomain(ctx) {
2007
2065
  autonomy: parseAutonomy(process.env.AUTONOMY),
2008
2066
  ...parseGovernanceDeclarations(),
2009
2067
  operatorPrincipals: csv("OPERATOR_PRINCIPALS"),
2068
+ operatorDrainPrincipals: csv("OPERATOR_DRAIN_PRINCIPALS"),
2010
2069
  operatorSingleUser: boolEnv("OPERATOR_SINGLE_USER", false),
2011
2070
  serviceTokenActsForDeployment: boolEnv("SERVICE_TOKEN_ACTS_FOR_DEPLOYMENT", true),
2012
2071
  configCatalogEnabled: boolEnv("CONFIG_CATALOG_ENABLED", true),
@@ -2127,23 +2186,8 @@ function parseOrchestrationDomain(ctx) {
2127
2186
  ? entryDeclarableRemoteExec(declaredLane)
2128
2187
  :
2129
2188
  declaredLane === "local-docker" && process.env.DOCKER_IMAGE
2130
- ? {
2131
- provider: "local-docker",
2132
- image: process.env.DOCKER_IMAGE,
2133
- ...(process.env.DOCKER_MOUNT_PATH ? { mountPath: process.env.DOCKER_MOUNT_PATH } : {}),
2134
- ...(process.env.DOCKER_PATH ? { dockerPath: process.env.DOCKER_PATH } : {}),
2135
- ...(process.env.DOCKER_HOST ? { dockerHost: process.env.DOCKER_HOST } : {}),
2136
- ...(process.env.DOCKER_MEMORY ? { memory: process.env.DOCKER_MEMORY } : {}),
2137
- ...((n) => (n !== undefined ? { cpus: n } : {}))(optNumEnvStrict("DOCKER_CPUS")),
2138
- ...((n) => (n !== undefined ? { pidsLimit: n } : {}))(optFinitePositiveEnv("DOCKER_PIDS_LIMIT")),
2139
- ...(boolEnv("DOCKER_DROP_CAPS", false) ? { dropAllCaps: true } : {}),
2140
- ...(process.env.DOCKER_NETWORK
2141
- ? { network: enumEnv("DOCKER_NETWORK", "bridge", ["none", "bridge", "host"]) }
2142
- : {}),
2143
- ...((n) => (n !== undefined ? { commandTimeoutMs: n } : {}))(optNumEnvStrict("DOCKER_COMMAND_TIMEOUT_MS")),
2144
- ...((names) => (names !== undefined ? { env: allowlistedEnv(names, process.env) } : {}))(parseEnvNameAllowlist("DOCKER_SANDBOX_ENV", singleUserTurnkey)),
2145
- ...((capacity) => (capacity !== undefined ? { capacity } : {}))(parseLocalDockerCapacityEnv()),
2146
- }
2189
+ ?
2190
+ { provider: "local-docker", ...parseLocalDockerLaneEnv(singleUserTurnkey), image: process.env.DOCKER_IMAGE }
2147
2191
  :
2148
2192
  declaredLane === "device"
2149
2193
  ? {
@@ -2488,12 +2532,14 @@ function parseCenterBaseUrl(name, raw, role) {
2488
2532
  }
2489
2533
  function parseWebAdmin(baseUrl, requirePrincipal, liveBaseUrl, webBaseUrl) {
2490
2534
  const worker = process.env[WEB_ADMIN_ENV.worker] || undefined;
2491
- const declared = readCenterCredentialDeclaration();
2535
+ const declared = readWebAdminCredentialDeclaration("access");
2536
+ const assertion = credentialOriginOf(readWebAdminCredentialDeclaration("assertion"));
2492
2537
  return {
2493
2538
  baseUrl,
2494
2539
  ...(liveBaseUrl !== undefined ? { liveBaseUrl } : {}),
2495
2540
  ...(webBaseUrl !== undefined ? { webBaseUrl } : {}),
2496
2541
  credential: createCenterCredentialSource(declared.from === "file" ? { ...declared, multiTenant: requirePrincipal } : declared, worker),
2542
+ ...(assertion.from !== "absent" ? { assertionToken: assertion } : {}),
2497
2543
  dryRun: boolEnv(WEB_ADMIN_ENV.dryRun, false),
2498
2544
  worker,
2499
2545
  };
@@ -2651,8 +2697,8 @@ const MEMORY_GROUP_KEYS = [
2651
2697
  const AUTH_GROUP_KEYS = [
2652
2698
  "authToken", "authTokens", "allowUnauthedWrites", "corsOrigins", "principalHeader", "requirePrincipal", "autonomy",
2653
2699
  "commandPolicy", "compliancePosture", "lockedConfigKeys", "retentionPolicy", "retentionSweep",
2654
- "operatorPrincipals", "operatorSingleUser", "serviceTokenActsForDeployment", "configCatalogEnabled", "principalJwtPubkeys", "principalJwtIss", "principalJwtAud",
2655
- "principalJwtMaxTtlSec", "authBridgeIssuer", "bindHost", "bindHostSource",
2700
+ "operatorPrincipals", "operatorDrainPrincipals", "operatorSingleUser", "serviceTokenActsForDeployment", "configCatalogEnabled", "principalJwtPubkeys", "principalJwtIss", "principalJwtAud",
2701
+ "principalJwtMaxTtlSec", "authBridgeIssuer", "bindHost",
2656
2702
  ];
2657
2703
  const ORCHESTRATION_GROUP_KEYS = [
2658
2704
  "sandboxGit", "remoteExec", "remoteExecHomeDir", "worktreeIsolation", "leaderEnabled", "leaderFanoutEnabled", "routerEnabled", "selfOrchestrationEnabled",
@@ -2750,7 +2796,7 @@ function k8sWorkspaceStore() {
2750
2796
  secretKey,
2751
2797
  ...(process.env.MINIO_REGION ? { region: process.env.MINIO_REGION } : {}),
2752
2798
  ...(keyPrefix !== undefined ? { keyPrefix } : {}),
2753
- ...((n) => (n !== undefined ? { presignTtlSec: n } : {}))(optNumEnvStrict("WORKSPACE_SNAPSHOT_TTL_SEC")),
2799
+ ...((n) => (n !== undefined ? { presignTtlSec: n } : {}))(workspaceSnapshotTtlKnob(process.env.WORKSPACE_SNAPSHOT_TTL_SEC)),
2754
2800
  },
2755
2801
  };
2756
2802
  }
@@ -2825,7 +2871,7 @@ export function loadConfig() {
2825
2871
  throw new Error(retentionRefusal);
2826
2872
  }
2827
2873
  const { directApprovalDoor, durableApproval: dgDurable, approvalHmacKeys: dgHmacKeys } = approval;
2828
- const { principalJwtPubkeys, principalJwtIss, principalJwtAud, operatorPrincipals: dgOperators, operatorSingleUser, authTokens } = auth;
2874
+ const { principalJwtPubkeys, principalJwtIss, principalJwtAud, operatorPrincipals: dgOperators, operatorDrainPrincipals, operatorSingleUser, authTokens } = auth;
2829
2875
  const directDoorActive = directApprovalDoor && dgDurable && dgHmacKeys.length > 0 && principalJwtPubkeys.length > 0 && !!principalJwtIss && !!principalJwtAud;
2830
2876
  const doorRefusal = halfOpenDirectDoorRefusal({
2831
2877
  directApprovalDoor,
@@ -2844,10 +2890,14 @@ export function loadConfig() {
2844
2890
  if (operatorsRefusal !== undefined) {
2845
2891
  throw new Error(operatorsRefusal);
2846
2892
  }
2847
- const singleUserOperatorRefusal = operatorSingleUserRefusal({ operatorSingleUser, requirePrincipal, operatorPrincipals: dgOperators });
2893
+ const singleUserOperatorRefusal = operatorSingleUserRefusal({ operatorSingleUser, requirePrincipal, operatorPrincipals: dgOperators, operatorDrainPrincipals });
2848
2894
  if (singleUserOperatorRefusal !== undefined) {
2849
2895
  throw new Error(singleUserOperatorRefusal);
2850
2896
  }
2897
+ const rosterRefusal = operatorRosterWellFormedRefusal({ operatorPrincipals: dgOperators, operatorDrainPrincipals });
2898
+ if (rosterRefusal !== undefined) {
2899
+ throw new Error(rosterRefusal);
2900
+ }
2851
2901
  const bakeOperatorsRefusal = bakeOperatorPrincipalsRefusal({ imageBakes: orchestration.imageBakes, operatorPrincipals: dgOperators });
2852
2902
  if (bakeOperatorsRefusal !== undefined) {
2853
2903
  throw new Error(bakeOperatorsRefusal);
@@ -0,0 +1,51 @@
1
+ import type { Server } from "node:http";
2
+ /** 开不了口的原因词(闭集;`listening` 行的 `controlSocketUnavailable` 取值;顺序 = 开口序)。 */
3
+ export declare const CONTROL_SOCKET_UNAVAILABLE_REASONS: readonly ["unsupported_platform", "data_root_not_exclusive", "path_too_long", "dir_not_private", "path_occupied", "bind_failed"];
4
+ export type ControlSocketUnavailableReason = (typeof CONTROL_SOCKET_UNAVAILABLE_REASONS)[number];
5
+ /** 开口的结局:在听(绝对路径)或缺席(原因词)—— 恰一形。 */
6
+ export type ControlSocketOpening = {
7
+ readonly listening: true;
8
+ readonly path: string;
9
+ } | {
10
+ readonly listening: false;
11
+ readonly reason: ControlSocketUnavailableReason;
12
+ };
13
+ /** 数据根(锁所守的物理路径)→ 控制 socket 的绝对路径。唯一推导:`listening` 行报的、开口判的、附着方连的是同一只。 */
14
+ export declare function controlSocketPathOf(physicalDataRoot: string): string;
15
+ /** 私有判的读数(`lstat`,不跟符号链接)。`absent` = 不在;`unreadable` = 读不出(按不私有处置)。 */
16
+ export type ControlPathReading = {
17
+ readonly kind: "absent";
18
+ } | {
19
+ readonly kind: "unreadable";
20
+ } | {
21
+ readonly kind: "directory" | "socket" | "symlink" | "other";
22
+ readonly uid: number;
23
+ readonly mode: number;
24
+ };
25
+ /** 读一只路径(`lstat`)。不在 ⇒ `absent`;别的读错 ⇒ `unreadable`。 */
26
+ export declare function readControlPath(path: string): ControlPathReading;
27
+ /** `control/` 私有吗:是目录(不是符号链接)∧ 属主 = `euid` ∧ 无组 / 他人位。任何别的读数 ⇒ 否。 */
28
+ export declare function controlDirIsPrivate(reading: ControlPathReading, euid: number): boolean;
29
+ /** `engine.sock` 是不是本用户的 socket:是 socket(不是符号链接)∧ 属主 = `euid`。任何别的读数 ⇒ 否。 */
30
+ export declare function controlSocketIsOwned(reading: ControlPathReading, euid: number): boolean;
31
+ export interface ControlSocketOpenOptions {
32
+ /** 本进程持锁独占的物理数据根(`StoreBackend.exclusiveDataRoot()`);缺席 ⇒ 不开口。 */
33
+ readonly exclusiveDataRoot: string | undefined;
34
+ /** 平台读数(缺省 = 全仓唯一平台读点 `HOST_PLATFORM`)。 */
35
+ readonly platform?: string;
36
+ /** 属主判对照的 euid(缺省 `process.geteuid()`)。 */
37
+ readonly euid?: number;
38
+ }
39
+ /**
40
+ * 在 `server`(控制口那只 `http.Server`,`createHttpServer` 交出的 `controlSocketServer`)上开控制 socket —— 判序见头注。
41
+ * 结局恰一形;`listening: false` 时 `server` 不在听(绑上又判不过的那一形已先关)。调用点:TCP listen 成功之后、`listening` 行之前(起服第 10 段)。
42
+ */
43
+ export declare function openControlSocket(server: Server, opts: ControlSocketOpenOptions): Promise<ControlSocketOpening>;
44
+ /** `listening` 行的两键 —— 同一次开口结局的投影,恰一键在场(`controlSocket` ⟺ 在听;`controlSocketUnavailable` ⟺ 缺席)。 */
45
+ export interface ControlSocketLineKeys {
46
+ readonly controlSocket?: string;
47
+ readonly controlSocketUnavailable?: ControlSocketUnavailableReason;
48
+ }
49
+ /** 开口结局 → `listening` 行两键(唯一投影)。 */
50
+ export declare function controlSocketLineKeysOf(opening: ControlSocketOpening): ControlSocketLineKeys;
51
+ //# sourceMappingURL=control-socket.d.ts.map
@@ -0,0 +1,115 @@
1
+ import { lstatSync, unlinkSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { ensureDir } from "@sema-agent/core";
4
+ import { HOST_PLATFORM } from "./plugins/host-platform.js";
5
+ export const CONTROL_SOCKET_UNAVAILABLE_REASONS = ["unsupported_platform", "data_root_not_exclusive", "path_too_long", "dir_not_private", "path_occupied", "bind_failed"];
6
+ const SUN_PATH_MAX_BYTES = {
7
+ darwin: 104,
8
+ linux: 107,
9
+ aix: "unsupported",
10
+ android: "unsupported",
11
+ freebsd: "unsupported",
12
+ haiku: "unsupported",
13
+ openbsd: "unsupported",
14
+ sunos: "unsupported",
15
+ win32: "unsupported",
16
+ cygwin: "unsupported",
17
+ netbsd: "unsupported",
18
+ };
19
+ export function controlSocketPathOf(physicalDataRoot) {
20
+ return join(physicalDataRoot, "control", "engine.sock");
21
+ }
22
+ function readingOf(stats) {
23
+ const kind = stats.isSymbolicLink() ? "symlink" : stats.isDirectory() ? "directory" : stats.isSocket() ? "socket" : "other";
24
+ return { kind, uid: stats.uid, mode: stats.mode };
25
+ }
26
+ export function readControlPath(path) {
27
+ try {
28
+ return readingOf(lstatSync(path));
29
+ }
30
+ catch (err) {
31
+ return err.code === "ENOENT" ? { kind: "absent" } : { kind: "unreadable" };
32
+ }
33
+ }
34
+ export function controlDirIsPrivate(reading, euid) {
35
+ return reading.kind === "directory" && reading.uid === euid && (reading.mode & 0o077) === 0;
36
+ }
37
+ export function controlSocketIsOwned(reading, euid) {
38
+ return reading.kind === "socket" && reading.uid === euid;
39
+ }
40
+ function sunPathMaxBytesOf(platform) {
41
+ if (!Object.hasOwn(SUN_PATH_MAX_BYTES, platform))
42
+ return undefined;
43
+ const limit = SUN_PATH_MAX_BYTES[platform];
44
+ return typeof limit === "number" ? limit : undefined;
45
+ }
46
+ const unavailable = (reason) => ({ listening: false, reason });
47
+ async function ioStep(act) {
48
+ try {
49
+ await act();
50
+ return { ok: true };
51
+ }
52
+ catch (error) {
53
+ return { ok: false, error };
54
+ }
55
+ }
56
+ function listenOn(server, path) {
57
+ return new Promise((resolve, reject) => {
58
+ const onError = (err) => reject(err);
59
+ server.once("error", onError);
60
+ server.listen(path, () => {
61
+ server.removeListener("error", onError);
62
+ resolve();
63
+ });
64
+ });
65
+ }
66
+ export async function openControlSocket(server, opts) {
67
+ const maxBytes = sunPathMaxBytesOf(opts.platform ?? HOST_PLATFORM);
68
+ if (maxBytes === undefined)
69
+ return unavailable("unsupported_platform");
70
+ const euid = opts.euid ?? process.geteuid?.();
71
+ if (euid === undefined)
72
+ return unavailable("unsupported_platform");
73
+ const root = opts.exclusiveDataRoot;
74
+ if (root === undefined)
75
+ return unavailable("data_root_not_exclusive");
76
+ const path = controlSocketPathOf(root);
77
+ if (Buffer.byteLength(path, "utf8") > maxBytes)
78
+ return unavailable("path_too_long");
79
+ const dir = dirname(path);
80
+ await ioStep(() => ensureDir(dir));
81
+ if (!controlDirIsPrivate(readControlPath(dir), euid))
82
+ return unavailable("dir_not_private");
83
+ const existing = readControlPath(path);
84
+ switch (existing.kind) {
85
+ case "absent":
86
+ break;
87
+ case "socket":
88
+ if (!controlSocketIsOwned(existing, euid))
89
+ return unavailable("path_occupied");
90
+ if (!(await ioStep(() => unlinkSync(path))).ok)
91
+ return unavailable("bind_failed");
92
+ break;
93
+ case "directory":
94
+ case "symlink":
95
+ case "other":
96
+ return unavailable("path_occupied");
97
+ case "unreadable":
98
+ return unavailable("bind_failed");
99
+ default: {
100
+ const unknownReading = existing;
101
+ throw new Error(`control socket: unknown path reading ${JSON.stringify(unknownReading)}`);
102
+ }
103
+ }
104
+ if (!(await ioStep(() => listenOn(server, path))).ok)
105
+ return unavailable("bind_failed");
106
+ if (!controlSocketIsOwned(readControlPath(path), euid) || !controlDirIsPrivate(readControlPath(dir), euid)) {
107
+ await new Promise((resolve) => server.close(() => resolve()));
108
+ return unavailable("bind_failed");
109
+ }
110
+ return { listening: true, path };
111
+ }
112
+ export function controlSocketLineKeysOf(opening) {
113
+ return opening.listening ? { controlSocket: opening.path } : { controlSocketUnavailable: opening.reason };
114
+ }
115
+ //# sourceMappingURL=control-socket.js.map
@@ -64,7 +64,8 @@ export interface PathAdjudication {
64
64
  * · `durable` —— checkpoint suspend/resume 服 ask(HTTP 腿 durable 开、park 赎回腿)。core 的问答策略
65
65
  * (`createDurableQuestionPolicy()`,原形逐字)**只**叠在这一形上:它对引擎的问题工具答 `ask`,落点归 core 的同步优先
66
66
  * (有问题席 ⇒ 先投卡、席在窗内拿到答即交答;没拿到 ⇒ 停驻 —— 卡由活面呈出而窗走完的那一问除外:席抛,引擎的投递失败臂不停驻)。
67
- * · `live` —— Runner 的活 onAsk 席当场服 ask(run-local 的 `createLocalApprover`:TTY 问 y/N / 无 TTY 当场拒;
67
+ * · `live` —— Runner 的活 onAsk 席当场服 ask(run-local 的 `createLocalApprover`:TTY 问 y/N / 无 TTY 当场拒;leader 车道不耐久的腿
68
+ * (`leader/leader.ts` `leaderLegDurability` 判为不耐久:各修复腿、没递停驻设施或续跑上下文没落的 worker)的无人值守层:答集内的类按策略答,其余交回 core 的缺席路 —— 这条腿没有停驻设施 ⇒ 拒;
68
69
  * core `isLiveApproverSeat(onAsk)` 为真时 `suspendAsk` 早退,ask 落回调)。三张名单与 durable 席**同一只**策略。
69
70
  * · `absent` —— 没有谁服 ask ⇒ adjudicated allow-all;**只**服务零名单(HTTP 腿「durable 关 ∧ 单用户零意图」)。
70
71
  * 带名单进来 = 响亮拒:名单被一条没有席的腿静默吞掉,正是 [ref] 的病形。
@@ -17,7 +17,7 @@
17
17
  * `holds` 的入参型 = 所声明轴读入形的交叉({@link DeploymentShapeInput}),所以调用方递完整 `ServiceConfig` 或只递那几键的窄形都行。
18
18
  *
19
19
  * ## 什么进表、什么不进
20
- * 进表的是**形规则**:只由部署形事实决定的布尔(去重后 15 行;同一条规则的多个消费者读同一行,不各成一行)。
20
+ * 进表的是**形规则**:只由部署形事实决定的布尔(去重后 16 行;同一条规则的多个消费者读同一行,不各成一行)。
21
21
  * 把一行与**非形事实**(锁键、合规档位、审批意图、请求身份、请求体)合取的能力判据是**消费者**,住在它自己的模块
22
22
  * (`mcpInjectionHonored` = 锁 ∧ 合规 ∧ `!multiTenant`;`taskHooksHonored`;身份门 …),读行、不读原始键。
23
23
  * 车道表(`execution-lane-caps.ts`)按车道词键控的布尔列(`laneIsolated` 等)是车道轴自己的事实表,不是「部署」的谓词;行读它们。
@@ -111,6 +111,14 @@ export declare const DEPLOYMENT_SHAPE_PREDICATES: Readonly<{
111
111
  * 一次性迁移 M48 的输入(`plugins/store-backend.ts`:有边界 ⇒ 不改写哨兵属主)。
112
112
  */
113
113
  identityBoundary: DeploymentShapePredicate<"principal" | "identity">;
114
+ /**
115
+ * 「这台部署接没接**过凭据门**的来源」的问法 —— 身份来源律 5(`identity-source.ts` 头注)在部署上的投影:配置接了的来源里有凭据门认的那一类
116
+ * (service 凭据,或鉴权桥 issuer —— 含中心回退;`passesCredentialGate` 那一列)。**不是** {@link DEPLOYMENT_SHAPE_PREDICATES.identityBoundary}:
117
+ * 那一行把 `REQUIRE_PRINCIPAL` / 只读 trace 凭据 / 直连门也算作边界(它们让主体头不再是 dev-open 的自报),本行只问「有没有一类凭据过得了门」——
118
+ * 三样都不过,所以只配其中之一的部署两行答案相反,这是两问,不是一问两答。没接 ⇒ 写门(问请求)对每一次请求都拒(`ALLOW_UNAUTHED_WRITES` 之外)。
119
+ * 读者:记忆整理阀门的启动期告警(`boot/stage-06-runners.ts`;「这台部署上 run 口对谁都开不了」)。请求面不读本行:写门问的是请求。
120
+ */
121
+ credentialGateSource: DeploymentShapePredicate<"identity">;
114
122
  /**
115
123
  * 租户轴的问法。今天与 {@link DEPLOYMENT_SHAPE_PREDICATES.principalRequired} 读**同一个声明**([ref] ①:托管 / 多租 ⇔ `REQUIRE_PRINCIPAL=true`,
116
124
  * 签发方配置是身份验签轴、不算租户证据)—— 两个问题、一根轴、一个读口;「鉴权必需」与「多租形」拆成两个声明时只改这一行的判官。
@@ -1,5 +1,5 @@
1
1
  import { capabilitiesFor, executionLaneCaps, executionLaneOf, handsOnWorkerFilePlane, laneWiresExecutionEnv } from "./execution-lane-caps.js";
2
- import { configuredIdentitySources } from "./identity-source.js";
2
+ import { configuredIdentitySources, passesCredentialGate } from "./identity-source.js";
3
3
  function readPrincipalAxis(deployment) {
4
4
  return { declared: deployment.requirePrincipal === true };
5
5
  }
@@ -54,6 +54,7 @@ const VM_ISOLATION_RUNTIME_CLASSES = new Set(["kata", "kata-qemu", "kata-clh", "
54
54
  export const DEPLOYMENT_SHAPE_PREDICATES = Object.freeze({
55
55
  principalRequired: createPredicate(["principal"], "身份轴:运维声明了 REQUIRE_PRINCIPAL=true —— 每个调用方都必须带一个验过的主体。", ({ principal }) => principal.declared),
56
56
  identityBoundary: createPredicate(["principal", "identity"], "身份轴:这台部署有身份边界 —— 声明了 REQUIRE_PRINCIPAL,或配置接了任一已验身份来源(service 凭据 / 鉴权桥 / 直连门),或声明了只读 trace 凭据。", ({ principal, identity }) => principal.declared || identity.sources.length > 0 || identity.traceTokenDeclared),
57
+ credentialGateSource: createPredicate(["identity"], "身份轴:这台部署接了一类过凭据门的来源 —— service 凭据,或鉴权桥(登录令牌);只开 REQUIRE_PRINCIPAL / 只配 trace 凭据 / 只开直连门都不算。", ({ identity }) => identity.sources.some(passesCredentialGate)),
57
58
  multiTenant: createPredicate(["principal"], "租户轴:这台部署服务不止一个主人(托管 / 多租;C-R100 ① 由 REQUIRE_PRINCIPAL=true 声明)。", ({ principal }) => principal.declared),
58
59
  callerCwd: createPredicate(["lane", "principal"], "车道 × 租户 / 设备归属:调用方送来的 cwd(与 settings.env)被尊重 —— host 车道且单主,或 device 车道。", ({ lane, principal }) => lane.caps !== undefined && capabilityHolds(lane.caps.callerCwd, principal)),
59
60
  callerOwnsWorkerDisk: createPredicate(["lane", "principal"], "车道 × 租户:手就在本 worker 的盘上且部署只有一个主人 —— 这块盘上的路径就是调用方自己的。", ({ lane, principal }) => lane.lane !== undefined && handsOnWorkerFilePlane(lane.lane) && !principal.declared),
@@ -7,11 +7,12 @@
7
7
  *
8
8
  * 为什么是精选而不是把 `device-ws-protocol.ts` 整只暴露:那个模块里还有**服务端**自己的半场(帧解析与准入、
9
9
  * 验签、各种铸 id)。把它们变成公开面,等于替实现细节背上 semver。这里只再导出 executor **会用到**的:
10
- * 闭集常量、两向帧型、构造握手签名字节所需的两只纯函数,以及两份「随协议修订号走」的事实:结局码按修订号分行的增量表
11
- * (`DEVICE_OUTCOME_ERROR_CODES_BY_REVISION` + 取集函数 `deviceOutcomeErrorCodesAt`:executor 按自己声明的修订号裁剪会发的词)与
10
+ * 闭集常量、两向帧型、构造握手签名字节所需的两只纯函数,以及三份「随协议修订号走」的事实:结局码按修订号分行的增量表
11
+ * (`DEVICE_OUTCOME_ERROR_CODES_BY_REVISION` + 取集函数 `deviceOutcomeErrorCodesAt`:executor 按自己声明的修订号裁剪会发的词)、指令 kind 按修订号分行的增量表
12
+ * (`DEVICE_INSTRUCTION_KINDS_BY_REVISION` + 取集函数 `deviceInstructionKindsAt`:executor 按自己声明的修订号裁剪 `hello.supports` —— 高于它的 kind 声明了也不会下发)与
12
13
  * helloAck 数值位的界表(`DEVICE_HELLO_ACK_BOUNDS` + 判据 `deviceHelloAckNumberFlaw`:executor 读到越界值 ⇒ 协议违例)。要加名字 = 改这只文件 + 同批改
13
14
  * `test/device-protocol-subpath.test.ts` 的闭集(新增公开面必须是一次有意的动作)。
14
15
  */
15
- export { DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_HELLO_DOMAIN_TAG, DEVICE_WS_LIMITS, DEVICE_FRAME_TYPES, DEVICE_SERVER_FRAME_TYPES, DEVICE_HELLO_REJECT_CODES, DEVICE_BYE_REASONS, DEVICE_GOODBYE_REASONS, DEVICE_CHUNK_KINDS, DEVICE_CANCEL_STATES, DEVICE_INSTRUCTION_KINDS, DEVICE_OUTCOME_ERROR_CODES, DEVICE_OUTCOME_ERROR_CODES_BY_REVISION, DEVICE_HELLO_ACK_BOUNDS, buildHelloSignaturePayload, decodeUlid16, deviceOutcomeErrorCodesAt, deviceHelloAckNumberFlaw, } from "./device-ws-protocol.js";
16
- export type { DeviceFrameType, DeviceServerFrameType, DeviceHelloRejectCode, DeviceByeReason, DeviceGoodbyeReason, DeviceChunkKind, DeviceCancelState, DeviceInstructionKind, DeviceOutcomeErrorCode, DeviceProtocolRevision, DeviceHelloAckNumericField, WireFileInfo, WireWriteExpectation, DeviceInstructionOutcome, DeviceInstructionArgsByKind, DeviceChallengeFrame, DeviceHelloAckFrame, DeviceHelloRejectFrame, DeviceInstructionFrame, DevicePayloadFrame, DeviceServerFrame, DeviceHelloFrame, DeviceFrame, DeviceResultFrame, DeviceChunkFrame, DeviceGoodbyeFrame, DeviceHeartbeatFrame, } from "./device-ws-protocol.js";
16
+ export { DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_HELLO_DOMAIN_TAG, DEVICE_WS_LIMITS, DEVICE_FRAME_TYPES, DEVICE_SERVER_FRAME_TYPES, DEVICE_HELLO_REJECT_CODES, DEVICE_BYE_REASONS, DEVICE_GOODBYE_REASONS, DEVICE_CHUNK_KINDS, DEVICE_CANCEL_STATES, DEVICE_INSTRUCTION_KINDS, DEVICE_INSTRUCTION_KINDS_BY_REVISION, DEVICE_BOUND_READ_OPS, DEVICE_OUTCOME_ERROR_CODES, DEVICE_OUTCOME_ERROR_CODES_BY_REVISION, DEVICE_HELLO_ACK_BOUNDS, buildHelloSignaturePayload, decodeUlid16, deviceOutcomeErrorCodesAt, deviceInstructionKindsAt, deviceHelloAckNumberFlaw, } from "./device-ws-protocol.js";
17
+ export type { DeviceFrameType, DeviceServerFrameType, DeviceHelloRejectCode, DeviceByeReason, DeviceGoodbyeReason, DeviceChunkKind, DeviceCancelState, DeviceInstructionKind, DeviceBoundReadOp, DeviceOutcomeErrorCode, DeviceProtocolRevision, DeviceHelloAckNumericField, WireFileInfo, WireWriteExpectation, DeviceInstructionOutcome, DeviceInstructionArgsByKind, DeviceChallengeFrame, DeviceHelloAckFrame, DeviceHelloRejectFrame, DeviceInstructionFrame, DevicePayloadFrame, DeviceServerFrame, DeviceHelloFrame, DeviceFrame, DeviceResultFrame, DeviceChunkFrame, DeviceGoodbyeFrame, DeviceHeartbeatFrame, } from "./device-ws-protocol.js";
17
18
  //# sourceMappingURL=device-protocol.d.ts.map
@@ -1,2 +1,2 @@
1
- export { DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_HELLO_DOMAIN_TAG, DEVICE_WS_LIMITS, DEVICE_FRAME_TYPES, DEVICE_SERVER_FRAME_TYPES, DEVICE_HELLO_REJECT_CODES, DEVICE_BYE_REASONS, DEVICE_GOODBYE_REASONS, DEVICE_CHUNK_KINDS, DEVICE_CANCEL_STATES, DEVICE_INSTRUCTION_KINDS, DEVICE_OUTCOME_ERROR_CODES, DEVICE_OUTCOME_ERROR_CODES_BY_REVISION, DEVICE_HELLO_ACK_BOUNDS, buildHelloSignaturePayload, decodeUlid16, deviceOutcomeErrorCodesAt, deviceHelloAckNumberFlaw, } from "./device-ws-protocol.js";
1
+ export { DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_HELLO_DOMAIN_TAG, DEVICE_WS_LIMITS, DEVICE_FRAME_TYPES, DEVICE_SERVER_FRAME_TYPES, DEVICE_HELLO_REJECT_CODES, DEVICE_BYE_REASONS, DEVICE_GOODBYE_REASONS, DEVICE_CHUNK_KINDS, DEVICE_CANCEL_STATES, DEVICE_INSTRUCTION_KINDS, DEVICE_INSTRUCTION_KINDS_BY_REVISION, DEVICE_BOUND_READ_OPS, DEVICE_OUTCOME_ERROR_CODES, DEVICE_OUTCOME_ERROR_CODES_BY_REVISION, DEVICE_HELLO_ACK_BOUNDS, buildHelloSignaturePayload, decodeUlid16, deviceOutcomeErrorCodesAt, deviceInstructionKindsAt, deviceHelloAckNumberFlaw, } from "./device-ws-protocol.js";
2
2
  //# sourceMappingURL=device-protocol.js.map
@@ -40,6 +40,7 @@ import { type DeviceOwner, type DeviceStore } from "./device-store.js";
40
40
  import type { DeviceEnrollment, DeviceRejection } from "./device-enrollment.js";
41
41
  import { type CidrSet } from "./net-address.js";
42
42
  import { type DeviceChunkKind, type DeviceInstructionArgsByKind, type DeviceInstructionKind, type DeviceInstructionOutcome } from "./device-ws-protocol.js";
43
+ import type { NonPersonTier } from "./operator-roster.js";
43
44
  /** 交给调用方的一片上行流(`data` 已从 base64 解回字节)。 */
44
45
  export interface DeviceChunkDelivery {
45
46
  streamSeq: number;
@@ -129,6 +130,12 @@ export interface DeviceWsHubOptions {
129
130
  enrollment: DeviceEnrollment;
130
131
  /** 本副本 id(写进连接租约行,跨副本排障用)。 */
131
132
  replicaId: string;
133
+ /**
134
+ * hello 准入的属主圈禁读者:这一台设备行的属主此刻落在名册的哪一档**非人档**(圈禁,`undefined` = 不圈禁)。答「是」⇒ `helloReject: auth_failed`,不夺租约、不顶替旧连接。
135
+ * 汇聚端自己不 import 名册、不判档位:判官只有一只(`http/principal-gate.ts` 的 `confinedTierOf`,设备读点 `deviceOwnerConfinedTier`),装配方(`boot/device-lane.ts`)把它连进来。
136
+ * **必填**:可选会让漏接静默(没接 = 不圈禁,安全轴上的静默放宽)—— 漏接编译红。每次 hello 现读(名册是现态,不拍快照);读者抛 ⇒ 握手失败、连接关(`device_hello_failed`),不放行。
137
+ */
138
+ ownerConfinedTier: (owner: DeviceOwner) => NonPersonTier | undefined;
132
139
  logger?: DeviceWsHubLogger;
133
140
  metrics?: {
134
141
  inc(name: string, labels?: Record<string, string>): void;
@@ -5,7 +5,7 @@ import { WebSocketServer } from "ws";
5
5
  import { DEVICE_DRAINING_CODE, DEVICE_ERROR_CODES, DEVICE_ERROR_STATUS, assertDeviceIdShape, } from "./device-store.js";
6
6
  import { MAX_TIMER_DELAY_MS } from "./config-types.js";
7
7
  import { canonicalAddress, createTrustedProxySet } from "./net-address.js";
8
- import { DEVICE_HELLO_ACK_BOUNDS, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_WS_LIMITS, DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, asInstructionKind, buildHelloSignaturePayload, deviceHelloAckNumberFlaw, deviceProtocolRevisionRefusal, formatGeneration, mintChallengeNonce, mintInstructionId, parseDeviceFrameText, verifyHelloSignature, } from "./device-ws-protocol.js";
8
+ import { DEVICE_HELLO_ACK_BOUNDS, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_WS_LIMITS, DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, asInstructionKindAt, buildHelloSignaturePayload, deviceHelloAckNumberFlaw, deviceProtocolRevisionRefusal, formatGeneration, mintChallengeNonce, mintInstructionId, parseDeviceFrameText, verifyHelloSignature, } from "./device-ws-protocol.js";
9
9
  const OUTCOME_UNKNOWN_SENTENCE = "outcome unknown — the command may have already executed on the device; verify its effect before re-running";
10
10
  const SETTLED_MEMO_MAX = 512;
11
11
  const DRAIN_RETRY_AFTER_SEC = 15;
@@ -66,6 +66,7 @@ const ALLOWED_SUCCESS_OUTCOME_KINDS = {
66
66
  remove: ["void"],
67
67
  createTempDir: ["write"],
68
68
  createTempFile: ["write"],
69
+ openBound: ["stat", "read"],
69
70
  };
70
71
  const HELLO_ACK_FIELD_SOURCES = {
71
72
  heartbeatIntervalMs: "option heartbeatIntervalMs",
@@ -120,7 +121,7 @@ function forwardedHopAddress(hop) {
120
121
  return canonicalAddress(t);
121
122
  }
122
123
  export function createDeviceWsHub(options) {
123
- const { store, enrollment, replicaId, logger, metrics } = options;
124
+ const { store, enrollment, replicaId, ownerConfinedTier, logger, metrics } = options;
124
125
  const heartbeatIntervalMs = options.heartbeatIntervalMs ?? 15_000;
125
126
  const heartbeatMisses = options.heartbeatMisses ?? 3;
126
127
  const leaseSeconds = options.leaseSeconds ?? 45;
@@ -437,6 +438,12 @@ export function createDeviceWsHub(options) {
437
438
  }
438
439
  if (row.status === "revoked")
439
440
  return rejectHello(conn, "revoked");
441
+ const confined = ownerConfinedTier(row.owner);
442
+ if (confined !== undefined) {
443
+ logger?.warn("device_hello_owner_confined", { deviceId: row.deviceId, tier: confined });
444
+ metrics?.inc("device_hello_rejected_total", { code: "auth_failed" });
445
+ return rejectHello(conn, "auth_failed");
446
+ }
440
447
  const existing = conns.get(row.deviceId);
441
448
  if (existing && existing !== conn) {
442
449
  const fresh = Date.now() - existing.lastFrameAt < heartbeatIntervalMs * heartbeatMisses;
@@ -500,7 +507,7 @@ export function createDeviceWsHub(options) {
500
507
  conn.workspaceRoot = frame.workspaceRoot;
501
508
  const supported = new Set();
502
509
  for (const s of frame.supports) {
503
- const k = asInstructionKind(s);
510
+ const k = asInstructionKindAt(s, frame.protocolVersion);
504
511
  if (k !== null)
505
512
  supported.add(k);
506
513
  }