@sema-agent/server 7.150.0 → 7.151.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 (341) hide show
  1. package/MIGRATION.md +185 -0
  2. package/USAGE.md +53 -25
  3. package/deploy/sema-up/README.md +7 -1
  4. package/deploy/sema-up/chart/Chart.yaml +1 -1
  5. package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
  6. package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
  7. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
  8. package/deploy/sema-up/chart/templates/server.yaml +5 -3
  9. package/deploy/sema-up/chart/values-full-single.yaml +3 -1
  10. package/deploy/sema-up/chart/values.yaml +8 -1
  11. package/deploy/sema-up/cluster-up.sh +1 -0
  12. package/deploy/sema-up/kube-up.sh +1 -1
  13. package/deploy/sema-up/lib/flagshape.sh +1 -1
  14. package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
  15. package/deploy/sema-up/lib/helm-values-kube.py +2 -0
  16. package/dist/adoption/import.js +3 -3
  17. package/dist/approval-ask-machine.d.ts +1 -1
  18. package/dist/approval-card.d.ts +2 -2
  19. package/dist/approval-gate-currency.d.ts +1 -1
  20. package/dist/auth-bridge.d.ts +20 -0
  21. package/dist/auth-bridge.js +9 -0
  22. package/dist/background-session-reap.d.ts +1 -1
  23. package/dist/bake-runner/main.d.ts +4 -2
  24. package/dist/bind-host.d.ts +2 -3
  25. package/dist/bind-host.js +2 -4
  26. package/dist/boot/budget-tracing.js +1 -1
  27. package/dist/boot/engine-lease.d.ts +5 -0
  28. package/dist/boot/engine-lease.js +1 -0
  29. package/dist/boot/execution-env.d.ts +8 -14
  30. package/dist/boot/execution-env.js +54 -17
  31. package/dist/boot/execution-lane.js +32 -5
  32. package/dist/boot/late-binds.d.ts +8 -4
  33. package/dist/boot/late-binds.js +7 -1
  34. package/dist/boot/memory-consolidation.d.ts +3 -2
  35. package/dist/boot/memory-consolidation.js +6 -6
  36. package/dist/boot/reapers.d.ts +5 -0
  37. package/dist/boot/reapers.js +12 -1
  38. package/dist/boot/resolve-spec.d.ts +3 -3
  39. package/dist/boot/resolve-spec.js +31 -22
  40. package/dist/boot/runner-deps.d.ts +9 -2
  41. package/dist/boot/runner-deps.js +3 -3
  42. package/dist/boot/session-age-out.d.ts +36 -0
  43. package/dist/boot/session-age-out.js +101 -0
  44. package/dist/boot/session-faces.d.ts +5 -14
  45. package/dist/boot/session-faces.js +9 -5
  46. package/dist/boot/stage-01-config.js +2 -0
  47. package/dist/boot/stage-05-execution-env.d.ts +5 -3
  48. package/dist/boot/stage-05-execution-env.js +2 -2
  49. package/dist/boot/stage-06-runners.d.ts +7 -4
  50. package/dist/boot/stage-06-runners.js +15 -6
  51. package/dist/boot/stage-07-capability-layer.d.ts +7 -4
  52. package/dist/boot/stage-07-capability-layer.js +2 -1
  53. package/dist/boot/stage-08-reapers.d.ts +7 -4
  54. package/dist/boot/stage-08-reapers.js +4 -2
  55. package/dist/boot/stage-09-leader.d.ts +11 -5
  56. package/dist/boot/stage-09-leader.js +12 -3
  57. package/dist/boot/stage-10-http-server.d.ts +11 -5
  58. package/dist/boot/stage-10-http-server.js +3 -6
  59. package/dist/boot/web-admin.js +3 -1
  60. package/dist/boot/workflow-orchestration.d.ts +7 -2
  61. package/dist/boot/workflow-orchestration.js +24 -7
  62. package/dist/bounded-rotation.d.ts +29 -0
  63. package/dist/bounded-rotation.js +24 -0
  64. package/dist/capability-facts.d.ts +22 -13
  65. package/dist/capability-facts.js +28 -18
  66. package/dist/center-credential.d.ts +25 -6
  67. package/dist/center-credential.js +25 -5
  68. package/dist/config-catalog.d.ts +26 -7
  69. package/dist/config-catalog.js +14 -11
  70. package/dist/config-invariants.d.ts +2 -1
  71. package/dist/config-invariants.js +4 -4
  72. package/dist/config-types.d.ts +10 -4
  73. package/dist/config.d.ts +51 -2
  74. package/dist/config.js +35 -24
  75. package/dist/deployment-shape.d.ts +9 -1
  76. package/dist/deployment-shape.js +2 -1
  77. package/dist/device-protocol.d.ts +5 -4
  78. package/dist/device-protocol.js +1 -1
  79. package/dist/device-ws-hub.js +3 -2
  80. package/dist/device-ws-protocol.d.ts +63 -10
  81. package/dist/device-ws-protocol.js +56 -25
  82. package/dist/engine-identity.d.ts +19 -7
  83. package/dist/engine-identity.js +10 -2
  84. package/dist/entry-mode-clamp-notice.d.ts +2 -1
  85. package/dist/execution-env-refusal.d.ts +23 -0
  86. package/dist/execution-env-refusal.js +5 -0
  87. package/dist/execution-lane-caps.d.ts +3 -1
  88. package/dist/field-conflict.d.ts +1 -1
  89. package/dist/file-history-capture.d.ts +11 -4
  90. package/dist/file-history-capture.js +9 -6
  91. package/dist/file-history-disclosure.d.ts +7 -5
  92. package/dist/file-history-disclosure.js +7 -5
  93. package/dist/fleet/drain-entry.d.ts +4 -0
  94. package/dist/hooks/hook-runner.js +2 -2
  95. package/dist/host-lsp-manager.d.ts +2 -2
  96. package/dist/http/admission.js +17 -2
  97. package/dist/http/approval-sweeps.js +5 -5
  98. package/dist/http/checkpoint-ctx.d.ts +2 -0
  99. package/dist/http/checkpoint-ctx.js +1 -0
  100. package/dist/http/dispatch.d.ts +2 -1
  101. package/dist/http/dispatch.js +34 -27
  102. package/dist/http/durable-run-leg.js +16 -16
  103. package/dist/http/health-self-report.d.ts +9 -1
  104. package/dist/http/health-self-report.js +2 -0
  105. package/dist/http/owner-access.d.ts +31 -11
  106. package/dist/http/owner-access.js +37 -6
  107. package/dist/http/resume-ctx-read.js +25 -3
  108. package/dist/http/resume-legs.d.ts +2 -1
  109. package/dist/http/resume-legs.js +259 -79
  110. package/dist/http/route-ctx.d.ts +18 -8
  111. package/dist/http/route-table.d.ts +1 -1
  112. package/dist/http/routes/admin-memory-optout.d.ts +1 -1
  113. package/dist/http/routes/agents-roster.js +2 -3
  114. package/dist/http/routes/approvals-assistant.js +4 -3
  115. package/dist/http/routes/background.d.ts +3 -3
  116. package/dist/http/routes/capabilities.js +8 -5
  117. package/dist/http/routes/fleet.js +10 -8
  118. package/dist/http/routes/projects.d.ts +3 -2
  119. package/dist/http/routes/projects.js +4 -5
  120. package/dist/http/routes/runs.js +102 -36
  121. package/dist/http/routes/session-sync.d.ts +4 -3
  122. package/dist/http/routes/session-sync.js +172 -77
  123. package/dist/http/routes/sessions-list.js +13 -7
  124. package/dist/http/routes/sessions.js +10 -6
  125. package/dist/http/routes/tasks.js +30 -16
  126. package/dist/http/routes/trace-usage.js +2 -2
  127. package/dist/http/server.d.ts +21 -27
  128. package/dist/http/server.js +2 -2
  129. package/dist/http/submit-ctx.js +5 -4
  130. package/dist/http/wire-types.d.ts +14 -4
  131. package/dist/identity-source.d.ts +20 -3
  132. package/dist/identity-source.js +14 -0
  133. package/dist/index.d.ts +4 -0
  134. package/dist/lane-home-probe.d.ts +3 -7
  135. package/dist/lane-home-probe.js +0 -1
  136. package/dist/leader/leader.d.ts +2 -1
  137. package/dist/leg-facts.d.ts +13 -5
  138. package/dist/leg-facts.js +2 -1
  139. package/dist/memory-scope.d.ts +5 -4
  140. package/dist/memory-scope.js +4 -4
  141. package/dist/memory-sync-client.d.ts +30 -2
  142. package/dist/memory-sync-client.js +16 -9
  143. package/dist/observability/err-text.d.ts +7 -0
  144. package/dist/observability/err-text.js +5 -0
  145. package/dist/observability/fail-open.d.ts +7 -3
  146. package/dist/observability/fail-open.js +7 -3
  147. package/dist/observability/metrics.js +1 -0
  148. package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
  149. package/dist/orchestration/workflow-notify-journal.js +12 -1
  150. package/dist/orchestration/workflow-park-decision.d.ts +70 -18
  151. package/dist/orchestration/workflow-park-decision.js +49 -10
  152. package/dist/orchestration/workflow-park-holder.d.ts +65 -0
  153. package/dist/orchestration/workflow-park-holder.js +98 -0
  154. package/dist/orchestration/workflow-record-fence.d.ts +36 -0
  155. package/dist/orchestration/workflow-record-fence.js +42 -0
  156. package/dist/owner-faces.d.ts +1 -1
  157. package/dist/parked-decide.d.ts +104 -53
  158. package/dist/parked-decide.js +153 -117
  159. package/dist/peer-directory.d.ts +2 -2
  160. package/dist/peer-inbound-face.d.ts +2 -6
  161. package/dist/peer-inbound-face.js +0 -3
  162. package/dist/permission-mode-admission.d.ts +41 -5
  163. package/dist/permission-mode-admission.js +29 -3
  164. package/dist/plugins/adoption-log-sql.d.ts +3 -1
  165. package/dist/plugins/adoption-log-sql.js +7 -1
  166. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  167. package/dist/plugins/approval-ask-store-file.js +8 -0
  168. package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
  169. package/dist/plugins/approval-ask-store-memory.js +28 -9
  170. package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
  171. package/dist/plugins/approval-ask-store-sql.js +34 -5
  172. package/dist/plugins/approval-exemption-store.js +3 -0
  173. package/dist/plugins/approval-nonce-store.js +2 -0
  174. package/dist/plugins/breaker-state-sql.js +2 -0
  175. package/dist/plugins/caching-session-store.d.ts +9 -15
  176. package/dist/plugins/caching-session-store.js +6 -0
  177. package/dist/plugins/device-store-sql.js +6 -0
  178. package/dist/plugins/error-origin.d.ts +18 -0
  179. package/dist/plugins/error-origin.js +10 -0
  180. package/dist/plugins/execution-placement-sql.js +6 -6
  181. package/dist/plugins/image-bake-store-sql.js +6 -0
  182. package/dist/plugins/image-index-sql.js +4 -0
  183. package/dist/plugins/landed-attendants.d.ts +212 -0
  184. package/dist/plugins/landed-attendants.js +161 -0
  185. package/dist/plugins/leader-run-store-sql.js +4 -0
  186. package/dist/plugins/local-session-live-reference.d.ts +40 -0
  187. package/dist/plugins/local-session-live-reference.js +39 -0
  188. package/dist/plugins/local-session-store.d.ts +71 -33
  189. package/dist/plugins/local-session-store.js +129 -27
  190. package/dist/plugins/memory-engine-pg.js +4 -0
  191. package/dist/plugins/memory-engine-sql-apply.js +5 -2
  192. package/dist/plugins/memory-engine-tidb.js +4 -0
  193. package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
  194. package/dist/plugins/memory-sync-store-pg.js +5 -0
  195. package/dist/plugins/memory-sync-store-tidb.js +5 -0
  196. package/dist/plugins/one-time-migrations.d.ts +57 -63
  197. package/dist/plugins/one-time-migrations.js +162 -90
  198. package/dist/plugins/org-delivery-quota-store.js +4 -1
  199. package/dist/plugins/outcome-ledger-sql.js +2 -0
  200. package/dist/plugins/permission-rule-store-sql.js +11 -4
  201. package/dist/plugins/pg-cost-quota.js +4 -0
  202. package/dist/plugins/pg-pool.js +24 -1
  203. package/dist/plugins/pg-rate-limiter.js +2 -0
  204. package/dist/plugins/posix-shell-fs.d.ts +6 -1
  205. package/dist/plugins/posix-shell-fs.js +4 -1
  206. package/dist/plugins/remote-env-adb.d.ts +19 -15
  207. package/dist/plugins/remote-env-adb.js +41 -15
  208. package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
  209. package/dist/plugins/remote-env-connect-seat.js +72 -0
  210. package/dist/plugins/remote-env-device.d.ts +22 -5
  211. package/dist/plugins/remote-env-device.js +106 -8
  212. package/dist/plugins/remote-env-e2b.d.ts +15 -6
  213. package/dist/plugins/remote-env-e2b.js +42 -32
  214. package/dist/plugins/remote-env-file-error.js +6 -2
  215. package/dist/plugins/remote-env-host.d.ts +17 -0
  216. package/dist/plugins/remote-env-host.js +30 -38
  217. package/dist/plugins/remote-env-k8s.d.ts +41 -39
  218. package/dist/plugins/remote-env-k8s.js +53 -30
  219. package/dist/plugins/remote-env-local-docker.d.ts +13 -8
  220. package/dist/plugins/remote-env-local-docker.js +34 -41
  221. package/dist/plugins/remote-env-ssh.d.ts +18 -12
  222. package/dist/plugins/remote-env-ssh.js +60 -59
  223. package/dist/plugins/remote-shell.d.ts +98 -1
  224. package/dist/plugins/remote-shell.js +218 -0
  225. package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
  226. package/dist/plugins/resume-anchor-store-sql.js +12 -5
  227. package/dist/plugins/retention-lane-store-sql.js +4 -0
  228. package/dist/plugins/retention-sql.d.ts +20 -2
  229. package/dist/plugins/retention-sql.js +11 -0
  230. package/dist/plugins/run-store-sql.d.ts +21 -2
  231. package/dist/plugins/run-store-sql.js +31 -7
  232. package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
  233. package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
  234. package/dist/plugins/schema-consistency.d.ts +4 -2
  235. package/dist/plugins/schema-consistency.js +19 -2
  236. package/dist/plugins/send-file-ledger.js +3 -0
  237. package/dist/plugins/serving-requirement.d.ts +26 -7
  238. package/dist/plugins/serving-requirement.js +11 -4
  239. package/dist/plugins/session-birth.d.ts +6 -2
  240. package/dist/plugins/session-capture-record-store-sql.js +2 -0
  241. package/dist/plugins/session-ext-table.d.ts +14 -1
  242. package/dist/plugins/session-ext-table.js +5 -1
  243. package/dist/plugins/session-row-sql.d.ts +49 -2
  244. package/dist/plugins/session-row-sql.js +56 -13
  245. package/dist/plugins/session-store-sql.d.ts +34 -18
  246. package/dist/plugins/session-store-sql.js +98 -17
  247. package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
  248. package/dist/plugins/shared-memory-store-sql.js +6 -2
  249. package/dist/plugins/sql-driver.d.ts +2 -1
  250. package/dist/plugins/sql-driver.js +18 -3
  251. package/dist/plugins/sql-errors.d.ts +11 -6
  252. package/dist/plugins/sql-errors.js +5 -6
  253. package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
  254. package/dist/plugins/stop-then-start-sentence.js +14 -10
  255. package/dist/plugins/stop-then-start.d.ts +109 -0
  256. package/dist/plugins/stop-then-start.js +104 -0
  257. package/dist/plugins/store-backend.d.ts +40 -13
  258. package/dist/plugins/store-backend.js +169 -27
  259. package/dist/plugins/store-boundary.d.ts +57 -0
  260. package/dist/plugins/store-boundary.js +139 -0
  261. package/dist/plugins/store-contracts.d.ts +17 -0
  262. package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
  263. package/dist/plugins/store-fault-sentence-m53.js +25 -0
  264. package/dist/plugins/store-fault.d.ts +26 -7
  265. package/dist/plugins/store-fault.js +18 -2
  266. package/dist/plugins/task-attachment-store.js +9 -0
  267. package/dist/plugins/task-list-store-sql.d.ts +2 -2
  268. package/dist/plugins/task-list-store-sql.js +10 -8
  269. package/dist/plugins/tidb-cost-quota.js +4 -0
  270. package/dist/plugins/tidb-pool.js +2 -1
  271. package/dist/plugins/tidb-rate-limiter.js +4 -0
  272. package/dist/plugins/user-input-ledger-sql.js +4 -0
  273. package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
  274. package/dist/plugins/workflow-run-store-sql.js +64 -4
  275. package/dist/plugins/workspace-fill.d.ts +4 -7
  276. package/dist/plugins/workspace-fill.js +2 -1
  277. package/dist/plugins/write-behind-counter.js +5 -0
  278. package/dist/project-context.d.ts +0 -2
  279. package/dist/project-context.js +4 -8
  280. package/dist/project-registry.d.ts +46 -0
  281. package/dist/project-registry.js +44 -0
  282. package/dist/request-key-closure.js +1 -1
  283. package/dist/request-value-closure.d.ts +4 -0
  284. package/dist/request-value-closure.js +10 -0
  285. package/dist/run-acceptance.d.ts +3 -2
  286. package/dist/run-acceptance.js +4 -6
  287. package/dist/run-local.js +1 -0
  288. package/dist/runs.d.ts +37 -8
  289. package/dist/runs.js +53 -12
  290. package/dist/runtime-governance.d.ts +5 -4
  291. package/dist/security.d.ts +30 -32
  292. package/dist/security.js +41 -7
  293. package/dist/server-secret-env.d.ts +12 -10
  294. package/dist/server-secret-env.js +24 -15
  295. package/dist/session-bindings.d.ts +82 -0
  296. package/dist/session-bindings.js +18 -0
  297. package/dist/session-children-retire.d.ts +2 -2
  298. package/dist/session-children-retire.js +2 -6
  299. package/dist/session-deletion.d.ts +16 -1
  300. package/dist/session-error-wire.d.ts +3 -3
  301. package/dist/session-error-wire.js +3 -3
  302. package/dist/session-incarnation.d.ts +10 -0
  303. package/dist/session-incarnation.js +10 -1
  304. package/dist/session-kind.d.ts +57 -0
  305. package/dist/session-kind.js +22 -0
  306. package/dist/session-row.d.ts +21 -1
  307. package/dist/session-row.js +7 -1
  308. package/dist/session-sync-kernel.d.ts +24 -14
  309. package/dist/session-sync-kernel.js +3 -6
  310. package/dist/session-sync.d.ts +4 -98
  311. package/dist/session-sync.js +1 -71
  312. package/dist/session-titler.d.ts +10 -3
  313. package/dist/session-titler.js +19 -6
  314. package/dist/ssh-host-key.d.ts +5 -0
  315. package/dist/ssh-host-key.js +3 -0
  316. package/dist/stores-sql/file-history-store-sql.d.ts +52 -2
  317. package/dist/stores-sql/file-history-store-sql.js +108 -70
  318. package/dist/stores-sql/pg-session-storage.d.ts +34 -7
  319. package/dist/stores-sql/pg-session-storage.js +37 -13
  320. package/dist/stores-sql/retention-store-sql.d.ts +1 -9
  321. package/dist/stores-sql/retention-store-sql.js +2 -10
  322. package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
  323. package/dist/stores-sql/session-policy-store-sql.js +61 -44
  324. package/dist/stores-sql/session-write-hooks.d.ts +11 -0
  325. package/dist/stores-sql/tidb-session-store.d.ts +58 -7
  326. package/dist/stores-sql/tidb-session-store.js +37 -13
  327. package/dist/submission-exit.d.ts +3 -2
  328. package/dist/submission-exit.js +9 -1
  329. package/dist/task-cwd.d.ts +2 -2
  330. package/dist/task-settings.d.ts +6 -5
  331. package/dist/terminal.d.ts +33 -2
  332. package/dist/terminal.js +139 -9
  333. package/dist/tool-approval.d.ts +140 -6
  334. package/dist/tool-approval.js +165 -72
  335. package/dist/trace/self-minted-wire.d.ts +290 -27
  336. package/dist/trace/self-minted-wire.js +101 -13
  337. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +78 -27
  338. package/package.json +2 -2
  339. package/wire-changes/server@7.151.0.json +762 -0
  340. package/dist/http/session-inherit-env.d.ts +0 -36
  341. package/dist/http/session-inherit-env.js +0 -6
@@ -18,6 +18,7 @@ import { headerStr } from "../http/principal-gate.js";
18
18
  import { routeListFilter } from "../http/owner-access.js";
19
19
  import { projectRegistry } from "../capability-facts.js";
20
20
  import { projectContextOf } from "../project-context.js";
21
+ import { memorySeedOf, memorySeedScopesOf } from "../project-registry.js";
21
22
  import { explicitOperatorOk } from "../http/server.js";
22
23
  import { isAtMentionable, matchCatalogModel, pickUserModel, refusedCatalogEntry, terminalCatalogName } from "../model-select.js";
23
24
  import { echoModelRef, modelNotAllowedMessage, modelUnavailableMessage, refusedNameLogField } from "../model-entry-refusal.js";
@@ -63,6 +64,7 @@ import { DeferredSandboxPathEnv, sandboxPathEnvSlots } from "./deferred-sandbox-
63
64
  import { executionLaneHomeDir, executionLaneOf, laneIsolated, laneWiresExecutionEnv } from "../execution-lane-caps.js";
64
65
  import { executionConfigRootOf } from "../execution-config-root.js";
65
66
  import { withUnattendedLeg } from "../unattended-permission-mode.js";
67
+ import { bindingsOf } from "../session-bindings.js";
66
68
  import { fieldConflictFacts } from "../field-conflict.js";
67
69
  function identityAxesOf(auth) {
68
70
  const subject = auth?.subject === undefined ? undefined : recoveredSubject(auth.subject);
@@ -74,7 +76,7 @@ function unrooted(spec) {
74
76
  return resolved;
75
77
  }
76
78
  export function createResolveSpec(ctx) {
77
- const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, fenceSessionOwner, hookLlm, hookAgent, belowTaskChainPatterns, fleetBus, hookWakeBus, historyAnchors, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, memorySyncRunner, durableEnabled, approvalExemptionStore, checkpointStore, imageIndex, perTaskImage, sessionEnvSelection, questionSeat, approverSeat, lockedKeys, loadedSkills, peerDesk, } = ctx;
79
+ const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, getKeyResolver, taskAttachmentStore, perSessionCwd, fenceSessionOwner, hookLlm, hookAgent, belowTaskChainPatterns, fleetBus, hookWakeBus, historyAnchors, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, memorySyncRunner, durableEnabled, approvalExemptionStore, checkpointStore, imageIndex, perTaskImage, sessionEnvSelection, questionSeat, approverSeat, lockedKeys, loadedSkills, peerDesk, } = ctx;
78
80
  const deploymentSkillSources = new Map(loadedSkills.map((k) => [k.spec.name, k.source]));
79
81
  const scenarioGate = createScenarioGate({ config, scenarios, principalCaps, logger }, "enforce");
80
82
  const sessionHeadOf = headReadOf(ownerAware);
@@ -85,10 +87,10 @@ export function createResolveSpec(ctx) {
85
87
  approvalSeat: durableEnabled ? "durable" : "absent",
86
88
  singleUserAutoAcceptBaseline: singleUserAutoAcceptBaselineApplies(config),
87
89
  });
88
- const realTaskRootOf = (root) => {
90
+ const realTaskRootOf = (legSessionCwd) => {
89
91
  if (DEPLOYMENT_SHAPE_PREDICATES.sandboxPathAdjudication.holds(config))
90
92
  return undefined;
91
- const sessionCwd = effectiveHostWorkspace(perSessionCwd.get(root), {});
93
+ const sessionCwd = effectiveHostWorkspace(legSessionCwd, {});
92
94
  return sessionCwd ?? (laneWiresExecutionEnv(config.remoteExec.provider) ? undefined : process.cwd());
93
95
  };
94
96
  const memoryProjectLayers = createMemoryProjectLayers({ stores: memoryEngine, syncRunner: memorySyncRunner, log: logger });
@@ -114,13 +116,18 @@ export function createResolveSpec(ctx) {
114
116
  assertRequestMcpEntries(body.mcpServers);
115
117
  const submittedProjectId = auth?.resolvedProjectId ?? (typeof body.projectId === "string" && body.projectId ? body.projectId.toLowerCase() : undefined);
116
118
  const legProjectId = await legProjectIdOf(submittedProjectId, sessionWorkspace, root);
119
+ const registryFact = projectRegistry({ config });
120
+ const registry = registryFact.available ? registryFact.registry : undefined;
121
+ const projectViewer = opts?.leg === "fresh" && req !== undefined ? routeListFilter(req, { config }, "project-get") : undefined;
122
+ const memorySeed = opts?.leg === "fresh" ? memorySeedOf(registry, submittedProjectId, projectViewer) : opts?.memorySeed;
123
+ if (opts?.leg !== "fresh" && memorySeed === undefined && submittedProjectId !== undefined)
124
+ logger.warn("resume_memory_seed_unjudged", { sessionId: root, projectId: submittedProjectId, note: "this continuation's stored rebuild input carries no memory-seed judgment (it was parked before this server version judged one), so the project registry's default read layers are not applied to it; submit the work again as a new task to have them" });
117
125
  let projectContext;
118
126
  if (opts?.leg === "fresh") {
119
- const registry = projectRegistry({ config });
120
127
  const decision = projectContextOf({
121
128
  projectId: legProjectId,
122
- registry: registry.available ? registry.registry : undefined,
123
- viewer: req === undefined ? undefined : routeListFilter(req, { config }, "project-get"),
129
+ registry,
130
+ viewer: projectViewer,
124
131
  pathsHonored: DEPLOYMENT_SHAPE_PREDICATES.callerOwnsWorkerDisk.holds(config),
125
132
  requestCwd: typeof body.cwd === "string" && body.cwd.length > 0,
126
133
  projectMemoryOff: body.projectMemory === "disabled",
@@ -229,12 +236,12 @@ export function createResolveSpec(ctx) {
229
236
  const gated = await gateScenarioAndAppend(body, auth, root, opts, settingsEnv);
230
237
  const effMode = effectivePermissionMode(body, gated.parsedSettings.settings);
231
238
  assertWriteFaceAdmitted(effMode, config);
232
- const lane = bindSettingsCwdEnvAndModel(body, auth, root, gated, opts, legCwd);
233
- const anchors = await resolveHistoryAnchors(body, req, auth, root, submittedProjectId, legProjectId);
234
- const projectKey = memoryEngine ? await memoryProjectLayers.prepare(config, auth?.memoryScope, realTaskRootOf(root)) : undefined;
239
+ const lane = judgeSettingsCwdEnvAndModel(body, auth, root, gated, opts, legCwd);
240
+ const anchors = await resolveHistoryAnchors(body, req, auth, root, memorySeedScopesOf(registry, memorySeed), legProjectId);
241
+ const projectKey = memoryEngine ? await memoryProjectLayers.prepare(config, auth?.memoryScope, realTaskRootOf(lane.sessionCwd)) : undefined;
235
242
  const runSkills = buildRunSkills({ scenario: gated.cap.skills, request: body.skills, disable: body.disableSkills === true, deploymentSources: deploymentSkillSources }, logger);
236
243
  const spec = assembleSpecLiteral(body, auth, root, req, opts, { ...gated, ...lane, ...anchors, projectKey, a2aPeers, storedToolAxes, runSkills, projectBrief: projectContext?.brief }, effMode);
237
- const folded = await foldGovernanceAndSettings(body, auth, root, spec, gated, projectContext?.brief);
244
+ const folded = await foldGovernanceAndSettings(body, auth, root, spec, gated, projectContext?.brief, lane.sessionCwd);
238
245
  const retiredNotice = opts.onNotice !== undefined ? buildNeverAutoRetiredNotice(gated.parsedSettings.settings?.tightenOnly?.neverAuto, root) : undefined;
239
246
  if (retiredNotice !== undefined)
240
247
  opts.onNotice?.(retiredNotice);
@@ -243,8 +250,7 @@ export function createResolveSpec(ctx) {
243
250
  scratchpadDir: folded.scratchpadDir,
244
251
  hostSemanticsLane: folded.hostSemanticsLane,
245
252
  });
246
- const registeredCwd = perSessionCwd.get(root);
247
- return { spec: final, facts: { hands: gated.hands, skills: runSkills.roster, sessionWitness: gated.sessionWitness, ...(registeredCwd !== undefined ? { registeredCwd } : {}), ...(projectContext !== undefined ? { projectContext } : {}) } };
253
+ return { spec: final, facts: { hands: gated.hands, skills: runSkills.roster, sessionWitness: gated.sessionWitness, sessionBindings: lane.sessionBindings, ...(projectContext !== undefined ? { projectContext } : {}), ...(memorySeed !== undefined ? { memorySeed } : {}) } };
248
254
  };
249
255
  const gateScenarioAndAppend = async (body, auth, root, opts, settingsEnv) => {
250
256
  const { parts: subjectParts, person } = identityAxesOf(auth);
@@ -302,22 +308,24 @@ export function createResolveSpec(ctx) {
302
308
  }
303
309
  return { scenarioName, cap, hands: cap.hands, acceptedAppend, objective, parsedSettings, attachmentNotice, sessionWitness };
304
310
  };
305
- const bindSettingsCwdEnvAndModel = (body, auth, root, gated, opts, cwd) => {
311
+ const judgeSettingsCwdEnvAndModel = (body, auth, root, gated, opts, cwd) => {
306
312
  const { objective, parsedSettings } = gated;
307
313
  const cwdWriteGate = DEPLOYMENT_SHAPE_PREDICATES.callerCwd.holds(config);
308
314
  const execLane = config.remoteExec.provider;
309
315
  fenceSessionOwner(root, auth?.subject ?? null, opts.execution.occupant?.incarnation);
316
+ let boundCwd;
310
317
  if (typeof cwd === "string" && cwd.length > 0) {
311
318
  if (cwdWriteGate && isAbsoluteHostPath(cwd))
312
- setSessionCwd(root, cwd);
319
+ boundCwd = cwd;
313
320
  else if (DEPLOYMENT_SHAPE_PREDICATES.noHandsSingleUser.holds(config) && isAbsoluteHostPath(cwd) && satisfiedByProcessCwd(cwd, realpathSync))
314
321
  logger.debug("task_cwd_inherited", { lane: execLane, sessionId: root });
315
322
  else
316
323
  logger.warn("task_cwd_ignored", { honored: cwdWriteGate, lane: execLane, sessionId: root });
317
324
  }
325
+ let boundShellEnv;
318
326
  if (parsedSettings.settings?.shellEnv) {
319
327
  if (cwdWriteGate)
320
- setSessionShellEnv(root, parsedSettings.settings.shellEnv);
328
+ boundShellEnv = parsedSettings.settings.shellEnv;
321
329
  else if (DEPLOYMENT_SHAPE_PREDICATES.noHandsSingleUser.holds(config)) {
322
330
  const requested = parsedSettings.settings.shellEnv;
323
331
  const mismatched = shellEnvMismatchCount(requested, process.env);
@@ -329,6 +337,8 @@ export function createResolveSpec(ctx) {
329
337
  else
330
338
  logger.warn("task_shell_env_ignored", { honored: false, lane: execLane, sessionId: root });
331
339
  }
340
+ const sessionCwd = boundCwd ?? perSessionCwd.get(root);
341
+ const sessionBindings = bindingsOf(sessionCwd, boundShellEnv, body.inheritEnv);
332
342
  const taskHooks = (() => {
333
343
  const hc = parsedSettings.settings?.hooks;
334
344
  if (!hc)
@@ -340,7 +350,7 @@ export function createResolveSpec(ctx) {
340
350
  return createSettingsHooksRegistrations(hc, {
341
351
  logger,
342
352
  sessionId: root,
343
- cwd: perSessionCwd.get(root) ?? process.cwd(),
353
+ cwd: sessionCwd ?? process.cwd(),
344
354
  hookEnvAllow: config.hookEnvAllow,
345
355
  ...(parsedSettings.settings?.shellEnv ? { shellEnv: parsedSettings.settings.shellEnv } : {}),
346
356
  httpHookAllowlistLayers: parsedSettings.settings?.httpHookAllowlist !== undefined ? [parsedSettings.settings.httpHookAllowlist] : [],
@@ -390,9 +400,9 @@ export function createResolveSpec(ctx) {
390
400
  metrics.inc("task_model_unknown_fallback_total");
391
401
  logger.warn("task_model_unknown_fallback", { requested: echoModelRef(picked.unknownExplicit), fallback: picked.model, sessionId: root });
392
402
  }
393
- return { taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked };
403
+ return { taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked, sessionBindings, sessionCwd };
394
404
  };
395
- const resolveHistoryAnchors = async (body, req, auth, root, submittedProjectId, legProjectId) => {
405
+ const resolveHistoryAnchors = async (body, req, auth, root, s4DefaultScopes, legProjectId) => {
396
406
  const anchorReader = req === undefined ? undefined : anchorReaderOf(req, { config, logger }, claimCallerOf(identityAxesOf(auth).subject, config));
397
407
  let resumeAtEntryId;
398
408
  if (typeof body.resumeAt === "string" && body.resumeAt.length > 0) {
@@ -406,7 +416,6 @@ export function createResolveSpec(ctx) {
406
416
  throw new HttpError(501, "rewind-files-to is not available on this worker (no session-store backend for the anchor map)");
407
417
  rewindFilesToEntryId = await resolveHistoryAnchor("rewindFilesTo", anchorsResolvable, anchorReader, root, body.rewindFilesTo, auth?.subject ?? null, "rewindFilesTo");
408
418
  }
409
- const s4DefaultScopes = submittedProjectId ? config.projects[submittedProjectId]?.defaultScopes : undefined;
410
419
  return { resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes, legProjectId };
411
420
  };
412
421
  const declaresInteractivePosture = (body, req, opts) => {
@@ -433,7 +442,7 @@ export function createResolveSpec(ctx) {
433
442
  ...(body.outputStyle !== undefined ? { outputStyle: body.outputStyle } : {}),
434
443
  ...(body.projectMemory !== undefined ? { projectMemory: body.projectMemory } : {}),
435
444
  ...(legProjectId !== undefined ? { projectId: legProjectId } : {}),
436
- principal: taskSpecIdentityOf(subjectParts).principal,
445
+ ...taskSpecIdentityOf(subjectParts),
437
446
  images: body.images,
438
447
  ...(body.userAttachments !== undefined ? { userAttachments: body.userAttachments } : {}),
439
448
  ...(body.clientContext ? { clientContext: { timeZone: body.clientContext.timeZone, userEmail: body.clientContext.userEmail } } : {}),
@@ -584,7 +593,7 @@ export function createResolveSpec(ctx) {
584
593
  };
585
594
  return spec;
586
595
  };
587
- const foldGovernanceAndSettings = async (body, auth, root, spec, gated, projectBrief) => {
596
+ const foldGovernanceAndSettings = async (body, auth, root, spec, gated, projectBrief, legSessionCwd) => {
588
597
  const { acceptedAppend, parsedSettings } = gated;
589
598
  const hostSemanticsLane = !DEPLOYMENT_SHAPE_PREDICATES.sandboxPathAdjudication.holds(config);
590
599
  const laneHomeBase = () => {
@@ -593,7 +602,7 @@ export function createResolveSpec(ctx) {
593
602
  };
594
603
  const pathAdjudication = hostSemanticsLane
595
604
  ? (() => {
596
- const realRoot = realTaskRootOf(root);
605
+ const realRoot = realTaskRootOf(legSessionCwd);
597
606
  const gateCwd = realRoot ?? join(config.localDataRoot ?? localRoot, "fs-write-gate-unrooted");
598
607
  return {
599
608
  env: new NodeExecutionEnv({ cwd: gateCwd }),
@@ -206,6 +206,13 @@ export interface RunnerDepsCtx {
206
206
  sharedMemoryStores: RunnerDeps["sharedMemoryStores"];
207
207
  toolResultStore: ToolResultStoreFull | undefined;
208
208
  sessionPolicyStore: ReturnType<StoreBackend["sessionPolicy"]> | undefined;
209
+ /**
210
+ * [ref] §K —— per-principal 运行期准入的**收紧面**(`boot/runtime-caps.ts` 一处合成;缺席 = 这条部署腿没有 per-principal 收紧,
211
+ * 部署级缺省照管)。进{@link createSharedRunnerDeps 共享基座}:引擎按腿以 `spec.principal` 解它(每条腿各解一次),委派子代的主体由引擎的
212
+ * 父 spec 座继承 —— 子腿是同一个主体,跑它的那只 Runner 不挂 = 中心对这个主体的拒位(bypass / fork / 自编排 / auto / 强制门 / 观察者 /
213
+ * 记忆 opt-out)与中心硬故障时的 fail-closed 降级项一位都到不了子腿(安全轴 fail-open)。它不是会话设施(不同于 selfOrchestration /
214
+ * scheduler / memory 那几席),所以没有「子腿刻意不给」的理由。
215
+ */
209
216
  runtimeCapsResolver: RunnerDeps["runtimeCapsResolver"];
210
217
  /** [ref] per-edited-file rewind history (core `RunnerDeps.fileHistoryStore`; replaces the retired E19
211
218
  * whole-tree snapshot seat — core 94632197 renamed the seat, not a coexistence). WIRING IS THE OPT-IN.
@@ -248,7 +255,7 @@ export interface RunnerDepsCtx {
248
255
  }
249
256
  /** [ref] A10 留档发现②:main runner `RunnerDeps` 与 main.ts subRunner 字面量之间此前手工重复
250
257
  * 的 ~15 个键,类型标注见 {@link createSharedRunnerDeps} 头注。 */
251
- export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "readDenyFloorRequired" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "delegationEntryCaps" | "crossSessionInbound" | "crossSessionDialogExpiry" | "writeProtectedPaths" | "memoryEngineDir" | "allowedTools" | "crossBoundaryPosture" | "models" | "roles" | "tiers" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "mods" | "toolResultStore" | "checkpointStore" | "fileHistoryStore" | "fileHistoryCapture" | "hands" | "sessionPolicyStore" | "usageWindows" | "usageWindowStore" | "memoryScopeAdmission" | "deploymentMemoryScopes" | "sharedMemoryStores" | "compliancePostureResolver" | "lockedConfig" | "retentionPolicy" | "onNotice" | "mcpRevocations" | "peerSeat">;
258
+ export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "readDenyFloorRequired" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "delegationEntryCaps" | "crossSessionInbound" | "crossSessionDialogExpiry" | "writeProtectedPaths" | "memoryEngineDir" | "allowedTools" | "crossBoundaryPosture" | "models" | "roles" | "tiers" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "mods" | "toolResultStore" | "checkpointStore" | "fileHistoryStore" | "fileHistoryCapture" | "hands" | "sessionPolicyStore" | "usageWindows" | "usageWindowStore" | "memoryScopeAdmission" | "deploymentMemoryScopes" | "sharedMemoryStores" | "compliancePostureResolver" | "lockedConfig" | "retentionPolicy" | "onNotice" | "mcpRevocations" | "peerSeat" | "runtimeCapsResolver">;
252
259
  /**
253
260
  * [ref] A10 留档发现②(review 2026-07-29,[ref]§三族A 同源修补的延续):main runner 的
254
261
  * `RunnerDeps` 字面量(下方 `createRunnerDeps`)与 `main.ts` 里 subRunner 的 `new Runner({...})`
@@ -275,7 +282,7 @@ export type SharedRunnerDeps = Pick<RunnerDeps, "brain" | "readFace" | "readDeny
275
282
  * 属性,比再抽一层共享基座更强的同源保证),不重复收纳进这里。
276
283
  */
277
284
  /** 基座真实消费的窄面(Pick)——subRunner 调用点(main.ts)只需凑这 13 个字段,不必造全量 ctx。 */
278
- export type SharedRunnerDepsCtx = Pick<RunnerDepsCtx, "config" | "brain" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "deploymentMods" | "toolResultStore" | "checkpointStore" | "fileHistoryStore" | "sessionPolicyStore" | "commitCoAuthor" | "usageWindowStore" | "orgMemoryAdmission" | "sharedMemoryStores" | "logger" | "governanceSeams" | "mcpRevocations" | "metrics" | "engineDataRoot" | "peerDesk">;
285
+ export type SharedRunnerDepsCtx = Pick<RunnerDepsCtx, "config" | "brain" | "pricing" | "tracer" | "promptSource" | "executionEnvFactory" | "lspManager" | "backgroundAgentStore" | "mailboxStore" | "rosterStore" | "deploymentMods" | "toolResultStore" | "checkpointStore" | "fileHistoryStore" | "sessionPolicyStore" | "commitCoAuthor" | "usageWindowStore" | "orgMemoryAdmission" | "sharedMemoryStores" | "logger" | "governanceSeams" | "mcpRevocations" | "metrics" | "engineDataRoot" | "peerDesk" | "runtimeCapsResolver">;
279
286
  /** 转发席只需要 `inc` —— 刻意窄到这一个动词,免得把整只 Metrics 拖进这条纯转发腿。 */
280
287
  export interface EngineNoticeMetricsSeat {
281
288
  inc: (name: string, labels?: Record<string, string>) => void;
@@ -133,7 +133,7 @@ export function createSharedRunnerDeps(ctx) {
133
133
  toolResultStore: ctx.toolResultStore,
134
134
  checkpointStore: ctx.checkpointStore ? ctx.checkpointStore : undefined,
135
135
  fileHistoryStore: ctx.fileHistoryStore ? ctx.fileHistoryStore : undefined,
136
- fileHistoryCapture: coreFileHistoryCaptureSeat(ctx.fileHistoryStore, ctx.config.fileHistoryCapture),
136
+ fileHistoryCapture: coreFileHistoryCaptureSeat(ctx.fileHistoryStore !== undefined, ctx.config.fileHistoryCapture),
137
137
  sessionPolicyStore: ctx.sessionPolicyStore ? ctx.sessionPolicyStore : undefined,
138
138
  memoryScopeAdmission: ctx.orgMemoryAdmission.memoryScopeAdmission ? ctx.orgMemoryAdmission.memoryScopeAdmission : undefined,
139
139
  deploymentMemoryScopes: ctx.orgMemoryAdmission.deploymentMemoryScopes && ctx.orgMemoryAdmission.deploymentMemoryScopes.length > 0 ? ctx.orgMemoryAdmission.deploymentMemoryScopes : undefined,
@@ -146,6 +146,7 @@ export function createSharedRunnerDeps(ctx) {
146
146
  retentionPolicy: ctx.governanceSeams.retentionPolicy,
147
147
  mcpRevocations: ctx.mcpRevocations ? ctx.mcpRevocations : undefined,
148
148
  peerSeat: ctx.peerDesk.seat,
149
+ runtimeCapsResolver: ctx.runtimeCapsResolver ? ctx.runtimeCapsResolver : undefined,
149
150
  };
150
151
  return shared;
151
152
  }
@@ -153,7 +154,7 @@ export function localOwnerRulesDeclared(config, permissionRuleStore) {
153
154
  return permissionRuleStore !== undefined && !DEPLOYMENT_SHAPE_PREDICATES.multiTenant.holds(config);
154
155
  }
155
156
  export function createRunnerDeps(ctx) {
156
- const { config, logger, metrics, localRoot, outcomeSink, elicitation, question, toolApproval, sessionStore, memoryEngine, sessionCaptureRecords, memorySyncRunner, runtimeCapsResolver, permissionRuleStore, fleetBus, workflowRunStore, workflowJournalStore, workflowAgentRegistry, workflowNotifyGate, deliverWorkflowCompletion, } = ctx;
157
+ const { config, logger, metrics, localRoot, outcomeSink, elicitation, question, toolApproval, sessionStore, memoryEngine, sessionCaptureRecords, memorySyncRunner, permissionRuleStore, fleetBus, workflowRunStore, workflowJournalStore, workflowAgentRegistry, workflowNotifyGate, deliverWorkflowCompletion, } = ctx;
157
158
  const peerSessionLister = sessionStore.listSessionRows?.bind(sessionStore);
158
159
  const memoryEngineIncident = createMemoryEngineIncidentSink({ logger, metrics });
159
160
  const sharedRunnerDeps = createSharedRunnerDeps(ctx);
@@ -237,7 +238,6 @@ export function createRunnerDeps(ctx) {
237
238
  memorySyncRunner.trigger("harvest");
238
239
  }
239
240
  : undefined,
240
- runtimeCapsResolver: runtimeCapsResolver ? runtimeCapsResolver : undefined,
241
241
  permissionRuleStore: permissionRuleStore ? permissionRuleStore : undefined,
242
242
  localOwnerRules: localOwnerRulesDeclared(config, permissionRuleStore),
243
243
  onBackgroundChildEvent: fleetBackgroundChildPublisher(fleetBus, (msg, fields) => logger.info(msg, fields)),
@@ -0,0 +1,36 @@
1
+ import type { SessionAgeOutExpectation, SessionPurgeOutcome } from "../session-deletion.js";
2
+ import type { OwnerAwareSessionStore } from "../security.js";
3
+ import type { Logger } from "../observability/logger.js";
4
+ import type { Metrics } from "../observability/metrics.js";
5
+ /** 每拍至多碰这么多只(一拍的删除量有上界:维护拍上其余各腿不被本腿拖住)。 */
6
+ export declare const SESSION_AGE_OUT_CAP = 64;
7
+ /** 每拍的时间预算(同上一句的理由)。 */
8
+ export declare const SESSION_AGE_OUT_BUDGET_MS = 5000;
9
+ /** 跳过的理由(闭集;计数的标签):条件在锁里不再成立 / 围栏判到认领 / 子代预检拒 / 另一次删除持有它 / 抛。 */
10
+ export type SessionAgeOutSkip = "changed" | "active" | "children_alive" | "in_progress" | "failed";
11
+ /** 一拍的读数(调用方记日志;钉读它)。 */
12
+ export interface SessionAgeOutReading {
13
+ readonly deleted: number;
14
+ readonly skipped: Readonly<Record<SessionAgeOutSkip, number>>;
15
+ /** 本拍因帽或预算停下而候选还没看完。 */
16
+ readonly truncated: boolean;
17
+ }
18
+ export interface SessionAgeOutDeps {
19
+ readonly store: Required<Pick<OwnerAwareSessionStore, "listIdleOfKind">>;
20
+ readonly purge: (sessionId: string, owner: string | null, opts: {
21
+ readonly ageOut: SessionAgeOutExpectation;
22
+ }) => Promise<SessionPurgeOutcome>;
23
+ /** 视界(`BG_AGENT_RETENTION_MS`;每拍现读 —— 热改下一拍生效)。 */
24
+ readonly retentionMs: () => number;
25
+ readonly logger: Pick<Logger, "info" | "warn">;
26
+ readonly metrics: Pick<Metrics, "inc">;
27
+ readonly now?: () => number;
28
+ readonly cap?: number;
29
+ readonly budgetMs?: number;
30
+ }
31
+ /**
32
+ * 铸老化腿(一只闭包,带进程内的跨拍轮转起点与在飞守卫):每次调用跑一拍,交回读数;在飞时再调 ⇒ 立刻交回空读数(不叠拍)。
33
+ * 候选读抛 ⇒ 本拍停在那里(读数照交,下拍从同一起点再来);单行删除抛 ⇒ 计 `failed`、节流 warn,本拍继续下一行。
34
+ */
35
+ export declare function createSessionAgeOut(deps: SessionAgeOutDeps): () => Promise<SessionAgeOutReading>;
36
+ //# sourceMappingURL=session-age-out.d.ts.map
@@ -0,0 +1,101 @@
1
+ import { SESSION_KINDS, idleSessionAfter } from "../session-kind.js";
2
+ import { seatText } from "../trace/exit-seat.js";
3
+ export const SESSION_AGE_OUT_CAP = 64;
4
+ export const SESSION_AGE_OUT_BUDGET_MS = 5_000;
5
+ function outcomeOf(outcome) {
6
+ if ("deleted" in outcome)
7
+ return outcome.deleted ? "deleted" : "changed";
8
+ if ("active" in outcome)
9
+ return "active";
10
+ if ("childrenAlive" in outcome)
11
+ return "children_alive";
12
+ if ("inProgress" in outcome)
13
+ return "in_progress";
14
+ const unknownOutcome = outcome;
15
+ throw new Error(`session age-out: no arm for purge outcome ${JSON.stringify(unknownOutcome)}`);
16
+ }
17
+ export function createSessionAgeOut(deps) {
18
+ const cap = deps.cap ?? SESSION_AGE_OUT_CAP;
19
+ const budgetMs = deps.budgetMs ?? SESSION_AGE_OUT_BUDGET_MS;
20
+ const now = deps.now ?? Date.now;
21
+ const resumeAfter = new Map();
22
+ let inFlight = false;
23
+ const empty = () => ({ changed: 0, active: 0, children_alive: 0, in_progress: 0, failed: 0 });
24
+ return async () => {
25
+ if (inFlight)
26
+ return { deleted: 0, skipped: empty(), truncated: false };
27
+ inFlight = true;
28
+ const started = now();
29
+ const skipped = empty();
30
+ let deleted = 0;
31
+ let touched = 0;
32
+ let truncated = false;
33
+ try {
34
+ for (const kind of SESSION_KINDS) {
35
+ const idleBefore = new Date(now() - deps.retentionMs());
36
+ const origin = resumeAfter.get(kind);
37
+ let after = origin;
38
+ let wrapped = origin === undefined;
39
+ let circled = false;
40
+ for (;;) {
41
+ if (touched >= cap || (touched > 0 && now() - started >= budgetMs)) {
42
+ truncated = true;
43
+ break;
44
+ }
45
+ const page = await deps.store.listIdleOfKind(kind, idleBefore, { ...(after !== undefined ? { after } : {}), limit: cap - touched });
46
+ if (page.length === 0) {
47
+ if (wrapped) {
48
+ resumeAfter.delete(kind);
49
+ break;
50
+ }
51
+ wrapped = true;
52
+ after = undefined;
53
+ continue;
54
+ }
55
+ for (const row of page) {
56
+ if (wrapped && origin !== undefined && !idleSessionAfter(origin, row)) {
57
+ circled = true;
58
+ break;
59
+ }
60
+ if (touched >= cap || (touched > 0 && now() - started >= budgetMs)) {
61
+ truncated = true;
62
+ break;
63
+ }
64
+ touched++;
65
+ after = { lastActivityAt: row.lastActivityAt, sessionId: row.sessionId };
66
+ resumeAfter.set(kind, after);
67
+ let verdict;
68
+ try {
69
+ verdict = outcomeOf(await deps.purge(row.sessionId, row.owner, { ageOut: { incarnation: row.incarnation, kind, idleBefore } }));
70
+ }
71
+ catch (err) {
72
+ verdict = "failed";
73
+ deps.logger.warn("session_age_out_failed", { sessionId: row.sessionId, err: seatText("operator-log-text", String(err)), effect: "the session stays; the next maintenance tick judges it again" });
74
+ }
75
+ if (verdict === "deleted") {
76
+ deleted++;
77
+ deps.metrics.inc("sidechain_sessions_aged_out_total", {}, 1);
78
+ deps.logger.info("session_aged_out", { sessionId: row.sessionId, sessionKind: kind, lastActivityAt: row.lastActivityAt });
79
+ }
80
+ else {
81
+ skipped[verdict]++;
82
+ deps.metrics.inc("sidechain_age_out_skipped_total", { reason: verdict }, 1);
83
+ }
84
+ }
85
+ if (truncated || circled)
86
+ break;
87
+ }
88
+ if (truncated)
89
+ break;
90
+ }
91
+ }
92
+ finally {
93
+ inFlight = false;
94
+ }
95
+ if (deleted > 0 || truncated || Object.values(skipped).some((n) => n > 0)) {
96
+ deps.logger.info("reaper_swept", { metric: "sidechain_sessions_aged_out_total", count: deleted, skipped, truncated });
97
+ }
98
+ return { deleted, skipped, truncated };
99
+ };
100
+ }
101
+ //# sourceMappingURL=session-age-out.js.map
@@ -1,15 +1,3 @@
1
- /**
2
- * [ref] A10:composition root 分段 —— session 只读/删除面(审计、watch 注册表、E21 purge 协调器、
3
- * degenerate 仪表、plan-cache 探针)。
4
- *
5
- * 纯搬运:函数体逐字来自 `main.ts`(原 2967-3092 行),缩进不变;新增的只有 import 与包壳。
6
- *
7
- * ⚠️ **位置即契约**:
8
- * 1. `sessionWatchRegistry` 必须在 `purgeSession` **之前**构造 —— purge 尾部的 `dropSession` 是
9
- * 同副本租户轮转围栏(delete 即终结旧 owner 的 SSE 订阅),两者是一对;空间回收座在它**之后**起、且不在应答路径里。
10
- * 2. `setLeafAdvanceListener(...)` 是**进程级单点**装载(leaf-bus 只有一个监听位),必须与
11
- * registry 的构造同段发生,晚于它、早于任何会 append 的路由。
12
- */
13
1
  import { type SessionAuditReadOpts } from "../audit.js";
14
2
  import type { ServiceConfig } from "../config.js";
15
3
  import type { Logger } from "../observability/logger.js";
@@ -25,7 +13,7 @@ import { SessionWatchRegistry } from "../session-watch.js";
25
13
  import type { TaskListLane } from "./task-list-lane.js";
26
14
  import { type RunnerDeps } from "@sema-agent/core";
27
15
  import type { MailboxRecipientLifecycle } from "../plugins/mailbox-recipient-lifecycle.js";
28
- import { type SessionPurgeOutcome } from "../session-deletion.js";
16
+ import { type SessionAgeOutExpectation, type SessionPurgeOutcome } from "../session-deletion.js";
29
17
  import { type SessionEraser, type SessionEraseSettler } from "../session-erase.js";
30
18
  import type { UserInputLedgerStore } from "../user-input-ledger.js";
31
19
  import type { SpaceReclaimer } from "../workspace-space.js";
@@ -75,6 +63,7 @@ export interface SessionFacesCtx {
75
63
  export declare function createSessionFaces(ctx: SessionFacesCtx): {
76
64
  ownerAware: OwnerAwareSessionStore;
77
65
  sessionAudit: ((sessionId: string, opts?: SessionAuditReadOpts) => Promise<{
66
+ sessionKind?: "sidechain" | undefined;
78
67
  projectId?: string | undefined;
79
68
  agent?: import("../session-agent.js").SessionAgent | undefined;
80
69
  owner: string | null;
@@ -90,7 +79,9 @@ export declare function createSessionFaces(ctx: SessionFacesCtx): {
90
79
  promptEpoch?: import("@sema-agent/core").StoredPromptEpoch;
91
80
  } | undefined>) | undefined;
92
81
  sessionWatchRegistry: SessionWatchRegistry | undefined;
93
- purgeSession: ((sessionId: string, owner: string | null) => Promise<SessionPurgeOutcome>) | undefined;
82
+ purgeSession: ((sessionId: string, owner: string | null, opts?: {
83
+ readonly ageOut?: SessionAgeOutExpectation;
84
+ }) => Promise<SessionPurgeOutcome>) | undefined;
94
85
  recoverPendingDeletions: (() => Promise<ReadonlyArray<{
95
86
  readonly sessionId: string;
96
87
  readonly outcome: SessionPurgeOutcome | {
@@ -1,3 +1,4 @@
1
+ import { sessionKindFaceOf } from "../session-kind.js";
1
2
  import { buildRewindHandles, buildSessionAudit, buildSessionAuditLocal, buildSessionAuditPg } from "../audit.js";
2
3
  import { readSessionAgent } from "../http/owner-access.js";
3
4
  import { readSessionProjectId, sessionWorkspaceStoreOf } from "../session-workspace.js";
@@ -24,6 +25,7 @@ export function createSessionFaces(ctx) {
24
25
  const ownerAware = sessionStore;
25
26
  const headOf = headReadOf(sessionStore);
26
27
  const workspaceStore = sessionWorkspaceStoreOf(sessionStore);
28
+ const kindFace = sessionKindFaceOf(sessionStore);
27
29
  const readSessionView = async (sessionId, opts) => {
28
30
  const handles = opts !== undefined && resumeAnchorStore !== undefined ? buildRewindHandles(await resumeAnchorStore.listBySession(sessionId), opts.reader) : undefined;
29
31
  const audit = mysqlPool
@@ -33,13 +35,15 @@ export function createSessionFaces(ctx) {
33
35
  : await buildSessionAuditLocal(auditLocalRows, sessionId, handles);
34
36
  if (!audit)
35
37
  return undefined;
36
- const [head, agent, projectId] = await Promise.all([
38
+ const [head, agent, projectId, kindRead] = await Promise.all([
37
39
  headOf?.(sessionId),
38
40
  opts !== undefined ? readSessionAgent(ownerAware, sessionId) : undefined,
39
41
  opts !== undefined ? readSessionProjectId(workspaceStore, sessionId) : undefined,
42
+ opts !== undefined ? kindFace?.sessionKindOf(sessionId) : undefined,
40
43
  ]);
41
44
  const owner = head?.owner;
42
- return { ...audit, owner: owner ?? null, ...(agent !== undefined ? { agent } : {}), ...(projectId !== undefined ? { projectId } : {}) };
45
+ const sessionKind = kindRead !== undefined && head !== undefined && kindRead.incarnation === head.incarnation ? kindRead.kind : undefined;
46
+ return { ...audit, owner: owner ?? null, ...(agent !== undefined ? { agent } : {}), ...(projectId !== undefined ? { projectId } : {}), ...(sessionKind !== undefined ? { sessionKind } : {}) };
43
47
  };
44
48
  const sessionAudit = mysqlPool || auditPgPool || auditLocalRows ? readSessionView : undefined;
45
49
  const probeWatchedHead = async (sid) => (headOf === undefined ? { owner: undefined, leafId: null } : ((await headOf(sid)) ?? { owner: undefined, leafId: null }));
@@ -64,7 +68,7 @@ export function createSessionFaces(ctx) {
64
68
  const attempts = new Map();
65
69
  const holder = (token) => attempts.get(token) ?? "elsewhere";
66
70
  const purge = eraser !== undefined && deletion !== undefined
67
- ? async (sessionId, owner, expect) => {
71
+ ? async (sessionId, owner, expect, ageOut) => {
68
72
  const tenantScope = sessionTenantScope(owner);
69
73
  const reach = await probeSessionChildren({ agentStore: backgroundAgentStore, checkpointStore, registry: defaultTaskRegistry }, sessionId, tenantScope);
70
74
  if (!reach.reachable) {
@@ -73,7 +77,7 @@ export function createSessionFaces(ctx) {
73
77
  }
74
78
  let fence;
75
79
  try {
76
- fence = await deletion.fence(sessionId, owner, expect === undefined ? { holder } : { holder, expect });
80
+ fence = await deletion.fence(sessionId, owner, { holder, ...(expect !== undefined ? { expect } : {}), ...(ageOut !== undefined ? { ageOut } : {}) });
77
81
  }
78
82
  catch (err) {
79
83
  if (err instanceof SessionActiveRunError)
@@ -143,7 +147,7 @@ export function createSessionFaces(ctx) {
143
147
  return { deleted: true };
144
148
  }
145
149
  : undefined;
146
- const purgeSession = purge !== undefined ? (sessionId, owner) => purge(sessionId, owner) : undefined;
150
+ const purgeSession = purge !== undefined ? (sessionId, owner, opts) => purge(sessionId, owner, undefined, opts?.ageOut) : undefined;
147
151
  const recoverOne = async (sessionId, owner, token) => {
148
152
  const unfinished = "the session stays in the deleting state (it reads as gone everywhere); the next start or a repeated DELETE by its owner finishes it";
149
153
  try {
@@ -12,6 +12,7 @@ import { installFileHistoryFailureRecorder } from "../file-history-disclosure.js
12
12
  import { installSecretEnvScrubRecorder } from "../observability/secret-env-scrub.js";
13
13
  import { setRunTerminalLogObserver } from "../observability/run-terminal.js";
14
14
  import { setRedactionObserver } from "../trace/redact.js";
15
+ import { setStoreBoundaryObserver } from "../terminal.js";
15
16
  import { installOutboundDispatcher } from "../outbound-dispatcher.js";
16
17
  import { bindOwnCredentialsConfig, declareServerWithheldEnv } from "../server-secret-env.js";
17
18
  import { admitLocalDataRoot } from "../plugins/local-data-root-admission.js";
@@ -53,6 +54,7 @@ export function runStage01() {
53
54
  });
54
55
  }
55
56
  setRedactionObserver((pattern, n, meta) => metrics.inc("redactions_applied_total", { pattern, arm: meta.arm }, n));
57
+ setStoreBoundaryObserver((site, faultClass) => metrics.inc("store_boundary_fault_total", { site, class: faultClass }));
56
58
  setWebSearchBadPayloadObserver((provider) => {
57
59
  metrics.inc("web_search_bad_payload_total", { provider });
58
60
  logger.warn("web_search_non_array_payload", { provider });
@@ -18,10 +18,12 @@ export declare function runStage05(ctx: Awaited<ReturnType<typeof runStage04>>):
18
18
  perSessionCwd: Map<string, string>;
19
19
  perTaskImage: import("../per-task-image.js").PerTaskImageRegistry;
20
20
  sendUserFileTaskEnvs: import("../capabilities/sandbox-file-send.js").TaskEnvRegistry | undefined;
21
+ sessionBindings: {
22
+ commitSessionBindings: (sessionId: string, bindings: import("../session-bindings.js").SessionBindings) => import("../session-bindings.js").SessionBindingReceipt;
23
+ withdrawSessionBindings: (receipt: import("../session-bindings.js").SessionBindingReceipt) => boolean;
24
+ settleSessionBindings: (receipt: import("../session-bindings.js").SessionBindingReceipt) => boolean;
25
+ };
21
26
  sessionEnvSelection: import("../capabilities/select-environment-tool.js").SessionEnvironmentSelection;
22
- setSessionCwd: (sid: string, cwd: string) => void;
23
- setSessionInheritEnv: (sid: string, policy: import("../request-value-closure.js").TaskInheritEnv | undefined) => void;
24
- setSessionShellEnv: (sid: string, env: Record<string, string>) => void;
25
27
  worktreeReap: (() => Promise<void>) | undefined;
26
28
  brain: import("@sema-agent/core").Brain;
27
29
  consolidationSeatWatch: import("./memory-consolidation.js").ConsolidationSeatWatch | undefined;
@@ -13,7 +13,7 @@ export async function runStage05(ctx) {
13
13
  const deviceLane = config.remoteExec.provider === "device" ? createDeviceLane({ config, logger, metrics, backend, seat: sessionStore.executionPlacement, replicaId: instanceId }) : undefined;
14
14
  const headOf = headReadOf(sessionStore);
15
15
  const spaceCommits = backend !== undefined ? () => runStore : undefined;
16
- const { perTaskImage, sessionEnvSelection, perSessionCwd, setSessionCwd, setSessionShellEnv, setSessionInheritEnv, fenceSessionOwner, dropSessionScoped, sessionResidentBackground, dropSessionScopedOf, executionEnvFactory, worktreeReap, sendUserFileTaskEnvs, lspManager, spaceReclaimer, sandboxSecretSeatGate, sandboxReaper, sandboxGitPlane: sandboxGitPlaneSeat, sandboxCapacity, } = createExecutionEnv({ config, logger, metrics, taskAttachmentStore, ...(deviceLane ? { deviceLane } : {}), ...(spaceCommits !== undefined ? { spaceCommits } : {}), ...(headOf !== undefined ? { headOf } : {}), ...(backend !== undefined ? { runRows: () => runStore } : {}) });
16
+ const { perTaskImage, sessionEnvSelection, perSessionCwd, sessionBindings, fenceSessionOwner, dropSessionScoped, sessionResidentBackground, dropSessionScopedOf, executionEnvFactory, worktreeReap, sendUserFileTaskEnvs, lspManager, spaceReclaimer, sandboxSecretSeatGate, sandboxReaper, sandboxGitPlane: sandboxGitPlaneSeat, sandboxCapacity, } = createExecutionEnv({ config, logger, metrics, taskAttachmentStore, ...(deviceLane ? { deviceLane } : {}), ...(spaceCommits !== undefined ? { spaceCommits } : {}), ...(headOf !== undefined ? { headOf } : {}), ...(backend !== undefined ? { runRows: () => runStore } : {}) });
17
17
  assertDeviceLaneWired(config.remoteExec.provider === "device", deviceLane, executionEnvFactory !== undefined);
18
18
  if (deviceLane !== undefined && config.remoteExec.provider === "device")
19
19
  await noteDeviceRelayBindings(config.remoteExec.relay, deviceLane.store, logger);
@@ -34,6 +34,6 @@ export async function runStage05(ctx) {
34
34
  const peerDesk = createPeerDesk({ log: logger });
35
35
  metrics.dynamicGauge("peer_registry_entries", "Peer desk entries (declared peer credentials registered for in-flight legs and the roster)", () => peerDesk.size().entries);
36
36
  metrics.dynamicGauge("peer_registry_holders", "Peer desk holders of entries (host leases and engine holds), summed across entries", () => peerDesk.size().holders);
37
- return { ...ctx, deploymentMods, deploymentModsLoaded, belowTaskChainPatterns, deviceLane, peerDesk, dropSessionScoped, dropSessionScopedOf, executionEnvFactory, fenceSessionOwner, sessionResidentBackground, lspManager, spaceReclaimer, sandboxReaper, sandboxGitPlane, sandboxCapacity, perSessionCwd, perTaskImage, sendUserFileTaskEnvs, sessionEnvSelection, setSessionCwd, setSessionInheritEnv, setSessionShellEnv, worktreeReap };
37
+ return { ...ctx, deploymentMods, deploymentModsLoaded, belowTaskChainPatterns, deviceLane, peerDesk, dropSessionScoped, dropSessionScopedOf, executionEnvFactory, fenceSessionOwner, sessionResidentBackground, lspManager, spaceReclaimer, sandboxReaper, sandboxGitPlane, sandboxCapacity, perSessionCwd, perTaskImage, sendUserFileTaskEnvs, sessionBindings, sessionEnvSelection, worktreeReap };
38
38
  }
39
39
  //# sourceMappingURL=stage-05-execution-env.js.map
@@ -34,7 +34,7 @@ export declare function runStage06(ctx: Awaited<ReturnType<typeof runStage05>>):
34
34
  sendUserFileToolSpec: import("@sema-agent/core").ToolSpec<import("@sema-agent/core").TSchema> | undefined;
35
35
  sessionTitler: import("../session-titler.js").SessionTitler | undefined;
36
36
  sharedMemoryStore: import("../plugins/shared-memory-store-sql.js").SqlSharedMemoryStore | undefined;
37
- sqlWorkflowRunStore: import("@sema-agent/core").WorkflowRunStore | undefined;
37
+ sqlWorkflowRunStore: import("../plugins/workflow-run-store-sql.js").SqlWorkflowRunStore | undefined;
38
38
  streamApprovalGate: import("../tool-approval.js").StreamApprovalGate<import("../approval-gate-currency.js").GateCurrencyStore>;
39
39
  subRunner: Runner;
40
40
  subagentSteerRegistry: import("../orchestration/subagent-steer.js").SubagentSteerRegistry;
@@ -45,6 +45,7 @@ export declare function runStage06(ctx: Awaited<ReturnType<typeof runStage05>>):
45
45
  workflowJournalStore: import("../plugins/store-backend.js").ServiceWorkflowJournalStore | undefined;
46
46
  workflowModelAllowlistSnapshot: readonly string[];
47
47
  workflowParkDecisions: import("../orchestration/workflow-park-decision.js").WorkflowParkDecisionStore | undefined;
48
+ workflowParkHolderPull: (() => Promise<import("../orchestration/workflow-park-holder.js").HolderPullTally>) | undefined;
48
49
  workflowNotifyGate: import("../orchestration/workflow-notify-journal.js").WorkflowNotifyGate | undefined;
49
50
  workflowNotifyJournal: import("../orchestration/workflow-notify-journal.js").WorkflowNotifyJournalStore | undefined;
50
51
  workflowRecoverOpts: {
@@ -73,10 +74,12 @@ export declare function runStage06(ctx: Awaited<ReturnType<typeof runStage05>>):
73
74
  perSessionCwd: Map<string, string>;
74
75
  perTaskImage: import("../per-task-image.js").PerTaskImageRegistry;
75
76
  sendUserFileTaskEnvs: import("../capabilities/sandbox-file-send.js").TaskEnvRegistry | undefined;
77
+ sessionBindings: {
78
+ commitSessionBindings: (sessionId: string, bindings: import("../session-bindings.js").SessionBindings) => import("../session-bindings.js").SessionBindingReceipt;
79
+ withdrawSessionBindings: (receipt: import("../session-bindings.js").SessionBindingReceipt) => boolean;
80
+ settleSessionBindings: (receipt: import("../session-bindings.js").SessionBindingReceipt) => boolean;
81
+ };
76
82
  sessionEnvSelection: import("../capabilities/select-environment-tool.js").SessionEnvironmentSelection;
77
- setSessionCwd: (sid: string, cwd: string) => void;
78
- setSessionInheritEnv: (sid: string, policy: import("../request-value-closure.js").TaskInheritEnv | undefined) => void;
79
- setSessionShellEnv: (sid: string, env: Record<string, string>) => void;
80
83
  worktreeReap: (() => Promise<void>) | undefined;
81
84
  brain: import("@sema-agent/core").Brain;
82
85
  consolidationSeatWatch: import("./memory-consolidation.js").ConsolidationSeatWatch | undefined;