@sema-agent/server 7.140.0 → 7.142.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 (296) hide show
  1. package/MIGRATION.md +505 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +142 -25
  5. package/dist/approval-ask-audit-store.d.ts +54 -38
  6. package/dist/approval-ask-audit-store.js +58 -39
  7. package/dist/approval-batch-census.d.ts +27 -0
  8. package/dist/approval-batch-census.js +27 -0
  9. package/dist/approval-card.d.ts +39 -24
  10. package/dist/approval-card.js +6 -3
  11. package/dist/approval-crash-convergence.d.ts +17 -7
  12. package/dist/approval-crash-convergence.js +94 -22
  13. package/dist/approval-deny-reasons.d.ts +34 -30
  14. package/dist/approval-deny-reasons.js +21 -6
  15. package/dist/approval-policy-settlement.d.ts +1 -1
  16. package/dist/approval-reconciler.d.ts +33 -1
  17. package/dist/approval-reconciler.js +43 -40
  18. package/dist/approval.d.ts +15 -0
  19. package/dist/approval.js +10 -0
  20. package/dist/audit.d.ts +4 -2
  21. package/dist/audit.js +2 -2
  22. package/dist/auth-bridge.d.ts +9 -6
  23. package/dist/auth-bridge.js +9 -3
  24. package/dist/boot/adoption.js +2 -1
  25. package/dist/boot/budget-tracing.d.ts +16 -0
  26. package/dist/boot/budget-tracing.js +10 -6
  27. package/dist/boot/device-lane.d.ts +11 -0
  28. package/dist/boot/device-lane.js +16 -0
  29. package/dist/boot/engine-lease.d.ts +24 -3
  30. package/dist/boot/engine-lease.js +9 -2
  31. package/dist/boot/execution-env.d.ts +24 -4
  32. package/dist/boot/execution-env.js +34 -27
  33. package/dist/boot/execution-lane.js +2 -1
  34. package/dist/boot/exit-boundary.js +5 -4
  35. package/dist/boot/memory-boundary.d.ts +2 -2
  36. package/dist/boot/memory-consolidation.d.ts +1 -1
  37. package/dist/boot/memory-consolidation.js +3 -2
  38. package/dist/boot/parked-revive-gate.js +2 -1
  39. package/dist/boot/permission-rules-audit.d.ts +0 -28
  40. package/dist/boot/permission-rules-audit.js +2 -1
  41. package/dist/boot/read-deny-anchor-audit.js +2 -1
  42. package/dist/boot/reapers.d.ts +2 -2
  43. package/dist/boot/reapers.js +4 -3
  44. package/dist/boot/resolve-spec.js +18 -6
  45. package/dist/boot/retention-lane.js +5 -3
  46. package/dist/boot/runner-deps.js +16 -13
  47. package/dist/boot/runtime-caps.js +3 -2
  48. package/dist/boot/session-faces.d.ts +1 -1
  49. package/dist/boot/session-faces.js +8 -6
  50. package/dist/boot/shutdown.js +8 -2
  51. package/dist/boot/stage-04-stores.js +3 -2
  52. package/dist/boot/stage-05-execution-env.d.ts +1 -1
  53. package/dist/boot/stage-05-execution-env.js +11 -7
  54. package/dist/boot/stage-06-runners.d.ts +1 -3
  55. package/dist/boot/stage-06-runners.js +3 -2
  56. package/dist/boot/stage-07-capability-layer.d.ts +1 -2
  57. package/dist/boot/stage-07-capability-layer.js +10 -11
  58. package/dist/boot/stage-08-reapers.d.ts +1 -2
  59. package/dist/boot/stage-08-reapers.js +3 -2
  60. package/dist/boot/stage-09-leader.d.ts +1 -2
  61. package/dist/boot/stage-10-http-server.d.ts +1 -2
  62. package/dist/boot/stage-10-http-server.js +6 -4
  63. package/dist/boot/stores.js +13 -6
  64. package/dist/boot/web-admin.js +18 -17
  65. package/dist/boot/webfetch-summarize-lane.js +2 -1
  66. package/dist/boot/workflow-orchestration.js +3 -2
  67. package/dist/capabilities/builtin-tools.d.ts +2 -1
  68. package/dist/capabilities/builtin-tools.js +2 -4
  69. package/dist/capabilities/composite-members.d.ts +2 -1
  70. package/dist/capabilities/composite-members.js +2 -1
  71. package/dist/capabilities/scenarios.d.ts +1 -1
  72. package/dist/capability-facts.d.ts +33 -0
  73. package/dist/capability-facts.js +32 -0
  74. package/dist/card-void.d.ts +38 -0
  75. package/dist/card-void.js +23 -0
  76. package/dist/config-catalog.js +12 -8
  77. package/dist/config-provider.d.ts +13 -13
  78. package/dist/config-provider.js +19 -33
  79. package/dist/config-types.d.ts +39 -10
  80. package/dist/config.d.ts +6 -0
  81. package/dist/config.js +72 -49
  82. package/dist/delegated-session-owner.d.ts +21 -19
  83. package/dist/delegated-session-owner.js +1 -1
  84. package/dist/device-store.d.ts +7 -0
  85. package/dist/device-store.js +3 -0
  86. package/dist/execution-config-root.d.ts +22 -0
  87. package/dist/execution-config-root.js +35 -0
  88. package/dist/execution-lane-caps.d.ts +50 -2
  89. package/dist/execution-lane-caps.js +90 -13
  90. package/dist/execution-placement.d.ts +3 -0
  91. package/dist/execution-placement.js +7 -0
  92. package/dist/fleet/drain-entry.d.ts +3 -0
  93. package/dist/fleet/fleet-bus.d.ts +6 -3
  94. package/dist/hooks/hook-runner.d.ts +6 -0
  95. package/dist/hooks/hook-runner.js +30 -1
  96. package/dist/hosted-posture.d.ts +8 -0
  97. package/dist/hosted-posture.js +4 -0
  98. package/dist/http/admission.js +3 -3
  99. package/dist/http/caller-trust.d.ts +3 -2
  100. package/dist/http/caller-trust.js +2 -1
  101. package/dist/http/dispatch.js +8 -2
  102. package/dist/http/execution-context.d.ts +2 -2
  103. package/dist/http/idempotency.d.ts +1 -1
  104. package/dist/http/live-frame.d.ts +24 -0
  105. package/dist/http/live-frame.js +16 -0
  106. package/dist/http/principal-gate.d.ts +3 -1
  107. package/dist/http/principal-gate.js +17 -8
  108. package/dist/http/resume-legs.js +42 -29
  109. package/dist/http/route-table.js +4 -0
  110. package/dist/http/routes/approvals-assistant.js +1 -0
  111. package/dist/http/routes/attachments.js +18 -0
  112. package/dist/http/routes/capabilities.js +10 -6
  113. package/dist/http/routes/diagnostics.d.ts +0 -19
  114. package/dist/http/routes/diagnostics.js +16 -2
  115. package/dist/http/routes/memory-bundle.d.ts +2 -2
  116. package/dist/http/routes/memory-bundle.js +1 -1
  117. package/dist/http/routes/memory-compliance.js +1 -1
  118. package/dist/http/routes/memory-policy.js +27 -7
  119. package/dist/http/routes/run-permission-mode.d.ts +75 -0
  120. package/dist/http/routes/run-permission-mode.js +170 -0
  121. package/dist/http/routes/runs.js +3 -3
  122. package/dist/http/routes/session-memory-sync.d.ts +63 -0
  123. package/dist/http/routes/session-memory-sync.js +157 -0
  124. package/dist/http/routes/session-sync.d.ts +3 -6
  125. package/dist/http/routes/session-sync.js +7 -2
  126. package/dist/http/routes/sessions-list.d.ts +2 -1
  127. package/dist/http/routes/sessions.js +5 -4
  128. package/dist/http/routes/tasks.js +70 -71
  129. package/dist/http/run-read-face.d.ts +7 -0
  130. package/dist/http/run-read-face.js +10 -4
  131. package/dist/http/send.d.ts +6 -1
  132. package/dist/http/send.js +10 -3
  133. package/dist/http/server.d.ts +20 -7
  134. package/dist/http/server.js +2 -4
  135. package/dist/http/sse-log.d.ts +3 -8
  136. package/dist/http/stored-body-replay.d.ts +3 -3
  137. package/dist/http/stored-body-replay.js +3 -1
  138. package/dist/http/submit-replay.d.ts +4 -3
  139. package/dist/http/submit-replay.js +2 -2
  140. package/dist/http/sync-submit-body.d.ts +21 -4
  141. package/dist/http/sync-submit-body.js +13 -0
  142. package/dist/identity-source.d.ts +21 -2
  143. package/dist/identity-source.js +6 -0
  144. package/dist/instruction-source-notice.d.ts +7 -0
  145. package/dist/instruction-source-notice.js +6 -6
  146. package/dist/mcp-assertion-header.d.ts +4 -0
  147. package/dist/mcp-assertion-header.js +5 -0
  148. package/dist/memory-incident-sink.d.ts +19 -6
  149. package/dist/memory-incident-sink.js +8 -4
  150. package/dist/memory-posture.d.ts +1 -1
  151. package/dist/memory-scope.d.ts +4 -4
  152. package/dist/memory-scope.js +1 -1
  153. package/dist/memory-sync-client.d.ts +35 -23
  154. package/dist/memory-sync-client.js +122 -52
  155. package/dist/memory-sync-identity.d.ts +24 -0
  156. package/dist/memory-sync-identity.js +57 -0
  157. package/dist/memory-sync.d.ts +7 -1
  158. package/dist/memory-sync.js +6 -3
  159. package/dist/observability/fail-open.d.ts +57 -12
  160. package/dist/observability/fail-open.js +50 -9
  161. package/dist/observability/metrics.js +0 -1
  162. package/dist/observability/run-terminal.d.ts +93 -31
  163. package/dist/observability/run-terminal.js +175 -171
  164. package/dist/observability/secret-env-scrub.d.ts +20 -1
  165. package/dist/observability/secret-env-scrub.js +14 -0
  166. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -2
  167. package/dist/orchestration/workflow-completion-inbox.js +13 -5
  168. package/dist/orchestration/workflow-notify-journal.d.ts +5 -3
  169. package/dist/orchestration/workflow-notify-journal.js +2 -1
  170. package/dist/permission-mode-admission.d.ts +68 -0
  171. package/dist/permission-mode-admission.js +23 -0
  172. package/dist/permission-rule-list.d.ts +55 -6
  173. package/dist/permission-rule-list.js +52 -5
  174. package/dist/plugins/approval-ask-store-file.d.ts +14 -4
  175. package/dist/plugins/approval-ask-store-file.js +48 -7
  176. package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
  177. package/dist/plugins/approval-ask-store-memory.js +9 -8
  178. package/dist/plugins/approval-ask-store-sql.d.ts +42 -10
  179. package/dist/plugins/approval-ask-store-sql.js +49 -19
  180. package/dist/plugins/caching-session-store.d.ts +6 -0
  181. package/dist/plugins/caching-session-store.js +3 -0
  182. package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
  183. package/dist/plugins/checkpoint-store-sql.js +74 -3
  184. package/dist/plugins/device-store-sql.d.ts +5 -2
  185. package/dist/plugins/device-store-sql.js +4 -1
  186. package/dist/plugins/execution-placement-sql.d.ts +11 -1
  187. package/dist/plugins/execution-placement-sql.js +12 -1
  188. package/dist/plugins/file-run-store.d.ts +7 -2
  189. package/dist/plugins/file-run-store.js +12 -2
  190. package/dist/plugins/fork-routing-session-store.d.ts +10 -32
  191. package/dist/plugins/fork-routing-session-store.js +2 -61
  192. package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
  193. package/dist/plugins/k8s-exec-protocol.js +6 -1
  194. package/dist/plugins/local-checkpoint-store.d.ts +10 -1
  195. package/dist/plugins/local-checkpoint-store.js +22 -0
  196. package/dist/plugins/local-session-store.d.ts +260 -39
  197. package/dist/plugins/local-session-store.js +582 -57
  198. package/dist/plugins/local-session-window.d.ts +17 -3
  199. package/dist/plugins/local-session-window.js +7 -13
  200. package/dist/plugins/local-task-attachment-store.d.ts +12 -2
  201. package/dist/plugins/local-task-attachment-store.js +67 -43
  202. package/dist/plugins/memory-key-guards.d.ts +3 -3
  203. package/dist/plugins/memory-run-store.d.ts +7 -2
  204. package/dist/plugins/memory-run-store.js +12 -2
  205. package/dist/plugins/one-time-migrations.d.ts +68 -2
  206. package/dist/plugins/one-time-migrations.js +120 -4
  207. package/dist/plugins/pg-pool.js +3 -2
  208. package/dist/plugins/pg-session-storage.d.ts +2 -0
  209. package/dist/plugins/pg-session-storage.js +3 -2
  210. package/dist/plugins/remote-env-e2b.d.ts +47 -7
  211. package/dist/plugins/remote-env-e2b.js +242 -46
  212. package/dist/plugins/remote-env-k8s.d.ts +51 -6
  213. package/dist/plugins/remote-env-k8s.js +234 -44
  214. package/dist/plugins/remote-env-local-docker.d.ts +40 -14
  215. package/dist/plugins/remote-env-local-docker.js +127 -33
  216. package/dist/plugins/run-store-sql.d.ts +11 -3
  217. package/dist/plugins/run-store-sql.js +13 -4
  218. package/dist/plugins/sandbox-read-floor.d.ts +273 -0
  219. package/dist/plugins/sandbox-read-floor.js +608 -0
  220. package/dist/plugins/session-ownership.d.ts +2 -1
  221. package/dist/plugins/session-placement.d.ts +17 -4
  222. package/dist/plugins/session-placement.js +2 -1
  223. package/dist/plugins/session-store.d.ts +18 -20
  224. package/dist/plugins/session-store.js +4 -12
  225. package/dist/plugins/store-backend.d.ts +41 -7
  226. package/dist/plugins/store-backend.js +22 -4
  227. package/dist/plugins/store-contracts.d.ts +35 -3
  228. package/dist/plugins/store-contracts.js +3 -0
  229. package/dist/plugins/task-attachment-store.d.ts +112 -14
  230. package/dist/plugins/task-attachment-store.js +221 -28
  231. package/dist/plugins/tidb-pool.js +2 -1
  232. package/dist/plugins/tidb-session-store.d.ts +4 -1
  233. package/dist/plugins/tidb-session-store.js +3 -2
  234. package/dist/plugins/workspace-fill.d.ts +60 -0
  235. package/dist/plugins/workspace-fill.js +106 -0
  236. package/dist/project-bundle.d.ts +38 -0
  237. package/dist/project-bundle.js +609 -0
  238. package/dist/run-cancel-context.d.ts +34 -0
  239. package/dist/run-cancel-context.js +7 -0
  240. package/dist/run-local.js +2 -8
  241. package/dist/runs.d.ts +39 -12
  242. package/dist/runs.js +69 -55
  243. package/dist/sandbox-egress-policy.d.ts +4 -1
  244. package/dist/sandbox-egress-policy.js +3 -1
  245. package/dist/sandbox-git-plane.d.ts +31 -12
  246. package/dist/sandbox-git-plane.js +24 -4
  247. package/dist/security.d.ts +11 -2
  248. package/dist/security.js +8 -0
  249. package/dist/server-secret-env.d.ts +2 -1
  250. package/dist/server-secret-env.js +2 -4
  251. package/dist/session-error-wire.d.ts +46 -4
  252. package/dist/session-error-wire.js +23 -0
  253. package/dist/session-incarnation.d.ts +9 -3
  254. package/dist/session-sync-kernel.d.ts +42 -1
  255. package/dist/session-sync-kernel.js +17 -0
  256. package/dist/session-sync.js +16 -4
  257. package/dist/sql-engine-coordinates.d.ts +49 -0
  258. package/dist/sql-engine-coordinates.js +27 -0
  259. package/dist/standing-answer-grant.d.ts +31 -2
  260. package/dist/standing-answer-grant.js +14 -2
  261. package/dist/store-posture.d.ts +1 -1
  262. package/dist/task-a2a.d.ts +1 -1
  263. package/dist/task-mcp.d.ts +1 -1
  264. package/dist/task-settings.d.ts +62 -27
  265. package/dist/task-settings.js +105 -29
  266. package/dist/terminal.d.ts +97 -20
  267. package/dist/terminal.js +107 -18
  268. package/dist/tool-approval.d.ts +4 -3
  269. package/dist/tool-approval.js +12 -14
  270. package/dist/trace/core-keyset-guard.d.ts +196 -2
  271. package/dist/trace/engine-notice-wire.d.ts +8 -2
  272. package/dist/trace/engine-notice-wire.js +4 -2
  273. package/dist/trace/exit-seat.d.ts +9 -1
  274. package/dist/trace/exit-seat.js +1 -0
  275. package/dist/trace/ledger-sink.d.ts +8 -4
  276. package/dist/trace/ledger-sink.js +2 -2
  277. package/dist/trace/model-segment.d.ts +2 -2
  278. package/dist/trace/project.d.ts +18 -1
  279. package/dist/trace/project.js +16 -0
  280. package/dist/trace/redact.js +323 -90
  281. package/dist/trace/self-minted-wire.d.ts +419 -4
  282. package/dist/trace/self-minted-wire.js +145 -0
  283. package/dist/trace/wire-projection-faces.d.ts +1 -1
  284. package/dist/trace/wire-projection-faces.js +1 -1
  285. package/dist/verifier-pause-card.d.ts +8 -0
  286. package/dist/verifier-pause-card.js +19 -0
  287. package/dist/web-admin-client/apply-effective.d.ts +5 -7
  288. package/dist/web-admin-client/apply-effective.js +22 -2
  289. package/dist/web-admin-client/candidate-gate.d.ts +1 -1
  290. package/dist/web-admin-client/effective-keys.js +2 -0
  291. package/dist/web-admin-client/read-warnings.d.ts +2 -2
  292. package/dist/web-admin-client/types.d.ts +4 -0
  293. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
  294. package/package.json +2 -2
  295. package/wire-changes/server@7.141.0.json +367 -0
  296. package/wire-changes/server@7.142.0.json +639 -0
@@ -19,6 +19,7 @@ import { buildCapturedOutput, createCutError } from "../exec-cut.js";
19
19
  import { SANDBOX_IPV6_DEFAULT, sandboxEgressGaps, sandboxPodSysctls } from "../sandbox-egress-policy.js";
20
20
  import { FileError, ExecutionError, RemoteExecutionError, withRetry, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
21
21
  import { capabilitiesFor } from "../execution-lane-caps.js";
22
+ import { ADAPTER_START, BOOTSTRAP_START, buildFloorPodSeat, createSandboxReadFloor, FLOOR_K8S_CONFIGMAP_KEY, engineStart, floorArgv, } from "./sandbox-read-floor.js";
22
23
  import { fileErrorFromExec, classifyFsStderr } from "./remote-env-file-error.js";
23
24
  import { createPosixShellFs } from "./posix-shell-fs.js";
24
25
  import { randomUUID } from "node:crypto";
@@ -47,6 +48,9 @@ export { applyPodSpecPatch } from "./k8s-exec-protocol.js";
47
48
  import { sandboxRunEndHoldMs } from "./k8s-pod-reaper.js";
48
49
  import { BROKER_COMMAND, BROKER_CONTAINER_NAME, BROKER_LEASE_DIR, BROKER_LEASE_KEY, BROKER_PROBE_ARG, BROKER_VOLUME_NAME } from "../broker/constants.js";
49
50
  import { buildSandboxLeaseFile, placeholderLeaseEntries, sandboxGitRouteEnv } from "../sandbox-git-lease.js";
51
+ function minted(c) {
52
+ return c.ok ? { ...c, origin: "minted" } : c;
53
+ }
50
54
  const CACHE_VOLUME = ADAPTER_VOLUME_NAMES.cache;
51
55
  function occupantKeyOf(occupant) {
52
56
  if (occupant === undefined)
@@ -202,6 +206,7 @@ function brokerContainer(image) {
202
206
  }
203
207
  export class RemoteK8sExecutionEnv {
204
208
  capabilities;
209
+ floor;
205
210
  cwd;
206
211
  podName;
207
212
  podIP;
@@ -211,6 +216,7 @@ export class RemoteK8sExecutionEnv {
211
216
  inFlight = new Set();
212
217
  idleWaiters = [];
213
218
  connectInFlight;
219
+ resumeInFlight;
214
220
  connectRefusal;
215
221
  get homeDir() {
216
222
  return this.homeSeat.home;
@@ -229,6 +235,7 @@ export class RemoteK8sExecutionEnv {
229
235
  cacheUnavailableSaid = false;
230
236
  logger;
231
237
  onWorkspaceSnapshot;
238
+ workspaceFill;
232
239
  cacheMisses;
233
240
  constructor(config, deps) {
234
241
  this.cfg = {
@@ -268,8 +275,10 @@ export class RemoteK8sExecutionEnv {
268
275
  this.cacheLane = cacheLaneOf(config.cache, config.spaceOccupant);
269
276
  this.logger = config.logger;
270
277
  this.onWorkspaceSnapshot = config.onWorkspaceSnapshot;
278
+ this.workspaceFill = config.workspaceFill;
271
279
  this.cacheMisses = config.cacheMisses;
272
- this.capabilities = capabilitiesFor({ remoteExec: { provider: PROVIDER, s3Snapshot: this.cfg.s3Snapshot } });
280
+ this.floor = this.deps.readFloor ?? createSandboxReadFloor({ lane: PROVIDER, knob: config.sandboxReadFloor, ...(config.logger !== undefined ? { logger: config.logger } : {}) });
281
+ this.capabilities = capabilitiesFor({ remoteExec: { provider: PROVIDER, s3Snapshot: this.cfg.s3Snapshot }, sandboxReadFloor: config.sandboxReadFloor });
273
282
  const bgMax = Math.max(1, Math.min(K8S_BG_MAX_TIMEOUT_SEC, Math.floor(this.cfg.timeoutMs / 1000)));
274
283
  this.backgroundCapabilities = {
275
284
  supported: true,
@@ -371,10 +380,14 @@ export class RemoteK8sExecutionEnv {
371
380
  });
372
381
  }
373
382
  connect(config) {
374
- this.connectInFlight ??= this.establish(config).finally(() => {
375
- this.connectInFlight = undefined;
383
+ if (this.connectInFlight)
384
+ return this.connectInFlight;
385
+ const walk = this.establish(config).finally(() => {
386
+ if (this.connectInFlight === walk)
387
+ this.connectInFlight = undefined;
376
388
  });
377
- return this.connectInFlight;
389
+ this.connectInFlight = walk;
390
+ return walk;
378
391
  }
379
392
  async establish(config) {
380
393
  if (this.connectRefusal)
@@ -383,10 +396,10 @@ export class RemoteK8sExecutionEnv {
383
396
  const lane = this.spaceLane;
384
397
  switch (lane.state) {
385
398
  case "off":
386
- return this.provision(signal);
399
+ return this.settle(minted(await this.provision(signal)));
387
400
  case "unavailable":
388
401
  this.sayUnavailable(lane.reason);
389
- return this.provision(signal);
402
+ return this.settle(minted(await this.provision(signal)));
390
403
  case "unreadable":
391
404
  return this.provision(signal);
392
405
  case "open": {
@@ -396,7 +409,7 @@ export class RemoteK8sExecutionEnv {
396
409
  const latest = await this.readLatest(lane.space, signal);
397
410
  if (!latest.ok)
398
411
  return latest;
399
- const c = latest.value === undefined ? await this.provision(signal) : await this.restoreSnapshot({ lane: "space", space: lane.space }, latest.value, signal);
412
+ const c = await this.settle(latest.value === undefined ? minted(await this.provision(signal)) : await this.restoreSnapshot({ lane: "space", space: lane.space }, latest.value, signal));
400
413
  if (c.ok)
401
414
  this.armSpace();
402
415
  return c;
@@ -407,6 +420,43 @@ export class RemoteK8sExecutionEnv {
407
420
  }
408
421
  }
409
422
  }
423
+ async settle(c) {
424
+ if (!c.ok)
425
+ return c;
426
+ const fill = this.workspaceFill;
427
+ if (fill !== undefined) {
428
+ const filled = await fill.fill(this.fillChannel(), this.cwd, c.origin);
429
+ if (!filled.ok) {
430
+ await this.releasePod();
431
+ return filled.standing ? this.holdRefusal(filled.error) : { ok: false, error: filled.error };
432
+ }
433
+ }
434
+ if (this.destroyed) {
435
+ await this.releasePod();
436
+ return { ok: false, error: new RemoteExecutionError("connect_failed", "env destroyed during connect") };
437
+ }
438
+ return { ok: true, value: c.value };
439
+ }
440
+ fillChannel() {
441
+ const exec = (command) => this.runExec(ADAPTER_START, command, { capMs: this.cfg.dataTimeoutMs });
442
+ return {
443
+ run: async (command) => {
444
+ const r = await exec(command);
445
+ return r.ok ? { ok: true, exitCode: r.value.exitCode, stdout: r.value.stdout, stderr: r.value.stderr } : { ok: false, error: r.error.message };
446
+ },
447
+ write: async (abs, bytes) => {
448
+ const w = await this.writeChunked(abs, bytes, true, undefined, exec);
449
+ return w.ok ? { ok: true } : { ok: false, error: w.error.message };
450
+ },
451
+ };
452
+ }
453
+ async releasePod() {
454
+ const name = this.podName;
455
+ this.podName = undefined;
456
+ this.podIP = undefined;
457
+ if (name)
458
+ await this.deletePod(name).catch(() => { });
459
+ }
410
460
  armSpace() {
411
461
  if (this.spaceLane.state === "open")
412
462
  this.spaceLane.space.fence.arm(this.cfg.dataTimeoutMs);
@@ -667,6 +717,8 @@ export class RemoteK8sExecutionEnv {
667
717
  ];
668
718
  const pkgSourceMarked = Boolean(this.cfg.podEnv?.SEMA_PKG_SOURCE || secretEnv.SEMA_PKG_SOURCE);
669
719
  const sysctls = sandboxPodSysctls(this.cfg.ipv6);
720
+ const floorSeat = await this.ensureFloorSeat(signal);
721
+ const mounts = [...(cache ? [{ name: CACHE_VOLUME, mountPath: cache.mount }] : []), ...(floorSeat?.mounts ?? [])];
670
722
  const pod = {
671
723
  apiVersion: "v1",
672
724
  kind: "Pod",
@@ -691,7 +743,7 @@ export class RemoteK8sExecutionEnv {
691
743
  ? ["sh", "-c", "[ -f /opt/sema/pkg-source.sh ] && sh /opt/sema/pkg-source.sh || true; sleep infinity"]
692
744
  : ["sh", "-c", "sleep infinity"],
693
745
  ...(envEntries.length > 0 ? { env: envEntries } : {}),
694
- ...(cache ? { volumeMounts: [{ name: CACHE_VOLUME, mountPath: cache.mount }] } : {}),
746
+ ...(mounts.length > 0 ? { volumeMounts: mounts } : {}),
695
747
  resources: { limits: { cpu: this.cfg.cpu, memory: this.cfg.memory } },
696
748
  },
697
749
  ...(broker !== undefined ? [brokerContainer(broker.image)] : []),
@@ -699,6 +751,7 @@ export class RemoteK8sExecutionEnv {
699
751
  ...((volumes) => (volumes.length > 0 ? { volumes } : {}))([
700
752
  ...(cache ? [{ name: CACHE_VOLUME, persistentVolumeClaim: { claimName: cache.claim.name } }] : []),
701
753
  ...(leaseName !== undefined ? [{ name: BROKER_VOLUME_NAME, secret: { secretName: leaseName, items: [{ key: BROKER_LEASE_KEY, path: BROKER_LEASE_KEY }], defaultMode: 0o400 } }] : []),
754
+ ...(floorSeat?.volumes ?? []),
702
755
  ]),
703
756
  },
704
757
  };
@@ -806,7 +859,7 @@ export class RemoteK8sExecutionEnv {
806
859
  this.podIP = podIP;
807
860
  this.leaseRef = leaseName !== undefined && broker !== undefined ? { namespace: ns, podName: name, leaseSecretName: leaseName, origins: [...broker.origins] } : undefined;
808
861
  const askHome = this.homeSeat.asks;
809
- const mk = await this.runExec(`mkdir -p ${shellQuote(this.cfg.mountPath)}${askHome ? ` && { ${LANE_HOME_PROBE_COMMAND} || true; }` : ""}`);
862
+ const mk = await this.runExec(ADAPTER_START, `mkdir -p ${shellQuote(this.cfg.mountPath)}${askHome ? ` && { ${LANE_HOME_PROBE_COMMAND} || true; }` : ""}`);
810
863
  if (!mk.ok || mk.value.exitCode !== 0) {
811
864
  await this.deletePod(name).catch(() => { });
812
865
  this.podName = undefined;
@@ -825,6 +878,7 @@ export class RemoteK8sExecutionEnv {
825
878
  }
826
879
  if (cache?.fresh)
827
880
  this.logger?.warn("workspace_cache_fresh", { space: incarnationLogPrefix(cache.spaceKey), claim: cache.claim.name, size: cache.size });
881
+ await this.floor.attach(this.floorTransport(), { origin: "created", workspaceRoot: this.cfg.mountPath });
828
882
  return ok(this.workspaceHandle());
829
883
  }
830
884
  async createPodSecret(secretName, podName, podUid, values, signal) {
@@ -1184,7 +1238,7 @@ export class RemoteK8sExecutionEnv {
1184
1238
  const excludes = (this.cfg.snapshotExclude ?? []).map((item) => ` --exclude=${shellQuote(`./${item}`)}`).join("");
1185
1239
  const cmd = `tar czf ${tmp}${excludes} -C ${shellQuote(this.cfg.mountPath)} . && curl -fsS -X PUT -T ${tmp} ${shellQuote(url)}; ` +
1186
1240
  `rc=$?; rm -f ${tmp}; exit $rc`;
1187
- const r = await this.runExec(cmd, { timeoutMs: boundMs });
1241
+ const r = await this.runExec(ADAPTER_START, cmd, { timeoutMs: boundMs });
1188
1242
  if (!r.ok)
1189
1243
  return { ok: false, error: new RemoteExecutionError("connect_failed", `workspace snapshot upload failed: ${this.redactUrl(r.error.message, url)}`, r.error) };
1190
1244
  if (r.value.exitCode !== 0)
@@ -1195,10 +1249,31 @@ export class RemoteK8sExecutionEnv {
1195
1249
  await this.deletePod(name).catch(() => { });
1196
1250
  return ok(snapshotId);
1197
1251
  }
1198
- async resumeVM(snapshotId, options) {
1252
+ resumeVM(snapshotId, options) {
1199
1253
  if (!this.cfg.s3Snapshot)
1200
- return unsupported("resumeVM");
1201
- const r = await this.restoreSnapshot({ lane: "park" }, snapshotId, options?.abortSignal);
1254
+ return Promise.resolve(unsupported("resumeVM"));
1255
+ const same = this.resumeInFlight;
1256
+ if (same?.snapshotId === snapshotId)
1257
+ return same.walk;
1258
+ const prior = this.connectInFlight;
1259
+ const walk = this.resumeWalk(prior, snapshotId, options).finally(() => {
1260
+ if (this.connectInFlight === walk)
1261
+ this.connectInFlight = undefined;
1262
+ if (this.resumeInFlight?.walk === walk)
1263
+ this.resumeInFlight = undefined;
1264
+ });
1265
+ this.connectInFlight = walk;
1266
+ this.resumeInFlight = { snapshotId, walk };
1267
+ return walk;
1268
+ }
1269
+ async resumeWalk(prior, snapshotId, options) {
1270
+ if (prior)
1271
+ await prior;
1272
+ if (this.podName) {
1273
+ this.logger?.warn("sandbox_pod_released_before_restore", { pod: this.podName, ...(this.cfg.sessionId ? { sessionId: this.cfg.sessionId } : {}), effect: "this env held a pod minted before the park snapshot's restore — it is deleted; the restore provisions the leg's one pod" });
1274
+ await this.releasePod();
1275
+ }
1276
+ const r = await this.settle(await this.restoreSnapshot({ lane: "park" }, snapshotId, options?.abortSignal));
1202
1277
  if (!r.ok)
1203
1278
  return r;
1204
1279
  this.handleSnapshotId = snapshotId;
@@ -1220,22 +1295,21 @@ export class RemoteK8sExecutionEnv {
1220
1295
  const c = await this.provision(abortSignal);
1221
1296
  if (!c.ok)
1222
1297
  return c;
1223
- const r = await this.runExec(cmd, { timeoutMs: this.cfg.dataTimeoutMs });
1298
+ const r = await this.runExec(ADAPTER_START, cmd, { timeoutMs: this.cfg.dataTimeoutMs });
1224
1299
  const failure = !r.ok
1225
1300
  ? { cls: r.error.code === "timeout" ? "timeout" : "transport", detail: `workspace snapshot restore failed: ${this.redactUrl(r.error.message, url)}`, cause: r.error }
1226
1301
  : r.value.exitCode !== 0
1227
1302
  ? { cls: restoreClassOfExit(r.value.exitCode), detail: `workspace snapshot restore exited ${r.value.exitCode}: ${this.redactUrl(r.value.stderr, url).slice(0, 300)}` }
1228
1303
  : undefined;
1229
1304
  if (!failure) {
1230
- if (target.lane === "space" && r.ok && r.value.stdout.includes("EMPTY_SNAPSHOT"))
1231
- await this.dropDanglingLatest(target.space, snapshotId);
1232
- return ok(this.workspaceHandle());
1305
+ if (r.ok && r.value.stdout.includes("EMPTY_SNAPSHOT")) {
1306
+ if (target.lane === "space")
1307
+ await this.dropDanglingLatest(target.space, snapshotId);
1308
+ return { ok: true, value: this.workspaceHandle(), origin: "minted" };
1309
+ }
1310
+ return { ok: true, value: this.workspaceHandle(), origin: "restored" };
1233
1311
  }
1234
- const name = this.podName;
1235
- this.podName = undefined;
1236
- this.podIP = undefined;
1237
- if (name)
1238
- await this.deletePod(name).catch(() => { });
1312
+ await this.releasePod();
1239
1313
  if (attempt < RESTORE_MAX_ATTEMPTS[target.lane] && restoreFailureIsTransient(failure.cls)) {
1240
1314
  if (await this.restorePause(abortSignal))
1241
1315
  continue;
@@ -1326,6 +1400,7 @@ export class RemoteK8sExecutionEnv {
1326
1400
  }
1327
1401
  async destroy() {
1328
1402
  await this.disposeBackgroundShells().catch(() => { });
1403
+ this.floor.dispose();
1329
1404
  this.destroyed = true;
1330
1405
  const lane = this.spaceLane;
1331
1406
  switch (lane.state) {
@@ -1410,7 +1485,7 @@ export class RemoteK8sExecutionEnv {
1410
1485
  async killPodProcesses() {
1411
1486
  if (!this.podName)
1412
1487
  return false;
1413
- const r = await this.runExec(buildKillAllScript(), { timeoutMs: this.cfg.rpcTimeoutMs + KILL_ALL_RECHECK_MS });
1488
+ const r = await this.runExec(ADAPTER_START, buildKillAllScript(), { timeoutMs: this.cfg.rpcTimeoutMs + KILL_ALL_RECHECK_MS });
1414
1489
  return r.ok && r.value.exitCode === 0;
1415
1490
  }
1416
1491
  async persistWorkspace(space) {
@@ -1463,23 +1538,124 @@ export class RemoteK8sExecutionEnv {
1463
1538
  await this.endSpace(space);
1464
1539
  }
1465
1540
  }
1466
- execUrl(command) {
1541
+ async ensureFloorSeat(signal) {
1542
+ const seat = buildFloorPodSeat(this.floor);
1543
+ if (seat === undefined)
1544
+ return undefined;
1545
+ if (seat.configMaps.length === 0) {
1546
+ this.floor.refusePlacement("this server carries no pinned supervisor build");
1547
+ return undefined;
1548
+ }
1549
+ for (const cm of seat.configMaps) {
1550
+ const body = { apiVersion: "v1", kind: "ConfigMap", metadata: { name: cm.name }, immutable: true, binaryData: { [FLOOR_K8S_CONFIGMAP_KEY]: cm.binaryDataB64 } };
1551
+ let r;
1552
+ try {
1553
+ r = await this.request("POST", `/api/v1/namespaces/${this.cfg.namespace}/configmaps`, body, { signal });
1554
+ }
1555
+ catch (e) {
1556
+ this.floor.refusePlacement(`creating the supervisor ConfigMap ${cm.name} failed: ${errorMessageOf(e)}`);
1557
+ return undefined;
1558
+ }
1559
+ if (r.status !== 409 && (r.status < 200 || r.status >= 300)) {
1560
+ this.floor.refusePlacement(`creating the supervisor ConfigMap ${cm.name} was answered ${r.status}${r.status === 401 || r.status === 403 ? " (the server's service account needs create on configmaps in this namespace)" : ""}`);
1561
+ return undefined;
1562
+ }
1563
+ }
1564
+ return seat;
1565
+ }
1566
+ floorTransport() {
1567
+ return {
1568
+ bootstrap: async (command) => {
1569
+ const r = await this.runExec(BOOTSTRAP_START, command, { timeoutMs: this.cfg.rpcTimeoutMs });
1570
+ return r.ok ? { ok: true, exitCode: r.value.exitCode, stdout: r.value.stdout, stderr: r.value.stderr } : { ok: false, error: r.error.message };
1571
+ },
1572
+ place: async () => ({ ok: true }),
1573
+ openRelay: (identity, command, events) => {
1574
+ let closed = false;
1575
+ const close = (why) => {
1576
+ if (closed)
1577
+ return;
1578
+ closed = true;
1579
+ events.closed(why);
1580
+ };
1581
+ switch (identity) {
1582
+ case "root":
1583
+ queueMicrotask(() => close("a k8s exec cannot start the relay as root"));
1584
+ return { send: () => { }, close: () => { } };
1585
+ case "exec-user":
1586
+ break;
1587
+ }
1588
+ let sock;
1589
+ try {
1590
+ const { url, headers } = this.execUrl(["sh", "-c", command], true);
1591
+ sock = this.openExec(url, headers);
1592
+ }
1593
+ catch (e) {
1594
+ queueMicrotask(() => close(`the relay exec could not be opened: ${errorMessageOf(e)}`));
1595
+ return { send: () => { }, close: () => { } };
1596
+ }
1597
+ const decoder = new StringDecoder("utf8");
1598
+ let open = false;
1599
+ const pending = [];
1600
+ const write = (frame) => {
1601
+ if (sock.send === undefined)
1602
+ return close("the exec socket cannot write (no stdin channel)");
1603
+ try {
1604
+ sock.send(frame);
1605
+ }
1606
+ catch (e) {
1607
+ close(`writing to the relay failed: ${errorMessageOf(e)}`);
1608
+ }
1609
+ };
1610
+ sock.on("open", () => {
1611
+ open = true;
1612
+ for (const f of pending.splice(0))
1613
+ write(f);
1614
+ });
1615
+ sock.on("message", (...args) => {
1616
+ const data = args[0];
1617
+ const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
1618
+ if (buf.length > 1 && buf[0] === 1)
1619
+ events.data(decoder.write(buf.subarray(1)));
1620
+ });
1621
+ sock.on("close", () => close("the relay exec closed"));
1622
+ sock.on("error", (e) => close(`the relay exec failed: ${errorMessageOf(e)}`));
1623
+ return {
1624
+ send: (line) => {
1625
+ const frame = Buffer.concat([Buffer.from([0]), Buffer.from(line, "utf8")]);
1626
+ if (open)
1627
+ write(frame);
1628
+ else
1629
+ pending.push(frame);
1630
+ },
1631
+ close: () => (sock.terminate ?? sock.close).call(sock),
1632
+ };
1633
+ },
1634
+ };
1635
+ }
1636
+ execUrl(argv, stdin = false) {
1467
1637
  const { apiUrl, token } = this.creds();
1468
1638
  const base = apiUrl.replace(/^http/, "ws");
1469
1639
  const q = new URLSearchParams();
1470
1640
  q.append("container", "sandbox");
1641
+ if (stdin)
1642
+ q.append("stdin", "true");
1471
1643
  q.append("stdout", "true");
1472
1644
  q.append("stderr", "true");
1473
- for (const part of ["sh", "-c", command])
1645
+ for (const part of argv)
1474
1646
  q.append("command", part);
1475
1647
  return { url: `${base}/api/v1/namespaces/${this.cfg.namespace}/pods/${this.podName}/exec?${q.toString()}`, headers: { authorization: `Bearer ${token}` } };
1476
1648
  }
1477
- runExec(command, opts) {
1649
+ runExec(start, command, opts) {
1650
+ const launch = this.floor.wrap(start);
1651
+ if (!launch.ok)
1652
+ return Promise.resolve(launch);
1653
+ opts?.onLaunch?.(launch.value);
1478
1654
  let sock;
1479
1655
  let headers;
1480
1656
  let url;
1481
1657
  try {
1482
- ({ url, headers } = this.execUrl(command));
1658
+ ({ url, headers } = this.execUrl(floorArgv(launch.value, ["sh", "-c", command])));
1483
1659
  sock = this.openExec(url, headers);
1484
1660
  }
1485
1661
  catch (e) {
@@ -1673,12 +1849,12 @@ export class RemoteK8sExecutionEnv {
1673
1849
  });
1674
1850
  }
1675
1851
  async exec(command, options) {
1676
- return this.execCall(createCwdGuardedCall("k8s", command, this.workingDirOf(options?.cwd), options?.env), options);
1852
+ return this.execCall(engineStart(options?.readFloor), createCwdGuardedCall("k8s", command, this.workingDirOf(options?.cwd), options?.env), options);
1677
1853
  }
1678
1854
  fsExec(command, abortSignal) {
1679
- return this.execCall(createCwdGuardedCall("k8s", command, undefined, undefined), { abortSignal });
1855
+ return this.execCall(ADAPTER_START, createCwdGuardedCall("k8s", command, undefined, undefined), { abortSignal });
1680
1856
  }
1681
- async execCall(call, options) {
1857
+ async execCall(start, call, options) {
1682
1858
  const c = await this.ensureConnected();
1683
1859
  if (!c.ok)
1684
1860
  return c;
@@ -1687,7 +1863,7 @@ export class RemoteK8sExecutionEnv {
1687
1863
  const abortSignal = options?.abortSignal ? AbortSignal.any([options.abortSignal, inflight.signal]) : inflight.signal;
1688
1864
  try {
1689
1865
  if (!detachSignal) {
1690
- return call.settle(await this.runExec(call.command, {
1866
+ return call.settle(await this.runExec(start, call.command, {
1691
1867
  signal: abortSignal,
1692
1868
  timeoutMs: options?.timeout != null ? options.timeout * 1000 : undefined,
1693
1869
  boundOutput: true,
@@ -1699,7 +1875,10 @@ export class RemoteK8sExecutionEnv {
1699
1875
  const adoptId = randomUUID();
1700
1876
  const dir = `${K8S_BG_DIR_ROOT}/exec-${adoptId}`;
1701
1877
  const tee = { out: seedMemStream(""), err: seedMemStream("") };
1702
- return call.settle(await this.runExec(buildDetachCapableExec(dir, call.command), {
1878
+ let startId;
1879
+ let adoptedHere = false;
1880
+ const settled = call.settle(await this.runExec(start.kind === "engine" ? engineStart(start.readFloor, true) : start, buildDetachCapableExec(dir, call.command), {
1881
+ onLaunch: (l) => void (startId = l.mode === "run" ? l.startId : undefined),
1703
1882
  signal: abortSignal,
1704
1883
  timeoutMs: options?.timeout != null ? options.timeout * 1000 : undefined,
1705
1884
  boundOutput: true,
@@ -1716,12 +1895,17 @@ export class RemoteK8sExecutionEnv {
1716
1895
  data: (channel, payload) => feedMemStream(channel === 1 ? mem.out : mem.err, payload, K8S_BG_MEM_CAP),
1717
1896
  closed: (terminal) => ctx.onTerminal(terminal.failed, terminal.exitCode),
1718
1897
  });
1719
- return { jobId: adoptId, dir, stdoutCursor: 0, stderrCursor: 0, adopt: { mem, sock: io.sock } };
1898
+ return { jobId: adoptId, dir, stdoutCursor: 0, stderrCursor: 0, adopt: { mem, sock: io.sock }, ...(startId !== undefined ? { startId } : {}) };
1720
1899
  });
1900
+ if (adopted !== undefined)
1901
+ adoptedHere = true;
1721
1902
  return adopted?.shellId;
1722
1903
  },
1723
1904
  },
1724
1905
  }));
1906
+ if (!adoptedHere)
1907
+ this.floor.release(startId);
1908
+ return settled;
1725
1909
  }
1726
1910
  finally {
1727
1911
  this.endExec(inflight);
@@ -1759,7 +1943,7 @@ export class RemoteK8sExecutionEnv {
1759
1943
  const cap = options?.maxOutputBytes;
1760
1944
  let bytes = 0;
1761
1945
  const signal = options?.signal ? AbortSignal.any([options.signal, ac.signal]) : ac.signal;
1762
- const done = this.runExec(buildCwdEnvCommand(command, this.workingDirOf(options?.cwd), options?.env, "raw").command, {
1946
+ const done = this.runExec(engineStart(undefined), buildCwdEnvCommand(command, this.workingDirOf(options?.cwd), options?.env, "raw").command, {
1763
1947
  signal,
1764
1948
  timeoutMs: options?.timeout != null ? options.timeout * 1000 : undefined,
1765
1949
  readTimeoutMs: options?.readTimeoutMs,
@@ -1828,7 +2012,8 @@ export class RemoteK8sExecutionEnv {
1828
2012
  }
1829
2013
  makeBgDriver() {
1830
2014
  const self = this;
1831
- const bgExec = (script, boundOutput) => self.runExec(script, { timeoutMs: self.cfg.rpcTimeoutMs, boundOutput });
2015
+ const bgExec = (start, script, boundOutput, onLaunch) => self.runExec(start, script, { timeoutMs: self.cfg.rpcTimeoutMs, boundOutput, ...(onLaunch !== undefined ? { onLaunch } : {}) });
2016
+ const under = (state) => ({ kind: "under", startId: state.startId });
1832
2017
  return {
1833
2018
  async launch(command, options, ctx) {
1834
2019
  const conn = await self.ensureConnected();
@@ -1839,14 +2024,17 @@ export class RemoteK8sExecutionEnv {
1839
2024
  const inner = buildCwdEnvCommand(command, self.workingDirOf(options?.cwd), options?.env, "raw").command;
1840
2025
  const cmdB64 = Buffer.from(inner, "utf8").toString("base64");
1841
2026
  const runnerB64 = Buffer.from(buildBgRunnerScript(dir), "utf8").toString("base64");
1842
- const r = await bgExec(buildBgLauncherScript(dir, cmdB64, runnerB64), true);
2027
+ let startId;
2028
+ const r = await bgExec(engineStart(options?.readFloor, true), buildBgLauncherScript(dir, cmdB64, runnerB64), true, (l) => void (startId = l.mode === "run" ? l.startId : undefined));
2029
+ if (!r.ok || r.value.exitCode !== 0 || !r.value.stdout.includes("SEMABG_LAUNCHED"))
2030
+ self.floor.release(startId);
1843
2031
  if (!r.ok)
1844
2032
  throw new Error(`background launch failed: ${r.error.message}`);
1845
2033
  if (r.value.exitCode !== 0 || !r.value.stdout.includes("SEMABG_LAUNCHED")) {
1846
2034
  throw new Error(`background launch exited ${r.value.exitCode}: ${r.value.stderr.slice(0, 200)}`);
1847
2035
  }
1848
2036
  void ctx;
1849
- return { jobId, dir, stdoutCursor: 0, stderrCursor: 0 };
2037
+ return { jobId, dir, stdoutCursor: 0, stderrCursor: 0, ...(startId !== undefined ? { startId } : {}) };
1850
2038
  },
1851
2039
  async read(state) {
1852
2040
  if (state.adopt) {
@@ -1859,7 +2047,7 @@ export class RemoteK8sExecutionEnv {
1859
2047
  bytesDroppedBeforeCursor: o.dropped + e.dropped,
1860
2048
  };
1861
2049
  }
1862
- const r = await bgExec(buildBgPollScript(state.dir, state.stdoutCursor, state.stderrCursor, K8S_BG_READ_CAP), false);
2050
+ const r = await bgExec(under(state), buildBgPollScript(state.dir, state.stdoutCursor, state.stderrCursor, K8S_BG_READ_CAP), false);
1863
2051
  if (!r.ok)
1864
2052
  throw new Error(`background poll failed: ${r.error.message}`);
1865
2053
  const p = parseBgPollOutput(r.value.stdout);
@@ -1874,7 +2062,7 @@ export class RemoteK8sExecutionEnv {
1874
2062
  state.stderrCursor = p.errTotal;
1875
2063
  let terminal = p.exitCode !== undefined ? { failed: false, exitCode: p.exitCode } : !p.alive ? { failed: true } : undefined;
1876
2064
  if (!terminal && (p.outTotal > K8S_BG_FILE_CAP || p.errTotal > K8S_BG_FILE_CAP)) {
1877
- void bgExec(buildBgKillScript(state.dir), true).catch(() => { });
2065
+ void bgExec(under(state), buildBgKillScript(state.dir), true).catch(() => { });
1878
2066
  terminal = { failed: true };
1879
2067
  }
1880
2068
  return {
@@ -1886,7 +2074,7 @@ export class RemoteK8sExecutionEnv {
1886
2074
  };
1887
2075
  },
1888
2076
  async kill(state) {
1889
- await bgExec(buildBgKillScript(state.dir), true).catch(() => { });
2077
+ await bgExec(under(state), buildBgKillScript(state.dir), true).catch(() => { });
1890
2078
  },
1891
2079
  async disposeOne(state) {
1892
2080
  const closeAdopted = () => {
@@ -1899,10 +2087,12 @@ export class RemoteK8sExecutionEnv {
1899
2087
  };
1900
2088
  if (self.destroyed) {
1901
2089
  closeAdopted();
2090
+ self.floor.release(state.startId);
1902
2091
  return;
1903
2092
  }
1904
- await bgExec(buildBgDisposeScript(state.dir), true).catch(() => { });
2093
+ await bgExec(under(state), buildBgDisposeScript(state.dir), true).catch(() => { });
1905
2094
  closeAdopted();
2095
+ self.floor.release(state.startId);
1906
2096
  },
1907
2097
  };
1908
2098
  }
@@ -1958,12 +2148,12 @@ export class RemoteK8sExecutionEnv {
1958
2148
  const abs = this.resolve(p);
1959
2149
  return appendFileStaged(this.stagedLane(content), abs, abortSignal, (ctx) => ctx.inPlace((signal) => this.writeChunked(abs, content, false, signal)));
1960
2150
  }
1961
- async writeChunked(abs, content, truncateFirst, abortSignal) {
2151
+ async writeChunked(abs, content, truncateFirst, abortSignal, exec = (command) => this.execData(command, abortSignal)) {
1962
2152
  const bytes = typeof content === "string" ? Buffer.from(content, "utf8") : Buffer.from(content);
1963
2153
  for (let off = 0, first = true; off < bytes.length || first; off += WRITE_CHUNK_BYTES, first = false) {
1964
2154
  const b64 = bytes.subarray(off, off + WRITE_CHUNK_BYTES).toString("base64");
1965
2155
  const redirect = first && truncateFirst ? ">" : ">>";
1966
- const r = await this.execData(`printf '%s' ${shellQuote(b64)} | base64 -d ${redirect} ${shellQuote(abs)}`, abortSignal);
2156
+ const r = await exec(`printf '%s' ${shellQuote(b64)} | base64 -d ${redirect} ${shellQuote(abs)}`);
1967
2157
  if (!r.ok)
1968
2158
  return { ok: false, error: fileErrorFromExec(r.error, abs) };
1969
2159
  if (r.value.exitCode !== 0)
@@ -2013,7 +2203,7 @@ export class RemoteK8sExecutionEnv {
2013
2203
  const c = await this.ensureConnected();
2014
2204
  if (!c.ok)
2015
2205
  return c;
2016
- return this.runExec(command, { signal: abortSignal, capMs: this.cfg.dataTimeoutMs });
2206
+ return this.runExec(ADAPTER_START, command, { signal: abortSignal, capMs: this.cfg.dataTimeoutMs });
2017
2207
  }
2018
2208
  workingDirOf(cwd) {
2019
2209
  const dir = cwd ?? this.cwd;