@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
@@ -1,24 +1,16 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { type LaneHomeConfig } from "../lane-home-probe.js";
2
3
  import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory } from "@sema-agent/core";
3
4
  /** Options accepted by `ExecutionEnv.exec` (core does not re-export the type; derive it from the seam). */
4
5
  type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
5
6
  /** Construction config for {@link RemoteLocalDockerExecutionEnv}. */
6
- export interface LocalDockerEnvConfig {
7
+ export interface LocalDockerEnvConfig extends LaneHomeConfig {
7
8
  /**
8
9
  * Base container image to run the task in. **REQUIRED — no default** (domestic-images iron rule: the registry
9
10
  * is the operator's choice, never a hardcoded `docker.io` origin). e.g. the docker.io/claybobby pool or an
10
11
  * in-network `node:20` mirror (SWR deprecated).
11
12
  */
12
13
  image: string;
13
- /**
14
- * S-213④ / core [ref] —— 本执行环境的 **home 目录**(`ExecutionEnv.homeDir` 座,绝对路径,本环境自己的
15
- * 命名空间里)。`~/…` 形权限规则(`Edit(~/.ssh/**)`)对**跑在本 env 里的调用**就以它为基。
16
- * 缺席 ⇒ 本 env 声明「我没有 home」,core 对 `~/` 规则判 `unreadable`(fail-closed 的 ask),
17
- * 绝不回落引擎进程自己的 home(那在远端腿上是另一个用户的另一个目录 —— 静默守错目录正是 [ref] 的病)。
18
- * 值由 `boot/execution-env.ts` 从**唯一属主** `execution-lane-caps.ts` 的 `executionLaneHomeDir` 递进来;
19
- * adapter 不自算(两处各算一份 = 422 门与引擎对同一条规则给相反答案)。
20
- */
21
- homeDir?: string;
22
14
  /** Workspace root INSIDE the container; relative paths resolve against it. Default {@link DEFAULT_MOUNT_PATH}. */
23
15
  mountPath?: string;
24
16
  /** Path to the docker binary (or a docker-compatible CLI). Default "docker" (must be on PATH in the worker). */
@@ -77,8 +69,8 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
77
69
  };
78
70
  /** Working directory inside the container; relative paths resolve against it (ExecutionEnv contract). */
79
71
  cwd: string;
80
- /** core `ExecutionEnv.homeDir`([ref]):本沙箱/目标机上执行用户的 home。见配置同名字段。 */
81
- readonly homeDir?: string | undefined;
72
+ /** core `ExecutionEnv.homeDir`([ref]):本容器里执行用户的 home —— 声明胜,否则开容器那一拍实测的 `$HOME`,见 {@link LaneHomeSeat}。读时才取(没声明时连上之前缺席)。 */
73
+ get homeDir(): string | undefined;
82
74
  /** core 7.49.0 #1554:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在容器里(镜像的 env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
83
75
  * 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
84
76
  readonly cdPath: "unknown";
@@ -93,6 +85,10 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
93
85
  private destroyed;
94
86
  /** In-flight connect, memoized so concurrent lazy first-use starts exactly one container (no double-run). */
95
87
  private connecting?;
88
+ /** 家目录:环境答了而与声明不一致 ⇒ 这只环境的拒,记一次、此后每次连接原样回它(同一镜像同一答案:不再起容器、不再问)。 */
89
+ private homeRefusal?;
90
+ /** 家目录的座(声明胜 · 否则开容器那一拍实测 · 实测缺席 ⇒ 缺席 + 一行 warn)。本车道对声明对证。 */
91
+ private readonly homeSeat;
96
92
  constructor(config: LocalDockerEnvConfig, deps?: LocalDockerEnvDeps);
97
93
  private resolve;
98
94
  workspaceHandle(): WorkspaceHandle;
@@ -104,6 +100,13 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
104
100
  error: RemoteExecutionError;
105
101
  }>;
106
102
  private doConnect;
103
+ /**
104
+ * 家目录:座要问({@link LaneHomeSeat.asks}:声明在场 ⇒ 对证;没声明 ⇒ 实测)⇒ 在本容器里问一次 `$HOME`(与命令同一条 `docker exec` 通道、同一份 `-e` env),读数交座。
105
+ * 声明在场:环境答了而不一致 / 不是绝对路径 ⇒ 回拒并记在环境上(同一镜像同一答案:此后每次连接原样回它,不再起容器、不再问);没答上(exec 失败 / 超时 / 非零退出)⇒ 这一次同样不开,
106
+ * 但不记(与任何一次起容器失败同:下一次连接重问)。没声明:座收下绝对路径;答不上 / 不是绝对路径 ⇒ 座缺席 + 一行 warn,环境照开(没声明就没有声明可拒)。
107
+ * 调用方中止 ⇒ `aborted`、不记、不交座。容器由调用方收。
108
+ */
109
+ private homeVerdict;
107
110
  suspendVM(_options?: VmLifecycleOptions): Promise<{
108
111
  ok: true;
109
112
  value: SnapshotId;
@@ -183,6 +186,12 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
183
186
  suffix?: string;
184
187
  abortSignal?: AbortSignal;
185
188
  }): Promise<Result<string, FileError>>;
189
+ /**
190
+ * 交给宿主 `docker` CLI 的 env —— 宿主子进程 env 的唯一组合(`server-secret-env.ts` `hostSubprocessEnv`),继承词 `"all"`:本服务自有凭据(起服声明的名与值)
191
+ * 任何词都不交,CLI 与它拉起的凭据助手 / CLI 插件要读的变量(`DOCKER_*` / `AWS_*` …)照交 —— 形状剥会剥 `AWS_SECRET_ACCESS_KEY` 一类,ECR / GCR 凭据助手因此断。
192
+ * 命令本身跑在容器里,容器的 env 只由 `execArgv` 的 `-e K=V` 显式给,本 env 到不了容器。每次起进程现算一次(与 host shell 同)。
193
+ */
194
+ private cliEnv;
186
195
  /** Prepend `-H <dockerHost>` to a docker argv when configured (per-invocation, not the process env). */
187
196
  private withHostFlag;
188
197
  /** Build the `docker exec` argv for a command, applying cwd (`-w`) and per-command env (`-e K=V`).
@@ -198,8 +207,13 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
198
207
  * ⇒ 保 sh(修前字节形,诚实降级);探测自身失败同。容器**创建**引导命令(mkdir && tail)不走
199
208
  * 本 shell——无 bash 语法且探测尚不可能。 */
200
209
  private containerShell;
201
- private containerShellProbed;
210
+ /** shell 探测的**一只在飞承诺**:并发的调用方(首用 exec / fs、connect、reconnect)都 join 它 —— 修前是先置真的布尔,第二个调用方在探测落定之前就拿 /bin/sh 往下走,
211
+ * 探测随后才把命令切到 bash(家目录对证因此可能问的是另一只 shell)。 */
212
+ private containerShellReady?;
213
+ /** 等一只共享的承诺,调用方的取消只退**它自己的**等待(承诺照常落定、照常服务其余等待者)。`false` = 取消了。 */
214
+ private untilOrAborted;
202
215
  private probeContainerShell;
216
+ private detectContainerShell;
203
217
  private ensureConnectedExec;
204
218
  /** Lazy connect for a FileSystem path → FileError on failure (fail closed, never throws). */
205
219
  private fsReady;
@@ -2,10 +2,12 @@ import path from "node:path";
2
2
  import os from "node:os";
3
3
  import fs from "node:fs/promises";
4
4
  import { spawn } from "node:child_process";
5
+ import { hostSubprocessEnv } from "../server-secret-env.js";
6
+ import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
5
7
  import { randomBytes } from "node:crypto";
6
8
  import { shellQuote, armPipeDestroyGrace } from "./remote-shell.js";
7
9
  import { signalNumber } from "./host-platform.js";
8
- import { commandBoundsOf, livenessCutMessage } from "../exec-bounds.js";
10
+ import { buildLivenessCut, commandBoundsOf } from "../exec-bounds.js";
9
11
  import { FileError, ExecutionError, RemoteExecutionError, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
10
12
  import { fileErrorFromExec, classifyFsStderr } from "./remote-env-file-error.js";
11
13
  import { createPosixShellFs } from "./posix-shell-fs.js";
@@ -21,7 +23,9 @@ const unsupported = (op) => ({
21
23
  export class RemoteLocalDockerExecutionEnv {
22
24
  capabilities = { isolation: true, suspendable: false, canonicalPathAuthoritative: true };
23
25
  cwd;
24
- homeDir;
26
+ get homeDir() {
27
+ return this.homeSeat.home;
28
+ }
25
29
  cdPath = "unknown";
26
30
  cfg;
27
31
  spawnFn;
@@ -30,6 +34,8 @@ export class RemoteLocalDockerExecutionEnv {
30
34
  handle;
31
35
  destroyed = false;
32
36
  connecting;
37
+ homeRefusal;
38
+ homeSeat;
33
39
  constructor(config, deps = {}) {
34
40
  if (!config.image || !config.image.trim()) {
35
41
  config = { ...config, image: config.image ?? "" };
@@ -43,7 +49,7 @@ export class RemoteLocalDockerExecutionEnv {
43
49
  controlTimeoutMs: config.controlTimeoutMs ?? DEFAULT_CONTROL_TIMEOUT_MS,
44
50
  };
45
51
  this.cwd = this.cfg.mountPath;
46
- this.homeDir = config.homeDir;
52
+ this.homeSeat = new LaneHomeSeat({ lane: PROVIDER, declared: config.homeDir, verifiesDeclared: true, onAbsent: config.onHomeAbsent });
47
53
  this.spawnFn = deps.spawn ?? spawn;
48
54
  const id = config.id ?? randomBytes(6).toString("hex");
49
55
  const suffix = randomBytes(4).toString("hex");
@@ -62,6 +68,8 @@ export class RemoteLocalDockerExecutionEnv {
62
68
  return unsupported("connect(snapshotId)");
63
69
  if (this.destroyed)
64
70
  return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env already destroyed") };
71
+ if (this.homeRefusal)
72
+ return { ok: false, error: this.homeRefusal };
65
73
  if (config?.abortSignal?.aborted)
66
74
  return { ok: false, error: new RemoteExecutionError("aborted", "connect aborted") };
67
75
  if (this.containerId)
@@ -112,12 +120,39 @@ export class RemoteLocalDockerExecutionEnv {
112
120
  await this.forceRemove().catch(() => { });
113
121
  return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
114
122
  }
123
+ if (this.homeSeat.asks && !(await this.untilOrAborted(this.probeContainerShell(), config?.abortSignal))) {
124
+ await this.forceRemove().catch(() => { });
125
+ return { ok: false, error: new RemoteExecutionError("aborted", "connect aborted while detecting the container's shell") };
126
+ }
127
+ const home = await this.homeVerdict(config?.abortSignal);
128
+ if (home !== undefined) {
129
+ await this.forceRemove().catch(() => { });
130
+ return { ok: false, error: home };
131
+ }
132
+ if (this.destroyed) {
133
+ await this.forceRemove().catch(() => { });
134
+ return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
135
+ }
115
136
  this.containerId = run.value.stdout.trim() || this.containerName;
116
137
  this.handle = { sandboxId: this.containerName, provider: PROVIDER, mountPath: this.cfg.mountPath, sessionToken: this.containerName };
117
138
  if (config?.secrets?.length) {
118
139
  }
119
140
  return ok(this.handle);
120
141
  }
142
+ async homeVerdict(signal) {
143
+ if (!this.homeSeat.asks)
144
+ return undefined;
145
+ const probe = await this.docker(this.execRaw(LANE_HOME_PROBE_COMMAND), { signal, timeoutMs: this.cfg.controlTimeoutMs });
146
+ if (!probe.ok && probe.error.code === "aborted")
147
+ return new RemoteExecutionError("aborted", "connect aborted while reading the environment's home");
148
+ const verdict = this.homeSeat.settle(probe.ok && probe.value.exitCode === 0 ? { ok: true, stdout: probe.value.stdout } : { ok: false, reason: probe.ok ? `exit ${probe.value.exitCode}` : probe.error.message });
149
+ if (verdict === undefined)
150
+ return undefined;
151
+ const error = new RemoteExecutionError("connect_failed", verdict.refusal);
152
+ if (verdict.answered)
153
+ this.homeRefusal = error;
154
+ return error;
155
+ }
121
156
  async suspendVM(_options) {
122
157
  return unsupported("suspendVM");
123
158
  }
@@ -130,11 +165,25 @@ export class RemoteLocalDockerExecutionEnv {
130
165
  async reconnect(sessionToken) {
131
166
  if (this.destroyed)
132
167
  return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env already destroyed") };
168
+ if (this.homeRefusal)
169
+ return { ok: false, error: this.homeRefusal };
133
170
  if (sessionToken && sessionToken !== this.containerName) {
134
171
  return { ok: false, error: new RemoteExecutionError("connect_failed", `reconnect token '${String(sessionToken)}' does not match this env's container '${this.containerName}'`) };
135
172
  }
173
+ if (this.connecting !== undefined && this.containerId === undefined) {
174
+ const joined = await this.connecting;
175
+ if (!joined.ok || this.containerId !== undefined)
176
+ return joined;
177
+ }
136
178
  const insp = await this.docker(["inspect", "-f", "{{.State.Running}}", this.containerName], { timeoutMs: this.cfg.controlTimeoutMs });
137
179
  if (insp.ok && insp.value.exitCode === 0 && insp.value.stdout.trim() === "true") {
180
+ if (this.containerId === undefined && this.homeSeat.asks)
181
+ await this.probeContainerShell();
182
+ const home = this.containerId === undefined ? await this.homeVerdict() : undefined;
183
+ if (home !== undefined)
184
+ return { ok: false, error: home };
185
+ if (this.destroyed || this.homeRefusal)
186
+ return { ok: false, error: this.homeRefusal ?? new RemoteExecutionError("connect_failed", "execution env destroyed during reconnect") };
138
187
  this.containerId = this.containerName;
139
188
  this.handle ??= { sandboxId: this.containerName, provider: PROVIDER, mountPath: this.cfg.mountPath, sessionToken: this.containerName };
140
189
  return ok(this.handle);
@@ -179,7 +228,7 @@ export class RemoteLocalDockerExecutionEnv {
179
228
  if (!ready.ok)
180
229
  throw new RemoteExecutionError("connect_failed", ready.error.message, ready.error);
181
230
  const execArgs = this.execArgv(command, options?.cwd, options?.env);
182
- const child = this.spawnFn(this.cfg.dockerPath, this.withHostFlag(execArgs), { stdio: ["ignore", "pipe", "pipe"] });
231
+ const child = this.spawnFn(this.cfg.dockerPath, this.withHostFlag(execArgs), { stdio: ["ignore", "pipe", "pipe"], env: this.cliEnv() });
183
232
  const queue = [];
184
233
  let finished = false;
185
234
  let failure;
@@ -286,7 +335,8 @@ export class RemoteLocalDockerExecutionEnv {
286
335
  child.kill("SIGKILL");
287
336
  }
288
337
  catch { }
289
- throw new RemoteExecutionError("timeout", livenessCutMessage(liveness));
338
+ const cut = buildLivenessCut(liveness);
339
+ throw new RemoteExecutionError(cut.code, cut.message);
290
340
  }
291
341
  }
292
342
  while (queue.length)
@@ -427,6 +477,9 @@ export class RemoteLocalDockerExecutionEnv {
427
477
  async createTempFile(options) {
428
478
  return this.posixFs.createTempFile(options);
429
479
  }
480
+ cliEnv() {
481
+ return hostSubprocessEnv({ site: "server.remote-env-local-docker.spawn-env", policy: "all", allow: [] });
482
+ }
430
483
  withHostFlag(args) {
431
484
  return this.cfg.dockerHost ? ["-H", this.cfg.dockerHost, ...args] : args;
432
485
  }
@@ -447,7 +500,7 @@ export class RemoteLocalDockerExecutionEnv {
447
500
  return new Promise((resolve) => {
448
501
  let settled = false;
449
502
  let forceSettleTimer;
450
- const child = this.spawnFn(this.cfg.dockerPath, this.withHostFlag(args), { stdio: ["ignore", "pipe", "pipe"] });
503
+ const child = this.spawnFn(this.cfg.dockerPath, this.withHostFlag(args), { stdio: ["ignore", "pipe", "pipe"], env: this.cliEnv() });
451
504
  const killGrace = () => {
452
505
  try {
453
506
  child.kill("SIGKILL");
@@ -505,11 +558,29 @@ export class RemoteLocalDockerExecutionEnv {
505
558
  });
506
559
  }
507
560
  containerShell = "/bin/sh";
508
- containerShellProbed = false;
509
- async probeContainerShell() {
510
- if (this.containerShellProbed)
511
- return;
512
- this.containerShellProbed = true;
561
+ containerShellReady;
562
+ async untilOrAborted(shared, signal) {
563
+ if (!signal) {
564
+ await shared;
565
+ return true;
566
+ }
567
+ if (signal.aborted)
568
+ return false;
569
+ let onAbort;
570
+ const aborted = new Promise((res) => {
571
+ onAbort = () => res(false);
572
+ signal.addEventListener("abort", onAbort, { once: true });
573
+ });
574
+ const won = await Promise.race([shared.then(() => true), aborted]);
575
+ if (onAbort)
576
+ signal.removeEventListener("abort", onAbort);
577
+ return won;
578
+ }
579
+ probeContainerShell() {
580
+ this.containerShellReady ??= this.detectContainerShell();
581
+ return this.containerShellReady;
582
+ }
583
+ async detectContainerShell() {
513
584
  try {
514
585
  const r = await this.docker(["exec", this.containerName, "/bin/sh", "-c", "command -v bash"], { timeoutMs: this.cfg.controlTimeoutMs });
515
586
  if (r.ok && r.value.exitCode === 0 && r.value.stdout.trim().length > 0)
@@ -1,22 +1,14 @@
1
1
  import { type SshHostKeyPolicy } from "../ssh-host-key.js";
2
2
  import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory } from "@sema-agent/core";
3
+ import { type LaneHomeConfig } from "../lane-home-probe.js";
3
4
  type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
4
- export interface SshEnvConfig {
5
+ export interface SshEnvConfig extends LaneHomeConfig {
5
6
  host: string;
6
7
  port?: number;
7
8
  username: string;
8
9
  /** PEM private key — from the adapter-held secret env (NEVER the workspace). [ref] §5 #2. */
9
10
  privateKey: string;
10
11
  passphrase?: string;
11
- /**
12
- * S-213④ / core [ref] —— 本执行环境的 **home 目录**(`ExecutionEnv.homeDir` 座,绝对路径,本环境自己的
13
- * 命名空间里)。`~/…` 形权限规则(`Edit(~/.ssh/**)`)对**跑在本 env 里的调用**就以它为基。
14
- * 缺席 ⇒ 本 env 声明「我没有 home」,core 对 `~/` 规则判 `unreadable`(fail-closed 的 ask),
15
- * 绝不回落引擎进程自己的 home(那在远端腿上是另一个用户的另一个目录 —— 静默守错目录正是 [ref] 的病)。
16
- * 值由 `boot/execution-env.ts` 从**唯一属主** `execution-lane-caps.ts` 的 `executionLaneHomeDir` 递进来;
17
- * adapter 不自算(两处各算一份 = 422 门与引擎对同一条规则给相反答案)。
18
- */
19
- homeDir?: string;
20
12
  /** Workspace root; relative paths resolve against it. Default "." (the login dir). */
21
13
  mountPath?: string;
22
14
  /** Connect handshake bound (ms). */
@@ -92,8 +84,14 @@ export declare class RemoteSshExecutionEnv implements RemoteExecutionEnv {
92
84
  * =重连风暴);②共享尝试**不携带任何 caller 信号**(首创者的 pre-abort 不得毒化 joiner;单 caller
93
85
  * 取消只退它自己的等待,底层握手余命 ≤ readyTimeout 有界,彻底取消归 destroy 代际闸)。 */
94
86
  private inFlight?;
95
- /** core `ExecutionEnv.homeDir`([ref]):本沙箱/目标机上执行用户的 home。见配置同名字段。 */
96
- readonly homeDir?: string | undefined;
87
+ /** core `ExecutionEnv.homeDir`([ref]):目标机上登录用户的 home —— 声明胜,否则连上之后实测的 `$HOME`,见 {@link LaneHomeSeat}。读时才取(没声明时连上之前缺席)。 */
88
+ get homeDir(): string | undefined;
89
+ /** 家目录的座(声明胜 · 否则连上之后实测 · 实测缺席 ⇒ 缺席 + 一行 warn)。本车道对声明对证。 */
90
+ private readonly homeSeat;
91
+ /** 家目录声明 × 实测的判定,按连接记(同一条连接只问一次;重连换了连接再问 —— 登录用户不变时答案相同,代价一次往返;没声明且已量到绝对路径之后不再问)。 */
92
+ private homeChecked?;
93
+ /** 目标机答了而与声明不一致 ⇒ 这只环境的拒,记一次、此后每个面原样回它(同一目标机同一登录用户同一答案:不再问、不再发命令)。 */
94
+ private homeRefusal?;
97
95
  /** core 7.49.0 #1554:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在远端登录 shell 里(目标机的 profile / env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
98
96
  * 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
99
97
  readonly cdPath: "unknown";
@@ -119,6 +117,17 @@ export declare class RemoteSshExecutionEnv implements RemoteExecutionEnv {
119
117
  * caller 的 signal 只中止**它自己的等待**(共享在飞尝试继续伺服其他等待者;彻底取消归 destroy 的代际
120
118
  * 闸管,handshake 余命 ≤ readyTimeout 有界)。 */
121
119
  private ensureConnected;
120
+ /** 家目录判定的 per-caller 可中止等待(共享的判定承诺不动,只退本 caller)。 */
121
+ private raceVerdictAbort;
122
+ /**
123
+ * 家目录:座要问({@link LaneHomeSeat.asks}:声明在场 ⇒ 对证;没声明 ⇒ 量到绝对路径为止)⇒ 在这条连接上问一次 `$HOME`(登录用户的 shell 答的,与命令同一个用户、同一份登录 env),读数交座。
124
+ * 声明在场:答了而不一致 / 不是绝对路径 ⇒ 拒记在环境上(每个面原样回它),命令一条都不发;没答上(通道开不出 / 非零退出 / 超时)⇒ 这一次同样不开、不记,下一次调用重问。
125
+ * 没声明:座收下绝对路径;答不上 / 不是绝对路径 ⇒ 座缺席 + 一行 warn,命令照跑(没声明就没有声明可拒)—— 判定对这条连接记下,换了连接再问。
126
+ * 问的是裸命令(不经工作目录守卫:工作目录进不去不影响家目录的答案)。上界 = 握手的 `readyTimeoutMs`(问一个环境变量,不是跑用户命令)。
127
+ */
128
+ private homeVerdict;
129
+ /** 连接本身(不含家目录判定):{@link ensureConnected} 的第一半。 */
130
+ private ensureTransport;
122
131
  private connectOnce;
123
132
  suspendVM(_options?: VmLifecycleOptions): Promise<{
124
133
  ok: true;
@@ -3,10 +3,11 @@ import { Client } from "ssh2";
3
3
  import { createSshHostKeyVerifier } from "../ssh-host-key.js";
4
4
  import { buildCwdEnvCommand, createCwdGuardedCall, shellQuote, kindFromMode } from "./remote-shell.js";
5
5
  import { signalNumber } from "./host-platform.js";
6
- import { commandBoundsOf, livenessCutMessage } from "../exec-bounds.js";
6
+ import { buildLivenessCut, commandBoundsOf } from "../exec-bounds.js";
7
7
  import { createPosixShellFs } from "./posix-shell-fs.js";
8
8
  import { FileError, ExecutionError, RemoteExecutionError, withRetry, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
9
9
  import { fileErrorFromExec } from "./remote-env-file-error.js";
10
+ import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
10
11
  const PROVIDER = "ssh";
11
12
  const ok = (value) => ({ ok: true, value });
12
13
  const unsupported = (op) => ({
@@ -24,7 +25,12 @@ export class RemoteSshExecutionEnv {
24
25
  destroyed = false;
25
26
  connEpoch = 0;
26
27
  inFlight;
27
- homeDir;
28
+ get homeDir() {
29
+ return this.homeSeat.home;
30
+ }
31
+ homeSeat;
32
+ homeChecked;
33
+ homeRefusal;
28
34
  cdPath = "unknown";
29
35
  cfg;
30
36
  injectedConnectOnce;
@@ -44,7 +50,7 @@ export class RemoteSshExecutionEnv {
44
50
  hostKey: config.hostKey,
45
51
  };
46
52
  this.cwd = this.cfg.mountPath;
47
- this.homeDir = config.homeDir;
53
+ this.homeSeat = new LaneHomeSeat({ lane: PROVIDER, declared: config.homeDir, verifiesDeclared: true, onAbsent: config.onHomeAbsent });
48
54
  }
49
55
  resolve(p) {
50
56
  return path.posix.isAbsolute(p) ? path.posix.normalize(p) : path.posix.normalize(path.posix.join(this.cwd, p));
@@ -103,6 +109,110 @@ export class RemoteSshExecutionEnv {
103
109
  return record.promise;
104
110
  }
105
111
  async ensureConnected(signal) {
112
+ for (let round = 0; round < 3; round++) {
113
+ if (this.homeRefusal)
114
+ return { ok: false, error: this.homeRefusal };
115
+ const transport = await this.ensureTransport(signal);
116
+ if (!transport.ok || !this.homeSeat.asks)
117
+ return transport;
118
+ const conn = this.conn;
119
+ if (!conn)
120
+ return { ok: false, error: new ExecutionError("shell_unavailable", "SSH connection dropped right after connect") };
121
+ if (this.homeChecked?.conn !== conn) {
122
+ const checked = { conn, verdict: this.homeVerdict(conn) };
123
+ this.homeChecked = checked;
124
+ void checked.verdict.then((r) => {
125
+ if (!r.ok && this.homeRefusal === undefined && this.homeChecked === checked)
126
+ this.homeChecked = undefined;
127
+ });
128
+ }
129
+ const verdict = await this.raceVerdictAbort(this.homeChecked.verdict, signal);
130
+ if (signal?.aborted)
131
+ return { ok: false, error: new ExecutionError("aborted", "aborted while checking the environment's home") };
132
+ if (!verdict.ok)
133
+ return verdict;
134
+ if (this.conn === conn)
135
+ return verdict;
136
+ }
137
+ return { ok: false, error: new ExecutionError("shell_unavailable", "SSH connection kept being replaced while the environment's home was being checked") };
138
+ }
139
+ async raceVerdictAbort(shared, signal) {
140
+ if (!signal)
141
+ return shared;
142
+ if (signal.aborted)
143
+ return { ok: false, error: new ExecutionError("aborted", "aborted while checking the environment's home") };
144
+ let onAbort;
145
+ const aborted = new Promise((res) => {
146
+ onAbort = () => res({ ok: false, error: new ExecutionError("aborted", "aborted while checking the environment's home") });
147
+ signal.addEventListener("abort", onAbort, { once: true });
148
+ });
149
+ const raced = await Promise.race([shared, aborted]);
150
+ if (onAbort)
151
+ signal.removeEventListener("abort", onAbort);
152
+ return raced;
153
+ }
154
+ homeVerdict(conn) {
155
+ return new Promise((resolve) => {
156
+ const chunks = [];
157
+ let outBytes = 0;
158
+ let settled = false;
159
+ let channel;
160
+ let channelClosed = false;
161
+ const closeChannel = (ch) => {
162
+ if (ch === undefined || channelClosed)
163
+ return undefined;
164
+ try {
165
+ ch.close();
166
+ return undefined;
167
+ }
168
+ catch (e) {
169
+ return `the probe channel could not be closed: ${e instanceof Error ? e.message : String(e)}`;
170
+ }
171
+ };
172
+ const settle = (probe) => {
173
+ if (settled)
174
+ return;
175
+ settled = true;
176
+ clearTimeout(timer);
177
+ const closeTrouble = closeChannel(channel);
178
+ if (closeTrouble !== undefined && !probe.ok)
179
+ probe = { ok: false, reason: `${probe.reason}; ${closeTrouble}` };
180
+ const verdict = this.homeSeat.settle(probe);
181
+ if (verdict === undefined)
182
+ return resolve(ok(undefined));
183
+ const error = new ExecutionError("shell_unavailable", verdict.refusal);
184
+ if (verdict.answered)
185
+ this.homeRefusal = error;
186
+ resolve({ ok: false, error });
187
+ };
188
+ const timer = setTimeout(() => settle({ ok: false, reason: `no answer within ${this.cfg.readyTimeoutMs}ms` }), this.cfg.readyTimeoutMs);
189
+ try {
190
+ conn.exec(LANE_HOME_PROBE_COMMAND, (err, stream) => {
191
+ if (err)
192
+ return settle({ ok: false, reason: err.message });
193
+ if (settled)
194
+ return void closeChannel(stream);
195
+ channel = stream;
196
+ stream
197
+ .on("data", (d) => {
198
+ if (outBytes < 4096) {
199
+ chunks.push(d);
200
+ outBytes += d.length;
201
+ }
202
+ })
203
+ .on("close", (code) => {
204
+ channelClosed = true;
205
+ settle(code === 0 ? { ok: true, stdout: Buffer.concat(chunks).toString("utf8") } : { ok: false, reason: code == null ? "the channel closed without an exit status" : `exit ${code}` });
206
+ });
207
+ stream.stderr.on("data", () => { });
208
+ });
209
+ }
210
+ catch (e) {
211
+ settle({ ok: false, reason: e instanceof Error ? e.message : String(e) });
212
+ }
213
+ });
214
+ }
215
+ async ensureTransport(signal) {
106
216
  if (this.destroyed)
107
217
  return { ok: false, error: new ExecutionError("shell_unavailable", "SSH env destroyed — no lazy reconnect after teardown") };
108
218
  if (signal?.aborted)
@@ -435,8 +545,10 @@ export class RemoteSshExecutionEnv {
435
545
  if (waitTimer !== undefined)
436
546
  clearTimeout(waitTimer);
437
547
  }
438
- if (liveness !== undefined && !finished && Date.now() - lastChunk >= liveness.ms)
439
- throw new RemoteExecutionError("timeout", livenessCutMessage(liveness));
548
+ if (liveness !== undefined && !finished && Date.now() - lastChunk >= liveness.ms) {
549
+ const cut = buildLivenessCut(liveness);
550
+ throw new RemoteExecutionError(cut.code, cut.message);
551
+ }
440
552
  }
441
553
  while (queue.length)
442
554
  yield queue.shift();
@@ -134,7 +134,6 @@ export declare function drainNumEnvWarnings(): Array<{
134
134
  raw: string;
135
135
  }>;
136
136
  export declare function numEnvOr(name: string, def: number, min: number): number;
137
- export declare const SYMLINK_CHAIN_MAX_HOPS = 64;
138
137
  /**
139
138
  * 一次往返走完叶 symlink 链的 POSIX sh 脚本(**纯数据**:返回一个命令串 ⇒ `build*`,CLAUDE.md 工厂律)。
140
139
  *
@@ -1,4 +1,4 @@
1
- import { ExecutionError } from "@sema-agent/core";
1
+ import { ExecutionError, SYMLINK_CHAIN_MAX_HOPS } from "@sema-agent/core";
2
2
  import { classifyFsStderr, fileErrorFromExec } from "./remote-env-file-error.js";
3
3
  import { randomBytes } from "node:crypto";
4
4
  export const EXEC_FORCE_SETTLE_GRACE_MS = 3000;
@@ -120,7 +120,6 @@ export function numEnvOr(name, def, min) {
120
120
  }
121
121
  return Math.max(min, (Number.isFinite(n) ? n : 0) || def);
122
122
  }
123
- export const SYMLINK_CHAIN_MAX_HOPS = 64;
124
123
  export function buildSymlinkChainCommand(absPath) {
125
124
  return (`{ if ! command -v readlink >/dev/null 2>&1; then printf 'readlink: not found\\n' >&2; exit 127; fi; ` +
126
125
  `c=${shellQuote(absPath)}; n=0; ` +
@@ -2,6 +2,7 @@ import { mysqlDriver, pgDriver } from "./sql-driver.js";
2
2
  import { TASK_LIST_ITEM_TABLE, TASK_LIST_META_TABLE, taskListKeyFor } from "./task-list-store-sql.js";
3
3
  import { USER_INPUT_ACCEPTANCE_TABLE } from "./user-input-ledger-sql.js";
4
4
  import { ensureIndexes } from "./ensure-index.js";
5
+ import { incarnationFromCell } from "../session-incarnation.js";
5
6
  export const MANAGED_RETENTION = "managed";
6
7
  export const UNMANAGED_RETENTION = "none";
7
8
  export const RETENTION_AUDIT_TABLE = "retention_audit";
@@ -302,7 +303,10 @@ export class SqlRetentionStore {
302
303
  const { rows } = await exec.query(this.q(`SELECT sm.session_id, sm.incarnation FROM session_meta sm WHERE ${w.sql} AND sm.updated_at < ? AND NOT ${this.liveReferenceExists()} ` +
303
304
  `ORDER BY sm.updated_at ASC LIMIT ?${suffix}`, `SELECT sm.session_id, sm.incarnation FROM session_meta sm WHERE ${w.sql} AND sm.updated_at < $2 AND NOT ${this.liveReferenceExists()} ` +
304
305
  `ORDER BY sm.updated_at ASC LIMIT $3${suffix}`), [...w.params, new Date(input.cutoffMs), RETENTION_SESSION_BATCH]);
305
- return rows.map((r) => ({ id: String(r.session_id), incarnation: typeof r.incarnation === "string" ? r.incarnation : "" }));
306
+ return rows.map((r) => {
307
+ const id = String(r.session_id);
308
+ return { id, incarnation: incarnationFromCell(id, r.incarnation, "absent") };
309
+ });
306
310
  }
307
311
  async countOrphanToolResultCandidates(exec, input) {
308
312
  return (await this.orphanToolResultCandidates(exec, input)).length;
@@ -337,7 +341,7 @@ export class SqlRetentionStore {
337
341
  tombstones = await this.writeTombstones(conn, input.domain, "session", ids);
338
342
  }
339
343
  await this.writeAuditRow(conn, { domain: input.domain, action: "deleted_sessions", audit, deleted, skipped, tombstones });
340
- const endedSpaces = doomed.filter((d) => d.incarnation !== "").map((d) => ({ sessionId: d.id, spaceKey: d.incarnation }));
344
+ const endedSpaces = doomed.flatMap((d) => (d.incarnation === undefined ? [] : [{ sessionId: d.id, spaceKey: d.incarnation }]));
341
345
  return { domain: input.domain, deleted, skipped, tombstones, ...(endedSpaces.length > 0 ? { endedSpaces } : {}) };
342
346
  });
343
347
  }
@@ -2,13 +2,14 @@ import type { TaskStatus } from "@sema-agent/core";
2
2
  import type { Pool as MySqlPool } from "mysql2/promise";
3
3
  import type { Pool as PgPool } from "pg";
4
4
  import { type UsageRow } from "../usage-analytics.js";
5
- import { type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
6
- import { type SqlDriver } from "./sql-driver.js";
5
+ import { type ClaimFenced, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunListQuery, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
6
+ import { type SqlDriver, type SqlTxConn } from "./sql-driver.js";
7
7
  import type { LedgerEventType } from "../trace/ledger-events.js";
8
8
  import { type SpaceCommitClaim, type SpaceCommitReading, type SpaceCommitState } from "../workspace-space-commit.js";
9
9
  export type { RunRecord, SessionSummary, RunEvent, LatestRunRef } from "./store-contracts.js";
10
10
  export declare class SqlRunStore {
11
- protected readonly db: SqlDriver;
11
+ readonly db: SqlDriver;
12
+ /** `db` 公开只读:会话认领住在这只池背后的库里,写在认领栅栏里的店(workflow 子代决定行)读写都走它 —— 那只店的池只有这一处来源。 */
12
13
  constructor(db: SqlDriver);
13
14
  /** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
14
15
  private q;
@@ -159,6 +160,17 @@ export declare class SqlRunStore {
159
160
  * (一个输掉的认领不许覆盖赢家的持有记录——同一条条件 UPDATE 天然保证)。
160
161
  */
161
162
  markResuming(taskId: string, instanceId: string): Promise<boolean>;
163
+ /**
164
+ * 认领当写栅栏用(进程内两孪生的契约 = `store-contracts.ts` 的 `InProcessClaimFence`;本孪生是它的事务形):一个事务 ——
165
+ * ① 锁读这条 run 行且它在跑(`task_run … FOR UPDATE`);② 锁读会话的认领行且它是这条 run 的(`task_active … FOR UPDATE`);
166
+ * ③ 刷新这条 run 的活性戳;④ `write` 在**同一个事务连接**上跑;提交即放锁。任一没读到 ⇒ 不持有,不刷新、`write` 不调。`write` 抛或提交失败 ⇒ 整只抛。
167
+ * 🔴 **取锁序 = task_run → task_active**,与 `setTerminal` / `reapStale` / `reapSuspended` 同序(它们先改 run 行、再删认领行):两行用两条语句按序锁,
168
+ * 不用连表锁读(那一形的先后由计划器定,与终局 / 收割相反时两只事务各攥一行成环)。`createRun` 只插认领行、`deleteBySession` 见认领行在就中止,
169
+ * 都不与本序成环。锁住之后:收割的改行 / 终局与收割的删认领 / 别人的建行都排在本事务之后,收割器提交后重判 `updated_at` 看到的是刚刷的。
170
+ * 锁读没命中时 InnoDB 可能取一把间隙锁;本事务此后不往这两张表插任何行(见 space-commit 那条锁形注)。
171
+ * 担保止于提交:判出「持有」的是这只事务;提交确认在路上迟到、这一跑随后失去认领,不在本栅栏的射程里(调用方的已知边界)。
172
+ */
173
+ whileHoldingClaim<T>(sessionId: string, taskId: string, write: (tx: SqlTxConn) => Promise<T>): Promise<ClaimFenced<T>>;
162
174
  /** The active run's taskId for a session (the `task_active` claim) — lets resume find the suspended run row. */
163
175
  getActiveTaskId(sessionId: string): Promise<string | undefined>;
164
176
  /** Shared row→record mapper — byte-identical between dialects (both drivers hand back the same column
@@ -194,17 +206,7 @@ export declare class SqlRunStore {
194
206
  * built with plain string pushes in call order. PG's `$n` needs a NUMBERED placeholder per param, so that arm
195
207
  * keeps its own positional-counter closure (`p()`) — collapsing the two into one shared counter would hide
196
208
  * the very placeholder-numbering divergence this file exists to keep visible. */
197
- listRuns(opts: {
198
- status?: string;
199
- jobId?: string;
200
- source?: string;
201
- owner?: string;
202
- cursor?: {
203
- createdAt: string;
204
- taskId: string;
205
- };
206
- limit: number;
207
- }): Promise<RunRecord[]>;
209
+ listRuns(opts: RunListQuery): Promise<RunRecord[]>;
208
210
  /**
209
211
  * S-297 —— 这个会话**最近一条腿**的窄指针(`/mcp` 面板的 `lastLegMcp` 与任何「上一条 run 是谁」的读面共用)。
210
212
  *