@sema-agent/server 7.131.0 → 7.133.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/MIGRATION.md +575 -0
  2. package/README.md +12 -9
  3. package/README.zh-CN.md +9 -6
  4. package/USAGE.md +326 -98
  5. package/deploy/sema-up/README.md +19 -1
  6. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
  7. package/deploy/sema-up/chart/templates/server.yaml +5 -2
  8. package/deploy/sema-up/stack/compose.yaml +3 -0
  9. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  10. package/dist/adoption/plan.d.ts +3 -2
  11. package/dist/adoption/plan.js +7 -5
  12. package/dist/adoption/runner.js +3 -10
  13. package/dist/adoption/sql.d.ts +3 -2
  14. package/dist/adoption/sql.js +3 -5
  15. package/dist/adoption/wire.d.ts +4 -1
  16. package/dist/adoption/wire.js +1 -0
  17. package/dist/approval-ask-audit-store.d.ts +31 -13
  18. package/dist/approval-ask-audit-store.js +272 -74
  19. package/dist/approval-ask-machine.d.ts +15 -0
  20. package/dist/approval-ask-machine.js +6 -0
  21. package/dist/approval-ask-retention.d.ts +136 -0
  22. package/dist/approval-ask-retention.js +102 -0
  23. package/dist/approval-card.d.ts +82 -20
  24. package/dist/approval-card.js +46 -16
  25. package/dist/approval-deny-reasons.d.ts +1 -1
  26. package/dist/approval.d.ts +9 -0
  27. package/dist/approval.js +24 -3
  28. package/dist/audit.d.ts +33 -19
  29. package/dist/audit.js +12 -16
  30. package/dist/auth-bridge.d.ts +4 -0
  31. package/dist/auth-bridge.js +10 -11
  32. package/dist/bake-runner/main.js +3 -2
  33. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  34. package/dist/boot/deployment-mods.d.ts +31 -0
  35. package/dist/boot/deployment-mods.js +26 -0
  36. package/dist/boot/execution-env.d.ts +1 -1
  37. package/dist/boot/execution-env.js +27 -12
  38. package/dist/boot/execution-lane.js +11 -0
  39. package/dist/boot/leader.js +2 -0
  40. package/dist/boot/memory-boundary.d.ts +2 -2
  41. package/dist/boot/memory-boundary.js +2 -2
  42. package/dist/boot/memory-consolidation.d.ts +5 -4
  43. package/dist/boot/memory-consolidation.js +7 -6
  44. package/dist/boot/org-delivery.d.ts +28 -0
  45. package/dist/boot/org-delivery.js +20 -0
  46. package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
  47. package/dist/boot/read-deny-anchor-audit.js +36 -0
  48. package/dist/boot/reapers.d.ts +3 -0
  49. package/dist/boot/reapers.js +21 -1
  50. package/dist/boot/resolve-spec.d.ts +4 -5
  51. package/dist/boot/resolve-spec.js +74 -123
  52. package/dist/boot/runner-deps.d.ts +19 -8
  53. package/dist/boot/runner-deps.js +15 -2
  54. package/dist/boot/session-faces.d.ts +2 -7
  55. package/dist/boot/session-faces.js +4 -2
  56. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  57. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  58. package/dist/boot/stage-03-store-backend.js +2 -2
  59. package/dist/boot/stage-04-stores.d.ts +1 -1
  60. package/dist/boot/stage-05-execution-env.d.ts +4 -4
  61. package/dist/boot/stage-05-execution-env.js +7 -10
  62. package/dist/boot/stage-06-runners.d.ts +4 -2
  63. package/dist/boot/stage-06-runners.js +11 -7
  64. package/dist/boot/stage-07-capability-layer.d.ts +4 -2
  65. package/dist/boot/stage-07-capability-layer.js +27 -6
  66. package/dist/boot/stage-08-reapers.d.ts +4 -2
  67. package/dist/boot/stage-08-reapers.js +2 -2
  68. package/dist/boot/stage-09-leader.d.ts +6 -9
  69. package/dist/boot/stage-10-http-server.d.ts +6 -9
  70. package/dist/boot/stage-10-http-server.js +7 -9
  71. package/dist/boot/stores.d.ts +1 -1
  72. package/dist/boot/stores.js +7 -8
  73. package/dist/boot/web-admin.d.ts +4 -3
  74. package/dist/boot/web-admin.js +186 -98
  75. package/dist/boot/workflow-orchestration.d.ts +2 -0
  76. package/dist/boot/workflow-orchestration.js +2 -1
  77. package/dist/brain.js +25 -25
  78. package/dist/breaker-key.d.ts +6 -0
  79. package/dist/breaker-key.js +29 -0
  80. package/dist/budget.js +5 -4
  81. package/dist/caller-text-echo.d.ts +23 -0
  82. package/dist/caller-text-echo.js +21 -0
  83. package/dist/capabilities/brand-identity.d.ts +26 -0
  84. package/dist/capabilities/brand-identity.js +27 -0
  85. package/dist/capabilities/center-plugins.d.ts +7 -0
  86. package/dist/capabilities/center-plugins.js +1 -1
  87. package/dist/capabilities/center-prompts.d.ts +32 -59
  88. package/dist/capabilities/center-prompts.js +18 -32
  89. package/dist/capabilities/composite-members.d.ts +1 -1
  90. package/dist/capabilities/composite-members.js +1 -1
  91. package/dist/capabilities/engine-capabilities.js +2 -1
  92. package/dist/capabilities/execution-lane.js +2 -2
  93. package/dist/capabilities/hands-lane.d.ts +30 -6
  94. package/dist/capabilities/hands-lane.js +11 -1
  95. package/dist/capabilities/mcp-probe.d.ts +48 -3
  96. package/dist/capabilities/mcp-probe.js +47 -135
  97. package/dist/capabilities/scenarios.d.ts +95 -45
  98. package/dist/capabilities/scenarios.js +53 -38
  99. package/dist/capabilities/skills.d.ts +19 -4
  100. package/dist/capabilities/skills.js +30 -10
  101. package/dist/capability-facts.d.ts +34 -4
  102. package/dist/capability-facts.js +28 -2
  103. package/dist/center-config-tier.d.ts +69 -0
  104. package/dist/center-config-tier.js +42 -0
  105. package/dist/checkpoint-identity.d.ts +16 -0
  106. package/dist/checkpoint-identity.js +19 -0
  107. package/dist/config-catalog.d.ts +17 -10
  108. package/dist/config-catalog.js +47 -32
  109. package/dist/config-d-migration.d.ts +3 -1
  110. package/dist/config-d-migration.js +2 -2
  111. package/dist/config-dir-trust.d.ts +114 -0
  112. package/dist/config-dir-trust.js +388 -0
  113. package/dist/config-invariants.d.ts +18 -5
  114. package/dist/config-invariants.js +35 -3
  115. package/dist/config-lkg.d.ts +9 -9
  116. package/dist/config-lkg.js +20 -4
  117. package/dist/config-provider.d.ts +9 -2
  118. package/dist/config-provider.js +18 -6
  119. package/dist/config-types.d.ts +75 -20
  120. package/dist/config-types.js +8 -0
  121. package/dist/config.d.ts +13 -0
  122. package/dist/config.js +137 -62
  123. package/dist/delegated-session-owner.d.ts +185 -0
  124. package/dist/delegated-session-owner.js +119 -0
  125. package/dist/device-protocol.d.ts +5 -3
  126. package/dist/device-protocol.js +1 -1
  127. package/dist/device-ws-hub.js +21 -2
  128. package/dist/device-ws-protocol.d.ts +70 -6
  129. package/dist/device-ws-protocol.js +50 -22
  130. package/dist/elicitation.js +3 -2
  131. package/dist/entry-problems.d.ts +34 -0
  132. package/dist/entry-problems.js +14 -0
  133. package/dist/env-name-allowlist-knobs.d.ts +12 -2
  134. package/dist/env-name-allowlist-knobs.js +5 -4
  135. package/dist/exec-bounds.d.ts +15 -3
  136. package/dist/exec-bounds.js +4 -0
  137. package/dist/execution-lane-caps.d.ts +56 -10
  138. package/dist/execution-lane-caps.js +50 -0
  139. package/dist/field-conflict.d.ts +43 -0
  140. package/dist/field-conflict.js +20 -0
  141. package/dist/fleet/fleet-bus.d.ts +80 -6
  142. package/dist/fleet/fleet-bus.js +41 -9
  143. package/dist/hooks/classic-stations.d.ts +91 -0
  144. package/dist/hooks/classic-stations.js +27 -0
  145. package/dist/hooks/command-spawn.d.ts +57 -0
  146. package/dist/hooks/command-spawn.js +139 -0
  147. package/dist/hooks/hook-llm.d.ts +8 -5
  148. package/dist/hooks/hook-llm.js +79 -36
  149. package/dist/hooks/hook-runner.d.ts +349 -95
  150. package/dist/hooks/hook-runner.js +855 -568
  151. package/dist/hooks/hook-source.d.ts +44 -0
  152. package/dist/hooks/hook-source.js +40 -0
  153. package/dist/http/active-run-conflict.d.ts +5 -13
  154. package/dist/http/active-run-conflict.js +17 -27
  155. package/dist/http/admission.d.ts +8 -2
  156. package/dist/http/admission.js +188 -101
  157. package/dist/http/approval-sweeps.js +99 -21
  158. package/dist/http/caller-trust.d.ts +77 -0
  159. package/dist/http/caller-trust.js +143 -0
  160. package/dist/http/checkpoint-ctx.d.ts +41 -24
  161. package/dist/http/checkpoint-ctx.js +23 -16
  162. package/dist/http/claimed-run.d.ts +14 -0
  163. package/dist/http/claimed-run.js +15 -0
  164. package/dist/http/device-placement.d.ts +2 -4
  165. package/dist/http/device-placement.js +7 -11
  166. package/dist/http/dispatch.d.ts +0 -4
  167. package/dist/http/dispatch.js +15 -13
  168. package/dist/http/durable-run-leg.d.ts +6 -33
  169. package/dist/http/durable-run-leg.js +36 -10
  170. package/dist/http/health-self-report.d.ts +7 -5
  171. package/dist/http/health-self-report.js +4 -18
  172. package/dist/http/owner-access.d.ts +56 -0
  173. package/dist/http/owner-access.js +42 -0
  174. package/dist/http/principal-gate.d.ts +70 -28
  175. package/dist/http/principal-gate.js +61 -15
  176. package/dist/http/readiness.d.ts +11 -5
  177. package/dist/http/readiness.js +10 -3
  178. package/dist/http/refusal-body.d.ts +21 -0
  179. package/dist/http/refusal-body.js +4 -0
  180. package/dist/http/request-guards.d.ts +43 -23
  181. package/dist/http/request-guards.js +53 -17
  182. package/dist/http/resume-ctx-read.d.ts +2 -5
  183. package/dist/http/resume-ctx-read.js +7 -4
  184. package/dist/http/resume-legs.d.ts +28 -4
  185. package/dist/http/resume-legs.js +169 -91
  186. package/dist/http/retired-service-deps.d.ts +43 -0
  187. package/dist/http/retired-service-deps.js +18 -0
  188. package/dist/http/route-ctx.d.ts +44 -28
  189. package/dist/http/route-ctx.js +4 -0
  190. package/dist/http/route-table.js +2 -0
  191. package/dist/http/routes/a2a-serve.js +3 -4
  192. package/dist/http/routes/admin-config-refresh.js +1 -1
  193. package/dist/http/routes/admin-drain.js +1 -1
  194. package/dist/http/routes/admin-memory-optout.js +5 -1
  195. package/dist/http/routes/adoption.js +2 -9
  196. package/dist/http/routes/approvals-assistant.js +49 -48
  197. package/dist/http/routes/background.js +3 -2
  198. package/dist/http/routes/capabilities.js +21 -5
  199. package/dist/http/routes/config-catalog.d.ts +3 -3
  200. package/dist/http/routes/config-catalog.js +1 -1
  201. package/dist/http/routes/devices.js +3 -17
  202. package/dist/http/routes/diagnostics.js +6 -2
  203. package/dist/http/routes/images.js +6 -7
  204. package/dist/http/routes/leader.js +1 -8
  205. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  206. package/dist/http/routes/mcp-reconnect.js +3 -2
  207. package/dist/http/routes/memory-bundle.js +1 -1
  208. package/dist/http/routes/memory-compliance.js +1 -1
  209. package/dist/http/routes/memory-consolidation.js +1 -1
  210. package/dist/http/routes/memory-origin.js +1 -1
  211. package/dist/http/routes/memory-policy.d.ts +1 -1
  212. package/dist/http/routes/memory-policy.js +3 -2
  213. package/dist/http/routes/notify-wake.js +8 -21
  214. package/dist/http/routes/observability.js +2 -2
  215. package/dist/http/routes/principal-inbox.d.ts +39 -0
  216. package/dist/http/routes/principal-inbox.js +76 -0
  217. package/dist/http/routes/retention-ops.js +2 -9
  218. package/dist/http/routes/rules.js +5 -18
  219. package/dist/http/routes/runs.d.ts +5 -0
  220. package/dist/http/routes/runs.js +34 -107
  221. package/dist/http/routes/session-sync.js +15 -26
  222. package/dist/http/routes/sessions.js +30 -40
  223. package/dist/http/routes/shared-memory.js +2 -13
  224. package/dist/http/routes/side-query.js +8 -7
  225. package/dist/http/routes/tasks.js +67 -21
  226. package/dist/http/routes/workflows.d.ts +351 -0
  227. package/dist/http/routes/workflows.js +153 -119
  228. package/dist/http/send.d.ts +33 -10
  229. package/dist/http/send.js +21 -4
  230. package/dist/http/server.d.ts +27 -18
  231. package/dist/http/server.js +34 -6
  232. package/dist/http/stored-body-replay.js +17 -4
  233. package/dist/http/submit-ctx.d.ts +25 -0
  234. package/dist/http/submit-ctx.js +40 -0
  235. package/dist/http/submit-replay.d.ts +4 -3
  236. package/dist/http/submit-replay.js +5 -4
  237. package/dist/http/wire-types.d.ts +11 -8
  238. package/dist/index.d.ts +2 -2
  239. package/dist/index.js +1 -2
  240. package/dist/lane-home-probe.d.ts +112 -0
  241. package/dist/lane-home-probe.js +101 -0
  242. package/dist/leader/endpoint.d.ts +4 -1
  243. package/dist/leader/endpoint.js +11 -10
  244. package/dist/limit-refusal.d.ts +59 -0
  245. package/dist/limit-refusal.js +15 -0
  246. package/dist/main.js +1 -1
  247. package/dist/mcp-assertion-header.d.ts +32 -19
  248. package/dist/mcp-assertion-header.js +10 -9
  249. package/dist/mcp-tool-faces.d.ts +5 -0
  250. package/dist/mcp-tool-faces.js +6 -4
  251. package/dist/memory-project-layer.d.ts +37 -0
  252. package/dist/memory-project-layer.js +46 -0
  253. package/dist/memory-scope.d.ts +24 -17
  254. package/dist/memory-scope.js +24 -8
  255. package/dist/memory-sync-client.d.ts +27 -13
  256. package/dist/memory-sync-client.js +107 -18
  257. package/dist/model-entry-refusal.d.ts +9 -1
  258. package/dist/model-entry-refusal.js +6 -1
  259. package/dist/model-plane-face.d.ts +51 -0
  260. package/dist/model-plane-face.js +24 -0
  261. package/dist/model-provider.d.ts +44 -12
  262. package/dist/model-provider.js +21 -2
  263. package/dist/model-route-endpoint.d.ts +9 -12
  264. package/dist/model-route-endpoint.js +8 -11
  265. package/dist/model-route-env.d.ts +22 -0
  266. package/dist/model-route-env.js +2 -0
  267. package/dist/model-route-gap.d.ts +60 -30
  268. package/dist/model-route-gap.js +21 -15
  269. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  270. package/dist/observability/corrupt-read-seat.js +9 -0
  271. package/dist/observability/cost-taxonomy.d.ts +7 -7
  272. package/dist/observability/err-text.d.ts +6 -0
  273. package/dist/observability/err-text.js +18 -4
  274. package/dist/observability/fail-open.d.ts +76 -14
  275. package/dist/observability/fail-open.js +76 -14
  276. package/dist/observability/metrics.js +4 -1
  277. package/dist/observability/prompt-manifest.d.ts +33 -82
  278. package/dist/observability/prompt-manifest.js +122 -17
  279. package/dist/observability/run-terminal.js +14 -6
  280. package/dist/observability/secret-env-scrub.d.ts +13 -1
  281. package/dist/observability/secret-env-scrub.js +13 -1
  282. package/dist/observability/tool-trace.d.ts +16 -21
  283. package/dist/observability/tool-trace.js +58 -49
  284. package/dist/operator-ask.d.ts +10 -0
  285. package/dist/operator-ask.js +3 -0
  286. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  287. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  288. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  289. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  290. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  291. package/dist/orchestration/workflow-notify-journal.js +27 -34
  292. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  293. package/dist/orchestration/workflow-park-decision.js +118 -0
  294. package/dist/org-delivery-gate.d.ts +81 -0
  295. package/dist/org-delivery-gate.js +59 -0
  296. package/dist/panel-tool-names.d.ts +23 -0
  297. package/dist/panel-tool-names.js +8 -0
  298. package/dist/parked-decide.d.ts +39 -6
  299. package/dist/parked-decide.js +98 -51
  300. package/dist/parked-revive-surface.d.ts +9 -2
  301. package/dist/parked-revive-surface.js +11 -8
  302. package/dist/per-task-image.d.ts +7 -1
  303. package/dist/per-task-image.js +3 -3
  304. package/dist/permission-rule-list.d.ts +1 -1
  305. package/dist/permission-rule-list.js +2 -2
  306. package/dist/plain-string-record.d.ts +25 -0
  307. package/dist/plain-string-record.js +32 -0
  308. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  309. package/dist/plugins/approval-ask-store-file.js +21 -0
  310. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  311. package/dist/plugins/approval-ask-store-memory.js +34 -2
  312. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  313. package/dist/plugins/approval-ask-store-sql.js +37 -1
  314. package/dist/plugins/blob-backend.d.ts +83 -15
  315. package/dist/plugins/blob-backend.js +68 -15
  316. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  317. package/dist/plugins/breaker-state-sql.js +4 -4
  318. package/dist/plugins/caching-session-store.d.ts +3 -0
  319. package/dist/plugins/caching-session-store.js +3 -0
  320. package/dist/plugins/checkpoint-store-sql.d.ts +28 -4
  321. package/dist/plugins/checkpoint-store-sql.js +59 -28
  322. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  323. package/dist/plugins/file-history-store-sql.js +3 -1
  324. package/dist/plugins/file-run-store.d.ts +5 -13
  325. package/dist/plugins/file-run-store.js +9 -0
  326. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  327. package/dist/plugins/fork-routing-session-store.js +12 -1
  328. package/dist/plugins/host-platform.d.ts +2 -0
  329. package/dist/plugins/host-platform.js +2 -1
  330. package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
  331. package/dist/plugins/k8s-bg-scripts.js +22 -0
  332. package/dist/plugins/local-checkpoint-store.d.ts +2 -0
  333. package/dist/plugins/local-checkpoint-store.js +11 -3
  334. package/dist/plugins/local-session-store.d.ts +1 -1
  335. package/dist/plugins/local-session-store.js +1 -1
  336. package/dist/plugins/local-session-window.d.ts +39 -0
  337. package/dist/plugins/local-session-window.js +54 -0
  338. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  339. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  340. package/dist/plugins/mailbox-store-sql.js +77 -52
  341. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  342. package/dist/plugins/memory-run-store.d.ts +5 -13
  343. package/dist/plugins/memory-run-store.js +8 -0
  344. package/dist/plugins/one-time-migrations.d.ts +245 -93
  345. package/dist/plugins/one-time-migrations.js +668 -207
  346. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  347. package/dist/plugins/org-delivery-quota-store.js +228 -0
  348. package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
  349. package/dist/plugins/permission-rule-store-sql.js +4 -18
  350. package/dist/plugins/pg-pool.js +39 -7
  351. package/dist/plugins/pg-session-storage.d.ts +20 -8
  352. package/dist/plugins/pg-session-storage.js +34 -21
  353. package/dist/plugins/remote-env-adb.d.ts +12 -12
  354. package/dist/plugins/remote-env-adb.js +21 -6
  355. package/dist/plugins/remote-env-device.js +3 -0
  356. package/dist/plugins/remote-env-e2b.d.ts +1 -1
  357. package/dist/plugins/remote-env-e2b.js +21 -9
  358. package/dist/plugins/remote-env-host.d.ts +9 -9
  359. package/dist/plugins/remote-env-host.js +10 -32
  360. package/dist/plugins/remote-env-k8s.d.ts +103 -38
  361. package/dist/plugins/remote-env-k8s.js +288 -95
  362. package/dist/plugins/remote-env-local-docker.d.ts +27 -13
  363. package/dist/plugins/remote-env-local-docker.js +82 -11
  364. package/dist/plugins/remote-env-ssh.d.ts +21 -12
  365. package/dist/plugins/remote-env-ssh.js +117 -5
  366. package/dist/plugins/remote-shell.d.ts +0 -1
  367. package/dist/plugins/remote-shell.js +1 -2
  368. package/dist/plugins/retention-store-sql.js +6 -2
  369. package/dist/plugins/run-store-sql.d.ts +16 -14
  370. package/dist/plugins/run-store-sql.js +22 -2
  371. package/dist/plugins/schema-consistency.d.ts +54 -0
  372. package/dist/plugins/schema-consistency.js +52 -0
  373. package/dist/plugins/schema-indexes.js +2 -0
  374. package/dist/plugins/send-user-file.js +2 -2
  375. package/dist/plugins/session-epoch-anchor.d.ts +39 -0
  376. package/dist/plugins/session-epoch-anchor.js +22 -0
  377. package/dist/plugins/session-store.d.ts +18 -8
  378. package/dist/plugins/session-store.js +15 -4
  379. package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
  380. package/dist/plugins/shared-memory-store-sql.js +5 -16
  381. package/dist/plugins/sql-driver.d.ts +205 -1
  382. package/dist/plugins/sql-driver.js +325 -13
  383. package/dist/plugins/sql-errors.d.ts +64 -0
  384. package/dist/plugins/sql-errors.js +57 -0
  385. package/dist/plugins/store-backend.d.ts +36 -1
  386. package/dist/plugins/store-backend.js +42 -15
  387. package/dist/plugins/store-contracts.d.ts +42 -0
  388. package/dist/plugins/store-contracts.js +1 -0
  389. package/dist/plugins/tidb-pool.d.ts +6 -1
  390. package/dist/plugins/tidb-pool.js +44 -10
  391. package/dist/plugins/tidb-session-storage.d.ts +8 -11
  392. package/dist/plugins/tidb-session-storage.js +6 -16
  393. package/dist/plugins/tidb-session-store.d.ts +24 -4
  394. package/dist/plugins/tidb-session-store.js +29 -5
  395. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  396. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  397. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  398. package/dist/plugins/workflow-run-store-sql.js +50 -9
  399. package/dist/posture-source.d.ts +18 -10
  400. package/dist/posture-source.js +4 -1
  401. package/dist/project-identity.d.ts +45 -6
  402. package/dist/project-identity.js +162 -8
  403. package/dist/project-layer-key.d.ts +28 -0
  404. package/dist/project-layer-key.js +29 -0
  405. package/dist/prompts-domain-validate.d.ts +17 -61
  406. package/dist/prompts-domain-validate.js +9 -119
  407. package/dist/question.js +3 -2
  408. package/dist/read-deny-entry.d.ts +25 -0
  409. package/dist/read-deny-entry.js +12 -0
  410. package/dist/read-face-posture.d.ts +37 -11
  411. package/dist/read-face-posture.js +32 -3
  412. package/dist/request-key-closure.d.ts +9 -2
  413. package/dist/request-key-closure.js +11 -5
  414. package/dist/request-value-closure.d.ts +5 -0
  415. package/dist/request-value-closure.js +11 -3
  416. package/dist/rule-entry-list.d.ts +38 -11
  417. package/dist/rule-entry-list.js +106 -30
  418. package/dist/rules-consent.js +3 -4
  419. package/dist/run-acceptance.d.ts +19 -3
  420. package/dist/run-acceptance.js +13 -1
  421. package/dist/run-local.js +54 -24
  422. package/dist/runs.d.ts +15 -8
  423. package/dist/runs.js +35 -1
  424. package/dist/runtime-caps-resolver.d.ts +16 -6
  425. package/dist/runtime-caps-resolver.js +18 -5
  426. package/dist/sandbox-pkg-source.d.ts +19 -1
  427. package/dist/sandbox-pkg-source.js +29 -7
  428. package/dist/security.d.ts +87 -9
  429. package/dist/security.js +52 -9
  430. package/dist/server-secret-env.d.ts +44 -18
  431. package/dist/server-secret-env.js +49 -8
  432. package/dist/session-error-wire.d.ts +19 -2
  433. package/dist/session-error-wire.js +5 -1
  434. package/dist/session-incarnation.d.ts +15 -5
  435. package/dist/session-incarnation.js +16 -9
  436. package/dist/session-titled-frame.d.ts +33 -0
  437. package/dist/session-titled-frame.js +4 -0
  438. package/dist/session-titler.d.ts +9 -1
  439. package/dist/session-titler.js +27 -6
  440. package/dist/spec-fields.d.ts +28 -16
  441. package/dist/spec-fields.js +66 -54
  442. package/dist/sql-engine-posture.d.ts +31 -4
  443. package/dist/sql-engine-posture.js +36 -1
  444. package/dist/stored-request-tool-axes-m19.d.ts +19 -4
  445. package/dist/stored-request-tool-axes-m19.js +30 -2
  446. package/dist/task-a2a.d.ts +9 -1
  447. package/dist/task-a2a.js +73 -47
  448. package/dist/task-cwd.d.ts +1 -1
  449. package/dist/task-mcp.d.ts +46 -58
  450. package/dist/task-mcp.js +82 -107
  451. package/dist/task-settings.d.ts +95 -108
  452. package/dist/task-settings.js +77 -98
  453. package/dist/text-bidi.d.ts +1 -48
  454. package/dist/text-bidi.js +3 -5
  455. package/dist/tighten-only-seats.d.ts +150 -0
  456. package/dist/tighten-only-seats.js +196 -0
  457. package/dist/tool-approval.d.ts +304 -88
  458. package/dist/tool-approval.js +623 -239
  459. package/dist/trace/core-keyset-guard.d.ts +122 -20
  460. package/dist/trace/engine-notice-wire.d.ts +11 -3
  461. package/dist/trace/engine-notice-wire.js +8 -1
  462. package/dist/trace/exit-seat.d.ts +28 -0
  463. package/dist/trace/exit-seat.js +76 -0
  464. package/dist/trace/ledger-events.d.ts +6 -3
  465. package/dist/trace/ledger-sink.js +4 -1
  466. package/dist/trace/model-segment.js +1 -1
  467. package/dist/trace/project.d.ts +98 -17
  468. package/dist/trace/project.js +98 -50
  469. package/dist/trace/projection-table.d.ts +100 -0
  470. package/dist/trace/projection-table.js +130 -0
  471. package/dist/trace/redact.d.ts +54 -0
  472. package/dist/trace/redact.js +778 -152
  473. package/dist/trace/self-minted-wire.d.ts +345 -1
  474. package/dist/trace/self-minted-wire.js +117 -1
  475. package/dist/trace/wire-projection-faces.d.ts +377 -3
  476. package/dist/trace/wire-projection-faces.js +164 -1
  477. package/dist/url-refusal.js +2 -0
  478. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  479. package/dist/web-admin-client/apply-effective.js +56 -5
  480. package/dist/web-admin-client/candidate-gate.d.ts +6 -6
  481. package/dist/web-admin-client/candidate-gate.js +3 -3
  482. package/dist/web-admin-client/facade.d.ts +1 -1
  483. package/dist/web-admin-client/facade.js +1 -1
  484. package/dist/web-admin-client/http-client.js +0 -6
  485. package/dist/web-admin-client/read-face.js +5 -9
  486. package/dist/web-admin-client/read-warnings.d.ts +13 -0
  487. package/dist/web-admin-client/read-warnings.js +10 -0
  488. package/dist/web-admin-client/skills-mcp.d.ts +3 -0
  489. package/dist/web-admin-client/skills-mcp.js +11 -9
  490. package/dist/web-admin-client/types.d.ts +2 -3
  491. package/dist/workspace-cache.d.ts +35 -0
  492. package/dist/workspace-cache.js +36 -0
  493. package/dist/workspace-space.d.ts +3 -2
  494. package/dist/workspace-space.js +2 -0
  495. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +65 -10
  496. package/package.json +8 -4
  497. package/scripts/drain-check-local.mjs +34 -1
  498. package/scripts/drain-check.mysql.sql +30 -2
  499. package/scripts/drain-check.pg.sql +29 -2
  500. package/dist/capabilities/memory-notice.d.ts +0 -138
  501. package/dist/capabilities/memory-notice.js +0 -64
  502. package/dist/capabilities/prompt.d.ts +0 -17
  503. package/dist/capabilities/prompt.js +0 -6
  504. package/dist/mcp-content-origin.d.ts +0 -34
  505. package/dist/mcp-content-origin.js +0 -10
  506. package/dist/tool-axis-words.d.ts +0 -27
  507. package/dist/tool-axis-words.js +0 -9
  508. package/dist/wire-name-bound.d.ts +0 -14
  509. package/dist/wire-name-bound.js +0 -13
@@ -8,7 +8,8 @@ export function authBridgeIssuerOf(config) {
8
8
  return { issuer: config.webAdmin.baseUrl, source: "fallback" };
9
9
  return undefined;
10
10
  }
11
- const DEFAULT_JWKS_TTL_SEC = 15 * 60;
11
+ export const DEFAULT_JWKS_TTL_SEC = 15 * 60;
12
+ export const JWKS_FETCH_TIMEOUT_MS = 10_000;
12
13
  const MAX_JWKS_BYTES = 256 * 1024;
13
14
  const MAX_TOKEN_CHARS = 16 * 1024;
14
15
  const MAX_SEGMENT_BYTES = 64 * 1024;
@@ -39,6 +40,7 @@ export function createWebAdminJwtVerifier(opts) {
39
40
  let lastFetchAttemptMs;
40
41
  let lastFetchSuccessMs;
41
42
  let inflight;
43
+ const withinGrace = () => lastFetchSuccessMs !== undefined && jwksWithinOfflineGrace({ lastFetchSuccessMs, nowMs: now() }, { offlineGraceSec });
42
44
  const fail = (error, kid) => {
43
45
  opts.metrics?.inc("auth_bridge_verify_total", { outcome: error });
44
46
  opts.logger?.warn?.("auth_bridge_rejected", { error, ...(kid ? { kid: kid.slice(0, 128) } : {}), iss: displayIssuer });
@@ -50,7 +52,7 @@ export function createWebAdminJwtVerifier(opts) {
50
52
  inflight = (async () => {
51
53
  lastFetchAttemptMs = now();
52
54
  try {
53
- const res = await doFetch(jwksUrl, { redirect: "error", signal: AbortSignal.timeout(10_000) });
55
+ const res = await doFetch(jwksUrl, { redirect: "error", signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS) });
54
56
  if (!res.ok)
55
57
  throw new Error(`jwks HTTP ${res.status}`);
56
58
  const cl = Number(res.headers.get("content-length"));
@@ -112,8 +114,9 @@ export function createWebAdminJwtVerifier(opts) {
112
114
  return fail("unknown_issuer", kid);
113
115
  if (classifyTimeClaims(payload, Math.floor(now() / 1000), clockSkewSec) !== "ok")
114
116
  return fail("expired", kid);
115
- const snapshot = () => ({ cachedKids: [...keys.keys()], lastFetchAttemptMs, nowMs: now() });
116
- if (keys.has(kid)) {
117
+ const usableKey = () => (withinGrace() ? keys.get(kid) : undefined);
118
+ const snapshot = () => ({ cachedKids: withinGrace() ? [...keys.keys()] : [], lastFetchAttemptMs, nowMs: now() });
119
+ if (usableKey()) {
117
120
  const ttlStale = lastFetchSuccessMs === undefined || now() - lastFetchSuccessMs > jwksTtlSec * 1000;
118
121
  if (ttlStale && !inflight && (lastFetchAttemptMs === undefined || now() - lastFetchAttemptMs >= refreshMin * 1000)) {
119
122
  void refreshJwks();
@@ -122,16 +125,12 @@ export function createWebAdminJwtVerifier(opts) {
122
125
  else {
123
126
  if (inflight)
124
127
  await inflight;
125
- if (!keys.has(kid) && shouldForceJwksRefresh(kid, snapshot(), { jwksRefreshMinIntervalSec: refreshMin }))
128
+ if (!usableKey() && shouldForceJwksRefresh(kid, snapshot(), { jwksRefreshMinIntervalSec: refreshMin }))
126
129
  await refreshJwks();
127
130
  }
128
- const key = keys.get(kid);
131
+ const key = usableKey();
129
132
  if (!key) {
130
- const graceOk = lastFetchSuccessMs !== undefined && jwksWithinOfflineGrace({ lastFetchSuccessMs, nowMs: now() }, { offlineGraceSec });
131
- return graceOk ? fail("invalid_signature", kid) : fail("jwks_unavailable", kid);
132
- }
133
- if (lastFetchSuccessMs !== undefined && !jwksWithinOfflineGrace({ lastFetchSuccessMs, nowMs: now() }, { offlineGraceSec })) {
134
- return fail("jwks_unavailable", kid);
133
+ return withinGrace() ? fail("invalid_signature", kid) : fail("jwks_unavailable", kid);
135
134
  }
136
135
  let sigOk = false;
137
136
  try {
@@ -5,6 +5,7 @@ import { logConfigDiagnostics, parseEnvNameAllowlist, parseNumOrFailNonNegative
5
5
  import { installSecretEnvScrubRecorder } from "../observability/secret-env-scrub.js";
6
6
  import { declareServerWithheldEnv, hostSubprocessEnv } from "../server-secret-env.js";
7
7
  import { shellQuote as shellSafe } from "../plugins/remote-shell.js";
8
+ import { echoCallerText } from "../caller-text-echo.js";
8
9
  import { BakeRunner, } from "./runner.js";
9
10
  const BAKE_CLAIM_INGEST_FETCH_TIMEOUT_MS = 30_000;
10
11
  const BAKE_HEARTBEAT_FETCH_TIMEOUT_MS = 10_000;
@@ -181,9 +182,9 @@ export async function execGroup(cmd, timeoutMs, envAllow) {
181
182
  try {
182
183
  const { code, signal } = await child.exited;
183
184
  if (timedOut)
184
- throw new Error(`host exec timed out after ${timeoutMs}ms (group killed): ${cmd.slice(0, 120)}`);
185
+ throw new Error(`host exec timed out after ${timeoutMs}ms (group killed): ${echoCallerText(cmd, { maxChars: 120 })}`);
185
186
  if (code !== 0)
186
- throw new Error(`host exec exited ${code ?? signal}: ${cmd.slice(0, 120)}${stderr.trim() ? ` — ${stderr.trim().slice(-400)}` : ""}`);
187
+ throw new Error(`host exec exited ${code ?? signal}: ${echoCallerText(cmd, { maxChars: 120 })}${stderr.trim() ? ` — ${stderr.trim().slice(-400)}` : ""}`);
187
188
  return { stdout };
188
189
  }
189
190
  finally {
@@ -118,7 +118,7 @@ export class DeferredSandboxPathEnv extends StubExecutionEnv {
118
118
  reason: found.reason,
119
119
  face,
120
120
  sessionId: this.sessionId ?? null,
121
- note: "the sandbox fs-write gate has no task environment to adjudicate against — every write target fails closed (ask, and deny under the sensitive-path set) until one is bound",
121
+ note: "the sandbox path adjudication has no task environment to read — the sensitive-path guard fails closed (deny) on every write target until one is bound",
122
122
  });
123
123
  }
124
124
  return {
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 部署座(`RunnerDeps.mods`)的注册:**铸**({@link createDeploymentMods})与**起服自证**({@link assertDeploymentModsAdmitted})都在这一处。
3
+ *
4
+ * 起服自证(律三:拒形只有引擎一种读法,本仓只负责「不写」与「启动时自证」):
5
+ * 部署座上的注册是本仓自己铸的。它们坏了
6
+ * —— 坏名、坏档、缺 `uses.calls`、`on` 越出 `uses`、只选无站的名字、`register` 抛 —— 引擎在每条腿的 prepare 里拒
7
+ * (`config.mods_invalid`),那就是每个请求都失败。所以起服时让引擎的 admission 判一次:判官仍是引擎(`admitModChain`),
8
+ * 本函数不判形,只把它的拒折成一句起服错误、拒启。两个起服入口(server 第五段、本地 CLI)同调这一只。
9
+ *
10
+ * 也拒启的两形(同一个理由:部署注册一张都不该缺席,也不该带病挂上):
11
+ * · admission 期的报告(引擎对坏 `budgetMs` 只报告、回落缺省,不拒)—— 部署注册不设 `budgetMs`,报告出现就是铸法坏了;
12
+ * · 被 `plugin.register` 判拒的注册(本部署没有这种判官;出现即装配错)。
13
+ * 腿外 admission 只建一只总线并跑一次各注册的 `register`(本仓的 `register` 是纯函数),不碰任何腿。
14
+ */
15
+ import { type EngineDollar, type ModRegistration } from "@sema-agent/core";
16
+ import type { Logger } from "../observability/logger.js";
17
+ import type { Metrics } from "../observability/metrics.js";
18
+ /**
19
+ * 部署座上的注册列表 —— 两个起服入口(server 第五段与本地 CLI)同一只铸法,哪几张、什么顺序只写在这里:
20
+ * · 拒绝计量恒挂、在前;工具追踪(`TOOL_TRACE=true`,交 `traceLogger`)在后。两张都是 `prepend` 档的观察者,引擎按「档 → 部署先于任务 → 座内顺序」
21
+ * 串行跑观察者、且都在链之前 ⇒ 同一次拒绝先计数、后写追踪行;
22
+ * · 品牌行(`brandIdentity`:品牌部署 = local / TOC)—— `prompt.compose` 上的一条部署类 overlay(`capabilities/brand-identity.ts`),与两只观察者
23
+ * 不在同一个事件上,顺序不影响它们。部署开不开品牌只在这一个入参表态。
24
+ */
25
+ export declare function createDeploymentMods(input: {
26
+ readonly metrics: Pick<Metrics, "inc">;
27
+ readonly traceLogger?: Logger | undefined;
28
+ readonly brandIdentity?: boolean | undefined;
29
+ }): readonly ModRegistration<EngineDollar>[];
30
+ export declare function assertDeploymentModsAdmitted(mods: readonly ModRegistration<EngineDollar>[]): Promise<void>;
31
+ //# sourceMappingURL=deployment-mods.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { admitModChain } from "@sema-agent/core";
2
+ import { createBrandIdentityRegistration } from "../capabilities/brand-identity.js";
3
+ import { createPermissionDeniedMeter, createToolTracer } from "../observability/tool-trace.js";
4
+ export function createDeploymentMods(input) {
5
+ return [
6
+ createPermissionDeniedMeter(input.metrics),
7
+ ...(input.traceLogger !== undefined ? [createToolTracer(input.traceLogger)] : []),
8
+ ...(input.brandIdentity === true ? [createBrandIdentityRegistration()] : []),
9
+ ];
10
+ }
11
+ const REFUSED = "deployment extension registration refused";
12
+ export async function assertDeploymentModsAdmitted(mods) {
13
+ const reports = [];
14
+ let records;
15
+ try {
16
+ ({ records } = await admitModChain({ deployment: mods }, (err) => void reports.push(err.message)));
17
+ }
18
+ catch (e) {
19
+ throw new Error(`${REFUSED}: ${e instanceof Error ? e.message : String(e)}`);
20
+ }
21
+ const refused = records.flatMap((r) => ("refusedBy" in r ? [`"${r.name}" refused by ${r.refusedBy}: ${r.reason}`] : []));
22
+ const problems = [...reports, ...refused];
23
+ if (problems.length > 0)
24
+ throw new Error(`${REFUSED}: ${problems.join("; ")}`);
25
+ }
26
+ //# sourceMappingURL=deployment-mods.js.map
@@ -62,7 +62,7 @@ export declare function createSessionScopedRegistries(maxEntries?: number): Sess
62
62
  * · **工作区空间的分区 = 会话化身**(`spaceOccupant.incarnation`):建这只 env 时按 id 读一次会话店的 `incarnationOf`(会话行上的那一格,
63
63
  * `session-incarnation.ts`;本工厂不取会话,正是 core 给「没取会话的读者」的那只读)。读数是闭集三臂(`SpaceOccupant`,适配器那边逐臂处置):
64
64
  * 答令牌 ⇒ 已知;答 `undefined`(没有这只会话)⇒ `{ unread: "incarnation_unknown" }` —— 没有空间:空间车道不开、缓存卷不挂,各一行;
65
- * 读抛 / 答出的不是非空串 ⇒ `{ fault: <code> }` —— 读不到空间 ≠ 没有空间:开着的空间车道 / 缓存卷让这只 env 一只 pod 都不建,
65
+ * 读抛 / 超时(`rpcTimeoutMs`,同一次 connect 里读围栏行与 `latest` 的那一只墙)/ 答出的不是非空串 ⇒ `{ fault: <code> }` —— 读不到空间 ≠ 没有空间:开着的空间车道 / 缓存卷让这只 env 一只 pod 都不建,
66
66
  * connect 与 resumeVM 都答 `connect_failed`(与 `latest` 读失败同一铸点),一行 `workspace_space_unreadable_occupant`;`code` 是店的错误码,
67
67
  * 从不带正文、从不带令牌。**绝不**以会话 id 代替;
68
68
  * 同时开这只 env 在空间提交围栏上的座(`spaceOccupant.fence`,run 店的 `workspace_space_commit` 行;法见 `workspace-space-commit.ts`);
@@ -10,7 +10,7 @@ import { adbExecutionEnvFactory } from "../plugins/remote-env-adb.js";
10
10
  import { deviceExecutionEnvFactory } from "../plugins/remote-env-device.js";
11
11
  import { e2bExecutionEnvFactory } from "../plugins/remote-env-e2b.js";
12
12
  import { hostExecutionEnvFactory, RemoteHostExecutionEnv } from "../plugins/remote-env-host.js";
13
- import { checkSandboxEgressPolicy, createSpaceReclaimer, K8S_SANDBOX_NAMESPACE_DEFAULT, k8sExecutionEnvFactory } from "../plugins/remote-env-k8s.js";
13
+ import { boundedStoreCall, checkSandboxEgressPolicy, createSpaceReclaimer, K8S_SANDBOX_NAMESPACE_DEFAULT, k8sExecutionEnvFactory, rpcTimeoutMsOf } from "../plugins/remote-env-k8s.js";
14
14
  import { createRunWorkspaceSnapshotSeat } from "../fleet/workspace-snapshot-residual.js";
15
15
  import { createSpaceCommitFence } from "../workspace-space-commit.js";
16
16
  import { localDockerExecutionEnvFactory } from "../plugins/remote-env-local-docker.js";
@@ -20,13 +20,15 @@ import { FileSchedulerBackend, defaultSchedulerStorePath } from "../plugins/sche
20
20
  import * as facts from "../capability-facts.js";
21
21
  import { materializeAttachmentsInto } from "../plugins/task-attachment-store.js";
22
22
  import { reapOrphanWorktrees, withWorktreeIsolation } from "../plugins/worktree-isolation.js";
23
- import { customPkgSourceFromEnv, derivePkgSourceEnv } from "../sandbox-pkg-source.js";
23
+ import { derivePkgSourceEnv } from "../sandbox-pkg-source.js";
24
24
  import { effectiveHostWorkspace } from "../task-cwd.js";
25
25
  import { taskInheritEnvRefusal } from "../hosted-posture.js";
26
+ import { createCacheMissMemory } from "../workspace-cache.js";
26
27
  import { workspaceSnapshotTimeoutOf } from "../workspace-space.js";
27
28
  import { sayEgressPolicyReading } from "../sandbox-egress-policy.js";
28
29
  import { isSandboxPathAdjudicationLane, sandboxPathEnvSlots, withSandboxPathEnvSlot } from "./deferred-sandbox-path-env.js";
29
- import { REMOTE_EXEC_PROVIDER_WORDS, executionLaneHomeDir, executionLaneOf, isSingleMachineDefaultLane, laneBindsReads, laneIsolated } from "../execution-lane-caps.js";
30
+ import { LANE_HOME_UNDECLARED_EVENT, createLaneHomeAbsenceReporter } from "../lane-home-probe.js";
31
+ import { REMOTE_EXEC_PROVIDER_WORDS, buildUndeclaredHomeNote, executionLaneHomeDir, executionLaneOf, isSingleMachineDefaultLane, laneBindsReads, laneIsolated } from "../execution-lane-caps.js";
30
32
  function boundedSessionSetter(map, maxEntries) {
31
33
  return (sid, value) => {
32
34
  map.delete(sid);
@@ -54,7 +56,7 @@ function forwardedSandboxEnvKeys(remoteExec) {
54
56
  }
55
57
  }
56
58
  function buildSandboxLaneEnv(config, explicit) {
57
- const merged = { ...derivePkgSourceEnv(config.sandboxPkgSource, customPkgSourceFromEnv()), ...(explicit ?? {}) };
59
+ const merged = { ...derivePkgSourceEnv(config.sandboxPkgSource, config.sandboxPkgSourceCustom), ...(explicit ?? {}) };
58
60
  return Object.keys(merged).length > 0 ? merged : undefined;
59
61
  }
60
62
  const MAX_CWD_SESSIONS = 4096;
@@ -108,15 +110,16 @@ export function createSessionScopedRegistries(maxEntries = MAX_CWD_SESSIONS) {
108
110
  };
109
111
  }
110
112
  export function createK8sRunEnvFactory(k8sCfg, seats, deps) {
113
+ const cacheMisses = createCacheMissMemory();
111
114
  return async (ctx) => {
112
115
  const onWorkspaceSnapshot = createRunWorkspaceSnapshotSeat(ctx.sessionId);
113
116
  const child = ctx.placementRootSessionId !== ctx.sessionId;
114
117
  const s3Snapshot = child && k8sCfg.s3Snapshot !== undefined ? spaceOff(k8sCfg.s3Snapshot) : k8sCfg.s3Snapshot;
115
- const spaceOccupant = child ? undefined : await occupantOf(seats, ctx.sessionId, ctx.taskId);
118
+ const spaceOccupant = child ? undefined : await occupantOf(seats, ctx.sessionId, ctx.taskId, rpcTimeoutMsOf(k8sCfg));
116
119
  const { cache, ...deploymentCfg } = k8sCfg;
117
120
  return k8sExecutionEnvFactory({
118
121
  ...deploymentCfg,
119
- ...(cache !== undefined && !child ? { cache } : {}),
122
+ ...(cache !== undefined && !child ? { cache, cacheMisses } : {}),
120
123
  ...(s3Snapshot !== undefined ? { s3Snapshot } : {}),
121
124
  image: seats.imageOf(ctx.sessionId) ?? k8sCfg.image,
122
125
  ...(spaceOccupant !== undefined ? { spaceOccupant } : {}),
@@ -125,10 +128,18 @@ export function createK8sRunEnvFactory(k8sCfg, seats, deps) {
125
128
  };
126
129
  }
127
130
  const STORE_ERROR_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
128
- async function occupantOf(seats, sessionId, taskId) {
131
+ const INCARNATION_READ_TIMEOUT = "incarnation_read_timeout";
132
+ async function occupantOf(seats, sessionId, taskId, boundMs) {
129
133
  let answer;
130
134
  try {
131
- answer = await seats.incarnationOf?.(sessionId);
135
+ const read = seats.incarnationOf;
136
+ answer =
137
+ read === undefined
138
+ ? undefined
139
+ : await boundedStoreCall(() => read(sessionId), {
140
+ ms: boundMs,
141
+ onTimeout: () => Object.assign(new Error(`session occupant read did not answer within ${boundMs}ms`), { code: INCARNATION_READ_TIMEOUT }),
142
+ });
132
143
  }
133
144
  catch (e) {
134
145
  const code = e?.code;
@@ -187,6 +198,7 @@ export function createExecutionEnv(ctx) {
187
198
  const { config, logger, metrics, taskAttachmentStore } = ctx;
188
199
  const laneHomeDir = executionLaneHomeDir(config);
189
200
  const homeDirSeat = laneHomeDir !== undefined ? { homeDir: laneHomeDir } : {};
201
+ const homeAbsentNotice = { onHomeAbsent: createLaneHomeAbsenceReporter((event, fields) => logger.warn(event, fields)) };
190
202
  const perTaskImage = new PerTaskImageRegistry();
191
203
  const sessionEnvSelection = new SessionEnvironmentSelection();
192
204
  const sessionScoped = createSessionScopedRegistries();
@@ -213,7 +225,7 @@ export function createExecutionEnv(ctx) {
213
225
  else if (config.remoteExec?.provider === "k8s") {
214
226
  const k8sCfg = {
215
227
  image: config.remoteExec.image,
216
- ...homeDirSeat,
228
+ ...homeDirSeat, ...homeAbsentNotice,
217
229
  ...(config.remoteExec.apiUrl ? { apiUrl: config.remoteExec.apiUrl } : {}),
218
230
  ...(config.remoteExec.token ? { token: config.remoteExec.token } : {}),
219
231
  ...(config.remoteExec.caCert ? { caCert: config.remoteExec.caCert } : {}),
@@ -244,7 +256,7 @@ export function createExecutionEnv(ctx) {
244
256
  executionEnvFactory = sshExecutionEnvFactory({
245
257
  host: config.remoteExec.host,
246
258
  username: config.remoteExec.username,
247
- ...homeDirSeat,
259
+ ...homeDirSeat, ...homeAbsentNotice,
248
260
  privateKey: config.remoteExec.privateKey,
249
261
  ...(config.remoteExec.port != null ? { port: config.remoteExec.port } : {}),
250
262
  ...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
@@ -268,7 +280,7 @@ export function createExecutionEnv(ctx) {
268
280
  else if (config.remoteExec?.provider === "adb") {
269
281
  executionEnvFactory = adbExecutionEnvFactory({
270
282
  serial: config.remoteExec.serial,
271
- ...homeDirSeat,
283
+ ...homeDirSeat, ...homeAbsentNotice,
272
284
  ...(config.remoteExec.adbPath ? { adbPath: config.remoteExec.adbPath } : {}),
273
285
  ...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
274
286
  });
@@ -317,7 +329,7 @@ export function createExecutionEnv(ctx) {
317
329
  executionEnvFactory = localDockerExecutionEnvFactory({
318
330
  image: config.remoteExec.image,
319
331
  ...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
320
- ...homeDirSeat,
332
+ ...homeDirSeat, ...homeAbsentNotice,
321
333
  ...(config.remoteExec.dockerPath ? { dockerPath: config.remoteExec.dockerPath } : {}),
322
334
  ...(config.remoteExec.dockerHost ? { dockerHost: config.remoteExec.dockerHost } : {}),
323
335
  ...(config.remoteExec.memory ? { memory: config.remoteExec.memory } : {}),
@@ -404,6 +416,9 @@ export function createExecutionEnv(ctx) {
404
416
  logger.info("remote_exec_enabled", { provider: config.remoteExec.provider, isolated, suspendable, ...(sandboxEnvKeys.length > 0 ? { sandboxEnvKeys } : {}) });
405
417
  if (!isolated)
406
418
  logger.warn("remote_exec_real_system", { provider: config.remoteExec.provider, note: buildRealSystemNote(config.remoteExec) });
419
+ const homeNote = buildUndeclaredHomeNote(config);
420
+ if (homeNote !== undefined)
421
+ logger.warn(LANE_HOME_UNDECLARED_EVENT, { provider: config.remoteExec.provider, note: homeNote });
407
422
  if (executionLaneOf(config.remoteExec.provider) === "host")
408
423
  logger.info("task_inherit_env_honored", { honored: taskInheritEnvRefusal(config) === undefined });
409
424
  }
@@ -1,13 +1,23 @@
1
1
  import { loadRemoteExec } from "@sema-agent/settings-schema/node";
2
+ import { assertLocalConfigDirTrusted } from "../config-dir-trust.js";
2
3
  import { crossInvariant } from "../config-invariants.js";
3
4
  import { executionLaneOf, laneIsolated } from "../execution-lane-caps.js";
5
+ import { buildReadFacePostureNotice, settleDerivedReadFace } from "../read-face-posture.js";
4
6
  import { settleHostShellAtBoot } from "../plugins/host-platform.js";
5
7
  export const FILE_SOURCED_LANES = ["host", "local-docker"];
6
8
  export async function composeExecutionLane(config, ctx) {
7
9
  if (ctx.configSource === "local")
8
10
  await applyRemoteExecFile(config, ctx);
11
+ settleReadFaceForFinalLane(config, ctx.logger);
9
12
  assertExecutionLaneInvariants(config);
10
13
  }
14
+ function settleReadFaceForFinalLane(config, logger) {
15
+ if (!settleDerivedReadFace(config, config.requirePrincipal !== true))
16
+ return;
17
+ const notice = buildReadFacePostureNotice(config);
18
+ if (notice !== undefined)
19
+ logger.info(notice.event, notice.fields);
20
+ }
11
21
  export async function settleHostLaneShell(config, logger) {
12
22
  if (config.remoteExec?.provider !== "host")
13
23
  return;
@@ -34,6 +44,7 @@ export function assertExecutionLaneInvariants(config) {
34
44
  }
35
45
  async function applyRemoteExecFile(config, ctx) {
36
46
  const { localRoot, logger } = ctx;
47
+ await assertLocalConfigDirTrusted({ root: localRoot, declaredOwnerUid: config.configLocalOwnerUid });
37
48
  let fileRx;
38
49
  try {
39
50
  fileRx = await loadRemoteExec(localRoot);
@@ -1,4 +1,5 @@
1
1
  import { createLeaderEndpoint } from "../leader/endpoint.js";
2
+ import { createLeaderRunVisibility } from "../http/owner-access.js";
2
3
  import { createLeaderRunner } from "../leader/wire.js";
3
4
  import { buildDeploymentPostureSeats } from "./runner-deps.js";
4
5
  import { hasApprovalListIntent } from "../approval.js";
@@ -86,6 +87,7 @@ export function createLeaderFace(ctx) {
86
87
  logger,
87
88
  requiredFields: ["objective", "durableRemote", "testCmd", "seedCmd", "baseSha"],
88
89
  ...(leaderRunStore ? { store: leaderRunStore } : {}),
90
+ ownerVisible: createLeaderRunVisibility(config),
89
91
  })
90
92
  : undefined;
91
93
  if (leaderEndpoint)
@@ -75,8 +75,8 @@ import type { MemoryEngineBackend } from "@sema-agent/settings-schema/execution-
75
75
  * 而且它断言的是 per-task 事实,不是本键的车道级语义。
76
76
  *
77
77
  * ## 位置与纪律
78
- * 单源:resolve-spec 的 spec 直通、`noPersistentMemoryNotice` 判别式、boot 审计的 declared 位
79
- * 三处都必须读本函数,禁各自重算(operator-knob 律:显式 env 的优先权在这一个函数里执法一次)。
78
+ * 单源:resolve-spec 的 spec 直通(引擎据它判「本会话没有持久记忆」的披露与四只记忆面臂)、boot 审计的 declared 位
79
+ * 两处都必须读本函数,禁各自重算(operator-knob 律:显式 env 的优先权在这一个函数里执法一次)。
80
80
  * 自动补位在 boot 日志上必须可见(stores.ts 的 info 行),部署方随时可用显式 env 覆盖。
81
81
  */
82
82
  export declare function effectiveMemoryPersistenceCapable(config: {
@@ -1,5 +1,5 @@
1
1
  import { resolve } from "node:path";
2
- import { executionLaneCaps, executionLaneOf } from "../execution-lane-caps.js";
2
+ import { executionLaneCaps, executionLaneOf, laneWiresExecutionEnv } from "../execution-lane-caps.js";
3
3
  export function effectiveMemoryPersistenceCapable(config) {
4
4
  if (config.memoryPersistenceCapable !== undefined)
5
5
  return config.memoryPersistenceCapable;
@@ -11,7 +11,7 @@ export function buildMemoryBoundaryLaneFacts(config, processCwd) {
11
11
  return {
12
12
  lane,
13
13
  hostSemanticsLane: caps.hostFilePlane === "supported",
14
- coreRemoteExecutionEnv: caps.coreRemoteExecutionEnv === "supported",
14
+ coreRemoteExecutionEnv: laneWiresExecutionEnv(lane),
15
15
  containmentRoots: lane === "in-process" ? [processCwd] : [],
16
16
  };
17
17
  }
@@ -298,9 +298,9 @@ export declare function judgeConsolidationValve(input: ConsolidationValveInput):
298
298
  *
299
299
  * consolidation 要后端自带引擎控制面归属 ⇒ 今天只有 file 记忆后端满足 ⇒ 本仓只在**单用户**形
300
300
  * (`REQUIRE_PRINCIPAL !== true`)上装配记忆引擎 —— 而那种部署的 `OPERATOR_PRINCIPALS` 通常是**空的**。
301
- * 空名单下 `explicitOperatorOk` 对任何身份恒假(那是它与 `isOperator` 刻意分家的地方:空名单绝不等于
302
- * 「人人都是 operator」),于是:阀门开着、启动成功、两口挂着、**每一次调用 403**,能力位诚实地报
303
- * `false` —— 唯独运维不知道为什么,而他刚刚显式拧了一根写着 "on" 的旋钮。
301
+ * 没有运维名册(名单空且没有单用户声明 `OPERATOR_SINGLE_USER`)时 `explicitOperatorOk` 对任何身份恒假(「谁是 operator」的唯一读法:空名单绝不等于
302
+ * 「人人都是 operator」),于是:阀门开着、启动成功、两口挂着、**每一次调用 501 `capability.operator_principals_required`**(运维面同一只拒发口;403 只留给名单非空而你不在名单上),
303
+ * 能力位诚实地报 `false` —— 唯独运维不知道为什么,而他刚刚显式拧了一根写着 "on" 的旋钮。
304
304
  *
305
305
  * ## 为什么是 warn 而不是拒启(与 D1 的三条拒启臂**刻意不同档**)
306
306
  *
@@ -322,7 +322,8 @@ export declare function judgeConsolidationValve(input: ConsolidationValveInput):
322
322
  export declare function buildConsolidationValveAudit(input: {
323
323
  /** 阀门判决({@link resolveConsolidationValve} 的 `enabled` + `source`)。 */
324
324
  valve: Pick<ConsolidationValve, "enabled" | "source">;
325
- operatorPrincipals: readonly string[];
325
+ /** 这台部署有没有运维名册(`operatorRosterPresent`:名单非空 ∨ 单用户声明)—— 判据不在本函数里另写一份。 */
326
+ operatorRosterPresent: boolean;
326
327
  /** 这台部署配了任何一把 service 凭证吗(`config.authToken` 或 `config.authTokens` 非空)。 */
327
328
  hasServiceAuth: boolean;
328
329
  /** 本地开发的显式逃生口(`ALLOW_UNAUTHED_WRITES=true`)。 */
@@ -1,5 +1,6 @@
1
1
  import { redactSecrets } from "../trace/redact.js";
2
2
  import { recordFailOpen } from "../observability/fail-open.js";
3
+ import { buildOperatorRosterWayOut } from "../http/principal-gate.js";
3
4
  import { memoryMountRootOf } from "../memory-scope.js";
4
5
  import { executionLaneHomeDir } from "../execution-lane-caps.js";
5
6
  import { DEFAULT_MODEL_REF, resolveMainModel } from "../model-select.js";
@@ -266,15 +267,15 @@ export function buildConsolidationValveAudit(input) {
266
267
  if (!input.valve.enabled || input.valve.source !== "explicit")
267
268
  return { warnings: [] };
268
269
  const warnings = [];
269
- if (input.operatorPrincipals.length === 0) {
270
+ if (!input.operatorRosterPresent) {
270
271
  warnings.push({
271
272
  tag: "memory_consolidation_valve_unreachable",
272
273
  detail: "MEMORY_CONSOLIDATION_DRIVER=on armed the consolidation valve and both admin endpoints are mounted, but " +
273
- "OPERATOR_PRINCIPALS is EMPTY — an empty operator list means NO ONE is an operator (it deliberately does " +
274
- "not mean 'everyone'), so POST /v1/admin/memory/consolidation/run and GET /v1/admin/memory/consolidation " +
275
- "answer 403 auth.operator_only to every caller and capabilities.memoryConsolidationDriver reports false. " +
276
- "Set OPERATOR_PRINCIPALS to the principal(s) allowed to drive consolidation, and send that principal in " +
277
- "the configured principal header. (Not a startup refusal: OPERATOR_PRINCIPALS is shared by every operator " +
274
+ "this worker has no operator: OPERATOR_PRINCIPALS is EMPTY and OPERATOR_SINGLE_USER is not set — an empty operator list means NO ONE " +
275
+ "is an operator (it deliberately does not mean 'everyone'), so POST /v1/admin/memory/consolidation/run and GET /v1/admin/memory/consolidation " +
276
+ "answer 501 capability.operator_principals_required to every caller and capabilities.memoryConsolidationDriver reports false. " +
277
+ `To fix: ${buildOperatorRosterWayOut()}. With OPERATOR_PRINCIPALS, callers must send a listed principal in the configured principal header; a single-user declaration needs no principal. ` +
278
+ "(Not a startup refusal: the operator roster is shared by every operator " +
278
279
  "endpoint on this worker, so one valve must not decide whether the whole worker starts.)",
279
280
  });
280
281
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * [ref] §10.2 —— 跨主体投递门的**装配点**(门本体与规则在 `src/org-delivery-gate.ts`)。
3
+ *
4
+ * 挂载规则(一条):**部署声明了 principal 收件箱的消费方 ⟺ 门在座**。声明 = `RunnerDeps.principalInboxConsumer`
5
+ * (由 `PRINCIPAL_INBOX_ASSISTANT` 铸,`boot/runner-deps.ts`);门要的四件 —— 消费方、耐久 mailbox、org 成员目录、配额店 ——
6
+ * 是这条声明的**前提**,不是可选项:声明在而任一件缺 ⇒ **拒启**,拒句点名缺哪件。不存在「声明了但门没挂」的静默半态:
7
+ * 那一形下收件箱有消费方却没有任何合法的写入方,运维以为跨主体投递开着,wire 上它恒 501。
8
+ *
9
+ * 消费方取自**同一个** `RunnerDeps` 对象(`principalInboxConsumerOf(runnerDeps)`),不从 config 再读一遍(core 契约原句:
10
+ * 「over the same RunnerDeps the deployment runs its legs with」)。
11
+ */
12
+ import { type MailboxStore, type OrgDeliveryGate, type RunnerDeps } from "@sema-agent/core";
13
+ import type { OrgMemoryDirectory } from "../org-memory-admission.js";
14
+ import type { StoreBackend } from "../plugins/store-backend.js";
15
+ import type { Logger } from "../observability/logger.js";
16
+ export interface OrgDeliveryMountInput {
17
+ /** 主 Runner 的那一份 `RunnerDeps`(消费方声明从它读)。 */
18
+ readonly runnerDeps: Pick<RunnerDeps, "principalInboxConsumer">;
19
+ /** 记忆准入 / memory-policy / 共享记忆读面共用的那一个目录实例(`boot/org-memory.ts`)。 */
20
+ readonly directory: OrgMemoryDirectory | undefined;
21
+ /** 与引擎 `RunnerDeps.mailboxStore` 同一只店。 */
22
+ readonly mailboxStore: MailboxStore | undefined;
23
+ readonly backend: Pick<StoreBackend, "orgDeliveryQuota"> | undefined;
24
+ readonly logger: Pick<Logger, "info">;
25
+ }
26
+ /** 门在座 ⇒ 门;部署没声明消费方 ⇒ `undefined`;声明了而前提缺 ⇒ 抛(拒启)。 */
27
+ export declare function mountOrgDeliveryGate(input: OrgDeliveryMountInput): OrgDeliveryGate | undefined;
28
+ //# sourceMappingURL=org-delivery.d.ts.map
@@ -0,0 +1,20 @@
1
+ import { principalInboxConsumerOf } from "@sema-agent/core";
2
+ import { createOrgDeliveryGate } from "../org-delivery-gate.js";
3
+ export function mountOrgDeliveryGate(input) {
4
+ const consumer = principalInboxConsumerOf(input.runnerDeps);
5
+ if (consumer.kind === "none")
6
+ return undefined;
7
+ const { mailboxStore, directory, backend } = input;
8
+ if (mailboxStore === undefined || directory === undefined || backend === undefined) {
9
+ const missing = [
10
+ ...(mailboxStore === undefined ? ["a durable mailbox store (DB_BACKEND=mysql|pg|local)"] : []),
11
+ ...(directory === undefined ? ["an organization membership directory (a web-admin center, or MEMORY_ORG_DIRECTORY_JSON)"] : []),
12
+ ...(backend === undefined ? ["a store backend for the delivery quota (DB_BACKEND=mysql|pg|local)"] : []),
13
+ ];
14
+ throw new Error(`PRINCIPAL_INBOX_ASSISTANT declares a principal-inbox consumer, so this deployment must mount the organization delivery gate — but it lacks ${missing.join("; ")}. ` +
15
+ `Refusing to boot rather than run with a declared inbox that nothing may legitimately write to; provide the missing pieces or unset PRINCIPAL_INBOX_ASSISTANT.`);
16
+ }
17
+ input.logger.info("org_delivery_gate_mounted", { consumer: consumer.kind });
18
+ return createOrgDeliveryGate({ directory, mailbox: mailboxStore, quota: backend.orgDeliveryQuota(), consumer });
19
+ }
20
+ //# sourceMappingURL=org-delivery.js.map
@@ -0,0 +1,17 @@
1
+ import type { Logger } from "../observability/logger.js";
2
+ /** 一行 warn 里最多点名的行数(超出只报总数与省略数):一份中心发布可以带很多行,启动日志的一行不随之变长。 */
3
+ export declare const READ_DENY_AUDIT_MAX_NAMED_ROWS = 20;
4
+ export interface ReadDenyAnchorAuditCtx {
5
+ /** 部署读拒行(`config.readDenyPatterns`);缺席 / 空 ⇒ 无话可说。 */
6
+ readonly rows: readonly {
7
+ readonly pattern: string;
8
+ readonly caseSensitive: boolean;
9
+ }[] | undefined;
10
+ readonly logger: Pick<Logger, "warn">;
11
+ }
12
+ /**
13
+ * 只由 `announceReadDenyRows` 调(一份值一次)。返回非锚定行的规范形(按配置顺序;无 ⇒ 空),并在有时打**恰一行** warn `read_deny_unanchored_rows`
14
+ * (`rows` 点名前 {@link READ_DENY_AUDIT_MAX_NAMED_ROWS} 行、`count` 总数、超出时 `omitted`;`note` 引 MIGRATION 第 45 条的改法)。绝不抛。
15
+ */
16
+ export declare function auditReadDenyAnchoring(ctx: ReadDenyAnchorAuditCtx): readonly string[];
17
+ //# sourceMappingURL=read-deny-anchor-audit.d.ts.map
@@ -0,0 +1,36 @@
1
+ import { compileReadDeny, readDenyPatternRun } from "@sema-agent/core";
2
+ import { echoCallerText } from "../caller-text-echo.js";
3
+ export const READ_DENY_AUDIT_MAX_NAMED_ROWS = 20;
4
+ const NAMED_ROW_ECHO_CHARS = 200;
5
+ function isAnchoredCanonicalRow(canonical) {
6
+ return readDenyPatternRun(canonical).homeAnchored || canonical.startsWith("/");
7
+ }
8
+ export function auditReadDenyAnchoring(ctx) {
9
+ if (ctx.rows === undefined || ctx.rows.length === 0)
10
+ return [];
11
+ let canonical;
12
+ try {
13
+ canonical = compileReadDeny(ctx.rows, "boot read-deny anchor audit", { tiers: [] }).entries.map((e) => e.pattern);
14
+ }
15
+ catch (err) {
16
+ ctx.logger.warn("read_deny_anchor_audit_failed", {
17
+ error: echoCallerText(err instanceof Error ? err.message : String(err), { maxChars: 400 }),
18
+ note: "the boot audit could not read the deployment read-deny rows, so it names none and changes nothing; the engine itself refuses a row it cannot read when the Runner is built",
19
+ });
20
+ return [];
21
+ }
22
+ const unanchored = canonical.filter((p) => !isAnchoredCanonicalRow(p));
23
+ if (unanchored.length === 0)
24
+ return [];
25
+ const named = unanchored.slice(0, READ_DENY_AUDIT_MAX_NAMED_ROWS).map((p) => echoCallerText(p, { maxChars: NAMED_ROW_ECHO_CHARS }));
26
+ ctx.logger.warn("read_deny_unanchored_rows", {
27
+ rows: named,
28
+ count: unanchored.length,
29
+ ...(unanchored.length > named.length ? { omitted: unanchored.length - named.length } : {}),
30
+ note: "recursive shell reads (grep -r and the like) are judged by the root the command names: a read-deny row spelled without a root or home anchor does not protect files below that root " +
31
+ "(reading from a parent directory returns their content; naming the directory or file itself is still refused). Anchor the row to protect it — `<workspace root>/…` or `~/…` — see MIGRATION 7.132.0 item 45. " +
32
+ "This notice changes nothing: enforcement is unchanged and the start is not refused",
33
+ });
34
+ return unanchored;
35
+ }
36
+ //# sourceMappingURL=read-deny-anchor-audit.js.map
@@ -25,6 +25,7 @@ import type { FileHistoryErasureFace } from "../file-history-capture.js";
25
25
  import type { ApprovalNonceStore, CheckpointStoreFull, CostQuotaStore, ImageBake, RateLimiterStore, ServiceWorkflowJournalStore, StoreBackend, ToolResultStoreFull } from "../plugins/store-backend.js";
26
26
  import type { ToolApprovalCoordinator } from "../tool-approval.js";
27
27
  import type { ParkCommitWatch } from "../plugins/park-commit-watch.js";
28
+ import { type AuditRotationPort } from "../approval-ask-retention.js";
28
29
  /** [ref] / [ref]§五(sema-comms `audits/failopen-governance-176.md` §7 "Z 类 1 条"):default consecutive-failure
29
30
  * count before a reaper leg's swallowed error gets a `warn` line. The ~15 `.catch(() => undefined)` sites
30
31
  * below are correct in DIRECTION (a hiccuping periodic sweep must never crash the whole tick loop — one bad
@@ -108,6 +109,8 @@ export interface ReapersCtx {
108
109
  * 受理的最后一刻),所以存量是「到达率 × TTL」而不是历史总量,清扫无需分批。无 backend 的 env-only
109
110
  * 部署 ⇒ undefined ⇒ 本腿零调用(那种部署也没有 durable 审批门)。 */
110
111
  approvalNonceStore: ApprovalNonceStore | undefined;
112
+ /** local 车道的审批审计账(装配三合取见 `boot/coordinators.ts`;SQL 车道 / 审批关着 ⇒ undefined)—— 本 tick 只用它的**留存轮转**一手。 */
113
+ approvalAskAudit: AuditRotationPort | undefined;
111
114
  /** 晚绑(server 造出来才有)——见文件头「位置即契约」①。 */
112
115
  getRunDenySweep: () => ((now: number) => Promise<void>) | undefined;
113
116
  }
@@ -4,6 +4,7 @@ import { CostQuota } from "../observability/cost-quota.js";
4
4
  import { isAdoptionQuiescing, trackMaintenanceLeg } from "../adoption/quiesce.js";
5
5
  import { createApprovalReconciler } from "../approval-reconciler.js";
6
6
  import { createE2bOrphanSandboxProvider, reclaimOrphanE2bSandboxes, E2B_ORPHAN_GRACE_MS } from "../plugins/e2b-orphan-reclaim.js";
7
+ import { APPROVAL_ASK_RETENTION_PASS_MS, runApprovalAskRetentionPass } from "../approval-ask-retention.js";
7
8
  export const REAPER_FAILURE_WARN_THRESHOLD = 5;
8
9
  export function createThrottledReaperCatch(name, logger, threshold = REAPER_FAILURE_WARN_THRESHOLD) {
9
10
  let streak = 0;
@@ -56,7 +57,7 @@ export function createPlacementAwareReapSessions(deps) {
56
57
  };
57
58
  }
58
59
  export function startReapers(ctx) {
59
- const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, parkCommits, rateLimiter, costQuota, toolResultStore, fileHistoryErasure, taskAttachmentStore, imageBakes, worktreeReap, workflowNotifyGate, workflowRecoverOpts, workflowJournalStore, sqlWorkflowRunStore, workflowNotifyJournal, rosterStore, backgroundAgentStore, mailboxStore, toolApproval, permissionRuleStores, approvalNonceStore, getRunDenySweep, userInputLedger, } = ctx;
60
+ const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, parkCommits, rateLimiter, costQuota, toolResultStore, fileHistoryErasure, taskAttachmentStore, imageBakes, worktreeReap, workflowNotifyGate, workflowRecoverOpts, workflowJournalStore, sqlWorkflowRunStore, workflowNotifyJournal, rosterStore, backgroundAgentStore, mailboxStore, toolApproval, permissionRuleStores, approvalNonceStore, getRunDenySweep, userInputLedger, approvalAskAudit, } = ctx;
60
61
  const leg = (p) => {
61
62
  if (p !== undefined)
62
63
  trackMaintenanceLeg(p);
@@ -101,6 +102,17 @@ export function startReapers(ctx) {
101
102
  const leaderRunStaleGuard = createThrottledReaperCatch("leader_run_reap_stale", logger);
102
103
  const leaderRunStore = config.leaderEnabled ? backend?.leaderRun?.() : undefined;
103
104
  const scratchpadSweepStaleGuard = createThrottledReaperCatch("scratchpad_sweep_stale", logger);
105
+ const approvalAskRetentionMs = config.approvalAskRetentionMs;
106
+ const approvalAskRetentionGuard = createThrottledReaperCatch("approval_ask_retention", logger);
107
+ let approvalAskRetentionLastRunMs = Number.NEGATIVE_INFINITY;
108
+ let approvalAskRetentionInFlight = false;
109
+ logger.info("approval_ask_retention", {
110
+ windowMs: approvalAskRetentionMs,
111
+ ledgers: { asks: backend !== undefined, audit: approvalAskAudit !== undefined },
112
+ note: approvalAskRetentionMs > 0
113
+ ? "settled approval asks quiet for longer than windowMs are deleted whole from the approval ledgers on the maintenance tick (at most once an hour); unsettled asks, and every ask hanging off something that can still move (a running / parked run or delegated child, by run id or session), are never aged out. APPROVAL_ASK_RETENTION_MS=0 keeps everything."
114
+ : "APPROVAL_ASK_RETENTION_MS=0 — the approval ledgers are kept forever (nothing is aged out).",
115
+ });
104
116
  const approvalReconcileGuard = createThrottledReaperCatch("approval_reconcile", logger);
105
117
  const approvalSuspendedPollGuard = createThrottledReaperCatch("approval_suspended_poll", logger);
106
118
  let approvalSuspendedPollInFlight = false;
@@ -325,6 +337,14 @@ export function startReapers(ctx) {
325
337
  if (permissionRuleStores?.reapExpired === undefined)
326
338
  permissionRuleReapInFlight = false;
327
339
  }
340
+ if (approvalAskRetentionMs > 0 && runStore !== undefined && !approvalAskRetentionInFlight && Date.now() - approvalAskRetentionLastRunMs >= APPROVAL_ASK_RETENTION_PASS_MS && (backend !== undefined || approvalAskAudit !== undefined)) {
341
+ approvalAskRetentionInFlight = true;
342
+ approvalAskRetentionLastRunMs = Date.now();
343
+ leg(Promise.resolve()
344
+ .then(() => runApprovalAskRetentionPass({ askStore: backend?.approvalAsk(), audit: approvalAskAudit, runs: runStore, backgroundAgents: backgroundAgentStore, checkpoints: backend?.checkpointReadView(), cutoffMs: Date.now() - approvalAskRetentionMs, logger, metrics }))
345
+ .then(() => approvalAskRetentionGuard.onSuccess(), approvalAskRetentionGuard.onError)
346
+ .finally(() => (approvalAskRetentionInFlight = false)));
347
+ }
328
348
  if (config.scratchpadSweepTtlMs > 0) {
329
349
  leg(sweepStaleScratchpads(config.localDataRoot ?? localRoot, { olderThanMs: config.scratchpadSweepTtlMs })
330
350
  .then((removed) => {