@sema-agent/server 7.150.0 → 7.152.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (514) hide show
  1. package/MIGRATION.md +451 -0
  2. package/README.md +15 -3
  3. package/README.zh-CN.md +10 -2
  4. package/USAGE.md +144 -87
  5. package/deploy/sema-up/README.md +11 -4
  6. package/deploy/sema-up/chart/Chart.yaml +1 -1
  7. package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
  9. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
  10. package/deploy/sema-up/chart/templates/server.yaml +5 -3
  11. package/deploy/sema-up/chart/values-full-single.yaml +3 -1
  12. package/deploy/sema-up/chart/values.yaml +8 -1
  13. package/deploy/sema-up/cluster-up.sh +7 -6
  14. package/deploy/sema-up/kube-up.sh +6 -6
  15. package/deploy/sema-up/lib/flagshape.sh +36 -8
  16. package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
  17. package/deploy/sema-up/lib/helm-values-kube.py +2 -0
  18. package/deploy/sema-up/machines.example.yaml +3 -1
  19. package/deploy/sema-up/sema-up.sh +22 -16
  20. package/dist/adoption/import.js +3 -3
  21. package/dist/approval-ask-audit-store.d.ts +1 -1
  22. package/dist/approval-ask-machine.d.ts +4 -10
  23. package/dist/approval-ask-retention.d.ts +1 -1
  24. package/dist/approval-card.d.ts +12 -14
  25. package/dist/approval-gate-currency.d.ts +9 -9
  26. package/dist/approval-gate-currency.js +3 -4
  27. package/dist/approval-hmac.d.ts +17 -1
  28. package/dist/approval-hmac.js +7 -1
  29. package/dist/approval-queue-kind.d.ts +1 -1
  30. package/dist/approval.d.ts +2 -2
  31. package/dist/approval.js +2 -2
  32. package/dist/auth-bridge.d.ts +20 -0
  33. package/dist/auth-bridge.js +9 -0
  34. package/dist/background-session-reap.d.ts +1 -1
  35. package/dist/bake-runner/main.d.ts +4 -2
  36. package/dist/bind-host.d.ts +3 -6
  37. package/dist/bind-host.js +4 -7
  38. package/dist/boot/budget-tracing.js +1 -1
  39. package/dist/boot/coordinators.d.ts +1 -1
  40. package/dist/boot/coordinators.js +9 -10
  41. package/dist/boot/device-lane.js +2 -0
  42. package/dist/boot/engine-lease.d.ts +5 -0
  43. package/dist/boot/engine-lease.js +1 -0
  44. package/dist/boot/execution-env.d.ts +9 -14
  45. package/dist/boot/execution-env.js +85 -22
  46. package/dist/boot/execution-lane.js +32 -5
  47. package/dist/boot/late-binds.d.ts +8 -4
  48. package/dist/boot/late-binds.js +7 -1
  49. package/dist/boot/leader.d.ts +31 -30
  50. package/dist/boot/leader.js +38 -28
  51. package/dist/boot/leg-path-adjudication.d.ts +40 -0
  52. package/dist/boot/leg-path-adjudication.js +18 -0
  53. package/dist/boot/memory-consolidation.d.ts +3 -2
  54. package/dist/boot/memory-consolidation.js +6 -6
  55. package/dist/boot/parked-revive-gate.js +3 -15
  56. package/dist/boot/reapers.d.ts +6 -1
  57. package/dist/boot/reapers.js +13 -2
  58. package/dist/boot/resolve-spec.d.ts +3 -3
  59. package/dist/boot/resolve-spec.js +43 -48
  60. package/dist/boot/runner-deps.d.ts +46 -35
  61. package/dist/boot/runner-deps.js +94 -91
  62. package/dist/boot/session-age-out.d.ts +36 -0
  63. package/dist/boot/session-age-out.js +101 -0
  64. package/dist/boot/session-faces.d.ts +5 -14
  65. package/dist/boot/session-faces.js +9 -5
  66. package/dist/boot/shutdown.d.ts +6 -0
  67. package/dist/boot/shutdown.js +10 -4
  68. package/dist/boot/stage-01-config.js +2 -0
  69. package/dist/boot/stage-02-web-admin-pull.js +4 -5
  70. package/dist/boot/stage-05-execution-env.d.ts +5 -3
  71. package/dist/boot/stage-05-execution-env.js +3 -2
  72. package/dist/boot/stage-06-runners.d.ts +9 -4
  73. package/dist/boot/stage-06-runners.js +24 -9
  74. package/dist/boot/stage-07-capability-layer.d.ts +8 -4
  75. package/dist/boot/stage-07-capability-layer.js +3 -2
  76. package/dist/boot/stage-08-reapers.d.ts +8 -4
  77. package/dist/boot/stage-08-reapers.js +4 -2
  78. package/dist/boot/stage-09-leader.d.ts +12 -5
  79. package/dist/boot/stage-09-leader.js +14 -5
  80. package/dist/boot/stage-10-http-server.d.ts +19 -5
  81. package/dist/boot/stage-10-http-server.js +14 -21
  82. package/dist/boot/stores.js +7 -4
  83. package/dist/boot/web-admin.js +5 -8
  84. package/dist/boot/workflow-orchestration.d.ts +7 -2
  85. package/dist/boot/workflow-orchestration.js +24 -7
  86. package/dist/bounded-rotation.d.ts +29 -0
  87. package/dist/bounded-rotation.js +24 -0
  88. package/dist/capabilities/approvals-push.d.ts +3 -3
  89. package/dist/capabilities/scenarios.d.ts +28 -13
  90. package/dist/capabilities/scenarios.js +2 -2
  91. package/dist/capability-facts.d.ts +43 -32
  92. package/dist/capability-facts.js +45 -51
  93. package/dist/card-rule-offers.d.ts +32 -0
  94. package/dist/card-rule-offers.js +130 -0
  95. package/dist/center-credential.d.ts +25 -6
  96. package/dist/center-credential.js +25 -5
  97. package/dist/config-catalog.d.ts +26 -7
  98. package/dist/config-catalog.js +26 -22
  99. package/dist/config-dir-trust.js +4 -2
  100. package/dist/config-invariants.d.ts +20 -8
  101. package/dist/config-invariants.js +55 -12
  102. package/dist/config-lkg.d.ts +5 -19
  103. package/dist/config-lkg.js +8 -62
  104. package/dist/config-provider.d.ts +1 -1
  105. package/dist/config-root-migration.d.ts +2 -2
  106. package/dist/config-types.d.ts +38 -42
  107. package/dist/config.d.ts +58 -7
  108. package/dist/config.js +90 -40
  109. package/dist/control-socket.d.ts +51 -0
  110. package/dist/control-socket.js +115 -0
  111. package/dist/deployment-governance.d.ts +2 -1
  112. package/dist/deployment-shape.d.ts +9 -1
  113. package/dist/deployment-shape.js +2 -1
  114. package/dist/device-protocol.d.ts +5 -4
  115. package/dist/device-protocol.js +1 -1
  116. package/dist/device-ws-hub.d.ts +7 -0
  117. package/dist/device-ws-hub.js +10 -3
  118. package/dist/device-ws-protocol.d.ts +63 -10
  119. package/dist/device-ws-protocol.js +56 -25
  120. package/dist/elicitation.js +2 -2
  121. package/dist/engine-identity.d.ts +19 -7
  122. package/dist/engine-identity.js +10 -2
  123. package/dist/entry-mode-clamp-notice.d.ts +2 -1
  124. package/dist/entry-problems.d.ts +40 -3
  125. package/dist/entry-problems.js +3 -1
  126. package/dist/execution-env-refusal.d.ts +29 -0
  127. package/dist/execution-env-refusal.js +8 -0
  128. package/dist/execution-lane-caps.d.ts +3 -1
  129. package/dist/field-conflict.d.ts +1 -1
  130. package/dist/file-history-capture.d.ts +11 -4
  131. package/dist/file-history-capture.js +9 -6
  132. package/dist/file-history-disclosure.d.ts +7 -5
  133. package/dist/file-history-disclosure.js +7 -5
  134. package/dist/fleet/drain-entry.d.ts +4 -0
  135. package/dist/fleet/engine-signal.d.ts +12 -29
  136. package/dist/fleet/engine-signal.js +1 -7
  137. package/dist/fleet-client.js +2 -5
  138. package/dist/gate-settlement.d.ts +1 -8
  139. package/dist/gate-settlement.js +0 -4
  140. package/dist/history-anchor.js +1 -1
  141. package/dist/hitl-delivery.d.ts +2 -3
  142. package/dist/hitl-delivery.js +0 -2
  143. package/dist/hooks/hook-llm.js +4 -2
  144. package/dist/hooks/hook-runner.d.ts +3 -2
  145. package/dist/hooks/hook-runner.js +18 -3
  146. package/dist/host-decision.d.ts +11 -11
  147. package/dist/host-lsp-manager.d.ts +2 -2
  148. package/dist/http/active-run-conflict.d.ts +35 -2
  149. package/dist/http/active-run-conflict.js +48 -19
  150. package/dist/http/admission.js +17 -2
  151. package/dist/http/approval-sweeps.d.ts +1 -1
  152. package/dist/http/approval-sweeps.js +10 -7
  153. package/dist/http/checkpoint-ctx.d.ts +4 -0
  154. package/dist/http/checkpoint-ctx.js +2 -0
  155. package/dist/http/dispatch.d.ts +8 -3
  156. package/dist/http/dispatch.js +59 -32
  157. package/dist/http/durable-run-leg.js +16 -17
  158. package/dist/http/health-reader.d.ts +16 -9
  159. package/dist/http/health-reader.js +2 -1
  160. package/dist/http/health-self-report.d.ts +9 -1
  161. package/dist/http/health-self-report.js +3 -1
  162. package/dist/http/owner-access.d.ts +33 -14
  163. package/dist/http/owner-access.js +40 -10
  164. package/dist/http/principal-gate.d.ts +49 -21
  165. package/dist/http/principal-gate.js +61 -11
  166. package/dist/http/request-channel.d.ts +23 -0
  167. package/dist/http/request-channel.js +9 -0
  168. package/dist/http/request-guards.js +17 -2
  169. package/dist/http/resume-ctx-read.js +42 -3
  170. package/dist/http/resume-legs.d.ts +4 -3
  171. package/dist/http/resume-legs.js +367 -117
  172. package/dist/http/route-ctx.d.ts +91 -15
  173. package/dist/http/route-ctx.js +17 -0
  174. package/dist/http/route-table.d.ts +5 -1
  175. package/dist/http/route-table.js +4 -0
  176. package/dist/http/routes/admin-config-refresh.js +3 -3
  177. package/dist/http/routes/admin-drain.d.ts +3 -0
  178. package/dist/http/routes/admin-drain.js +7 -7
  179. package/dist/http/routes/admin-memory-optout.d.ts +1 -1
  180. package/dist/http/routes/admin-memory-optout.js +3 -3
  181. package/dist/http/routes/adoption.js +3 -5
  182. package/dist/http/routes/agents-roster.js +2 -3
  183. package/dist/http/routes/approvals-assistant.d.ts +2 -1
  184. package/dist/http/routes/approvals-assistant.js +99 -51
  185. package/dist/http/routes/background.d.ts +3 -3
  186. package/dist/http/routes/capabilities.d.ts +4 -0
  187. package/dist/http/routes/capabilities.js +38 -10
  188. package/dist/http/routes/config-catalog.js +2 -2
  189. package/dist/http/routes/devices.js +1 -1
  190. package/dist/http/routes/diagnostics.d.ts +3 -3
  191. package/dist/http/routes/diagnostics.js +19 -7
  192. package/dist/http/routes/fleet.js +10 -8
  193. package/dist/http/routes/images.js +10 -10
  194. package/dist/http/routes/memory-bundle.js +3 -3
  195. package/dist/http/routes/memory-compliance.js +3 -3
  196. package/dist/http/routes/memory-consolidation.js +2 -2
  197. package/dist/http/routes/memory-origin.js +3 -3
  198. package/dist/http/routes/memory-policy.js +2 -2
  199. package/dist/http/routes/observability.js +3 -3
  200. package/dist/http/routes/projects.d.ts +3 -2
  201. package/dist/http/routes/projects.js +4 -5
  202. package/dist/http/routes/retention-ops.js +3 -3
  203. package/dist/http/routes/rules.js +5 -5
  204. package/dist/http/routes/run-permission-mode.d.ts +2 -1
  205. package/dist/http/routes/run-permission-mode.js +2 -2
  206. package/dist/http/routes/runs.d.ts +4 -9
  207. package/dist/http/routes/runs.js +171 -65
  208. package/dist/http/routes/session-sync.d.ts +22 -9
  209. package/dist/http/routes/session-sync.js +204 -107
  210. package/dist/http/routes/sessions-list.js +13 -7
  211. package/dist/http/routes/sessions.js +30 -15
  212. package/dist/http/routes/tasks.js +46 -41
  213. package/dist/http/routes/trace-usage.js +2 -2
  214. package/dist/http/routes/workflows.js +1 -1
  215. package/dist/http/server.d.ts +30 -30
  216. package/dist/http/server.js +16 -4
  217. package/dist/http/submit-ctx.d.ts +1 -1
  218. package/dist/http/submit-ctx.js +7 -4
  219. package/dist/http/wire-types.d.ts +14 -4
  220. package/dist/human-facing-args.d.ts +33 -0
  221. package/dist/human-facing-args.js +33 -0
  222. package/dist/identity-source.d.ts +20 -3
  223. package/dist/identity-source.js +14 -0
  224. package/dist/index.d.ts +5 -1
  225. package/dist/k8s-api-credentials.d.ts +29 -0
  226. package/dist/k8s-api-credentials.js +25 -0
  227. package/dist/lane-home-probe.d.ts +3 -7
  228. package/dist/lane-home-probe.js +2 -2
  229. package/dist/leader/diffup.d.ts +19 -0
  230. package/dist/leader/diffup.js +7 -0
  231. package/dist/leader/leader.d.ts +116 -11
  232. package/dist/leader/leader.js +69 -5
  233. package/dist/leader/repair-wire.js +2 -2
  234. package/dist/leader/run-entry.d.ts +2 -1
  235. package/dist/leader/run-entry.js +1 -1
  236. package/dist/leader/wire.d.ts +42 -132
  237. package/dist/leader/wire.js +81 -67
  238. package/dist/leg-facts.d.ts +13 -5
  239. package/dist/leg-facts.js +2 -1
  240. package/dist/memory-scope.d.ts +23 -11
  241. package/dist/memory-scope.js +18 -6
  242. package/dist/memory-sync-client.d.ts +30 -2
  243. package/dist/memory-sync-client.js +16 -9
  244. package/dist/model-entry-headers.d.ts +9 -10
  245. package/dist/model-entry-headers.js +0 -4
  246. package/dist/model-entry-refusal.d.ts +7 -4
  247. package/dist/model-entry-refusal.js +11 -5
  248. package/dist/model-plane-face.d.ts +1 -1
  249. package/dist/model-plane-face.js +3 -1
  250. package/dist/model-route-endpoint.d.ts +13 -7
  251. package/dist/model-route-endpoint.js +14 -11
  252. package/dist/model-select.d.ts +22 -0
  253. package/dist/model-select.js +9 -0
  254. package/dist/model-unreachable-notice.d.ts +11 -0
  255. package/dist/model-unreachable-notice.js +4 -4
  256. package/dist/object-store-buckets.d.ts +640 -6
  257. package/dist/object-store-buckets.js +166 -0
  258. package/dist/observability/err-text.d.ts +7 -0
  259. package/dist/observability/err-text.js +5 -0
  260. package/dist/observability/fail-open.d.ts +25 -17
  261. package/dist/observability/fail-open.js +25 -17
  262. package/dist/observability/logger.js +3 -1
  263. package/dist/observability/metrics.js +1 -0
  264. package/dist/operator-roster.d.ts +68 -0
  265. package/dist/operator-roster.js +32 -0
  266. package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
  267. package/dist/orchestration/workflow-notify-journal.js +12 -1
  268. package/dist/orchestration/workflow-park-decision.d.ts +70 -18
  269. package/dist/orchestration/workflow-park-decision.js +49 -10
  270. package/dist/orchestration/workflow-park-holder.d.ts +65 -0
  271. package/dist/orchestration/workflow-park-holder.js +98 -0
  272. package/dist/orchestration/workflow-record-fence.d.ts +36 -0
  273. package/dist/orchestration/workflow-record-fence.js +42 -0
  274. package/dist/outbound-dispatcher.d.ts +71 -8
  275. package/dist/outbound-dispatcher.js +48 -7
  276. package/dist/owner-faces.d.ts +2 -2
  277. package/dist/parked-decide.d.ts +106 -55
  278. package/dist/parked-decide.js +153 -117
  279. package/dist/peer-directory.d.ts +2 -2
  280. package/dist/peer-inbound-face.d.ts +2 -6
  281. package/dist/peer-inbound-face.js +0 -3
  282. package/dist/permission-mode-admission.d.ts +74 -5
  283. package/dist/permission-mode-admission.js +56 -3
  284. package/dist/plugins/adoption-log-sql.d.ts +3 -1
  285. package/dist/plugins/adoption-log-sql.js +7 -1
  286. package/dist/plugins/approval-ask-store-file.d.ts +14 -2
  287. package/dist/plugins/approval-ask-store-file.js +11 -0
  288. package/dist/plugins/approval-ask-store-memory.d.ts +10 -1
  289. package/dist/plugins/approval-ask-store-memory.js +35 -10
  290. package/dist/plugins/approval-ask-store-sql.d.ts +69 -4
  291. package/dist/plugins/approval-ask-store-sql.js +45 -5
  292. package/dist/plugins/approval-exemption-store.js +3 -0
  293. package/dist/plugins/approval-nonce-store.js +2 -0
  294. package/dist/plugins/blob-backend.d.ts +83 -7
  295. package/dist/plugins/blob-backend.js +57 -6
  296. package/dist/plugins/breaker-state-sql.js +2 -0
  297. package/dist/plugins/caching-session-store.d.ts +9 -15
  298. package/dist/plugins/caching-session-store.js +6 -0
  299. package/dist/plugins/checkpoint-index-columns.d.ts +20 -16
  300. package/dist/plugins/checkpoint-index-columns.js +3 -6
  301. package/dist/plugins/checkpoint-store-face.d.ts +119 -61
  302. package/dist/plugins/checkpoint-store-face.js +134 -55
  303. package/dist/plugins/device-store-sql.js +6 -0
  304. package/dist/plugins/error-origin.d.ts +18 -0
  305. package/dist/plugins/error-origin.js +10 -0
  306. package/dist/plugins/execution-placement-sql.js +6 -6
  307. package/dist/plugins/image-bake-store-sql.js +6 -0
  308. package/dist/plugins/image-index-sql.js +4 -0
  309. package/dist/plugins/landed-attendants.d.ts +212 -0
  310. package/dist/plugins/landed-attendants.js +161 -0
  311. package/dist/plugins/leader-run-store-sql.js +4 -0
  312. package/dist/plugins/local-checkpoint-store.d.ts +13 -3
  313. package/dist/plugins/local-checkpoint-store.js +38 -49
  314. package/dist/plugins/local-session-live-reference.d.ts +40 -0
  315. package/dist/plugins/local-session-live-reference.js +39 -0
  316. package/dist/plugins/local-session-store.d.ts +71 -33
  317. package/dist/plugins/local-session-store.js +129 -27
  318. package/dist/plugins/memory-engine-pg.js +4 -0
  319. package/dist/plugins/memory-engine-sql-apply.js +5 -2
  320. package/dist/plugins/memory-engine-tidb.js +4 -0
  321. package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
  322. package/dist/plugins/memory-sync-store-pg.js +5 -0
  323. package/dist/plugins/memory-sync-store-tidb.js +5 -0
  324. package/dist/plugins/one-time-migrations.d.ts +104 -80
  325. package/dist/plugins/one-time-migrations.js +226 -132
  326. package/dist/plugins/org-delivery-quota-store.js +4 -1
  327. package/dist/plugins/outcome-ledger-sql.js +2 -0
  328. package/dist/plugins/permission-rule-store-sql.js +11 -4
  329. package/dist/plugins/pg-cost-quota.js +4 -0
  330. package/dist/plugins/pg-pool.js +35 -10
  331. package/dist/plugins/pg-rate-limiter.js +2 -0
  332. package/dist/plugins/posix-shell-fs.d.ts +6 -1
  333. package/dist/plugins/posix-shell-fs.js +4 -1
  334. package/dist/plugins/remote-env-adb.d.ts +19 -15
  335. package/dist/plugins/remote-env-adb.js +41 -15
  336. package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
  337. package/dist/plugins/remote-env-connect-seat.js +72 -0
  338. package/dist/plugins/remote-env-device.d.ts +22 -5
  339. package/dist/plugins/remote-env-device.js +106 -8
  340. package/dist/plugins/remote-env-e2b.d.ts +15 -6
  341. package/dist/plugins/remote-env-e2b.js +42 -32
  342. package/dist/plugins/remote-env-file-error.js +6 -2
  343. package/dist/plugins/remote-env-host.d.ts +46 -10
  344. package/dist/plugins/remote-env-host.js +124 -52
  345. package/dist/plugins/remote-env-k8s.d.ts +109 -41
  346. package/dist/plugins/remote-env-k8s.js +160 -54
  347. package/dist/plugins/remote-env-local-docker.d.ts +13 -8
  348. package/dist/plugins/remote-env-local-docker.js +34 -41
  349. package/dist/plugins/remote-env-ssh.d.ts +18 -12
  350. package/dist/plugins/remote-env-ssh.js +60 -59
  351. package/dist/plugins/remote-shell.d.ts +98 -1
  352. package/dist/plugins/remote-shell.js +218 -0
  353. package/dist/plugins/replica-registration.d.ts +1 -1
  354. package/dist/plugins/replica-registration.js +1 -1
  355. package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
  356. package/dist/plugins/resume-anchor-store-sql.js +12 -5
  357. package/dist/plugins/retention-lane-store-sql.js +4 -0
  358. package/dist/plugins/retention-sql.d.ts +20 -2
  359. package/dist/plugins/retention-sql.js +11 -0
  360. package/dist/plugins/run-store-sql.d.ts +21 -2
  361. package/dist/plugins/run-store-sql.js +31 -7
  362. package/dist/plugins/s3-presign.d.ts +23 -0
  363. package/dist/plugins/s3-presign.js +37 -3
  364. package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
  365. package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
  366. package/dist/plugins/scheduler-support.d.ts +2 -2
  367. package/dist/plugins/scheduler-support.js +0 -3
  368. package/dist/plugins/schema-consistency.d.ts +4 -2
  369. package/dist/plugins/schema-consistency.js +19 -2
  370. package/dist/plugins/schema-indexes.js +2 -0
  371. package/dist/plugins/send-file-ledger.d.ts +2 -2
  372. package/dist/plugins/send-file-ledger.js +5 -2
  373. package/dist/plugins/send-user-file.d.ts +3 -4
  374. package/dist/plugins/send-user-file.js +56 -52
  375. package/dist/plugins/serving-requirement.d.ts +26 -7
  376. package/dist/plugins/serving-requirement.js +11 -4
  377. package/dist/plugins/session-birth.d.ts +6 -2
  378. package/dist/plugins/session-blob-claim-token.d.ts +15 -0
  379. package/dist/plugins/session-blob-claim-token.js +20 -0
  380. package/dist/plugins/session-blob-namespace.d.ts +46 -0
  381. package/dist/plugins/session-blob-namespace.js +116 -0
  382. package/dist/plugins/session-capture-record-store-sql.js +2 -0
  383. package/dist/plugins/session-ext-table.d.ts +14 -1
  384. package/dist/plugins/session-ext-table.js +5 -1
  385. package/dist/plugins/session-row-sql.d.ts +49 -2
  386. package/dist/plugins/session-row-sql.js +56 -13
  387. package/dist/plugins/session-store-sql.d.ts +34 -18
  388. package/dist/plugins/session-store-sql.js +98 -17
  389. package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
  390. package/dist/plugins/shared-memory-store-sql.js +6 -2
  391. package/dist/plugins/snapshot-bucket-presence.d.ts +25 -2
  392. package/dist/plugins/snapshot-bucket-presence.js +8 -2
  393. package/dist/plugins/sql-driver.d.ts +2 -1
  394. package/dist/plugins/sql-driver.js +18 -3
  395. package/dist/plugins/sql-errors.d.ts +11 -6
  396. package/dist/plugins/sql-errors.js +5 -6
  397. package/dist/plugins/sql-json-column.d.ts +1 -1
  398. package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
  399. package/dist/plugins/stop-then-start-sentence.js +14 -10
  400. package/dist/plugins/stop-then-start.d.ts +109 -0
  401. package/dist/plugins/stop-then-start.js +104 -0
  402. package/dist/plugins/store-backend.d.ts +84 -15
  403. package/dist/plugins/store-backend.js +236 -72
  404. package/dist/plugins/store-boundary.d.ts +57 -0
  405. package/dist/plugins/store-boundary.js +139 -0
  406. package/dist/plugins/store-contracts.d.ts +17 -0
  407. package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
  408. package/dist/plugins/store-fault-sentence-m53.js +25 -0
  409. package/dist/plugins/store-fault.d.ts +26 -7
  410. package/dist/plugins/store-fault.js +18 -2
  411. package/dist/plugins/task-attachment-store.d.ts +2 -1
  412. package/dist/plugins/task-attachment-store.js +14 -1
  413. package/dist/plugins/task-list-store-sql.d.ts +2 -2
  414. package/dist/plugins/task-list-store-sql.js +10 -8
  415. package/dist/plugins/tidb-cost-quota.js +4 -0
  416. package/dist/plugins/tidb-pool.js +21 -25
  417. package/dist/plugins/tidb-rate-limiter.js +4 -0
  418. package/dist/plugins/user-input-ledger-sql.js +4 -0
  419. package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
  420. package/dist/plugins/workflow-run-store-sql.js +64 -4
  421. package/dist/plugins/workspace-custody.d.ts +4 -3
  422. package/dist/plugins/workspace-fill.d.ts +4 -7
  423. package/dist/plugins/workspace-fill.js +2 -1
  424. package/dist/plugins/write-behind-counter.js +5 -0
  425. package/dist/project-context.d.ts +0 -2
  426. package/dist/project-context.js +4 -8
  427. package/dist/project-registry.d.ts +46 -0
  428. package/dist/project-registry.js +44 -0
  429. package/dist/question.d.ts +2 -1
  430. package/dist/question.js +5 -13
  431. package/dist/request-form.d.ts +6 -1
  432. package/dist/request-form.js +4 -1
  433. package/dist/request-key-closure.js +1 -1
  434. package/dist/request-value-closure.d.ts +4 -0
  435. package/dist/request-value-closure.js +10 -0
  436. package/dist/rule-issue-reading.d.ts +1 -1
  437. package/dist/rules-consent.d.ts +1 -1
  438. package/dist/run-acceptance.d.ts +3 -2
  439. package/dist/run-acceptance.js +4 -6
  440. package/dist/run-local.js +9 -9
  441. package/dist/runs.d.ts +54 -16
  442. package/dist/runs.js +67 -13
  443. package/dist/runtime-governance.d.ts +5 -4
  444. package/dist/security.d.ts +30 -32
  445. package/dist/security.js +41 -7
  446. package/dist/sema-config-dir.d.ts +2 -1
  447. package/dist/server-secret-env.d.ts +12 -10
  448. package/dist/server-secret-env.js +24 -15
  449. package/dist/session-bindings.d.ts +82 -0
  450. package/dist/session-bindings.js +18 -0
  451. package/dist/session-children-retire.d.ts +2 -2
  452. package/dist/session-children-retire.js +2 -6
  453. package/dist/session-deletion.d.ts +16 -1
  454. package/dist/session-error-wire.d.ts +3 -3
  455. package/dist/session-error-wire.js +3 -3
  456. package/dist/session-incarnation.d.ts +10 -0
  457. package/dist/session-incarnation.js +10 -1
  458. package/dist/session-kind.d.ts +57 -0
  459. package/dist/session-kind.js +22 -0
  460. package/dist/session-row.d.ts +21 -1
  461. package/dist/session-row.js +7 -1
  462. package/dist/session-sync-kernel.d.ts +24 -14
  463. package/dist/session-sync-kernel.js +3 -6
  464. package/dist/session-sync.d.ts +25 -103
  465. package/dist/session-sync.js +14 -76
  466. package/dist/session-titler.d.ts +10 -3
  467. package/dist/session-titler.js +19 -6
  468. package/dist/ssh-host-key.d.ts +5 -0
  469. package/dist/ssh-host-key.js +3 -0
  470. package/dist/stores-sql/blob-index-sql.d.ts +30 -9
  471. package/dist/stores-sql/blob-index-sql.js +40 -21
  472. package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
  473. package/dist/stores-sql/checkpoint-store-sql.js +70 -146
  474. package/dist/stores-sql/file-history-store-sql.d.ts +113 -15
  475. package/dist/stores-sql/file-history-store-sql.js +205 -95
  476. package/dist/stores-sql/pg-session-storage.d.ts +34 -7
  477. package/dist/stores-sql/pg-session-storage.js +37 -13
  478. package/dist/stores-sql/retention-store-sql.d.ts +1 -9
  479. package/dist/stores-sql/retention-store-sql.js +5 -19
  480. package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
  481. package/dist/stores-sql/session-policy-store-sql.js +61 -44
  482. package/dist/stores-sql/session-write-hooks.d.ts +11 -0
  483. package/dist/stores-sql/tidb-session-store.d.ts +58 -7
  484. package/dist/stores-sql/tidb-session-store.js +37 -13
  485. package/dist/submission-exit.d.ts +3 -2
  486. package/dist/submission-exit.js +9 -1
  487. package/dist/task-cwd.d.ts +2 -2
  488. package/dist/task-settings.d.ts +7 -5
  489. package/dist/task-settings.js +3 -3
  490. package/dist/terminal.d.ts +33 -2
  491. package/dist/terminal.js +139 -9
  492. package/dist/tool-approval.d.ts +465 -507
  493. package/dist/tool-approval.js +606 -1222
  494. package/dist/trace/core-keyset-guard.d.ts +1 -1
  495. package/dist/trace/ledger-events.d.ts +3 -3
  496. package/dist/trace/project.d.ts +2 -3
  497. package/dist/trace/redact.js +3 -2
  498. package/dist/trace/self-minted-wire.d.ts +571 -178
  499. package/dist/trace/self-minted-wire.js +189 -56
  500. package/dist/web-admin-client/apply-effective.js +2 -2
  501. package/dist/web-admin-client/read-warnings.d.ts +2 -2
  502. package/dist/web-admin-client/read-warnings.js +1 -1
  503. package/dist/web-admin-client/types.d.ts +1 -1
  504. package/dist/workspace-space.d.ts +10 -4
  505. package/dist/workspace-space.js +4 -1
  506. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +79 -28
  507. package/package.json +7 -3
  508. package/scripts/embed-minimal.mjs +3 -3
  509. package/wire-changes/server@7.151.0.json +762 -0
  510. package/wire-changes/server@7.152.0.json +900 -0
  511. package/dist/config-d-migration.d.ts +0 -37
  512. package/dist/config-d-migration.js +0 -60
  513. package/dist/http/session-inherit-env.d.ts +0 -36
  514. package/dist/http/session-inherit-env.js +0 -6
@@ -0,0 +1,72 @@
1
+ import { RemoteExecutionError, isRetryableRemoteErrorCode } from "@sema-agent/core";
2
+ export const CONNECT_REFUSAL_CODE = {
3
+ home_unconfirmed: "env.home_unconfirmed",
4
+ snapshot_bucket_missing: "env.snapshot_bucket_missing",
5
+ occupant_missing: "env.occupant_missing",
6
+ pod_admission_refused: "env.sandbox_refused",
7
+ credential_broker_refused: "env.sandbox_refused",
8
+ archive_unrecoverable: "env.sandbox_refused",
9
+ workspace_fill_refused: "env.sandbox_refused",
10
+ host_key_rejected: "env.host_key_rejected",
11
+ pod_quota_exceeded: "connect_failed",
12
+ occupant_unreadable: "connect_failed",
13
+ target_settling: "connect_failed",
14
+ };
15
+ const ENGINE_FIELD_STILL_CLOSED = true;
16
+ void ENGINE_FIELD_STILL_CLOSED;
17
+ function mintRefusalError(code, message, cause) {
18
+ return new RemoteExecutionError(code, message, cause);
19
+ }
20
+ function standsFor(code) {
21
+ return !isRetryableRemoteErrorCode(code);
22
+ }
23
+ export function connectRefusal(fact, message, cause) {
24
+ const code = CONNECT_REFUSAL_CODE[fact];
25
+ const error = mintRefusalError(code, message, cause);
26
+ return standsFor(code) ? { ok: false, error, standing: true } : { ok: false, error, standing: false };
27
+ }
28
+ export function withdrawOnAbort(walk, signal) {
29
+ if (signal === undefined)
30
+ return walk;
31
+ if (signal.aborted)
32
+ return Promise.resolve({ ok: false, error: new RemoteExecutionError("aborted", "connect aborted") });
33
+ return new Promise((resolve, reject) => {
34
+ const onAbort = () => resolve({ ok: false, error: new RemoteExecutionError("aborted", "connect aborted while waiting") });
35
+ signal.addEventListener("abort", onAbort, { once: true });
36
+ walk.then((r) => {
37
+ signal.removeEventListener("abort", onAbort);
38
+ resolve(r);
39
+ }, (e) => {
40
+ signal.removeEventListener("abort", onAbort);
41
+ reject(e);
42
+ });
43
+ });
44
+ }
45
+ export function createConnectSeat(lane) {
46
+ let held;
47
+ return {
48
+ get held() {
49
+ return held;
50
+ },
51
+ answer(refusal) {
52
+ if (refusal.standing && held === undefined)
53
+ held = refusal;
54
+ return refusal;
55
+ },
56
+ connect(config) {
57
+ if (held !== undefined)
58
+ return Promise.resolve(held);
59
+ const signal = config?.abortSignal;
60
+ const walking = lane.inFlight();
61
+ if (walking !== undefined)
62
+ return withdrawOnAbort(walking, signal);
63
+ const handle = lane.live();
64
+ if (handle !== undefined)
65
+ return Promise.resolve({ ok: true, value: handle });
66
+ if (signal?.aborted)
67
+ return Promise.resolve({ ok: false, error: new RemoteExecutionError("aborted", "connect aborted") });
68
+ return lane.establish(config);
69
+ },
70
+ };
71
+ }
72
+ //# sourceMappingURL=remote-env-connect-seat.js.map
@@ -1,4 +1,4 @@
1
- import { ExecutionError, FileError, RemoteExecutionError, type ExecutionEnv, type ExecutionEnvFactory, type ExecStreamOptions, type FileInfo, type OutputChunk, type RemoteConnectConfig, type RemoteExecutionEnv, type Result, type SessionToken, type SnapshotId, type VmLifecycleOptions, type WorkspaceHandle, type WriteExpectation, type WriteReceipt } from "@sema-agent/core";
1
+ import { ExecutionError, FileError, RemoteExecutionError, type ExecutionEnv, type ExecutionEnvFactory, type ExecStreamOptions, type FileInfo, type OutputChunk, type RemoteConnectConfig, type RemoteExecutionEnv, type Result, type SessionToken, type SnapshotId, type VmLifecycleOptions, type WorkspaceHandle, type WriteExpectation, type WriteReceipt, type BoundFileObject } from "@sema-agent/core";
2
2
  import { type DeviceOwner, type DeviceRejectCode, type DeviceRow, type DeviceStore } from "../device-store.js";
3
3
  import type { DeviceEnrollment } from "../device-enrollment.js";
4
4
  import { type ExecutionPlacementSeat } from "../execution-placement.js";
@@ -48,6 +48,13 @@ type RejectCode = DeviceRejectCode;
48
48
  */
49
49
  export declare const DEVICE_REJECT_TO_EXEC_ERROR: Readonly<Record<RejectCode, ExecutionError["code"]>>;
50
50
  export declare const DEVICE_REJECT_TO_FILE_ERROR: Readonly<Record<RejectCode, FileError["code"]>>;
51
+ /**
52
+ * 生命周期面(connect/reconnect)的 typed 拒 → `RemoteExecutionErrorCode`。
53
+ *
54
+ * `connect_failed` = 本次到不了(**可重试**,core `RETRYABLE_REMOTE_ERROR_CODES` 含它);
55
+ * `auth_failed` = 永久拒(NEVER retry —— 换绑/吊销/不是你的设备,重试一万次也是同一答)。
56
+ */
57
+ export declare const DEVICE_REJECT_TO_REMOTE_ERROR: Readonly<Record<RejectCode, RemoteExecutionError["code"]>>;
51
58
  export interface DeviceEnvLogger {
52
59
  warn(msg: string, fields?: Record<string, unknown>): void;
53
60
  info?(msg: string, fields?: Record<string, unknown>): void;
@@ -102,9 +109,15 @@ export declare class RemoteDeviceExecutionEnv implements RemoteExecutionEnv {
102
109
  readLink?: (path: string, abortSignal?: AbortSignal) => Promise<Result<string, FileError>>;
103
110
  writeFileExclusive?: (path: string, content: string | Uint8Array, abortSignal?: AbortSignal) => Promise<Result<void, FileError>>;
104
111
  writeFileGuarded?: (path: string, content: string | Uint8Array, expect: WriteExpectation, abortSignal?: AbortSignal) => Promise<Result<WriteReceipt, FileError>>;
112
+ openBound?: (path: string, abortSignal?: AbortSignal) => Promise<Result<BoundFileObject, FileError>>;
105
113
  private connected;
106
114
  /** 在飞的那一次准入(单飞记忆)——见 {@link admitShared}。settle 即清,**不缓存败诺**。 */
107
115
  private connectPromise?;
116
+ /**
117
+ * 建连座(`remote-env-connect-seat.ts`):`connect` 的唯一次序 —— 准入在飞 ⇒ 等那一次(调用方的取消只退它自己的等待)· 已连 ⇒ 当下的把手、不再准入 · 否则准入一次。
118
+ * 本车道不记拒:准入每次都是对绑定 / 吊销 / 在线的一次新读(拒码按生命周期表拼:{@link DEVICE_REJECT_TO_REMOTE_ERROR})。
119
+ */
120
+ private readonly seat;
108
121
  /** 拆除是**终态**(六条兄弟腿同纪律:destroy 之后 connect/exec/读面一律 fail-closed,不复活)。 */
109
122
  private destroyed;
110
123
  constructor(cfg: DeviceEnvConfig);
@@ -170,10 +183,8 @@ export declare class RemoteDeviceExecutionEnv implements RemoteExecutionEnv {
170
183
  /**
171
184
  * 懒连接:**首次调用任一面**(exec / execStream / 文件面)时自动走一次准入。
172
185
  *
173
- * 🔴 为什么这条必须在 adapter 里(而不是「谁用谁先 connect」):task/run 车道**没有任何人**会替
174
- * adapter 调 `connect()` —— 工厂铸出 env 就直接用它的 exec/文件面(本仓亲核:`src/` 里对执行环境的
175
- * `.connect()` 只有 bench 与生命周期面自己)。所以一条「设了未连闸、又不自连」的腿,它的每一次工具
176
- * 调用都被自家的闸挡回,而设备侧一条指令帧都收不到。e2b(首用建 VM)/ k8s(`connectPromise ??=`)/
186
+ * 🔴 为什么这条必须在 adapter 里(而不是「谁用谁先 connect」):面可能在任何人连它之前就被调到(工厂交出之前的附件物化层、
187
+ * 委派子代的放置检查)。所以一条「设了未连闸、又不自连」的腿,它的每一次工具调用都被自家的闸挡回,而设备侧一条指令帧都收不到。e2b(首用建 VM)/ k8s(`connectPromise ??=`)/
177
188
  * ssh(single-flight join)/ local-docker 四腿早就是懒连接;本腿从此同形,`connect()` 的语义
178
189
  * (准入 + 取活连接 + 保护面对拍)一个字不动,只是触发时机与兄弟一致。
179
190
  *
@@ -262,6 +273,12 @@ export declare class RemoteDeviceExecutionEnv implements RemoteExecutionEnv {
262
273
  canonicalPath(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
263
274
  fileInfo(p: string, abortSignal?: AbortSignal): Promise<Result<FileInfo, FileError>>;
264
275
  private doReadLink;
276
+ private doOpenBound;
277
+ /**
278
+ * 逐答重绑的答者:每一答一条 `openBound` 指令,结局 kind **按 op 精确对拍**(`open` / `size` / `list` ⇒ `stat`,`readBytes` ⇒ `read`;答错 = 协议违约,不猜)。
279
+ * 开答之后的三答带开答时的 `identity` + `kind`,执行器在本机核对这一次打开的对象与它们都相等;每一答前照文件面同一道门(已拆 ⇒ 拒;首用准入)。
280
+ */
281
+ private boundAnswers;
265
282
  readBinaryFile(p: string, abortSignal?: AbortSignal): Promise<Result<Uint8Array, FileError>>;
266
283
  readTextFile(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
267
284
  readTextLines(p: string, options?: {
@@ -1,10 +1,12 @@
1
1
  import { posix } from "node:path";
2
2
  import { anchoredPath, anchorUnder, joinedPath } from "./exec-path-law.js";
3
3
  import { ExecutionError, FileError, RemoteExecutionError, } from "@sema-agent/core";
4
+ import { openRebinding } from "./remote-shell.js";
4
5
  import { capabilitiesFor } from "../execution-lane-caps.js";
5
6
  import { DEVICE_ERROR_CODES, isDeviceAbsolutePath, } from "../device-store.js";
6
7
  import { boundDeviceOf } from "../execution-placement.js";
7
8
  import { createCutError, createExecFailure } from "../exec-cut.js";
9
+ import { createConnectSeat, withdrawOnAbort } from "./remote-env-connect-seat.js";
8
10
  export const DEVICE_PROVIDER = "device";
9
11
  const ok = (value) => ({ ok: true, value });
10
12
  const STREAM_PENDING_MAX_BYTES = 2 * 1024 * 1024;
@@ -89,12 +91,12 @@ export const DEVICE_REJECT_TO_FILE_ERROR = {
89
91
  "limit.rate_exceeded": "target_unavailable",
90
92
  "draining": "target_unavailable",
91
93
  };
92
- const DEVICE_REJECT_TO_REMOTE_ERROR = {
94
+ export const DEVICE_REJECT_TO_REMOTE_ERROR = {
93
95
  "device.not_bound": "connect_failed",
94
96
  "device.offline": "connect_failed",
95
97
  "device.busy": "connect_failed",
96
98
  "device.attached_elsewhere": "connect_failed",
97
- "device.claim_conflict": "auth_failed",
99
+ "device.claim_conflict": "connect_failed",
98
100
  "device.provider_mismatch": "auth_failed",
99
101
  "device.identity_mismatch": "auth_failed",
100
102
  "device.revoked": "auth_failed",
@@ -110,6 +112,9 @@ function rejectText(reject) {
110
112
  }
111
113
  const ENV_TERMINAL = { kind: "env_terminal" };
112
114
  const ENV_TERMINAL_MESSAGE = "execution env already destroyed";
115
+ function connectAnswerOf(admitted) {
116
+ return admitted.ok ? { ok: true, value: admitted.value } : { ok: false, error: new RemoteExecutionError(admitted.failure.remote, admitted.failure.message) };
117
+ }
113
118
  function failureFor(code, message) {
114
119
  return { remote: DEVICE_REJECT_TO_REMOTE_ERROR[code], exec: DEVICE_REJECT_TO_EXEC_ERROR[code], file: DEVICE_REJECT_TO_FILE_ERROR[code], message };
115
120
  }
@@ -137,8 +142,14 @@ export class RemoteDeviceExecutionEnv {
137
142
  readLink;
138
143
  writeFileExclusive;
139
144
  writeFileGuarded;
145
+ openBound;
140
146
  connected = false;
141
147
  connectPromise;
148
+ seat = createConnectSeat({
149
+ live: () => (this.connected && !this.destroyed ? this.workspaceHandle() : undefined),
150
+ inFlight: () => this.connectPromise?.then(connectAnswerOf),
151
+ establish: (config) => withdrawOnAbort(this.admitShared().then(connectAnswerOf), config?.abortSignal),
152
+ });
142
153
  destroyed = false;
143
154
  constructor(cfg) {
144
155
  this.cfg = cfg;
@@ -150,6 +161,8 @@ export class RemoteDeviceExecutionEnv {
150
161
  this.writeFileExclusive = (p, c, s) => this.doWrite("writeFileExclusive", p, c, undefined, s);
151
162
  if (cfg.supports?.has("writeFileGuarded") === true)
152
163
  this.writeFileGuarded = (p, c, e, s) => this.doGuardedWrite(p, c, e, s);
164
+ if (cfg.supports?.has("openBound") === true)
165
+ this.openBound = (p, s) => this.doOpenBound(p, s);
153
166
  }
154
167
  guardFaceSnapshot() {
155
168
  const out = new Set();
@@ -196,12 +209,7 @@ export class RemoteDeviceExecutionEnv {
196
209
  };
197
210
  }
198
211
  async connect(config) {
199
- if (config?.abortSignal?.aborted === true)
200
- return { ok: false, error: new RemoteExecutionError("aborted", "connect aborted") };
201
- const admitted = await this.admitShared();
202
- if (admitted.ok)
203
- return ok(admitted.value);
204
- return { ok: false, error: new RemoteExecutionError(admitted.failure.remote, admitted.failure.message) };
212
+ return this.seat.connect(config);
205
213
  }
206
214
  async admitShared() {
207
215
  const inflight = this.connectPromise;
@@ -577,6 +585,96 @@ export class RemoteDeviceExecutionEnv {
577
585
  return ok(o.linkTarget);
578
586
  });
579
587
  }
588
+ async doOpenBound(p, abortSignal) {
589
+ const gated = await this.fsGate(p);
590
+ if (gated)
591
+ return gated;
592
+ const abs = this.resolve(p);
593
+ return openRebinding(abs, this.boundAnswers(abs), abortSignal);
594
+ }
595
+ boundAnswers(abs) {
596
+ const send = async (args, signal, onChunk) => {
597
+ const gated = await this.fsGate(abs);
598
+ if (gated)
599
+ return gated;
600
+ return this.dispatch("openBound", { path: abs, ...args }, { timeoutMs: this.cfg.execTimeoutMs, ...(signal === undefined ? {} : { signal }), ...(onChunk === undefined ? {} : { onChunk }) });
601
+ };
602
+ const violation = (what) => ({ ok: false, error: new FileError("unknown", `device returned an openBound outcome ${what} — protocol violation`, abs) });
603
+ return {
604
+ open: async (signal) => {
605
+ const res = await send({ op: "open" }, signal);
606
+ if ("ok" in res)
607
+ return res;
608
+ return this.fileOutcome(res, abs, (o) => {
609
+ if (o.kind !== "stat")
610
+ return this.wrongOutcome("stat", o.kind, abs);
611
+ if (typeof o.identity !== "string" || o.identity === "" || o.info === undefined)
612
+ return violation("without identity and info for the open answer");
613
+ if (o.info.kind !== "file" && o.info.kind !== "dir")
614
+ return violation(`naming a ${o.info.kind} (an executor refuses anything but a regular file or a directory with invalid)`);
615
+ return ok({ identity: o.identity, kind: o.info.kind === "dir" ? "directory" : "file" });
616
+ });
617
+ },
618
+ size: async (bound) => {
619
+ const res = await send({ op: "size", identity: bound.identity, kind: bound.kind }, undefined);
620
+ if ("ok" in res)
621
+ return res;
622
+ return this.fileOutcome(res, abs, (o) => {
623
+ if (o.kind !== "stat")
624
+ return this.wrongOutcome("stat", o.kind, abs);
625
+ if (o.info === undefined)
626
+ return violation("without info for the size answer");
627
+ return ok(o.info.size);
628
+ });
629
+ },
630
+ readBytes: async (bound, max, signal) => {
631
+ const parts = [];
632
+ let got = 0;
633
+ let stray;
634
+ const res = await send({ op: "readBytes", identity: bound.identity, kind: bound.kind, max }, signal, (c) => {
635
+ if (c.kind !== "data") {
636
+ stray ??= c.kind;
637
+ return;
638
+ }
639
+ if (c.data === undefined || c.data.length === 0)
640
+ return;
641
+ got += c.data.length;
642
+ if (got <= max)
643
+ parts.push(c.data);
644
+ });
645
+ if ("ok" in res)
646
+ return res;
647
+ return this.fileOutcome(res, abs, (o) => {
648
+ if (o.kind !== "read")
649
+ return this.wrongOutcome("read", o.kind, abs);
650
+ if (stray !== undefined)
651
+ return violation(`carrying a ${stray} chunk for a readBytes answer (only data chunks belong to it)`);
652
+ if (got > max)
653
+ return { ok: false, error: new FileError("invalid", `The held file is over the ${max}-byte read cap (${got} bytes or more arrived); it was not read`, abs) };
654
+ return ok(new Uint8Array(Buffer.concat(parts)));
655
+ });
656
+ },
657
+ list: async (bound, signal) => {
658
+ const res = await send({ op: "list", identity: bound.identity, kind: bound.kind }, signal);
659
+ if ("ok" in res)
660
+ return res;
661
+ return this.fileOutcome(res, abs, (o) => {
662
+ if (o.kind !== "stat")
663
+ return this.wrongOutcome("stat", o.kind, abs);
664
+ if (o.entries === undefined)
665
+ return violation("without entries for the list answer");
666
+ const entries = [];
667
+ for (const w of o.entries) {
668
+ const kind = w.kind === "dir" ? "directory" : w.kind === "symlink" ? "symlink" : w.kind === "file" ? "file" : undefined;
669
+ if (kind === undefined)
670
+ continue;
671
+ entries.push({ name: posix.basename(w.path), kind, size: w.size, mtimeMs: w.mtimeMs });
672
+ }
673
+ return ok(entries);
674
+ });
675
+ },
676
+ };
677
+ }
580
678
  async readBinaryFile(p, abortSignal) {
581
679
  const gated = await this.fsGate(p);
582
680
  if (gated)
@@ -20,7 +20,7 @@
20
20
  * iterator MAY throw `RemoteExecutionError` mid-stream before an `exit` chunk (seam contract, OutputChunk).
21
21
  */
22
22
  import { Sandbox, type SandboxOpts, type SandboxConnectOpts } from "e2b";
23
- import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type ExecResult, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type ExecutionEnvFactory, type VmLifecycleOptions, type BackgroundShellCapability, type BackgroundShellId, type BackgroundShellError, type BackgroundSpawnOptions, type BackgroundPoll, type ExecutionEnvCapabilities } from "@sema-agent/core";
23
+ import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type ExecResult, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type BoundFileObject, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type ExecutionEnvFactory, type VmLifecycleOptions, type BackgroundShellCapability, type BackgroundShellId, type BackgroundShellError, type BackgroundSpawnOptions, type BackgroundPoll, type ExecutionEnvCapabilities } from "@sema-agent/core";
24
24
  import { type SandboxReadFloorKnob } from "../execution-lane-caps.js";
25
25
  import { type SandboxReadFloor } from "./sandbox-read-floor.js";
26
26
  import { type LaneHomeConfig } from "../lane-home-probe.js";
@@ -127,9 +127,12 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
127
127
  private destroyed;
128
128
  /** 家目录的座(主张在场 ⇒ 每只沙箱对证 · 否则建沙箱那一拍实测 · 实测缺席 ⇒ 缺席 + 一行 warn)。 */
129
129
  private readonly homeSeat;
130
- /** 这只环境的拒 —— 记一次、此后每次连接 / 恢复原样回它(同一模板同一个答案:不再建沙箱、不再问)。两个写者:家目录(沙箱答了而与主张不一致,或答的不是绝对路径)
131
- * 与恢复点的填充(换一台沙箱也是同一个答的拒:种子不是项目包、摘要不符、镜像没有 `tar`、镜像预置撞名 —— `FillOutcome.standing`)。 */
132
- private connectRefusal?;
130
+ /**
131
+ * 建连座(`remote-env-connect-seat.ts`):`connect` 的唯一次序(记住的拒 ⇒ 原样再答 · 一走在飞 ⇒ 等它 · 已连 ⇒ 当下的把手 · 否则建一只沙箱),并持有这只环境记住的拒 ——
132
+ * 记一次、此后每次连接 / 恢复原样回它(同一模板同一个答案:不再建沙箱、不再问)。两件立定的事实写它:家目录(沙箱答了而与主张不一致,或答的不是绝对路径;`env.home_unconfirmed`)
133
+ * 与恢复点的填充(换一台沙箱也是同一个答的拒:种子不是项目包、摘要不符、镜像没有 `tar`、镜像预置撞名 —— `FillOutcome.standing`;`env.sandbox_refused`)。
134
+ */
135
+ private readonly seat;
133
136
  /** In-flight connect/resume, memoized so concurrent lazy first-use OR resume provisions exactly one VM (no double-bill). `target` = the snapshot a resume
134
137
  * restores (`undefined` = a fresh sandbox): {@link resumeVM} shares only a resume of the SAME snapshot — a connect for anything else is not the
135
138
  * workspace it is asked to restore (it waits that one out, then releases the sandbox it left). */
@@ -223,8 +226,9 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
223
226
  }>;
224
227
  /**
225
228
  * 家目录:座要问({@link LaneHomeSeat.asks}:主张在场 ⇒ 对证;没主张 ⇒ 量到绝对路径为止)⇒ 在这只沙箱里问一次 `$HOME`(前台 `commands.run`,与命令同一个
226
- * 模板缺省用户、同一份沙箱 env),读数交座。返回这只沙箱的拒(`connect_failed`,拒句 = 同一只判官的句子),或 `undefined`(照用)。
227
- * 沙箱答了的拒记在环境上(同一模板同一个答案);没答上(非零退出 / RPC 失败 / 输出里没有标记行)⇒ 这一次不开、不记,下一次重问;调用方中止 ⇒ `aborted`、不交座。
229
+ * 模板缺省用户、同一份沙箱 env),读数交座。返回这只沙箱的拒(拒句 = 同一只判官的句子),或 `undefined`(照用)。
230
+ * 沙箱答了的拒是立定的拒(`env.home_unconfirmed`,建连座记住它:同一模板同一个答案);没答上(非零退出 / RPC 失败 / 输出里没有标记行)⇒ 这一次不开、不记(`connect_failed`),
231
+ * 下一次重问;调用方中止 ⇒ `aborted`、不交座。
228
232
  * 上界 = 控制面 RPC 的墙钟(`rpcTimeoutMs`:问一个环境变量,不是跑用户命令)。
229
233
  */
230
234
  private homeVerdict;
@@ -295,6 +299,11 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
295
299
  * 🔴 exit≠0 归 `unknown` 而不是 `not_found`(与本腿 `readLink` 那一格刻意分家,同 `posix-shell-fs` 的理由):
296
300
  * 「叶不是软链」与「叶不存在」在这条命令上都是 exit 0 + 空 stdout,所以 exit≠0 一定不是「文件不在」。 */
297
301
  canonicalChain(p: string, abortSignal?: AbortSignal): Promise<Result<SymlinkChain, FileError>>;
302
+ /** 绑定读(逐答重绑,Linux 读法)。本腿不并进 `posix-shell-fs` 基座(原生 SDK 腿),但脚本、读法与工厂与四条 shell 腿**是同一只**
303
+ * (`remote-shell.ts` `openBoundOverShell`),这里只多一条传输:{@link execInternal}(适配器自己的固定命令那一起动,与链脚本同一形)、数据界。
304
+ * 🔴 字节只经 stdout 的 base64 回来 —— `files.read` 按路径读,不能用;也不「拷进暂存件再按路径读」(同身份进程可换暂存件或它的祖先目录)。 */
305
+ openBound(p: string, abortSignal?: AbortSignal): Promise<Result<BoundFileObject, FileError>>;
306
+ private get boundLane();
298
307
  canonicalPath(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
299
308
  exists(p: string, abortSignal?: AbortSignal): Promise<Result<boolean, FileError>>;
300
309
  createDir(p: string, options?: {
@@ -7,7 +7,8 @@ import { DEPLOYMENT_SHAPE_PREDICATES } from "../deployment-shape.js";
7
7
  import { ADAPTER_START, BOOTSTRAP_START, createSandboxReadFloor, e2bFloorCommand, engineStart, } from "./sandbox-read-floor.js";
8
8
  import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
9
9
  import { fileErrorFromExec } from "./remote-env-file-error.js";
10
- import { appendFileStaged, readyUpload, rewriteAppend, numEnvOr, runSymlinkChain, shellQuote, writeFileStaged } from "./remote-shell.js";
10
+ import { connectRefusal, createConnectSeat } from "./remote-env-connect-seat.js";
11
+ import { appendFileStaged, openBoundOverShell, readyUpload, rewriteAppend, numEnvOr, runSymlinkChain, shellQuote, writeFileStaged } from "./remote-shell.js";
11
12
  import { buildLivenessCut, commandBoundsOf, firstBoundOf, laneLivenessOf, LIVENESS_MS_DEFAULT } from "../exec-bounds.js";
12
13
  import { createCutError } from "../exec-cut.js";
13
14
  import { BackgroundShellManager } from "./background-shell-support.js";
@@ -37,7 +38,22 @@ export class RemoteContainerExecutionEnv {
37
38
  handle;
38
39
  destroyed = false;
39
40
  homeSeat;
40
- connectRefusal;
41
+ seat = createConnectSeat({
42
+ live: () => (this.sbx !== undefined && !this.paused ? this.workspaceHandle() : undefined),
43
+ inFlight: () => this.connecting?.promise,
44
+ establish: (config) => {
45
+ if (this.paused)
46
+ return Promise.resolve({ ok: false, error: new RemoteExecutionError("connect_failed", "execution env is suspended (paused) — resumeVM(snapshotId) before use") });
47
+ const mine = { target: undefined, promise: this.doConnect(config) };
48
+ this.connecting = mine;
49
+ const settled = () => {
50
+ if (this.connecting === mine)
51
+ this.connecting = undefined;
52
+ };
53
+ void mine.promise.then(settled, settled);
54
+ return mine.promise;
55
+ },
56
+ });
41
57
  connecting;
42
58
  activeCommands = 0;
43
59
  paused = false;
@@ -156,20 +172,7 @@ export class RemoteContainerExecutionEnv {
156
172
  }
157
173
  if (this.destroyed)
158
174
  return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env already destroyed") };
159
- if (this.connectRefusal)
160
- return { ok: false, error: this.connectRefusal };
161
- if (this.paused)
162
- return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env is suspended (paused) — resumeVM(snapshotId) before use") };
163
- if (this.sbx)
164
- return ok(this.workspaceHandle());
165
- if (this.connecting)
166
- return this.connecting.promise;
167
- const mine = { target: undefined, promise: this.doConnect(config) };
168
- this.connecting = mine;
169
- const r = await mine.promise;
170
- if (!r.ok && this.connecting === mine)
171
- this.connecting = undefined;
172
- return r;
175
+ return this.seat.connect(config);
173
176
  }
174
177
  async doConnect(config) {
175
178
  try {
@@ -200,9 +203,7 @@ export class RemoteContainerExecutionEnv {
200
203
  if (!filled.ok || this.destroyed) {
201
204
  await sbx.kill().catch(() => { });
202
205
  this.cfg.metrics?.inc("remote_env_connect_total", { provider: PROVIDER, result: "error" });
203
- if (!filled.ok && filled.standing)
204
- this.connectRefusal = filled.error;
205
- return { ok: false, error: filled.ok ? new RemoteExecutionError("connect_failed", "execution env destroyed during connect") : filled.error };
206
+ return filled.ok ? { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") } : this.seat.answer(filled);
206
207
  }
207
208
  this.sbx = sbx;
208
209
  this.paused = false;
@@ -256,8 +257,9 @@ export class RemoteContainerExecutionEnv {
256
257
  resumeVM(snapshotId, options) {
257
258
  if (this.destroyed)
258
259
  return Promise.resolve({ ok: false, error: new RemoteExecutionError("connect_failed", "env already destroyed") });
259
- if (this.connectRefusal)
260
- return Promise.resolve({ ok: false, error: this.connectRefusal });
260
+ const held = this.seat.held;
261
+ if (held)
262
+ return Promise.resolve(held);
261
263
  if (this.sbx && !this.paused && this.sbx.sandboxId === snapshotId)
262
264
  return Promise.resolve(ok(this.workspaceHandle()));
263
265
  const inFlight = this.connecting;
@@ -269,10 +271,7 @@ export class RemoteContainerExecutionEnv {
269
271
  if (this.connecting === mine)
270
272
  this.connecting = undefined;
271
273
  };
272
- mine.promise.then((r) => {
273
- if (!r.ok)
274
- forget();
275
- }, forget);
274
+ mine.promise.then(forget, forget);
276
275
  return mine.promise;
277
276
  }
278
277
  async resumeWalk(inFlight, snapshotId, options) {
@@ -280,6 +279,9 @@ export class RemoteContainerExecutionEnv {
280
279
  await inFlight.promise;
281
280
  if (this.destroyed)
282
281
  return { ok: false, error: new RemoteExecutionError("connect_failed", "env already destroyed") };
282
+ const held = this.seat.held;
283
+ if (held)
284
+ return held;
283
285
  if (this.sbx && !this.paused && this.sbx.sandboxId === snapshotId)
284
286
  return ok(this.workspaceHandle());
285
287
  }
@@ -329,9 +331,7 @@ export class RemoteContainerExecutionEnv {
329
331
  if (!filled.ok) {
330
332
  await this.rpc("sandbox.pause", (signal) => sbx.pause({ signal }), undefined, this.cfg.dataTimeoutMs).catch((e) => this.cfg.logger?.warn?.("remote_env_fill_refused_repause_failed", { sandboxId: sbx.sandboxId, error: errMsg(e) }));
331
333
  this.cfg.metrics?.inc("remote_env_resume_total", { provider: PROVIDER, result: "error" });
332
- if (filled.standing)
333
- this.connectRefusal = filled.error;
334
- return { ok: false, error: filled.error };
334
+ return this.seat.answer(filled);
335
335
  }
336
336
  this.sbx = sbx;
337
337
  this.paused = false;
@@ -383,10 +383,7 @@ export class RemoteContainerExecutionEnv {
383
383
  const verdict = this.homeSeat.settle(probe);
384
384
  if (verdict === undefined)
385
385
  return undefined;
386
- const error = new RemoteExecutionError("connect_failed", verdict.refusal);
387
- if (verdict.answered)
388
- this.connectRefusal = error;
389
- return error;
386
+ return verdict.answered ? this.seat.answer(connectRefusal("home_unconfirmed", verdict.refusal)).error : new RemoteExecutionError("connect_failed", verdict.refusal);
390
387
  }
391
388
  fillAt(sbx, root, origin) {
392
389
  return this.cfg.workspaceFill === undefined ? Promise.resolve({ ok: true }) : this.cfg.workspaceFill.fill(this.fillChannel(sbx), root, origin);
@@ -968,6 +965,19 @@ export class RemoteContainerExecutionEnv {
968
965
  async canonicalChain(p, abortSignal) {
969
966
  return runSymlinkChain(this.resolve(p), (cmd) => this.execInternal(cmd, { abortSignal }));
970
967
  }
968
+ async openBound(p, abortSignal) {
969
+ return openBoundOverShell(this.resolve(p), this.boundLane, abortSignal);
970
+ }
971
+ get boundLane() {
972
+ return {
973
+ run: async (cmd, _cap, abortSignal) => {
974
+ const r = await this.execInternal(cmd, { cwd: "/", timeout: this.cfg.dataTimeoutMs / 1000, ...(abortSignal !== undefined ? { abortSignal } : {}) });
975
+ return r.ok ? { ok: true, value: { stdout: Buffer.from(r.value.stdout, "utf8"), stderr: r.value.stderr, exitCode: r.value.exitCode } } : r;
976
+ },
977
+ payload: "base64",
978
+ boundSec: this.cfg.dataTimeoutMs / 1000,
979
+ };
980
+ }
971
981
  async canonicalPath(p, abortSignal) {
972
982
  const abs = this.resolve(p);
973
983
  const r = await this.execInternal(`realpath -- ${shellQuote(abs)}`, { abortSignal });
@@ -1,9 +1,13 @@
1
1
  import { FileError, RemoteExecutionError } from "@sema-agent/core";
2
+ import { isExecutionEnvRefusalCode } from "../execution-env-refusal.js";
3
+ function sayEnvNotOpened(code) {
4
+ return code === "connect_failed" || isExecutionEnvRefusalCode(code);
5
+ }
2
6
  function neverOpened(e) {
3
- if (e.code === "connect_failed")
7
+ if (sayEnvNotOpened(e.code))
4
8
  return true;
5
9
  const cause = e.cause;
6
- return cause instanceof RemoteExecutionError && cause.code === "connect_failed";
10
+ return cause instanceof RemoteExecutionError && sayEnvNotOpened(cause.code);
7
11
  }
8
12
  export function fileErrorFromExec(e, path) {
9
13
  const code = e.code === "aborted" ? "aborted" : neverOpened(e) ? "target_unavailable" : "unknown";
@@ -1,3 +1,4 @@
1
+ import { type PlatformPath } from "node:path";
1
2
  import { FileError, type InheritEnvPolicy, ExecutionError, RemoteExecutionError, SchedulerError, type SchedulerCapability, type ScheduledIntent, type SchedulerContext, type ScheduledTaskId, type ScheduledTaskSummary, type ExecutionEnv, type ExecResult, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type BoundFileObject, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory, type ExecutionEnvFactoryContext, BackgroundShellError, type BackgroundShellCapability, type BackgroundShellId, type BackgroundHardKillOutcome, type BackgroundPoll, type BackgroundSpawnOptions, type SecretEnvFinding } from "@sema-agent/core";
2
3
  import { type LaneHomeConfig } from "../lane-home-probe.js";
3
4
  import { type CustodyMember } from "./workspace-custody.js";
@@ -45,7 +46,8 @@ export interface HostEnvConfig extends LaneHomeConfig {
45
46
  * user's OWN directory (e.g. the cwd `run-local` was invoked in), not an adapter-created ephemeral sandbox,
46
47
  * so the agent's file edits PERSIST and are user-visible (like a local coding agent working in your repo).
47
48
  * Takes precedence over `workspaceBase`/`id` (those are ignored). Default unset = ephemeral random + cleanup.
48
- * 唯一的例外由托管表说:它落在一只本服务铸的临时根里({@link custody} 的 `sharedRoot`)⇒ 本环境共持那只根,不是调用方自有目录。
49
+ * 唯一的例外由托管表说:它落在一只本服务铸的临时根里 ⇒ 本环境(也)持有那只根 —— 铸时就判得出的({@link custody} 的 `sharedRoot`)从铸起共持;
50
+ * 铸时判不出、在那只根的最后一只持有者放手那一拍读得出地落在里面的,当场接过删除({@link RemoteHostExecutionEnv.assumeRoot})。
49
51
  */
50
52
  workspaceDir?: string;
51
53
  /**
@@ -71,10 +73,16 @@ export interface HostEnvConfig extends LaneHomeConfig {
71
73
  }
72
74
  /** 工作区托管表交给它铸的环境的那一面(`workspace-custody.ts`;host 车道的读法)。 */
73
75
  export interface HostWorkspaceCustodySeat {
74
- /** `workspaceDir` 落在这只本服务铸的临时根里(委派子代按父的工作目录落根)⇒ 本环境与它的铸者共持这只根:建成后登记、收场时放手、最后放手的持有者删它。 */
76
+ /**
77
+ * 铸时那一判:`workspaceDir` 落在这只本服务铸的临时根里(委派子代按父的工作目录落根)⇒ 本环境从铸起与它的持有者共持这只根。
78
+ * 这是删除责任的**提前交接**,不是删除的闸 —— 删不删只由 {@link passOn} 在放手那一拍答。
79
+ */
75
80
  readonly sharedRoot?: string;
76
- /** 表里除 `self` 之外还有没有成员持有 `root` —— 收场放手时问;有 ⇒ 删交给最后放手的那一只。 */
77
- heldElsewhere(self: RemoteHostExecutionEnv, root: string): boolean;
81
+ /**
82
+ * 删前那一判(本环境放手 `root` 的同一同步段里问;同步、永不抛):「此刻还有谁在 `root` 里」—— 另有持有者 / 有还没离场的环境读得出地落在里面(它当场接过)/
83
+ * 有读不出的(留给退出兜底)⇒ `true`,不删;读得出地没人 ⇒ `false`,本环境在同一同步段里把它移出原路径再删。
84
+ */
85
+ passOn(self: RemoteHostExecutionEnv, root: string): boolean;
78
86
  }
79
87
  export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, SchedulerCapability, BackgroundShellCapability, CustodyMember<never> {
80
88
  /** 能力块的唯一作者 = `capabilitiesFor`(`execution-lane-caps.ts`;逐键表态与理由在那里,本类零能力字面量)。 */
@@ -190,10 +198,17 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
190
198
  */
191
199
  private drainInflightFs;
192
200
  private ensureSpoolRoot;
193
- /** 本环境对它工作区的租期({@link HostWorkspaceTenure}):借用的永不删;持有的收场放手、最后放手的持有者删。唯一写处 = 构造与 {@link removeOwnedTrees}。 */
201
+ /** 本环境对它工作区的租期({@link HostWorkspaceTenure}):借用的永不删;持有的收场放手、放手那一拍判得没人才删。唯一写处 = 构造、{@link assumeRoot} 与 {@link removeOwnedTrees}。 */
194
202
  private tenure;
203
+ /** 离场({@link left}):唯一写处 = {@link removeOwnedTrees} 的放手段。 */
204
+ private hasLeft;
195
205
  /** Memoized lazy `mkdir -p` so concurrent first-use prepares the workspace exactly once. */
196
206
  private preparing?;
207
+ /**
208
+ * 建连座(`remote-env-connect-seat.ts`):`connect` 的唯一次序 —— 建工作目录在飞 ⇒ 等那一次(调用方的取消只退它自己的等待)· 已建好 ⇒ 当下的把手 · 否则建一次。
209
+ * 本车道不记拒:主张证不了的家目录在构造时就拒了(环境不铸),建目录的失败是那一次的(下一次重来)。
210
+ */
211
+ private readonly seat;
197
212
  private readonly handle;
198
213
  constructor(config?: HostEnvConfig);
199
214
  /** 收场的进度(托管表读):活着 ⇒ 缺席;{@link destroy} 开始 ⇒ 那一次收场。 */
@@ -202,10 +217,20 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
202
217
  get released(): boolean;
203
218
  /** 本车道收场不欠同一身份下一只环境任何账(删不掉的根留在退出兜底簿上,不交接)。 */
204
219
  readonly leftover: undefined;
205
- /** 收场落定且已放手 ⇒ 出托管表(超时臂里放手挂在在飞写之后:落定了还持有 ⇒ 仍是持有者)。 */
220
+ /**
221
+ * 离场:本环境自己的收场放手那一段({@link removeOwnedTrees},在飞写落地之后)跑过。删前那一判只问还没离场的环境「你在不在这只根里」——
222
+ * 收场开始了而写还没落地的仍在场(它的写还会落进去);离场之后它不再动工作区(残余镜像写只许落在借用目录 / spool 根上)。
223
+ */
224
+ get left(): boolean;
225
+ /** 收场落定且已离场 ⇒ 出托管表(超时臂里放手挂在在飞写之后:落定了还没离场 ⇒ 仍在表里,借用的与持有的同一句)。 */
206
226
  get settled(): boolean;
207
- /** 本环境此刻持有的、本服务铸的临时根(托管表的持有读法读它);借用 / 已放手 ⇒ 缺席。 */
208
- get heldWorkspace(): string | undefined;
227
+ /** 本环境此刻持有的、本服务铸的临时根(托管表的持有读法读它;正常流至多一只);借用 / 已放手 ⇒ 空。 */
228
+ get heldRoots(): readonly string[];
229
+ /**
230
+ * 删前那一判把 `root` 的删除交给本环境。唯一调用方 = 工厂的 {@link passOnRoot}(与放手者的判在同一同步段;前提:本环境还没离场、工作目录读得出地落在 `root` 里):
231
+ * 持有集合加上它(借用的从此持有;已持有别的根的两只都持有),离场时按同一句律逐根再判。`root` 在盘或读不出 ⇒ 当场登记退出兜底簿(本环境的 prepare 可能早已跑过、不会再登记)。
232
+ */
233
+ assumeRoot(root: string): void;
209
234
  workspaceHandle(): WorkspaceHandle;
210
235
  connect(config?: RemoteConnectConfig): Promise<{
211
236
  ok: true;
@@ -214,6 +239,10 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
214
239
  ok: false;
215
240
  error: RemoteExecutionError;
216
241
  }>;
242
+ /** 工作目录已建好时 `connect` 的那一答。 */
243
+ private preparedAnswer;
244
+ /** 建工作目录失败时 `connect` 的那一答(那一次的失败:下一次重来)。 */
245
+ private prepareFailed;
217
246
  suspendVM(_options?: VmLifecycleOptions): Promise<{
218
247
  ok: true;
219
248
  value: SnapshotId;
@@ -474,6 +503,13 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
474
503
  private childHome;
475
504
  private fileError;
476
505
  }
506
+ /**
507
+ * host 环境配置座的拼法(构造期的 `workspaceDir` / `workspaceBase` / 托管 `sharedRoot`,与工厂托管判读的腿目录同一只):与执行缝同一只读者
508
+ * (`exec-path-law.ts` 的 `anchoredPath`)—— 绝对的原样,相对的锚在本进程工作目录上,不折 `..`、不解链接。win32 的盘相对拼写(`C:work`)相对的是
509
+ * **那只盘**上的工作目录:锚在本进程在那只盘上的工作目录(`resolve("C:")`)下、余下原样接上(不这样读,它会被当成一段名字接在工作目录后面:`<cwd>\C:work`)。
510
+ * `pathApi` 只为让 POSIX 上的钉量 win32 形;生产读本机的 `path`。
511
+ */
512
+ export declare function hostSeatPath(p: string, pathApi?: PlatformPath): string;
477
513
  /**
478
514
  * `ExecutionEnvFactory` for the TOC `host` backend (DUAL-MODE-DESIGN §5). Wiring this onto a deployment makes
479
515
  * its agent run DIRECTLY on the worker's machine (no container) — the local-coding-agent default. One fresh
@@ -490,8 +526,8 @@ export interface HostLegConfig extends Pick<HostEnvConfig, "workspaceDir" | "env
490
526
  /**
491
527
  * host 车道的工厂。**一只身份一只工作区**:经工作区托管表(`workspace-custody.ts`,与 local-docker 车道同一只)铸环境 ——
492
528
  * 同一身份(`ctx.taskId ?? ctx.sessionId`)还有一只没收场的环境 ⇒ 交回它(停驻腿的环境 = 续跑腿的环境:引擎 park-only 契约要的「重连到同一工作区」);
493
- * 正在收场 ⇒ 等它落定再铸。铸的时候问同一张表「腿的目录落在哪只本服务铸的临时根里」:落在里面(委派子代按父的工作目录落根)⇒ 与铸者共持那只根,
494
- * 父收场时子代还持有它就不删,最后放手的持有者删。`legOf` 先于交回 / 铸判(它可以拒)。
529
+ * 正在收场 ⇒ 等它落定再铸。本服务铸的临时根只在它的最后一只持有者放手那一拍、按表里还没离场的环境此刻的工作目录判得没人之后才删({@link passOnRoot});
530
+ * 铸时那一判({@link heldRootContaining})只把落在持有根里的新腿当场记成共持者。`legOf` 先于交回 / 铸判(它可以拒)。
495
531
  * 起服铸**一只**工厂(每次调用另铸一只工厂 = 没有表)。
496
532
  */
497
533
  export declare function hostExecutionEnvFactory(config?: HostEnvConfig, legOf?: (ctx: ExecutionEnvFactoryContext) => HostLegConfig): ExecutionEnvFactory;