@opengeni/runtime 0.14.1 → 0.14.15

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 (79) hide show
  1. package/dist/{chunk-4YJ5Z52Z.js → chunk-7E2ZSCZK.js} +6 -6
  2. package/dist/{chunk-4YJ5Z52Z.js.map → chunk-7E2ZSCZK.js.map} +1 -1
  3. package/dist/{chunk-HHWIZHQM.js → chunk-GNEGANUF.js} +942 -300
  4. package/dist/chunk-GNEGANUF.js.map +1 -0
  5. package/dist/codex-tool-search.d.ts +100 -0
  6. package/dist/context-compaction.d.ts +236 -0
  7. package/dist/history-sanitizer.d.ts +320 -0
  8. package/dist/index.d.ts +186 -718
  9. package/dist/index.js +612 -126
  10. package/dist/index.js.map +1 -1
  11. package/dist/{localSources-T3HZ6KY4.js → localSources-BXHBKGF4.js} +2 -2
  12. package/dist/mcp-network.d.ts +32 -35
  13. package/dist/metrics.d.ts +33 -0
  14. package/dist/sandbox/capabilities.d.ts +11 -0
  15. package/dist/sandbox/channel-a.d.ts +226 -0
  16. package/dist/sandbox/display-stack.d.ts +99 -0
  17. package/dist/sandbox/errors.d.ts +16 -0
  18. package/dist/sandbox/exec-banner.d.ts +19 -0
  19. package/dist/sandbox/index.d.ts +190 -6
  20. package/dist/sandbox/index.js +20 -4
  21. package/dist/sandbox/op-correlation.d.ts +24 -0
  22. package/dist/sandbox/provider-errors.d.ts +32 -0
  23. package/dist/sandbox/provider-operation-gate.d.ts +12 -0
  24. package/dist/sandbox/providers/blaxel.d.ts +2 -0
  25. package/dist/sandbox/providers/cloudflare.d.ts +2 -0
  26. package/dist/sandbox/providers/daytona.d.ts +2 -0
  27. package/dist/sandbox/providers/docker.d.ts +2 -0
  28. package/dist/sandbox/providers/e2b.d.ts +2 -0
  29. package/dist/sandbox/providers/index.d.ts +11 -0
  30. package/dist/sandbox/providers/local.d.ts +2 -0
  31. package/dist/sandbox/providers/modal.d.ts +132 -0
  32. package/dist/sandbox/providers/none.d.ts +2 -0
  33. package/dist/sandbox/providers/runloop.d.ts +2 -0
  34. package/dist/sandbox/providers/selfhosted.d.ts +2 -0
  35. package/dist/sandbox/providers/types.d.ts +30 -0
  36. package/dist/sandbox/providers/vercel.d.ts +2 -0
  37. package/dist/sandbox/recording.d.ts +80 -0
  38. package/dist/sandbox/routing/backend-resolver.d.ts +173 -0
  39. package/dist/sandbox/routing/routing-session.d.ts +401 -0
  40. package/dist/sandbox/run-credentials.d.ts +65 -0
  41. package/dist/sandbox/select.d.ts +120 -0
  42. package/dist/sandbox/selfhosted/capabilities.d.ts +91 -0
  43. package/dist/sandbox/selfhosted/control-rpc.d.ts +175 -0
  44. package/dist/sandbox/selfhosted/fault-rendering.d.ts +40 -0
  45. package/dist/sandbox/selfhosted/op-observer.d.ts +40 -0
  46. package/dist/sandbox/selfhosted/op-stream.d.ts +104 -0
  47. package/dist/sandbox/selfhosted/op-testing.d.ts +108 -0
  48. package/dist/sandbox/selfhosted/op-transport.d.ts +60 -0
  49. package/dist/sandbox/selfhosted/retry-policy.d.ts +106 -0
  50. package/dist/sandbox/selfhosted/session.d.ts +552 -0
  51. package/dist/sandbox/selfhosted/testing.d.ts +48 -0
  52. package/dist/sandbox/stream-port.d.ts +80 -0
  53. package/dist/sandbox/stream-token.d.ts +44 -0
  54. package/dist/sandbox/terminal-server.d.ts +67 -0
  55. package/dist/sandbox/toolspace-token.d.ts +23 -0
  56. package/dist/sandbox/turn-tool-cancellation.d.ts +72 -0
  57. package/dist/sandbox/workspace-archive.d.ts +39 -0
  58. package/dist/sandbox-computer.d.ts +227 -0
  59. package/dist/screenshot-error-card.d.ts +1 -0
  60. package/dist/skill-library.d.ts +10 -12
  61. package/dist/usage-telemetry.d.ts +45 -0
  62. package/dist/workspace-skills.d.ts +31 -0
  63. package/package.json +7 -7
  64. package/src/context-compaction.ts +600 -6
  65. package/src/history-sanitizer.ts +10 -92
  66. package/src/index.ts +301 -62
  67. package/src/sandbox/channel-a.ts +267 -81
  68. package/src/sandbox/index.ts +56 -94
  69. package/src/sandbox/provider-operation-gate.ts +110 -0
  70. package/src/sandbox/providers/docker.ts +13 -1
  71. package/src/sandbox/providers/modal.ts +433 -3
  72. package/src/sandbox/routing/routing-session.ts +84 -8
  73. package/src/sandbox/selfhosted/session.ts +7 -6
  74. package/src/sandbox/turn-tool-cancellation.ts +47 -7
  75. package/src/sandbox/workspace-archive.ts +176 -73
  76. package/src/sandbox-computer.ts +25 -75
  77. package/dist/chunk-HHWIZHQM.js.map +0 -1
  78. package/dist/index-BraazrAO.d.ts +0 -2931
  79. /package/dist/{localSources-T3HZ6KY4.js.map → localSources-BXHBKGF4.js.map} +0 -0
@@ -28,7 +28,7 @@ import {
28
28
  validateCredentialPair,
29
29
  validateRemoteSandboxPathForManifest,
30
30
  validateSandboxArchiveLimits
31
- } from "./chunk-4YJ5Z52Z.js";
31
+ } from "./chunk-7E2ZSCZK.js";
32
32
  import {
33
33
  FileMode,
34
34
  Manifest,
@@ -129,7 +129,7 @@ function assertDescriptorRegistryInvariants() {
129
129
  }
130
130
  }
131
131
 
132
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/editor.mjs
132
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/editor.mjs
133
133
  var RemoteSandboxEditor = class {
134
134
  io;
135
135
  constructor(io) {
@@ -184,7 +184,7 @@ var RemoteSandboxEditor = class {
184
184
  }
185
185
  };
186
186
 
187
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/archive.mjs
187
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/archive.mjs
188
188
  var TAR_BLOCK_SIZE = 512;
189
189
  var ZERO_BLOCK = new Uint8Array(TAR_BLOCK_SIZE);
190
190
  function assertTarWorkspacePersistence(providerName, workspacePersistence) {
@@ -624,7 +624,7 @@ function tarError(member, reason) {
624
624
  });
625
625
  }
626
626
 
627
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/metadata.mjs
627
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/metadata.mjs
628
628
  var MOUNT_MANIFEST_METADATA_SUPPORT = {
629
629
  mounts: true
630
630
  };
@@ -705,7 +705,7 @@ function joinSandboxPath(parent, child) {
705
705
  return `${parent.replace(/\/+$/u, "")}/${normalizedChild}`;
706
706
  }
707
707
 
708
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/ports.mjs
708
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/ports.mjs
709
709
  function assertConfiguredExposedPort(args) {
710
710
  const port = normalizeExposedPort(args.port);
711
711
  if (args.allowOnDemand) {
@@ -768,7 +768,7 @@ function parseExposedPortEndpoint(value, args) {
768
768
  };
769
769
  }
770
770
 
771
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/pty.mjs
771
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/pty.mjs
772
772
  var PTY_YIELD_TIME_MS_MIN = 250;
773
773
  var PTY_EMPTY_YIELD_TIME_MS_MIN = 5e3;
774
774
  var PTY_YIELD_TIME_MS_MAX = 3e4;
@@ -1085,7 +1085,7 @@ function formatWebSocketEvent(event) {
1085
1085
  return "unknown error";
1086
1086
  }
1087
1087
 
1088
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/session.mjs
1088
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/session.mjs
1089
1089
  async function closeRemoteSessionOnManifestError(providerName, session, manifestError) {
1090
1090
  try {
1091
1091
  await session.close();
@@ -1434,7 +1434,7 @@ function isNotFoundErrorMessage(message) {
1434
1434
  return /\b(sandbox|sandbox instance|instance|devbox)\b.*\b(not found|missing|does not exist|no such)\b/iu.test(text) || /\b(not found|missing|does not exist|no such)\b.*\b(sandbox|sandbox instance|instance|devbox)\b/iu.test(text);
1435
1435
  }
1436
1436
 
1437
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/runAs.mjs
1437
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/runAs.mjs
1438
1438
  function sandboxUserShellCommand(command, user) {
1439
1439
  if (!user) {
1440
1440
  return command;
@@ -1566,7 +1566,7 @@ function randomId() {
1566
1566
  return (globalThis.crypto?.randomUUID?.() ?? Math.random().toString(16).slice(2)).replace(/-/gu, "");
1567
1567
  }
1568
1568
 
1569
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/sessionBase.mjs
1569
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/sessionBase.mjs
1570
1570
  import { randomUUID as randomUUID2 } from "crypto";
1571
1571
  var RemoteSandboxSessionBase = class {
1572
1572
  state;
@@ -2004,7 +2004,7 @@ function joinRemoteCommandOutput(result) {
2004
2004
  return [result.stdout ?? "", result.stderr ?? ""].filter((value) => value.trim().length > 0).join("\n");
2005
2005
  }
2006
2006
 
2007
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/sessionState.mjs
2007
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/sessionState.mjs
2008
2008
  function serializeRemoteSandboxSessionState(state) {
2009
2009
  return {
2010
2010
  ...state,
@@ -2034,7 +2034,7 @@ function deserializeRemotePersistedEnvironmentForRuntime(manifest, environment,
2034
2034
  };
2035
2035
  }
2036
2036
 
2037
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/snapshots.mjs
2037
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/snapshots.mjs
2038
2038
  var NATIVE_SNAPSHOT_PREFIXES = {
2039
2039
  e2b: "E2B_SANDBOX_SNAPSHOT_V1\n",
2040
2040
  modal_snapshot_directory: "MODAL_SANDBOX_DIR_SNAPSHOT_V1\n",
@@ -2076,10 +2076,10 @@ function decodeNativeSnapshotRef(data) {
2076
2076
  return void 0;
2077
2077
  }
2078
2078
 
2079
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/blaxel/mounts.mjs
2079
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/blaxel/mounts.mjs
2080
2080
  import { createHash } from "crypto";
2081
2081
 
2082
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/shared/inContainerMounts.mjs
2082
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/shared/inContainerMounts.mjs
2083
2083
  var DEFAULT_PACKAGE_MANAGERS = ["apt"];
2084
2084
  var SAFE_PIDFILE_KILL_FUNCTION = String.raw`openai_agents_kill_pidfile() {
2085
2085
  pidfile=$1
@@ -2699,7 +2699,7 @@ function normalizeBoxRemotePath(path) {
2699
2699
  return path?.replace(/^\/+/gu, "") ?? "";
2700
2700
  }
2701
2701
 
2702
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/blaxel/mounts.mjs
2702
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/blaxel/mounts.mjs
2703
2703
  var GCSFUSE_VERSION = "3.4.4";
2704
2704
  var GCSFUSE_AMD64_DEB_SHA256 = "406945ecc736e8cf0eee92a617fd4a038d138c9c31e48980b99862a5f1f55bb5";
2705
2705
  var GCSFUSE_ARM64_DEB_SHA256 = "8587fe2ee274075d8ec5a363e32761bc523a72c531922a69dd35035a371fdf3a";
@@ -3157,7 +3157,7 @@ function safeId(value) {
3157
3157
  return createHash("sha256").update(value).digest("hex");
3158
3158
  }
3159
3159
 
3160
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/blaxel/sandbox.mjs
3160
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/blaxel/sandbox.mjs
3161
3161
  var BLAXEL_AUTOGENERATED_NAME_CREATE_ATTEMPTS = 5;
3162
3162
  var BLAXEL_NON_RESUMABLE_SANDBOX_STATUSES = /* @__PURE__ */ new Set([
3163
3163
  "DEACTIVATING",
@@ -4292,7 +4292,7 @@ var blaxelProvider = {
4292
4292
  }
4293
4293
  };
4294
4294
 
4295
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/cloudflare/mounts.mjs
4295
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/cloudflare/mounts.mjs
4296
4296
  function buildCloudflareBucketMountConfig(mount) {
4297
4297
  if (isS3Mount(mount)) {
4298
4298
  const accessKeyId = readOptionalString(mount, "accessKeyId");
@@ -4428,7 +4428,7 @@ function validateCredentialPair4(args) {
4428
4428
  });
4429
4429
  }
4430
4430
 
4431
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/cloudflare/sandbox.mjs
4431
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/cloudflare/sandbox.mjs
4432
4432
  var CloudflareSandboxSession = class {
4433
4433
  state;
4434
4434
  apiKey;
@@ -4651,7 +4651,7 @@ var CloudflareSandboxSession = class {
4651
4651
  async materializeEntry(args) {
4652
4652
  assertSandboxEntryMetadataSupported("CloudflareSandboxClient", args.path, args.entry, MOUNT_MANIFEST_METADATA_SUPPORT);
4653
4653
  if (entryContainsLocalSource(args.entry)) {
4654
- const { applyLocalSourceManifestEntryToState: applyLocalSourceManifestEntryToState2 } = await import("./localSources-T3HZ6KY4.js");
4654
+ const { applyLocalSourceManifestEntryToState: applyLocalSourceManifestEntryToState2 } = await import("./localSources-BXHBKGF4.js");
4655
4655
  await applyLocalSourceManifestEntryToState2(this.state, args.path, args.entry, "cloudflare", this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(args.runAs));
4656
4656
  return;
4657
4657
  }
@@ -4662,7 +4662,7 @@ var CloudflareSandboxSession = class {
4662
4662
  assertSandboxManifestMetadataSupported("CloudflareSandboxClient", manifest, MOUNT_MANIFEST_METADATA_SUPPORT);
4663
4663
  assertCloudflareManifestMountsSupported(manifest);
4664
4664
  if (manifestContainsLocalSource(manifest)) {
4665
- const { applyLocalSourceManifestToState: applyLocalSourceManifestToState2 } = await import("./localSources-T3HZ6KY4.js");
4665
+ const { applyLocalSourceManifestToState: applyLocalSourceManifestToState2 } = await import("./localSources-BXHBKGF4.js");
4666
4666
  await applyLocalSourceManifestToState2(this.state, manifest, "cloudflare", this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(runAs));
4667
4667
  return;
4668
4668
  }
@@ -5581,12 +5581,12 @@ var cloudflareProvider = {
5581
5581
  }
5582
5582
  };
5583
5583
 
5584
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/daytona/mounts.mjs
5584
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/daytona/mounts.mjs
5585
5585
  function isDaytonaCloudBucketMountEntry(entry) {
5586
5586
  return isRcloneCloudBucketMountEntry(entry, "daytona_cloud_bucket");
5587
5587
  }
5588
5588
 
5589
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/daytona/sandbox.mjs
5589
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/daytona/sandbox.mjs
5590
5590
  var DEFAULT_WORKSPACE_ROOT = "/home/daytona/workspace";
5591
5591
  var DEFAULT_EXPOSED_PORT_URL_TTL_S = 60;
5592
5592
  var DAYTONA_DELETE_RETRY_DELAYS_MS = [1e3, 2e3, 4e3];
@@ -10647,27 +10647,37 @@ function getHostDockerUser() {
10647
10647
  }
10648
10648
 
10649
10649
  // src/sandbox/providers/docker.ts
10650
+ import { isAbsolute as isAbsolute4 } from "path";
10650
10651
  var dockerProvider = {
10651
10652
  backend: "docker",
10652
10653
  descriptor: CAPABILITY_DESCRIPTORS.docker,
10653
10654
  // Local dev container — no credentials. (The dockerNetwork decoration is
10654
10655
  // applied by the factory, not here: it wraps the constructed client.)
10655
- validateCredentials() {
10656
+ validateCredentials(settings) {
10657
+ const workspaceBaseDir = settings.dockerWorkspaceBaseDir?.trim();
10658
+ if (workspaceBaseDir && !isAbsolute4(workspaceBaseDir)) {
10659
+ throw new SandboxConfigError(
10660
+ "docker",
10661
+ "OPENGENI_DOCKER_WORKSPACE_BASE_DIR must be an absolute path"
10662
+ );
10663
+ }
10656
10664
  },
10657
10665
  build({ settings, exposedPorts }) {
10666
+ const workspaceBaseDir = settings.dockerWorkspaceBaseDir?.trim();
10658
10667
  return new DockerSandboxClient({
10659
10668
  image: settings.dockerImage,
10660
- exposedPorts
10669
+ exposedPorts,
10670
+ ...workspaceBaseDir ? { workspaceBaseDir } : {}
10661
10671
  });
10662
10672
  }
10663
10673
  };
10664
10674
 
10665
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/e2b/mounts.mjs
10675
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/e2b/mounts.mjs
10666
10676
  function isE2BCloudBucketMountEntry(entry) {
10667
10677
  return isRcloneCloudBucketMountEntry(entry, "e2b_cloud_bucket");
10668
10678
  }
10669
10679
 
10670
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/e2b/sandbox.mjs
10680
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/e2b/sandbox.mjs
10671
10681
  var E2BSandboxSession = class extends RemoteSandboxSessionBase {
10672
10682
  sandbox;
10673
10683
  ptyProcesses = new PtyProcessRegistry();
@@ -11449,10 +11459,10 @@ var localProvider = {
11449
11459
  }
11450
11460
  };
11451
11461
 
11452
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/modal/sandbox.mjs
11462
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/modal/sandbox.mjs
11453
11463
  import { posix as pathPosix } from "path";
11454
11464
 
11455
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/modal/mounts.mjs
11465
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/modal/mounts.mjs
11456
11466
  var ModalCloudBucketMountStrategy = class {
11457
11467
  type = "modal_cloud_bucket";
11458
11468
  secretName;
@@ -11636,7 +11646,7 @@ function isGCSMount2(entry) {
11636
11646
  return entry.type === "gcs_mount";
11637
11647
  }
11638
11648
 
11639
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/modal/sandbox.mjs
11649
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/modal/sandbox.mjs
11640
11650
  var DEFAULT_MODAL_IMAGE_TAG = "debian:bookworm-slim";
11641
11651
  var DEFAULT_EXEC_YIELD_TIME_MS2 = 1e4;
11642
11652
  var DEFAULT_WRITE_STDIN_YIELD_TIME_MS2 = 250;
@@ -13058,7 +13068,11 @@ async function terminateModalSandboxAfterTimeout(sandbox) {
13058
13068
 
13059
13069
  // src/sandbox/providers/modal.ts
13060
13070
  import { effectiveModalIdleTimeoutSeconds } from "@opengeni/config";
13071
+ import {
13072
+ canonicalModalCheckpointProviderBinding
13073
+ } from "@opengeni/contracts";
13061
13074
  var MODAL_ORPHAN_SWEEP_LIMIT = 50;
13075
+ var OPENGENI_MODAL_SDK_VERSION = "0.9.0";
13062
13076
  var MODAL_UNATTRIBUTED_ORPHAN_GRACE_MS = 2 * 6e4;
13063
13077
  function modalSandboxAttributionEnvironment(input) {
13064
13078
  return {
@@ -13075,6 +13089,113 @@ function modalSandboxAttributionTags(input) {
13075
13089
  opengeni_sandbox_group_id: input.sandboxGroupId
13076
13090
  };
13077
13091
  }
13092
+ var modalRetentionWrappedSessions = /* @__PURE__ */ new WeakSet();
13093
+ var modalFilesystemRetentionWrappedSandboxes = /* @__PURE__ */ new WeakSet();
13094
+ var modalDirectoryRetentionWrappedSandboxes = /* @__PURE__ */ new WeakSet();
13095
+ var MODAL_EXEC_STDIN_WRITE_PATH = "/modal.task_command_router.TaskCommandRouter/TaskExecStdinWrite";
13096
+ var MODAL_EXEC_ALREADY_COMPLETED_DETAILS = /^Exec has already completed; stdin is no longer accepting writes(?: \(Error code: [A-Z0-9]+\))?$/;
13097
+ function isModalExecAlreadyCompletedError(error) {
13098
+ if (!error || typeof error !== "object") return false;
13099
+ const record = error;
13100
+ return record.name === "ClientError" && record.path === MODAL_EXEC_STDIN_WRITE_PATH && record.code === 9 && typeof record.details === "string" && MODAL_EXEC_ALREADY_COMPLETED_DETAILS.test(record.details);
13101
+ }
13102
+ function assertPinnedModalSdk(session) {
13103
+ const actualVersion = session.modal?.version?.();
13104
+ if (actualVersion !== OPENGENI_MODAL_SDK_VERSION) {
13105
+ throw new Error(
13106
+ `OpenGeni Modal snapshot compatibility requires modal@${OPENGENI_MODAL_SDK_VERSION}; the active session reported ${actualVersion ?? "no version"}`
13107
+ );
13108
+ }
13109
+ }
13110
+ function installModalNativeSnapshotRetention(session) {
13111
+ const persistence = session.state?.workspacePersistence;
13112
+ if (persistence !== "snapshot_filesystem" && persistence !== "snapshot_directory") {
13113
+ return;
13114
+ }
13115
+ const sandbox = session.sandbox;
13116
+ if (!sandbox || typeof sandbox !== "object") {
13117
+ throw new Error(`Modal ${persistence} persistence has no active provider sandbox`);
13118
+ }
13119
+ if (persistence === "snapshot_filesystem") {
13120
+ if (modalFilesystemRetentionWrappedSandboxes.has(sandbox)) return;
13121
+ const snapshotFilesystem = sandbox.snapshotFilesystem;
13122
+ if (typeof snapshotFilesystem !== "function") {
13123
+ throw new Error("Modal snapshot_filesystem persistence is unavailable");
13124
+ }
13125
+ sandbox.snapshotFilesystem = async (legacyParams) => {
13126
+ if (legacyParams !== void 0 && typeof legacyParams !== "number") {
13127
+ throw new Error("Unexpected Modal snapshot_filesystem adapter call shape");
13128
+ }
13129
+ return await snapshotFilesystem.call(sandbox, {
13130
+ ...legacyParams === void 0 ? {} : { timeoutMs: legacyParams },
13131
+ ttlMs: null
13132
+ });
13133
+ };
13134
+ modalFilesystemRetentionWrappedSandboxes.add(sandbox);
13135
+ return;
13136
+ }
13137
+ if (modalDirectoryRetentionWrappedSandboxes.has(sandbox)) return;
13138
+ const snapshotDirectory = sandbox.snapshotDirectory;
13139
+ if (typeof snapshotDirectory !== "function") {
13140
+ throw new Error("Modal snapshot_directory persistence is unavailable");
13141
+ }
13142
+ sandbox.snapshotDirectory = async (path, legacyParams) => {
13143
+ if (typeof path !== "string" || legacyParams !== void 0) {
13144
+ throw new Error("Unexpected Modal snapshot_directory adapter call shape");
13145
+ }
13146
+ return await snapshotDirectory.call(sandbox, path, {
13147
+ ...session.state?.snapshotFilesystemTimeoutMs === void 0 ? {} : { timeoutMs: session.state.snapshotFilesystemTimeoutMs },
13148
+ ttlMs: null
13149
+ });
13150
+ };
13151
+ modalDirectoryRetentionWrappedSandboxes.add(sandbox);
13152
+ }
13153
+ function installModalExecCompletionRecovery(session) {
13154
+ const writeStdin = session.writeStdin;
13155
+ if (typeof writeStdin !== "function") return;
13156
+ session.writeStdin = async (args) => {
13157
+ try {
13158
+ return await writeStdin.call(session, args);
13159
+ } catch (error) {
13160
+ if (!isModalExecAlreadyCompletedError(error) || !Number.isSafeInteger(args.sessionId) || args.sessionId <= 0) {
13161
+ throw error;
13162
+ }
13163
+ try {
13164
+ return await writeStdin.call(session, { ...args, chars: "" });
13165
+ } catch {
13166
+ return `write_stdin failed: session not found: ${args.sessionId}`;
13167
+ }
13168
+ }
13169
+ };
13170
+ }
13171
+ function installOpenGeniModalSnapshotPolicy(session) {
13172
+ const mutable = session;
13173
+ if (modalRetentionWrappedSessions.has(session)) return session;
13174
+ if (typeof mutable.persistWorkspace !== "function") {
13175
+ throw new Error("Modal session does not expose workspace persistence");
13176
+ }
13177
+ assertPinnedModalSdk(mutable);
13178
+ installModalNativeSnapshotRetention(mutable);
13179
+ installModalExecCompletionRecovery(mutable);
13180
+ const persistWorkspace = mutable.persistWorkspace.bind(session);
13181
+ mutable.persistWorkspace = async () => {
13182
+ assertPinnedModalSdk(mutable);
13183
+ installModalNativeSnapshotRetention(mutable);
13184
+ return await persistWorkspace();
13185
+ };
13186
+ modalRetentionWrappedSessions.add(session);
13187
+ return session;
13188
+ }
13189
+ var OpenGeniModalSandboxClient = class extends ModalSandboxClient {
13190
+ async create(args, manifestOptions) {
13191
+ const session = await super.create(args, manifestOptions);
13192
+ return installOpenGeniModalSnapshotPolicy(session);
13193
+ }
13194
+ async resume(state) {
13195
+ const session = await super.resume(state);
13196
+ return installOpenGeniModalSnapshotPolicy(session);
13197
+ }
13198
+ };
13078
13199
  var modalProvider = {
13079
13200
  backend: "modal",
13080
13201
  descriptor: CAPABILITY_DESCRIPTORS.modal,
@@ -13119,7 +13240,7 @@ var modalProvider = {
13119
13240
  if (settings.modalEnvironment) {
13120
13241
  options.environment = settings.modalEnvironment;
13121
13242
  }
13122
- return new ModalSandboxClient(options);
13243
+ return new OpenGeniModalSandboxClient(options);
13123
13244
  }
13124
13245
  };
13125
13246
  var defaultModalLoader = () => import("modal");
@@ -13177,14 +13298,148 @@ function modalClientOptions(settings) {
13177
13298
  return {
13178
13299
  ...settings.modalTokenId ? { tokenId: settings.modalTokenId } : {},
13179
13300
  ...settings.modalTokenSecret ? { tokenSecret: settings.modalTokenSecret } : {},
13180
- ...settings.modalEnvironment ? { environment: settings.modalEnvironment } : {},
13181
- ...settings.modalTimeoutSeconds ? { timeoutMs: settings.modalTimeoutSeconds * 1e3 } : {}
13301
+ ...settings.modalEnvironment ? { environment: settings.modalEnvironment } : {}
13182
13302
  };
13183
13303
  }
13184
13304
  async function createModalClient(settings) {
13185
13305
  const modal = await import("modal");
13186
13306
  return new modal.ModalClient(modalClientOptions(settings));
13187
13307
  }
13308
+ function isModalNotFoundError(error) {
13309
+ const candidate = error;
13310
+ return candidate?.name === "NotFoundError" || candidate?.code === 5;
13311
+ }
13312
+ async function modalCheckpointProviderBindingForClient(settings, modal) {
13313
+ const identity = await modal.cpClient.workspaceNameLookup({});
13314
+ const workspaceName = identity.workspaceName || identity.username;
13315
+ if (!workspaceName) {
13316
+ throw new Error("Modal credential resolved no workspace identity");
13317
+ }
13318
+ const resolved = canonicalModalCheckpointProviderBinding({
13319
+ version: 1,
13320
+ serverUrl: modal.profile.serverUrl,
13321
+ workspaceName,
13322
+ // Resolve through the authenticated client, not the optional OpenGeni
13323
+ // override alone. When the override is absent Modal may select a profile
13324
+ // environment; persisting "" would fail to fence a later profile change.
13325
+ environment: modal.environmentName(settings.modalEnvironment)
13326
+ });
13327
+ if (!resolved) {
13328
+ throw new Error("Modal credential resolved an invalid checkpoint provider identity");
13329
+ }
13330
+ return resolved.binding;
13331
+ }
13332
+ var modalSessionCheckpointBindings = /* @__PURE__ */ new WeakMap();
13333
+ async function resolveModalCheckpointProviderBindingForSession(settings, session) {
13334
+ if (!session || typeof session !== "object") {
13335
+ throw new Error("Modal checkpoint session identity is unavailable");
13336
+ }
13337
+ const cached = modalSessionCheckpointBindings.get(session);
13338
+ if (cached) return await cached;
13339
+ const modal = session.modal;
13340
+ if (!modal || typeof modal.cpClient?.workspaceNameLookup !== "function" || typeof modal.profile?.serverUrl !== "string" || typeof modal.environmentName !== "function") {
13341
+ throw new Error("Pinned Modal session no longer exposes its authenticated checkpoint identity");
13342
+ }
13343
+ const pending = modalCheckpointProviderBindingForClient(settings, modal).then(
13344
+ (binding) => canonicalModalCheckpointProviderBinding(binding)
13345
+ );
13346
+ modalSessionCheckpointBindings.set(session, pending);
13347
+ try {
13348
+ return await pending;
13349
+ } catch (error) {
13350
+ modalSessionCheckpointBindings.delete(session);
13351
+ throw error;
13352
+ }
13353
+ }
13354
+ async function modalSessionMatchesCheckpointProviderBinding(settings, session, expectedBindingKey) {
13355
+ const identity = await resolveModalCheckpointProviderBindingForSession(settings, session);
13356
+ return identity.key === expectedBindingKey;
13357
+ }
13358
+ async function resolveModalCheckpointProviderBinding(settings, createClient = createModalClient) {
13359
+ const modal = await createClient(settings);
13360
+ try {
13361
+ const binding = await modalCheckpointProviderBindingForClient(settings, modal);
13362
+ return canonicalModalCheckpointProviderBinding(binding);
13363
+ } finally {
13364
+ modal.close();
13365
+ }
13366
+ }
13367
+ async function resolveModalCheckpointProviderBindingForLiveSandbox(settings, sandboxId, createClient = createModalClient) {
13368
+ if (!sandboxId) throw new Error("Modal live-sandbox identity requires a sandbox id");
13369
+ const modal = await createClient(settings);
13370
+ try {
13371
+ const binding = await modalCheckpointProviderBindingForClient(settings, modal);
13372
+ const sandbox = await modal.sandboxes.fromId(sandboxId);
13373
+ const exitCode = await sandbox.poll();
13374
+ if (exitCode !== null) {
13375
+ throw new Error(`Modal sandbox ${sandboxId} is no longer running`);
13376
+ }
13377
+ return canonicalModalCheckpointProviderBinding(binding);
13378
+ } finally {
13379
+ modal.close();
13380
+ }
13381
+ }
13382
+ async function inspectModalSandboxLifecycle(settings, sandboxId, expectedBindingKey, createClient = createModalClient) {
13383
+ if (!sandboxId) throw new Error("Modal lifecycle inspection requires a sandbox id");
13384
+ const modal = await createClient(settings);
13385
+ try {
13386
+ const binding = canonicalModalCheckpointProviderBinding(
13387
+ await modalCheckpointProviderBindingForClient(settings, modal)
13388
+ );
13389
+ if (expectedBindingKey && binding.key !== expectedBindingKey) {
13390
+ throw new Error(
13391
+ "Modal lifecycle inspection refused because the configured credential workspace changed"
13392
+ );
13393
+ }
13394
+ try {
13395
+ const sandbox = await modal.sandboxes.fromId(sandboxId);
13396
+ const exitCode = await sandbox.poll();
13397
+ return exitCode === null ? {
13398
+ status: "running",
13399
+ providerBindingKey: binding.key,
13400
+ providerBinding: binding.binding
13401
+ } : {
13402
+ status: "terminated",
13403
+ exitCode,
13404
+ providerBindingKey: binding.key,
13405
+ providerBinding: binding.binding
13406
+ };
13407
+ } catch (error) {
13408
+ if (isModalNotFoundError(error)) {
13409
+ return {
13410
+ status: "not_found",
13411
+ providerBindingKey: binding.key,
13412
+ providerBinding: binding.binding
13413
+ };
13414
+ }
13415
+ throw error;
13416
+ }
13417
+ } finally {
13418
+ modal.close();
13419
+ }
13420
+ }
13421
+ async function deleteModalCheckpointSnapshot(settings, expectedBindingKey, snapshotId, createClient = createModalClient) {
13422
+ if (!snapshotId) throw new Error("Modal checkpoint deletion requires a snapshot id");
13423
+ const modal = await createClient(settings);
13424
+ try {
13425
+ const binding = await modalCheckpointProviderBindingForClient(settings, modal);
13426
+ const identity = canonicalModalCheckpointProviderBinding(binding);
13427
+ if (expectedBindingKey !== identity.key) {
13428
+ throw new Error(
13429
+ "Modal checkpoint deletion refused because the configured credential workspace changed"
13430
+ );
13431
+ }
13432
+ try {
13433
+ await modal.images.delete(snapshotId);
13434
+ return "deleted";
13435
+ } catch (error) {
13436
+ if (isModalNotFoundError(error)) return "not_found";
13437
+ throw error;
13438
+ }
13439
+ } finally {
13440
+ modal.close();
13441
+ }
13442
+ }
13188
13443
  async function tagModalSandbox(settings, sandboxId, attribution) {
13189
13444
  if (!sandboxId) {
13190
13445
  return false;
@@ -13359,15 +13614,15 @@ var noneProvider = {
13359
13614
  }
13360
13615
  };
13361
13616
 
13362
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/runloop/sandbox.mjs
13617
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/runloop/sandbox.mjs
13363
13618
  import { posix as pathPosix2 } from "path";
13364
13619
 
13365
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/runloop/mounts.mjs
13620
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/runloop/mounts.mjs
13366
13621
  function isRunloopCloudBucketMountEntry(entry) {
13367
13622
  return isRcloneCloudBucketMountEntry(entry, "runloop_cloud_bucket");
13368
13623
  }
13369
13624
 
13370
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/runloop/sandbox.mjs
13625
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/runloop/sandbox.mjs
13371
13626
  var DEFAULT_RUNLOOP_WORKSPACE_ROOT = "/home/user";
13372
13627
  var DEFAULT_RUNLOOP_ROOT_WORKSPACE_ROOT = "/root";
13373
13628
  var UNKNOWN_RUNLOOP_EXIT_CODE = 1;
@@ -15950,10 +16205,11 @@ var SelfhostedSession = class {
15950
16205
  }
15951
16206
  }
15952
16207
  }
15953
- /** The clamped exec process deadline (ms): the exec-specific budget when threaded,
15954
- * else the control timeout. Shared by `exec()` (the wire deadline) and
15955
- * `execCommand()` (the timed-out hint's "N-second limit"), so the two never drift. */
15956
- execDeadlineMs() {
16208
+ /** The effective clamped exec process deadline (ms): the exec-specific budget
16209
+ * when threaded, else the control timeout. Public so adapters that project a
16210
+ * structured command receipt can report the exact deadline the agent enforces
16211
+ * instead of repeating (and potentially drifting from) this normalization. */
16212
+ get effectiveExecDeadlineMs() {
15957
16213
  return Math.max(
15958
16214
  1,
15959
16215
  Math.min(Math.trunc(this.execTimeoutMs ?? this.timeoutMs), SELFHOSTED_MAX_EXEC_TIMEOUT_MS)
@@ -15961,7 +16217,7 @@ var SelfhostedSession = class {
15961
16217
  }
15962
16218
  /** Channel-A `exec`: run a command on the machine and return its output. */
15963
16219
  async exec(args) {
15964
- const executionTimeoutMs = this.execDeadlineMs();
16220
+ const executionTimeoutMs = this.effectiveExecDeadlineMs;
15965
16221
  const execReq = {
15966
16222
  // The agent does NOT shell-interpret unless `shell` — Channel-A passes a
15967
16223
  // single shell command string, so run it through the platform shell.
@@ -16090,7 +16346,7 @@ var SelfhostedSession = class {
16090
16346
  async execCommand(args) {
16091
16347
  const result = await this.exec({ cmd: args.cmd, workdir: args.workdir, runAs: args.runAs });
16092
16348
  if (result.timedOut) {
16093
- const hint = execDeadlineHint(Math.round(this.execDeadlineMs() / 1e3));
16349
+ const hint = execDeadlineHint(Math.round(this.effectiveExecDeadlineMs / 1e3));
16094
16350
  return result.output ? `${result.output}
16095
16351
  ${hint}` : hint;
16096
16352
  }
@@ -16606,7 +16862,7 @@ var selfhostedProvider = {
16606
16862
  }
16607
16863
  };
16608
16864
 
16609
- // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+d7f081875ac70c34/node_modules/@openai/agents-extensions/dist/sandbox/vercel/sandbox.mjs
16865
+ // ../../node_modules/.bun/@openai+agents-extensions@0.13.3+b8edd3968b3469c2/node_modules/@openai/agents-extensions/dist/sandbox/vercel/sandbox.mjs
16610
16866
  var DEFAULT_VERCEL_WORKSPACE_ROOT = "/vercel/sandbox";
16611
16867
  var VercelSandboxSession = class _VercelSandboxSession extends RemoteSandboxSessionBase {
16612
16868
  sandbox;
@@ -17602,7 +17858,99 @@ function isProviderSandboxTransientError(backendId, error) {
17602
17858
 
17603
17859
  // src/sandbox/workspace-archive.ts
17604
17860
  import { createHash as createHash4 } from "crypto";
17605
- var WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION = 1;
17861
+ import {
17862
+ WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
17863
+ decodeNativeSnapshotRef as decodeNativeSnapshotRef2,
17864
+ parseWorkspaceArchiveDescriptor
17865
+ } from "@opengeni/contracts";
17866
+
17867
+ // src/sandbox/provider-operation-gate.ts
17868
+ var providerOperationGates = /* @__PURE__ */ new WeakMap();
17869
+ function sessionIdentity(session) {
17870
+ const identityType = typeof session;
17871
+ if (!["object", "function"].includes(identityType) || session === null) {
17872
+ throw new Error("Sandbox provider operation has no session identity");
17873
+ }
17874
+ return session;
17875
+ }
17876
+ function gateFor(session) {
17877
+ const existing = providerOperationGates.get(session);
17878
+ if (existing) return existing;
17879
+ const created = {
17880
+ activeOperations: 0,
17881
+ captureActive: false,
17882
+ operationWaiters: [],
17883
+ captureWaiters: []
17884
+ };
17885
+ providerOperationGates.set(session, created);
17886
+ return created;
17887
+ }
17888
+ async function enterOperation(gate) {
17889
+ if (!gate.captureActive && gate.captureWaiters.length === 0) {
17890
+ gate.activeOperations += 1;
17891
+ return;
17892
+ }
17893
+ await new Promise((resolve5) => gate.operationWaiters.push(resolve5));
17894
+ }
17895
+ function leaveOperation(gate) {
17896
+ gate.activeOperations -= 1;
17897
+ if (gate.activeOperations < 0) {
17898
+ throw new Error("Sandbox provider operation gate underflow");
17899
+ }
17900
+ if (gate.activeOperations === 0) {
17901
+ const nextCapture = gate.captureWaiters.shift();
17902
+ if (nextCapture) {
17903
+ gate.captureActive = true;
17904
+ nextCapture();
17905
+ }
17906
+ }
17907
+ }
17908
+ async function enterCapture(gate) {
17909
+ if (!gate.captureActive && gate.activeOperations === 0) {
17910
+ gate.captureActive = true;
17911
+ return;
17912
+ }
17913
+ await new Promise((resolve5) => gate.captureWaiters.push(resolve5));
17914
+ }
17915
+ function leaveCapture(gate) {
17916
+ if (!gate.captureActive) {
17917
+ throw new Error("Sandbox provider capture gate was not held");
17918
+ }
17919
+ const nextCapture = gate.captureWaiters.shift();
17920
+ if (nextCapture) {
17921
+ nextCapture();
17922
+ return;
17923
+ }
17924
+ gate.captureActive = false;
17925
+ const operations = gate.operationWaiters.splice(0);
17926
+ gate.activeOperations += operations.length;
17927
+ for (const operation of operations) operation();
17928
+ }
17929
+ async function withSandboxProviderOperation(session, operation) {
17930
+ const gate = gateFor(sessionIdentity(session));
17931
+ await enterOperation(gate);
17932
+ try {
17933
+ return await operation();
17934
+ } finally {
17935
+ leaveOperation(gate);
17936
+ }
17937
+ }
17938
+ async function withSandboxProviderCapture(session, capture) {
17939
+ const gate = gateFor(sessionIdentity(session));
17940
+ await enterCapture(gate);
17941
+ try {
17942
+ return await capture();
17943
+ } finally {
17944
+ leaveCapture(gate);
17945
+ }
17946
+ }
17947
+
17948
+ // src/sandbox/workspace-archive.ts
17949
+ import {
17950
+ WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION as WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION2,
17951
+ decodeNativeSnapshotRef as decodeNativeSnapshotRef3,
17952
+ parseWorkspaceArchiveDescriptor as parseWorkspaceArchiveDescriptor2
17953
+ } from "@opengeni/contracts";
17606
17954
  var WorkspaceArchiveIntegrityError = class extends Error {
17607
17955
  constructor(code, message, options = {}) {
17608
17956
  super(message);
@@ -17612,23 +17960,9 @@ var WorkspaceArchiveIntegrityError = class extends Error {
17612
17960
  name = "WorkspaceArchiveIntegrityError";
17613
17961
  retryable;
17614
17962
  };
17615
- var SHA256 = /^[a-f0-9]{64}$/;
17616
- var REVISION = /^wa1:[0-9]{13}:[a-f0-9]{64}$/;
17617
17963
  function sha256(bytes) {
17618
17964
  return createHash4("sha256").update(bytes).digest("hex");
17619
17965
  }
17620
- function nonnegativeInteger(value) {
17621
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
17622
- }
17623
- function parseWorkspaceArchiveDescriptor(value) {
17624
- if (!value || typeof value !== "object") return null;
17625
- const candidate = value;
17626
- const workspace = candidate.workspace;
17627
- if (candidate.version !== WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION || typeof candidate.revision !== "string" || !REVISION.test(candidate.revision) || typeof candidate.archiveSha256 !== "string" || !SHA256.test(candidate.archiveSha256) || !nonnegativeInteger(candidate.archiveBytes) || candidate.archiveBytes === 0 || typeof candidate.capturedAt !== "string" || !Number.isFinite(Date.parse(candidate.capturedAt)) || !workspace || workspace.algorithm !== "sha256" || typeof workspace.sha256 !== "string" || !SHA256.test(workspace.sha256) || !nonnegativeInteger(workspace.entryCount) || !nonnegativeInteger(workspace.fileCount) || !nonnegativeInteger(workspace.totalFileBytes)) {
17628
- return null;
17629
- }
17630
- return candidate;
17631
- }
17632
17966
  function decodeBase64Strict(value) {
17633
17967
  if (value.length === 0 || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(value)) {
17634
17968
  return null;
@@ -17636,6 +17970,29 @@ function decodeBase64Strict(value) {
17636
17970
  const bytes = Uint8Array.from(Buffer.from(value, "base64"));
17637
17971
  return Buffer.from(bytes).toString("base64") === value ? bytes : null;
17638
17972
  }
17973
+ function describeNativeSnapshotArchive(bytes, capturedAtMs = Date.now()) {
17974
+ const native = decodeNativeSnapshotRef2(bytes);
17975
+ if (!native) return null;
17976
+ const archiveSha256 = sha256(bytes);
17977
+ return {
17978
+ version: WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
17979
+ kind: "provider_snapshot",
17980
+ revision: `wa2:${String(capturedAtMs).padStart(13, "0")}:${archiveSha256}`,
17981
+ archiveSha256,
17982
+ archiveBytes: bytes.length,
17983
+ capturedAt: new Date(capturedAtMs).toISOString(),
17984
+ provider: native.provider,
17985
+ snapshotId: native.snapshotId,
17986
+ ...native.workspacePersistence ? { workspacePersistence: native.workspacePersistence } : {}
17987
+ };
17988
+ }
17989
+ function describeLegacyNativeSnapshotArchive(base642, observedAtMs = Date.now()) {
17990
+ if (typeof base642 !== "string") return null;
17991
+ const bytes = decodeBase64Strict(base642);
17992
+ if (!bytes) return null;
17993
+ const descriptor = describeNativeSnapshotArchive(bytes, observedAtMs);
17994
+ return descriptor ? { archiveBase64: base642, descriptor } : null;
17995
+ }
17639
17996
  function readVerifiedWorkspaceArchive(base642, metadata) {
17640
17997
  if (base642 === void 0 || base642 === null || base642 === "") return null;
17641
17998
  if (typeof base642 !== "string") {
@@ -17671,7 +18028,27 @@ function readVerifiedWorkspaceArchive(base642, metadata) {
17671
18028
  `workspace archive revision ${descriptor.revision} failed SHA-256/size verification`
17672
18029
  );
17673
18030
  }
17674
- return { bytes, base64: base642, descriptor };
18031
+ const nativeSnapshot = decodeNativeSnapshotRef2(bytes);
18032
+ if (descriptor.version === WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION) {
18033
+ if (!nativeSnapshot || nativeSnapshot.provider !== descriptor.provider || nativeSnapshot.snapshotId !== descriptor.snapshotId || nativeSnapshot.workspacePersistence !== descriptor.workspacePersistence) {
18034
+ throw new WorkspaceArchiveIntegrityError(
18035
+ "native_snapshot_reference_invalid",
18036
+ `native snapshot receipt does not match descriptor revision ${descriptor.revision}`
18037
+ );
18038
+ }
18039
+ } else if (nativeSnapshot) {
18040
+ throw new WorkspaceArchiveIntegrityError(
18041
+ "native_snapshot_reference_invalid",
18042
+ `legacy native snapshot receipt ${descriptor.revision} was not durably upgraded to a v2 provider descriptor`
18043
+ );
18044
+ }
18045
+ return {
18046
+ bytes,
18047
+ base64: base642,
18048
+ descriptor,
18049
+ kind: descriptor.version === WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION ? "provider_snapshot" : "tar",
18050
+ ...descriptor.version === WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION && nativeSnapshot ? { nativeSnapshot } : {}
18051
+ };
17675
18052
  }
17676
18053
  function stdoutFromExecResult(value) {
17677
18054
  if (typeof value === "string") {
@@ -17682,15 +18059,33 @@ function stdoutFromExecResult(value) {
17682
18059
  const output = value;
17683
18060
  return typeof output.stdout === "string" ? output.stdout : typeof output.output === "string" ? output.output : "";
17684
18061
  }
17685
- var WORKSPACE_FINGERPRINT_COMMAND = String.raw`bash -o pipefail -c '
17686
- set -eu
18062
+ function shellQuote3(value) {
18063
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
18064
+ }
18065
+ function workspaceFingerprintExcludes(session) {
18066
+ const paths = session.state?.manifest?.ephemeralPersistencePaths?.();
18067
+ if (!paths) return [];
18068
+ return [...paths].filter((path) => typeof path === "string" && path.length > 0).sort((left, right) => left.localeCompare(right));
18069
+ }
18070
+ function workspaceFingerprintCommand(excludedPaths) {
18071
+ const tarExcludes = excludedPaths.flatMap((path) => [
18072
+ shellQuote3(`--exclude=${path}`),
18073
+ shellQuote3(`--exclude=./${path}`)
18074
+ ]);
18075
+ const findExcludes = excludedPaths.flatMap((path) => [
18076
+ `-path ${shellQuote3(`./${path}`)}`,
18077
+ `-path ${shellQuote3(`./${path}/*`)}`
18078
+ ]);
18079
+ const findPrefix = findExcludes.length === 0 ? "" : `\\( ${findExcludes.join(" -o ")} \\) -prune -o `;
18080
+ const script = String.raw`set -eu
17687
18081
  cd /workspace
17688
- digest=$(LC_ALL=C tar --sort=name --mtime="@0" --owner=0 --group=0 --numeric-owner --format=gnu -cf - . | sha256sum | awk "{print \$1}")
17689
- entries=$(find . -xdev -mindepth 1 -printf x | wc -c | tr -d " ")
17690
- files=$(find . -xdev -type f -printf x | wc -c | tr -d " ")
17691
- bytes=$(find . -xdev -type f -printf "%s\n" | awk "{s+=\$1} END {printf \"%.0f\", s+0}")
17692
- printf "OPENGENI_WORKSPACE_FINGERPRINT_V1 %s %s %s %s\n" "$digest" "$entries" "$files" "$bytes"
17693
- '`;
18082
+ digest=$(LC_ALL=C tar ${tarExcludes.join(" ")} --sort=name --mtime="@0" --owner=0 --group=0 --numeric-owner --hard-dereference --format=gnu -cf - . | sha256sum | awk "{print \$1}")
18083
+ entries=$(find . -xdev -mindepth 1 ${findPrefix}-printf x | wc -c | tr -d " ")
18084
+ files=$(find . -xdev ${findPrefix}-type f -printf x | wc -c | tr -d " ")
18085
+ bytes=$(find . -xdev ${findPrefix}-type f -printf "%s\n" | awk "{s+=\$1} END {printf \"%.0f\", s+0}")
18086
+ printf "OPENGENI_WORKSPACE_FINGERPRINT_V1 %s %s %s %s\n" "$digest" "$entries" "$files" "$bytes"`;
18087
+ return `bash -o pipefail -c ${shellQuote3(script)}`;
18088
+ }
17694
18089
  async function fingerprintSandboxWorkspace(session) {
17695
18090
  const target = session;
17696
18091
  const run2 = target.exec ?? target.execCommand;
@@ -17701,7 +18096,7 @@ async function fingerprintSandboxWorkspace(session) {
17701
18096
  );
17702
18097
  }
17703
18098
  const result = await run2.call(target, {
17704
- cmd: WORKSPACE_FINGERPRINT_COMMAND,
18099
+ cmd: workspaceFingerprintCommand(workspaceFingerprintExcludes(target)),
17705
18100
  yieldTimeMs: 12e4,
17706
18101
  maxOutputTokens: 1e3
17707
18102
  });
@@ -17734,6 +18129,11 @@ function fingerprintsEqual(a, b) {
17734
18129
  return a.sha256 === b.sha256 && a.entryCount === b.entryCount && a.fileCount === b.fileCount && a.totalFileBytes === b.totalFileBytes;
17735
18130
  }
17736
18131
  async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now()) {
18132
+ return await withSandboxProviderCapture(session, async () => {
18133
+ return await captureVerifiedWorkspaceArchiveExclusive(session, capturedAtMs);
18134
+ });
18135
+ }
18136
+ async function captureVerifiedWorkspaceArchiveExclusive(session, capturedAtMs) {
17737
18137
  const target = session;
17738
18138
  if (typeof target.persistWorkspace !== "function") {
17739
18139
  throw new WorkspaceArchiveIntegrityError(
@@ -17741,7 +18141,10 @@ async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now(
17741
18141
  "sandbox session does not support workspace persistence"
17742
18142
  );
17743
18143
  }
17744
- const before = await fingerprintSandboxWorkspace(target);
18144
+ const configuredPersistence = target.state?.workspacePersistence;
18145
+ const configuredTarFallback = workspaceFingerprintExcludes(target).length > 0;
18146
+ const expectsNativeSnapshot = typeof configuredPersistence === "string" && configuredPersistence !== "tar" && !configuredTarFallback;
18147
+ const before = expectsNativeSnapshot ? null : await fingerprintSandboxWorkspace(target);
17745
18148
  const bytes = await target.persistWorkspace();
17746
18149
  if (!bytes || bytes.length === 0) {
17747
18150
  throw new WorkspaceArchiveIntegrityError(
@@ -17750,8 +18153,25 @@ async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now(
17750
18153
  { retryable: true }
17751
18154
  );
17752
18155
  }
18156
+ const nativeSnapshot = decodeNativeSnapshotRef2(bytes);
18157
+ if (nativeSnapshot) {
18158
+ const descriptor2 = describeNativeSnapshotArchive(bytes, capturedAtMs);
18159
+ return {
18160
+ bytes,
18161
+ base64: Buffer.from(bytes).toString("base64"),
18162
+ descriptor: descriptor2,
18163
+ kind: "provider_snapshot",
18164
+ nativeSnapshot
18165
+ };
18166
+ }
18167
+ if (expectsNativeSnapshot) {
18168
+ throw new WorkspaceArchiveIntegrityError(
18169
+ "native_snapshot_fallback_unverified",
18170
+ `sandbox configured for ${String(configuredPersistence)} returned a tar archive instead of a native snapshot receipt`
18171
+ );
18172
+ }
17753
18173
  const after = await fingerprintSandboxWorkspace(target);
17754
- if (!fingerprintsEqual(before, after)) {
18174
+ if (!before || !fingerprintsEqual(before, after)) {
17755
18175
  throw new WorkspaceArchiveIntegrityError(
17756
18176
  "workspace_changed_during_capture",
17757
18177
  "workspace changed while its durable archive was being captured",
@@ -17760,7 +18180,7 @@ async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now(
17760
18180
  }
17761
18181
  const archiveSha256 = sha256(bytes);
17762
18182
  const descriptor = {
17763
- version: WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
18183
+ version: 1,
17764
18184
  revision: `wa1:${String(capturedAtMs).padStart(13, "0")}:${archiveSha256}`,
17765
18185
  archiveSha256,
17766
18186
  archiveBytes: bytes.length,
@@ -17770,10 +18190,14 @@ async function captureVerifiedWorkspaceArchive(session, capturedAtMs = Date.now(
17770
18190
  return {
17771
18191
  bytes,
17772
18192
  base64: Buffer.from(bytes).toString("base64"),
17773
- descriptor
18193
+ descriptor,
18194
+ kind: "tar"
17774
18195
  };
17775
18196
  }
17776
18197
  async function verifyRestoredWorkspace(session, descriptor) {
18198
+ if (descriptor.version === WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION) {
18199
+ return null;
18200
+ }
17777
18201
  const actual = await fingerprintSandboxWorkspace(session);
17778
18202
  if (!fingerprintsEqual(actual, descriptor.workspace)) {
17779
18203
  throw new WorkspaceArchiveIntegrityError(
@@ -18136,7 +18560,7 @@ function buildDisplayStackScript(options = {}) {
18136
18560
  const port = options.port ?? DESKTOP_STREAM_PORT4;
18137
18561
  const env = `DESKTOP_W=${geometry.width} DESKTOP_H=${geometry.height} DESKTOP_DPI=${geometry.dpi} STREAM_PORT=${port}`;
18138
18562
  const lockedLauncher = `ds_started=$1; fw=$2; ds_class=cold; ds_stage() { ds_now=$(date +%s%3N); echo "OPENGENI_DISPLAY_STAGE stage=$1 elapsed_ms=$((ds_now-ds_started)) classification=$ds_class"; }; fa=$(date +%s%3N); fd=$((fa-fw)); [ "$fd" -ge 50 ] && ds_class=contention; ds_stage outer_flock_acquired; ds_stage launcher_issued; env ${env} opengeni-desktop-up; urc=$?; ds_stage launcher_complete; exit "$urc"`;
18139
- const bringUp = `if nc -z 127.0.0.1 ${port} >/dev/null 2>&1 && nc -z 127.0.0.1 5900 >/dev/null 2>&1; then ds_class=already_ready; ds_stage precheck_ready; echo "OPENGENI_DESKTOP_UP port=${port} geometry=${geometry.width}x${geometry.height} dpi=${geometry.dpi} (precheck)"; else ds_class=cold; ds_stage precheck_miss; mkdir -p /tmp/opengeni-desktop; ds_stage outer_flock_wait; fw=$(date +%s%3N); flock --close --conflict-exit-code 75 --wait 45 /tmp/opengeni-desktop/up.outer.lock bash -c ${shellQuote3(lockedLauncher)} _ "$ds_started" "$fw"; frc=$?; if [ "$frc" -eq 75 ]; then ds_stage outer_flock_timeout; echo "OPENGENI_DESKTOP_LOCK_TIMEOUT"; exit 15; fi; if [ "$frc" -ne 0 ]; then exit "$frc"; fi; fi`;
18563
+ const bringUp = `if nc -z 127.0.0.1 ${port} >/dev/null 2>&1 && nc -z 127.0.0.1 5900 >/dev/null 2>&1; then ds_class=already_ready; ds_stage precheck_ready; echo "OPENGENI_DESKTOP_UP port=${port} geometry=${geometry.width}x${geometry.height} dpi=${geometry.dpi} (precheck)"; else ds_class=cold; ds_stage precheck_miss; mkdir -p /tmp/opengeni-desktop; ds_stage outer_flock_wait; fw=$(date +%s%3N); flock --close --conflict-exit-code 75 --wait 45 /tmp/opengeni-desktop/up.outer.lock bash -c ${shellQuote4(lockedLauncher)} _ "$ds_started" "$fw"; frc=$?; if [ "$frc" -eq 75 ]; then ds_stage outer_flock_timeout; echo "OPENGENI_DESKTOP_LOCK_TIMEOUT"; exit 15; fi; if [ "$frc" -ne 0 ]; then exit "$frc"; fi; fi`;
18140
18564
  const paintProbe = `ds_stage paint_probe_started; p=/tmp/opengeni-desktop/paint-probe.png; prev=0; for i in $(seq 1 ${PAINT_PROBE_ATTEMPTS}); do if DISPLAY=:0 scrot -o "$p" >/dev/null 2>&1; then sz=$(wc -c < "$p" 2>/dev/null || echo 0); else sz=0; fi; rm -f "$p"; if [ "$sz" -ge ${PAINT_MIN_BYTES} ] && [ "$prev" -ge ${PAINT_MIN_BYTES} ]; then d=$((sz-prev)); [ "$d" -lt 0 ] && d=$((0-d)); if [ "$d" -le ${PAINT_SETTLE_DELTA_BYTES} ]; then ds_stage paint_ready; break; fi; fi; prev=$sz; if [ "$i" = "${PAINT_PROBE_ATTEMPTS}" ]; then ds_stage paint_failed; echo "OPENGENI_DESKTOP_NOT_PAINTING scrot below ${PAINT_MIN_BYTES}B or unsettled after warmup (last=$sz)"; exit 14; fi; sleep ${PAINT_PROBE_INTERVAL_S}; done`;
18141
18565
  const trace = `ds_started=$(date +%s%3N); ds_class=unknown; ds_stage() { ds_now=$(date +%s%3N); echo "OPENGENI_DISPLAY_STAGE stage=$1 elapsed_ms=$((ds_now-ds_started)) classification=$ds_class"; }; ds_stage script_entry`;
18142
18566
  return `${trace}; mkdir -p /tmp/opengeni-desktop; { ${bringUp} ; } && { ${paintProbe} ; }`;
@@ -18163,7 +18587,7 @@ function execResultSessionId(result) {
18163
18587
  const value = result.sessionId ?? result.session_id;
18164
18588
  return typeof value === "number" ? value : null;
18165
18589
  }
18166
- function shellQuote3(value) {
18590
+ function shellQuote4(value) {
18167
18591
  return `'${value.replaceAll("'", `'"'"'`)}'`;
18168
18592
  }
18169
18593
  function boundedDisplayStackCommand(command, timeoutMs, markerPath, markerToken) {
@@ -18175,13 +18599,13 @@ function boundedDisplayStackCommand(command, timeoutMs, markerPath, markerToken)
18175
18599
  const killAfterMs = Math.max(1, Math.floor(graceMs / 2));
18176
18600
  const commandTimeoutSeconds = (commandTimeoutMs / 1e3).toFixed(3);
18177
18601
  const killAfterSeconds = (killAfterMs / 1e3).toFixed(3);
18178
- const managedCommand = `marker=${shellQuote3(markerPath)}; token=${shellQuote3(markerToken)}; cancel="$marker.cancelled"; if [ -e "$cancel" ]; then echo "OPENGENI_DISPLAY_CANCELLED"; exit 124; fi; pid=$$; pgid=$(ps -o pgid= -p "$pid" 2>/dev/null | tr -d ' '); start=$(awk '{print $22}' "/proc/$pid/stat" 2>/dev/null || true); printf '%s %s %s %s\\n' "$pid" "$pgid" "$start" "$token" >"$marker"; if [ -e "$cancel" ]; then rm -f "$marker"; echo "OPENGENI_DISPLAY_CANCELLED"; exit 124; fi; bash -c ${shellQuote3(command)}; rc=$?; rm -f "$marker"; exit "$rc"`;
18602
+ const managedCommand = `marker=${shellQuote4(markerPath)}; token=${shellQuote4(markerToken)}; cancel="$marker.cancelled"; if [ -e "$cancel" ]; then echo "OPENGENI_DISPLAY_CANCELLED"; exit 124; fi; pid=$$; pgid=$(ps -o pgid= -p "$pid" 2>/dev/null | tr -d ' '); start=$(awk '{print $22}' "/proc/$pid/stat" 2>/dev/null || true); printf '%s %s %s %s\\n' "$pid" "$pgid" "$start" "$token" >"$marker"; if [ -e "$cancel" ]; then rm -f "$marker"; echo "OPENGENI_DISPLAY_CANCELLED"; exit 124; fi; bash -c ${shellQuote4(command)}; rc=$?; rm -f "$marker"; exit "$rc"`;
18179
18603
  return (
18180
18604
  // Do not use timeout --foreground here. The display command contains flock
18181
18605
  // supervisors and launcher children; default process-group mode is required
18182
18606
  // so a deadline cannot leave a waiter alive to acquire the lock and launch
18183
18607
  // after the caller has already failed.
18184
- `timeout --signal=TERM --kill-after=${killAfterSeconds}s ${commandTimeoutSeconds}s bash -c ${shellQuote3(managedCommand)}; rc=$?; if [ "$rc" -eq 124 ]; then echo "OPENGENI_DISPLAY_TIMEOUT elapsed_ms=${commandTimeoutMs}"; fi; exit "$rc"`
18608
+ `timeout --signal=TERM --kill-after=${killAfterSeconds}s ${commandTimeoutSeconds}s bash -c ${shellQuote4(managedCommand)}; rc=$?; if [ "$rc" -eq 124 ]; then echo "OPENGENI_DISPLAY_TIMEOUT elapsed_ms=${commandTimeoutMs}"; fi; exit "$rc"`
18185
18609
  );
18186
18610
  }
18187
18611
  var DisplayStackWallTimeoutError = class extends Error {
@@ -18416,10 +18840,10 @@ async function beforeDeadline(promise, deadline, now = monotonicNow) {
18416
18840
  }
18417
18841
  }
18418
18842
  function displayStackCleanupCommand(markerPath, markerToken) {
18419
- const marker = shellQuote3(markerPath);
18420
- const token = shellQuote3(markerToken);
18843
+ const marker = shellQuote4(markerPath);
18844
+ const token = shellQuote4(markerToken);
18421
18845
  const script = `marker=${marker}; token=${token}; cancel="$marker.cancelled"; : >"$cancel" || { echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75; }; if [ ! -r "$marker" ]; then echo "OPENGENI_DISPLAY_CLEANUP status=stopped"; exit 0; fi; read -r pid pgid start actual <"$marker" || { echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75; }; [ "$actual" = "$token" ] || { echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75; }; case "$pid" in ''|*[!0-9]*) echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75;; esac; case "$pgid" in ''|*[!0-9]*) echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75;; esac; case "$start" in ''|*[!0-9]*) echo "OPENGENI_DISPLAY_CLEANUP status=invalid"; exit 75;; esac; current=$(awk '{print $22}' "/proc/$pid/stat" 2>/dev/null || true); if [ -z "$current" ] || [ "$current" != "$start" ]; then rm -f "$marker"; echo "OPENGENI_DISPLAY_CLEANUP status=stopped"; exit 0; fi; kill -TERM -- "-$pgid" 2>/dev/null || true; for i in $(seq 1 10); do if ! kill -0 -- "-$pgid" 2>/dev/null; then rm -f "$marker"; echo "OPENGENI_DISPLAY_CLEANUP status=stopped"; exit 0; fi; sleep 0.05; done; kill -KILL -- "-$pgid" 2>/dev/null || true; for i in $(seq 1 20); do if ! kill -0 -- "-$pgid" 2>/dev/null; then rm -f "$marker"; echo "OPENGENI_DISPLAY_CLEANUP status=stopped"; exit 0; fi; sleep 0.05; done; echo "OPENGENI_DISPLAY_CLEANUP status=alive"; exit 75`;
18422
- return `timeout --signal=TERM --kill-after=0.2s 1.5s bash -c ${shellQuote3(script)}`;
18846
+ return `timeout --signal=TERM --kill-after=0.2s 1.5s bash -c ${shellQuote4(script)}`;
18423
18847
  }
18424
18848
  async function runProviderCommandToDeadline(session, command, deadline) {
18425
18849
  const controller = new AbortController();
@@ -19163,7 +19587,7 @@ function runCredentialRoot(sessionId) {
19163
19587
  function runCredentialPointerFile(sessionId) {
19164
19588
  return `${runCredentialRoot(sessionId)}/current`;
19165
19589
  }
19166
- function shellQuote4(value) {
19590
+ function shellQuote5(value) {
19167
19591
  return `'${value.replace(/'/g, "'\\''")}'`;
19168
19592
  }
19169
19593
  function base64(value) {
@@ -19181,8 +19605,8 @@ function portableBase64DecodeCommand() {
19181
19605
  ].join("\n");
19182
19606
  }
19183
19607
  function pointerLockAcquireCommands(root) {
19184
- const lockFile = shellQuote4(`${root}/.pointer.lock`);
19185
- const lockDirectory = shellQuote4(`${root}/.pointer.lockdir`);
19608
+ const lockFile = shellQuote5(`${root}/.pointer.lock`);
19609
+ const lockDirectory = shellQuote5(`${root}/.pointer.lockdir`);
19186
19610
  return [
19187
19611
  `if command -v flock >/dev/null 2>&1; then`,
19188
19612
  ` exec 9>${lockFile}`,
@@ -19228,7 +19652,7 @@ ${cmd}
19228
19652
  printf '\\n${COMMAND_OK_MARKER}\\n'`;
19229
19653
  const args = {
19230
19654
  cmd: `set +x
19231
- env -u BASH_ENV bash --noprofile --norc -c ${shellQuote4(marked)}`,
19655
+ env -u BASH_ENV bash --noprofile --norc -c ${shellQuote5(marked)}`,
19232
19656
  yieldTimeMs: 12e4,
19233
19657
  maxOutputTokens: 4e3
19234
19658
  };
@@ -19238,19 +19662,19 @@ env -u BASH_ENV bash --noprofile --norc -c ${shellQuote4(marked)}`,
19238
19662
  }
19239
19663
  }
19240
19664
  async function writeCredentialFile(session, path, content, commandRunner) {
19241
- await runCredentialCommand(session, `: > ${shellQuote4(path)}`, commandRunner);
19665
+ await runCredentialCommand(session, `: > ${shellQuote5(path)}`, commandRunner);
19242
19666
  const encoded = base64(content);
19243
19667
  for (let offset = 0; offset < encoded.length; offset += WRITE_CHUNK_BYTES) {
19244
19668
  const chunk = encoded.slice(offset, offset + WRITE_CHUNK_BYTES);
19245
19669
  await runCredentialCommand(
19246
19670
  session,
19247
- `printf %s ${shellQuote4(chunk)} | ${portableBase64DecodeCommand()} >> ${shellQuote4(path)}`,
19671
+ `printf %s ${shellQuote5(chunk)} | ${portableBase64DecodeCommand()} >> ${shellQuote5(path)}`,
19248
19672
  commandRunner
19249
19673
  );
19250
19674
  }
19251
19675
  await runCredentialCommand(
19252
19676
  session,
19253
- `[ "$(wc -c < ${shellQuote4(path)} | tr -d '[:space:]')" = ${shellQuote4(String(byteLength(content)))} ]`,
19677
+ `[ "$(wc -c < ${shellQuote5(path)} | tr -d '[:space:]')" = ${shellQuote5(String(byteLength(content)))} ]`,
19254
19678
  commandRunner
19255
19679
  );
19256
19680
  }
@@ -19275,19 +19699,19 @@ async function materializeRunCredentials(session, material, options) {
19275
19699
  session,
19276
19700
  [
19277
19701
  "umask 077",
19278
- `mkdir -p -- ${shellQuote4(`${root}/versions`)}`,
19279
- `chmod 0700 -- ${shellQuote4(root)} ${shellQuote4(`${root}/versions`)}`,
19280
- `rm -rf -- ${shellQuote4(stage)}`,
19281
- `mkdir -p -- ${shellQuote4(`${stage}/files`)}`
19702
+ `mkdir -p -- ${shellQuote5(`${root}/versions`)}`,
19703
+ `chmod 0700 -- ${shellQuote5(root)} ${shellQuote5(`${root}/versions`)}`,
19704
+ `rm -rf -- ${shellQuote5(stage)}`,
19705
+ `mkdir -p -- ${shellQuote5(`${stage}/files`)}`
19282
19706
  ].join("\n"),
19283
19707
  options.commandRunner
19284
19708
  );
19285
19709
  const environmentLines = [
19286
19710
  ...Object.entries(material.environment).map(
19287
- ([name, value]) => `export ${name}=${shellQuote4(value)}`
19711
+ ([name, value]) => `export ${name}=${shellQuote5(value)}`
19288
19712
  ),
19289
19713
  ...Object.entries(material.fileEnvironment).map(
19290
- ([name, path]) => `export ${name}=${shellQuote4(`${version}/files/${path}`)}`
19714
+ ([name, path]) => `export ${name}=${shellQuote5(`${version}/files/${path}`)}`
19291
19715
  )
19292
19716
  ];
19293
19717
  await writeCredentialFile(
@@ -19299,17 +19723,17 @@ async function materializeRunCredentials(session, material, options) {
19299
19723
  );
19300
19724
  await runCredentialCommand(
19301
19725
  session,
19302
- `chmod 0600 -- ${shellQuote4(`${stage}/env`)}`,
19726
+ `chmod 0600 -- ${shellQuote5(`${stage}/env`)}`,
19303
19727
  options.commandRunner
19304
19728
  );
19305
19729
  for (const file of material.files) {
19306
19730
  const target = `${stage}/files/${file.path}`;
19307
19731
  const parent = target.slice(0, target.lastIndexOf("/"));
19308
- await runCredentialCommand(session, `mkdir -p -- ${shellQuote4(parent)}`, options.commandRunner);
19732
+ await runCredentialCommand(session, `mkdir -p -- ${shellQuote5(parent)}`, options.commandRunner);
19309
19733
  await writeCredentialFile(session, target, file.content, options.commandRunner);
19310
19734
  await runCredentialCommand(
19311
19735
  session,
19312
- `chmod ${shellQuote4(file.mode ?? "0600")} -- ${shellQuote4(target)}`,
19736
+ `chmod ${shellQuote5(file.mode ?? "0600")} -- ${shellQuote5(target)}`,
19313
19737
  options.commandRunner
19314
19738
  );
19315
19739
  }
@@ -19317,19 +19741,19 @@ async function materializeRunCredentials(session, material, options) {
19317
19741
  session,
19318
19742
  [
19319
19743
  ...pointerLockAcquireCommands(root),
19320
- `previous=$(cat -- ${shellQuote4(`${root}/current`)} 2>/dev/null || :)`,
19321
- `mv -- ${shellQuote4(stage)} ${shellQuote4(version)}`,
19322
- `printf '%s\\n' ${shellQuote4(versionName)} > ${shellQuote4(`${root}/.next`)}`,
19323
- `mv -f -- ${shellQuote4(`${root}/.next`)} ${shellQuote4(`${root}/current`)}`,
19744
+ `previous=$(cat -- ${shellQuote5(`${root}/current`)} 2>/dev/null || :)`,
19745
+ `mv -- ${shellQuote5(stage)} ${shellQuote5(version)}`,
19746
+ `printf '%s\\n' ${shellQuote5(versionName)} > ${shellQuote5(`${root}/.next`)}`,
19747
+ `mv -f -- ${shellQuote5(`${root}/.next`)} ${shellQuote5(`${root}/current`)}`,
19324
19748
  ...options.prunePreviousGenerations ? [
19325
- `find ${shellQuote4(`${root}/versions`)} -mindepth 1 -maxdepth 1 ! -name ${shellQuote4(versionName)} -exec rm -rf -- {} +`
19749
+ `find ${shellQuote5(`${root}/versions`)} -mindepth 1 -maxdepth 1 ! -name ${shellQuote5(versionName)} -exec rm -rf -- {} +`
19326
19750
  ] : options.pruneOtherAttempts ? [
19327
- `find ${shellQuote4(`${root}/versions`)} -mindepth 1 -maxdepth 1 ! -name ${shellQuote4(`${attemptId}-${options.executionGeneration}-*`)} -exec rm -rf -- {} +`
19751
+ `find ${shellQuote5(`${root}/versions`)} -mindepth 1 -maxdepth 1 ! -name ${shellQuote5(`${attemptId}-${options.executionGeneration}-*`)} -exec rm -rf -- {} +`
19328
19752
  ] : options.pruneSupersededGenerations ? [
19329
- `for candidate in ${shellQuote4(`${root}/versions`)}/${prefix}*; do`,
19753
+ `for candidate in ${shellQuote5(`${root}/versions`)}/${prefix}*; do`,
19330
19754
  ` [ -e "$candidate" ] || continue`,
19331
19755
  ` name=\${candidate##*/}`,
19332
- ` [ "$name" = ${shellQuote4(versionName)} ] || [ "$name" = "$previous" ] || rm -rf -- "$candidate"`,
19756
+ ` [ "$name" = ${shellQuote5(versionName)} ] || [ "$name" = "$previous" ] || rm -rf -- "$candidate"`,
19333
19757
  "done"
19334
19758
  ] : [],
19335
19759
  ...pointerLockReleaseCommands()
@@ -19342,10 +19766,10 @@ async function clearRunCredentials(session, sessionId, commandRunner) {
19342
19766
  await runCredentialCommand(
19343
19767
  session,
19344
19768
  [
19345
- `if [ -d ${shellQuote4(root)} ]; then`,
19769
+ `if [ -d ${shellQuote5(root)} ]; then`,
19346
19770
  ...pointerLockAcquireCommands(root).map((line) => ` ${line}`),
19347
- ` rm -f -- ${shellQuote4(`${root}/current`)} ${shellQuote4(`${root}/.next`)}`,
19348
- ` rm -rf -- ${shellQuote4(`${root}/versions`)}`,
19771
+ ` rm -f -- ${shellQuote5(`${root}/current`)} ${shellQuote5(`${root}/.next`)}`,
19772
+ ` rm -rf -- ${shellQuote5(`${root}/versions`)}`,
19349
19773
  ...pointerLockReleaseCommands().map((line) => ` ${line}`),
19350
19774
  "fi"
19351
19775
  ].join("\n"),
@@ -19362,15 +19786,15 @@ async function clearRunCredentialsForAttempt(session, options, commandRunner) {
19362
19786
  await runCredentialCommand(
19363
19787
  session,
19364
19788
  [
19365
- `if [ -d ${shellQuote4(root)} ]; then`,
19789
+ `if [ -d ${shellQuote5(root)} ]; then`,
19366
19790
  ...pointerLockAcquireCommands(root).map((line) => ` ${line}`),
19367
- ` if [ -r ${shellQuote4(`${root}/current`)} ]; then`,
19368
- ` current=$(cat -- ${shellQuote4(`${root}/current`)} 2>/dev/null || :)`,
19369
- ` case "$current" in ${shellQuote4(prefix)}*) rm -f -- ${shellQuote4(`${root}/current`)} ;; esac`,
19791
+ ` if [ -r ${shellQuote5(`${root}/current`)} ]; then`,
19792
+ ` current=$(cat -- ${shellQuote5(`${root}/current`)} 2>/dev/null || :)`,
19793
+ ` case "$current" in ${shellQuote5(prefix)}*) rm -f -- ${shellQuote5(`${root}/current`)} ;; esac`,
19370
19794
  " fi",
19371
- ` if [ -d ${shellQuote4(`${root}/versions`)} ]; then`,
19372
- ` find ${shellQuote4(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote4(`${prefix}*`)} -exec rm -rf -- {} +`,
19373
- ` find ${shellQuote4(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote4(`.stage-${prefix}*`)} -exec rm -rf -- {} +`,
19795
+ ` if [ -d ${shellQuote5(`${root}/versions`)} ]; then`,
19796
+ ` find ${shellQuote5(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote5(`${prefix}*`)} -exec rm -rf -- {} +`,
19797
+ ` find ${shellQuote5(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote5(`.stage-${prefix}*`)} -exec rm -rf -- {} +`,
19374
19798
  " fi",
19375
19799
  ...pointerLockReleaseCommands().map((line) => ` ${line}`),
19376
19800
  "fi"
@@ -19382,12 +19806,12 @@ function withRunCredentialEnvironment(cmd, sessionId) {
19382
19806
  const root = runCredentialRoot(sessionId);
19383
19807
  const pointerFile = runCredentialPointerFile(sessionId);
19384
19808
  return [
19385
- `if [ -r ${shellQuote4(pointerFile)} ]; then`,
19386
- ` _opengeni_credential_version=$(cat -- ${shellQuote4(pointerFile)} 2>/dev/null || :)`,
19809
+ `if [ -r ${shellQuote5(pointerFile)} ]; then`,
19810
+ ` _opengeni_credential_version=$(cat -- ${shellQuote5(pointerFile)} 2>/dev/null || :)`,
19387
19811
  ' case "$_opengeni_credential_version" in',
19388
19812
  " ''|*[!A-Za-z0-9_-]*) ;;",
19389
19813
  " *)",
19390
- ` _opengeni_credential_env=${shellQuote4(`${root}/versions`)}/"$_opengeni_credential_version/env"`,
19814
+ ` _opengeni_credential_env=${shellQuote5(`${root}/versions`)}/"$_opengeni_credential_version/env"`,
19391
19815
  ' if [ -r "$_opengeni_credential_env" ]; then',
19392
19816
  " set -a",
19393
19817
  ' . "$_opengeni_credential_env"',
@@ -19465,7 +19889,7 @@ var ToolspaceTokenPathError = class extends Error {
19465
19889
  this.name = "ToolspaceTokenPathError";
19466
19890
  }
19467
19891
  };
19468
- function shellQuote5(value) {
19892
+ function shellQuote6(value) {
19469
19893
  return `'${value.replace(/'/g, "'\\''")}'`;
19470
19894
  }
19471
19895
  function assertToolspaceSessionId(sessionId) {
@@ -19490,7 +19914,7 @@ function assertToolspaceFilePath(value, label) {
19490
19914
  }
19491
19915
  function shellToolspacePath(value) {
19492
19916
  const validated = assertToolspaceFilePath(value, "Toolspace token file");
19493
- return isHomeRelativeToolspacePath(validated) ? `"${validated}"` : shellQuote5(validated);
19917
+ return isHomeRelativeToolspacePath(validated) ? `"${validated}"` : shellQuote6(validated);
19494
19918
  }
19495
19919
  function toolspaceTokenFileForSession(manifestTokenFile, sessionId) {
19496
19920
  const normalizedManifestFile = assertToolspaceFilePath(
@@ -20161,7 +20585,10 @@ var RoutingSandboxSession = class {
20161
20585
  if (!write) throw new RoutingUnsupportedError(op, record.backend.kind);
20162
20586
  let result;
20163
20587
  try {
20164
- result = await write.call(record.backend.session, args);
20588
+ result = await withSandboxProviderOperation(
20589
+ record.backend.session,
20590
+ () => write.call(record.backend.session, args)
20591
+ );
20165
20592
  } catch (error) {
20166
20593
  if (this.deps.afterProcessMutation) {
20167
20594
  const pending = {
@@ -20222,7 +20649,10 @@ var RoutingSandboxSession = class {
20222
20649
  await this.ensureParentPromotion(record);
20223
20650
  const write = record.backend.session.writeStdin;
20224
20651
  if (!write) throw new RoutingUnsupportedError("writeStdin", record.backend.kind);
20225
- const result = await write.call(record.backend.session, args);
20652
+ const result = await withSandboxProviderOperation(
20653
+ record.backend.session,
20654
+ () => write.call(record.backend.session, args)
20655
+ );
20226
20656
  const proof = retainedProcessTerminalProof(result, providerSessionId);
20227
20657
  if (proof) await this.settleRetainedProcess(record, proof, result);
20228
20658
  return result;
@@ -20246,7 +20676,7 @@ var RoutingSandboxSession = class {
20246
20676
  const admission = mutatesWorkspace ? await this.deps.beforeMutation?.({ op, backend }) : void 0;
20247
20677
  let result;
20248
20678
  try {
20249
- result = await fn(backend.session);
20679
+ result = await withSandboxProviderOperation(backend.session, () => fn(backend.session));
20250
20680
  } catch (error) {
20251
20681
  if (mutatesWorkspace && this.deps.afterMutation) {
20252
20682
  try {
@@ -20466,11 +20896,21 @@ var RoutingSandboxSession = class {
20466
20896
  return terminal.result;
20467
20897
  }
20468
20898
  await this.ensureParentPromotion(record);
20469
- if (record.backend.session.execCommand) {
20470
- return await record.backend.session.execCommand(args);
20899
+ const execCommand = record.backend.session.execCommand;
20900
+ if (execCommand) {
20901
+ return await withSandboxProviderOperation(
20902
+ record.backend.session,
20903
+ () => execCommand.call(record.backend.session, args)
20904
+ );
20471
20905
  }
20472
- if (record.backend.session.exec) {
20473
- return formatExecResult(await record.backend.session.exec(args));
20906
+ const exec = record.backend.session.exec;
20907
+ if (exec) {
20908
+ return formatExecResult(
20909
+ await withSandboxProviderOperation(
20910
+ record.backend.session,
20911
+ () => exec.call(record.backend.session, args)
20912
+ )
20913
+ );
20474
20914
  }
20475
20915
  throw new RoutingUnsupportedError("execCommand", record.backend.kind);
20476
20916
  }
@@ -20525,7 +20965,11 @@ var RoutingSandboxSession = class {
20525
20965
  if (!s.materializeEntry) {
20526
20966
  throw new RoutingUnsupportedError("materializeEntry", this.cached?.kind ?? "unknown");
20527
20967
  }
20528
- return s.materializeEntry(args);
20968
+ await s.materializeEntry(args);
20969
+ const path = args && typeof args === "object" && typeof args.path === "string" ? args.path : null;
20970
+ if (path) {
20971
+ await assertProviderCanSeeMaterializedPath(s, path);
20972
+ }
20529
20973
  });
20530
20974
  }
20531
20975
  /** PTY support reflects the LAST-resolved backend (a synchronous probe; the SDK
@@ -20589,6 +21033,39 @@ var RoutingSandboxSession = class {
20589
21033
  return this.resolve();
20590
21034
  }
20591
21035
  };
21036
+ var MATERIALIZED_PATH_MARKER = "__OPENGENI_MATERIALIZED_PATH_VISIBLE__";
21037
+ async function assertProviderCanSeeMaterializedPath(session, path) {
21038
+ const command = `test -e ${shellSingleQuote(path)} && printf %s ${shellSingleQuote(
21039
+ MATERIALIZED_PATH_MARKER
21040
+ )}`;
21041
+ const args = {
21042
+ cmd: command,
21043
+ workdir: providerManifestRoot(session) ?? "/workspace",
21044
+ shell: "sh",
21045
+ login: false,
21046
+ tty: false
21047
+ };
21048
+ let output;
21049
+ if (session.execCommand) {
21050
+ output = await session.execCommand(args);
21051
+ } else if (session.exec) {
21052
+ output = formatExecResult(await session.exec(args));
21053
+ } else {
21054
+ throw new RoutingUnsupportedError("materializeEntry.verify", "unknown");
21055
+ }
21056
+ if (!output.includes(MATERIALIZED_PATH_MARKER)) {
21057
+ throw new Error(
21058
+ `Sandbox materialization completed but the provider cannot read the destination path: ${path}`
21059
+ );
21060
+ }
21061
+ }
21062
+ function providerManifestRoot(session) {
21063
+ const root = session.state?.manifest?.root;
21064
+ return typeof root === "string" && root.length > 0 ? root : null;
21065
+ }
21066
+ function shellSingleQuote(value) {
21067
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
21068
+ }
20592
21069
 
20593
21070
  // src/sandbox/turn-tool-cancellation.ts
20594
21071
  var TURN_EXEC_YIELD_MS = 250;
@@ -20692,15 +21169,52 @@ function singleQuote(value) {
20692
21169
  function shellMarkerPath(token) {
20693
21170
  return `${SHELL_MARKER_DIR}/${token}`;
20694
21171
  }
21172
+ function processInspectionCommandLines() {
21173
+ return [
21174
+ "__opengeni_process_group_id() {",
21175
+ ' __opengeni_lookup_pid="$1"',
21176
+ ' __opengeni_lookup_pgid=""',
21177
+ " if command -v ps >/dev/null 2>&1; then",
21178
+ ` __opengeni_lookup_pgid="$(command ps -o pgid= -p "$__opengeni_lookup_pid" 2>/dev/null | command tr -d '[:space:]')"`,
21179
+ " fi",
21180
+ ' case "$__opengeni_lookup_pgid" in',
21181
+ ' ""|*[!0-9]*) ;;',
21182
+ ` *) command printf '%s\\n' "$__opengeni_lookup_pgid"; return 0 ;;`,
21183
+ " esac",
21184
+ ' [ -r "/proc/$__opengeni_lookup_pid/stat" ] || return 1',
21185
+ ' IFS= read -r __opengeni_lookup_stat < "/proc/$__opengeni_lookup_pid/stat" || return 1',
21186
+ ' __opengeni_lookup_tail="${__opengeni_lookup_stat##*) }"',
21187
+ ' [ "$__opengeni_lookup_tail" != "$__opengeni_lookup_stat" ] || return 1',
21188
+ " set -- $__opengeni_lookup_tail",
21189
+ ' [ "$#" -ge 3 ] || return 1',
21190
+ ' case "$3" in ""|*[!0-9]*) return 1 ;; esac',
21191
+ ` command printf '%s\\n' "$3"`,
21192
+ "}",
21193
+ "__opengeni_process_args() {",
21194
+ ' __opengeni_lookup_pid="$1"',
21195
+ ' __opengeni_lookup_args=""',
21196
+ " if command -v ps >/dev/null 2>&1; then",
21197
+ ' __opengeni_lookup_args="$(command ps -ww -o args= -p "$__opengeni_lookup_pid" 2>/dev/null)"',
21198
+ " fi",
21199
+ ' if [ -n "$__opengeni_lookup_args" ]; then',
21200
+ ` command printf '%s\\n' "$__opengeni_lookup_args"`,
21201
+ " return 0",
21202
+ " fi",
21203
+ ' [ -r "/proc/$__opengeni_lookup_pid/cmdline" ] || return 1',
21204
+ ` command tr '\\000' ' ' < "/proc/$__opengeni_lookup_pid/cmdline"`,
21205
+ "}"
21206
+ ];
21207
+ }
20695
21208
  function cancellableGroupLeaderCommand(command, markerPath) {
20696
21209
  const marker = singleQuote(markerPath);
20697
21210
  const markerDir = singleQuote(SHELL_MARKER_DIR);
20698
21211
  return [
21212
+ ...processInspectionCommandLines(),
20699
21213
  `__opengeni_marker=${marker}`,
20700
21214
  "umask 077",
20701
21215
  `command mkdir -p ${markerDir} || exit 125`,
20702
21216
  '__opengeni_pid="$$"',
20703
- `__opengeni_pgid="$(command ps -o pgid= -p "$__opengeni_pid" 2>/dev/null | command tr -d '[:space:]')"`,
21217
+ '__opengeni_pgid="$(__opengeni_process_group_id "$__opengeni_pid")"',
20704
21218
  'case "$__opengeni_pid:$__opengeni_pgid" in *[!0-9:]*|*:|:*) exit 125 ;; esac',
20705
21219
  '[ "$__opengeni_pid" -gt 1 ] && [ "$__opengeni_pgid" -gt 1 ] || exit 125',
20706
21220
  // Never signal a provider/container-wide process group. A cancellable PTY
@@ -20718,8 +21232,9 @@ function cancellableGroupLeaderCommand(command, markerPath) {
20718
21232
  function cancellableShellCommand(command, markerPath) {
20719
21233
  const groupLeaderCommand = cancellableGroupLeaderCommand(command, markerPath);
20720
21234
  return [
21235
+ ...processInspectionCommandLines(),
20721
21236
  '__opengeni_outer_pid="$$"',
20722
- `__opengeni_outer_pgid="$(command ps -o pgid= -p "$__opengeni_outer_pid" 2>/dev/null | command tr -d '[:space:]')"`,
21237
+ '__opengeni_outer_pgid="$(__opengeni_process_group_id "$__opengeni_outer_pid")"',
20723
21238
  'case "$__opengeni_outer_pid:$__opengeni_outer_pgid" in *[!0-9:]*|*:|:*) exit 125 ;; esac',
20724
21239
  'if [ "$__opengeni_outer_pid" != "$__opengeni_outer_pgid" ]; then',
20725
21240
  ' __opengeni_setsid="$(command -v setsid 2>/dev/null)"',
@@ -20764,15 +21279,16 @@ function identityGuardScript(state, body, missingIdentityExitCode) {
20764
21279
  if (!identity || !state.token) return `exit ${missingIdentityExitCode}`;
20765
21280
  const token = singleQuote(state.token);
20766
21281
  return [
21282
+ ...processInspectionCommandLines(),
20767
21283
  `__opengeni_pid=${identity.pid}`,
20768
21284
  `__opengeni_pgid=${identity.processGroupId}`,
20769
21285
  `__opengeni_token=${token}`,
20770
- // The randomized token lands late in the wrapped command line. Procps
20771
- // otherwise truncates `args` to the terminal width, which can make a live
20772
- // group look stale and open the quiescence fence without signalling it.
20773
- '__opengeni_args="$(command ps -ww -o args= -p "$__opengeni_pid" 2>/dev/null)"',
21286
+ // The randomized token lands late in the wrapped command line. Procps needs
21287
+ // `-ww` to avoid terminal-width truncation; minimal Linux images may omit ps,
21288
+ // so the same exact command line is read from /proc instead.
21289
+ `__opengeni_args="$(__opengeni_process_args "$__opengeni_pid")" || exit ${missingIdentityExitCode}`,
20774
21290
  'case "$__opengeni_args" in *"$__opengeni_token"*) ;; *) exit 0 ;; esac',
20775
- `__opengeni_live_pgid="$(command ps -o pgid= -p "$__opengeni_pid" 2>/dev/null | command tr -d '[:space:]')"`,
21291
+ `__opengeni_live_pgid="$(__opengeni_process_group_id "$__opengeni_pid")" || exit ${missingIdentityExitCode}`,
20776
21292
  '[ "$__opengeni_live_pgid" = "$__opengeni_pgid" ] || exit 0',
20777
21293
  body
20778
21294
  ].join("\n");
@@ -21445,6 +21961,42 @@ var FS_LIST_TRUNCATED_MARKER = "__OPENGENI_FS_LIST_TRUNCATED__";
21445
21961
  var FS_LIST_MAX_OUTPUT_BYTES = 768 * 1024;
21446
21962
  var GIT_COMMAND_CHUNK_BYTES = 512 * 1024;
21447
21963
  var GIT_METADATA_MAX_BYTES = 2 * 1024 * 1024;
21964
+ var GIT_MEASURE_FRAME = "__OPENGENI_GIT_MEASURE_V1__";
21965
+ var GIT_CHUNK_FRAME = "__OPENGENI_GIT_CHUNK_V1__";
21966
+ var GIT_CHUNK_FRAME_END = "__OPENGENI_GIT_CHUNK_END_V1__";
21967
+ var PORTABLE_SHA256_FILE_FUNCTION = [
21968
+ "opengeni_sha256_file() {",
21969
+ ` if command -v sha256sum >/dev/null 2>&1 && digest=$(sha256sum -- "$1" 2>/dev/null); then printf "%s\\n" "$digest" | awk '{print $1}'; return; fi`,
21970
+ ` if command -v shasum >/dev/null 2>&1 && digest=$(shasum -a 256 "$1" 2>/dev/null); then printf "%s\\n" "$digest" | awk '{print $1}'; return; fi`,
21971
+ ` if command -v openssl >/dev/null 2>&1 && digest=$(openssl dgst -sha256 "$1" 2>/dev/null); then printf "%s\\n" "$digest" | sed 's/^.*= //'; return; fi`,
21972
+ " return 127",
21973
+ "}"
21974
+ ].join("\n");
21975
+ var PORTABLE_DESCRIPTOR_FUNCTIONS = [
21976
+ "opengeni_set_fd_path() {",
21977
+ ' fd="$1"',
21978
+ " opengeni_fd_path=",
21979
+ ' if opengeni_fd_path=$(readlink -f -- "/proc/$$/fd/$fd" 2>/dev/null); then [ -n "$opengeni_fd_path" ]; return; fi',
21980
+ " lsof_bin=",
21981
+ " if [ -x /usr/sbin/lsof ]; then lsof_bin=/usr/sbin/lsof; elif command -v lsof >/dev/null 2>&1; then lsof_bin=$(command -v lsof); else return 127; fi",
21982
+ ` while IFS= read -r -d '' field; do case "$field" in n*) opengeni_fd_path=\${field#n} ;; esac; done < <("$lsof_bin" -a -p "$$" -d "$fd" -Fn0 2>/dev/null)`,
21983
+ ' [ -n "$opengeni_fd_path" ]',
21984
+ "}",
21985
+ "opengeni_fd_identity() {",
21986
+ ' fd="$1"',
21987
+ ' if identity=$(stat -Lc "%d:%i" -- "/proc/$$/fd/$fd" 2>/dev/null); then printf "%s" "$identity"; return; fi',
21988
+ ' stat -f "%d:%i" "/dev/fd/$fd" 2>/dev/null',
21989
+ "}",
21990
+ "opengeni_path_identity() {",
21991
+ ' if identity=$(stat -c "%d:%i" -- "$1" 2>/dev/null); then printf "%s" "$identity"; return; fi',
21992
+ ' stat -f "%d:%i" "$1" 2>/dev/null',
21993
+ "}",
21994
+ "opengeni_fd_size() {",
21995
+ ' fd="$1"',
21996
+ ' if size=$(stat -Lc "%s" -- "/proc/$$/fd/$fd" 2>/dev/null); then printf "%s" "$size"; return; fi',
21997
+ ' stat -f "%z" "/dev/fd/$fd" 2>/dev/null',
21998
+ "}"
21999
+ ].join("\n");
21448
22000
  var US = String.fromCharCode(31);
21449
22001
  var RS = String.fromCharCode(30);
21450
22002
  var SELFHOSTED_VIRTUAL_ROOT2 = "/workspace";
@@ -21534,11 +22086,11 @@ var SandboxChannelAService = class {
21534
22086
  const depthArg = Math.max(1, req.depth);
21535
22087
  const maxCommandEntries = req.maxEntries + 1;
21536
22088
  const gnuPrint = `-printf '%y\\t%s\\t%T@\\t%m\\t%p\\0'`;
21537
- const gnuSelector = pruneNames.length ? `\\( -type d \\( ${pruneNames.map((name) => `-name ${shellQuote6(name)}`).join(" -o ")} \\) ${gnuPrint} -prune \\) -o ${gnuPrint}` : gnuPrint;
22089
+ const gnuSelector = pruneNames.length ? `\\( -type d \\( ${pruneNames.map((name) => `-name ${shellQuote7(name)}`).join(" -o ")} \\) ${gnuPrint} -prune \\) -o ${gnuPrint}` : gnuPrint;
21538
22090
  const gnuVisibleSelector = req.includeHidden ? gnuSelector : `\\( -path '*/.*' -prune \\) -o \\( ${gnuSelector} \\)`;
21539
22091
  const gnuFind = `find ${findRoot} -mindepth 1 -maxdepth ${depthArg} \\( ${gnuVisibleSelector} \\) 2>/dev/null`;
21540
22092
  const portableHiddenGuard = req.includeHidden ? "" : `if [[ "$base" == .* ]]; then continue; fi;`;
21541
- const portablePruneCase = pruneNames.length ? `case "$base" in ${pruneNames.map(shellQuote6).join("|")}) pruned=1 ;; *) pruned=0 ;; esac;` : "pruned=0;";
22093
+ const portablePruneCase = pruneNames.length ? `case "$base" in ${pruneNames.map(shellQuote7).join("|")}) pruned=1 ;; *) pruned=0 ;; esac;` : "pruned=0;";
21542
22094
  const portableWalk = [
21543
22095
  "shopt -s nullglob dotglob; count=0; stop=0;",
21544
22096
  'walk() { local dir="$1" level="$2" p base t size mtime mode pruned;',
@@ -21567,12 +22119,12 @@ var SandboxChannelAService = class {
21567
22119
  `if [ "$records" -ge ${req.maxEntries} ] || [ $((bytes + record_bytes + 1)) -gt ${FS_LIST_MAX_OUTPUT_BYTES} ]; then truncated=1; break; fi;`,
21568
22120
  `printf '%s\\0' "$record"; bytes=$((bytes + record_bytes + 1)); records=$((records + 1));`,
21569
22121
  "done;",
21570
- `if [ "$truncated" -eq 1 ]; then printf '%s\\0' ${shellQuote6(FS_LIST_TRUNCATED_MARKER)}; fi`
22122
+ `if [ "$truncated" -eq 1 ]; then printf '%s\\0' ${shellQuote7(FS_LIST_TRUNCATED_MARKER)}; fi`
21571
22123
  ].join(" ");
21572
22124
  const findCommand = [
21573
22125
  `{ ${rawFindCommand}; } | { ${boundedOutput}; };`,
21574
22126
  "producer_status=${PIPESTATUS[0]};",
21575
- `if [ "$producer_status" -ne 0 ] && [ "$producer_status" -ne 141 ]; then printf '%s\\0' ${shellQuote6(FS_LIST_TRUNCATED_MARKER)}; fi`
22127
+ `if [ "$producer_status" -ne 0 ] && [ "$producer_status" -ne 141 ]; then printf '%s\\0' ${shellQuote7(FS_LIST_TRUNCATED_MARKER)}; fi`
21576
22128
  ].join(" ");
21577
22129
  const { stdout, exitCode } = await this.runInConfinedDirectory(root, {
21578
22130
  cmd: internalBashCommand(findCommand),
@@ -21665,11 +22217,11 @@ var SandboxChannelAService = class {
21665
22217
  async assertConfinedExistingDirectory(path) {
21666
22218
  const root = this.workspaceRoot || ".";
21667
22219
  const abs = this.joinRoot(path);
21668
- const rejectLink = path ? `test ! -L ${shellQuote6(abs)} || { printf '__OPENGENI_FS_SYMLINK__'; exit 68; }` : ":";
22220
+ const rejectLink = path ? `test ! -L ${shellQuote7(abs)} || { printf '__OPENGENI_FS_SYMLINK__'; exit 68; }` : ":";
21669
22221
  const script = [
21670
- `root=$(realpath -e -- ${shellQuote6(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
22222
+ `root=$(realpath -e -- ${shellQuote7(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
21671
22223
  rejectLink,
21672
- `target=$(realpath -e -- ${shellQuote6(abs)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
22224
+ `target=$(realpath -e -- ${shellQuote7(abs)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
21673
22225
  `case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
21674
22226
  `test -d "$target" || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
21675
22227
  `printf '__OPENGENI_FS_CONFINED_OK__'`
@@ -21680,13 +22232,13 @@ var SandboxChannelAService = class {
21680
22232
  async assertConfinedMutationParent(path, options) {
21681
22233
  const root = this.workspaceRoot || ".";
21682
22234
  const abs = this.joinRoot(path);
21683
- const rejectLink = options.rejectFinalSymlink ? `test ! -L ${shellQuote6(abs)} || { printf '__OPENGENI_FS_SYMLINK__'; exit 68; }` : ":";
22235
+ const rejectLink = options.rejectFinalSymlink ? `test ! -L ${shellQuote7(abs)} || { printf '__OPENGENI_FS_SYMLINK__'; exit 68; }` : ":";
21684
22236
  const locateParent = options.allowMissingParents ? 'probe="$parent"; while [ ! -e "$probe" ] && [ ! -L "$probe" ]; do next=$(dirname -- "$probe"); [ "$next" != "$probe" ] || break; probe="$next"; done' : 'probe="$parent"';
21685
22237
  const requireParent = options.allowMissingParents ? ":" : 'test -d "$parent" || { printf "__OPENGENI_FS_NOT_FOUND__"; exit 66; }';
21686
22238
  const script = [
21687
- `root=$(realpath -e -- ${shellQuote6(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
22239
+ `root=$(realpath -e -- ${shellQuote7(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
21688
22240
  rejectLink,
21689
- `parent=$(dirname -- ${shellQuote6(abs)})`,
22241
+ `parent=$(dirname -- ${shellQuote7(abs)})`,
21690
22242
  locateParent,
21691
22243
  `target=$(realpath -e -- "$probe") || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
21692
22244
  `case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
@@ -21723,8 +22275,8 @@ var SandboxChannelAService = class {
21723
22275
  const root = this.workspaceRoot || ".";
21724
22276
  const abs = this.joinRoot(path);
21725
22277
  const script = [
21726
- `root=$(realpath -e -- ${shellQuote6(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
21727
- `exec 3<${shellQuote6(abs)} || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
22278
+ `root=$(realpath -e -- ${shellQuote7(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
22279
+ `exec 3<${shellQuote7(abs)} || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
21728
22280
  `target=$(readlink -f -- "/proc/$$/fd/3") || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
21729
22281
  `case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
21730
22282
  `test -f "$target" || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
@@ -21793,7 +22345,7 @@ var SandboxChannelAService = class {
21793
22345
  });
21794
22346
  if (!req.overwrite) {
21795
22347
  const { exitCode: exitCode2 } = await this.run({
21796
- cmd: `test -e ${shellQuote6(abs)} || test -L ${shellQuote6(abs)}`
22348
+ cmd: `test -e ${shellQuote7(abs)} || test -L ${shellQuote7(abs)}`
21797
22349
  });
21798
22350
  if (exitCode2 === 0) {
21799
22351
  throw new ChannelAConflictError(`path exists and overwrite is false: ${path}`);
@@ -21801,7 +22353,7 @@ var SandboxChannelAService = class {
21801
22353
  }
21802
22354
  if (req.createParents) {
21803
22355
  const dir = dirnameAbs(abs);
21804
- if (dir) await this.run({ cmd: `mkdir -p ${shellQuote6(dir)}` });
22356
+ if (dir) await this.run({ cmd: `mkdir -p ${shellQuote7(dir)}` });
21805
22357
  await this.assertConfinedMutationParent(path, {
21806
22358
  allowMissingParents: false,
21807
22359
  rejectFinalSymlink: true
@@ -21809,7 +22361,7 @@ var SandboxChannelAService = class {
21809
22361
  }
21810
22362
  const b64 = bytes.toString("base64");
21811
22363
  const { exitCode, stderr } = await this.run({
21812
- cmd: `printf %s ${shellQuote6(b64)} | base64 -d > ${shellQuote6(abs)}`
22364
+ cmd: `printf %s ${shellQuote7(b64)} | base64 -d > ${shellQuote7(abs)}`
21813
22365
  });
21814
22366
  if (exitCode !== null && exitCode !== 0) {
21815
22367
  if (req.encoding !== "base64" && this.session.createEditor) {
@@ -21850,7 +22402,7 @@ var SandboxChannelAService = class {
21850
22402
  rejectFinalSymlink: false
21851
22403
  });
21852
22404
  const flag = req.recursive ? "-rf" : "-f";
21853
- const { exitCode, stderr } = await this.run({ cmd: `rm ${flag} ${shellQuote6(abs)}` });
22405
+ const { exitCode, stderr } = await this.run({ cmd: `rm ${flag} ${shellQuote7(abs)}` });
21854
22406
  if (exitCode !== null && exitCode !== 0) {
21855
22407
  throw new ChannelAValidationError(
21856
22408
  `failed to delete ${path}: ${stderr || `exit ${exitCode}`}`
@@ -21875,7 +22427,7 @@ var SandboxChannelAService = class {
21875
22427
  });
21876
22428
  if (!req.overwrite) {
21877
22429
  const { exitCode: exitCode2 } = await this.run({
21878
- cmd: `test -e ${shellQuote6(newAbs)} || test -L ${shellQuote6(newAbs)}`
22430
+ cmd: `test -e ${shellQuote7(newAbs)} || test -L ${shellQuote7(newAbs)}`
21879
22431
  });
21880
22432
  if (exitCode2 === 0) {
21881
22433
  throw new ChannelAConflictError(`destination exists and overwrite is false: ${newPath}`);
@@ -21883,7 +22435,7 @@ var SandboxChannelAService = class {
21883
22435
  }
21884
22436
  if (req.createParents) {
21885
22437
  const dir = dirnameAbs(newAbs);
21886
- if (dir) await this.run({ cmd: `mkdir -p ${shellQuote6(dir)}` });
22438
+ if (dir) await this.run({ cmd: `mkdir -p ${shellQuote7(dir)}` });
21887
22439
  await this.assertConfinedMutationParent(newPath, {
21888
22440
  allowMissingParents: false,
21889
22441
  rejectFinalSymlink: true
@@ -21891,7 +22443,7 @@ var SandboxChannelAService = class {
21891
22443
  }
21892
22444
  const flag = req.overwrite ? "-f " : "";
21893
22445
  const { exitCode, stderr } = await this.run({
21894
- cmd: `mv ${flag}${shellQuote6(abs)} ${shellQuote6(newAbs)}`
22446
+ cmd: `mv ${flag}${shellQuote7(abs)} ${shellQuote7(newAbs)}`
21895
22447
  });
21896
22448
  if (exitCode !== null && exitCode !== 0) {
21897
22449
  throw new ChannelAValidationError(
@@ -21916,7 +22468,7 @@ var SandboxChannelAService = class {
21916
22468
  rejectFinalSymlink: true
21917
22469
  });
21918
22470
  const flag = req.recursive ? "-p " : "";
21919
- const { exitCode, stderr } = await this.run({ cmd: `mkdir ${flag}${shellQuote6(abs)}` });
22471
+ const { exitCode, stderr } = await this.run({ cmd: `mkdir ${flag}${shellQuote7(abs)}` });
21920
22472
  if (exitCode !== null && exitCode !== 0) {
21921
22473
  throw new ChannelAValidationError(`failed to mkdir ${path}: ${stderr || `exit ${exitCode}`}`);
21922
22474
  }
@@ -21931,44 +22483,60 @@ var SandboxChannelAService = class {
21931
22483
  async measureConfinedCommandBytes(repo, command) {
21932
22484
  const measured = await this.runInConfinedDirectory(repo, {
21933
22485
  cmd: [
21934
- "set -o pipefail",
21935
- `{ ${command}; } 2>/dev/null | { bytes=$(wc -c | tr -d ' \\n'); printf '%s' "$bytes"; }`,
21936
- "producer_status=${PIPESTATUS[0]}",
21937
- `printf '\\t%s\\n' "$producer_status"`
22486
+ PORTABLE_SHA256_FILE_FUNCTION,
22487
+ "tmp=$(mktemp) || exit 70",
22488
+ `trap 'rm -f "$tmp"' EXIT`,
22489
+ `/bin/bash --noprofile --norc -c ${shellQuote7(command)} >"$tmp" 2>/dev/null`,
22490
+ "producer_status=$?",
22491
+ `bytes=$(wc -c <"$tmp" | tr -d ' \\n')`,
22492
+ `sha256=$(opengeni_sha256_file "$tmp") || exit 71`,
22493
+ `printf '${GIT_MEASURE_FRAME}\\t%s\\t%s\\t%s' "$producer_status" "$bytes" "$sha256"`
21938
22494
  ].join("; "),
21939
22495
  maxOutputTokens: 1024
21940
22496
  });
21941
- const match = measured.stdout.match(/^(\d+)\t(\d+)\n?$/);
21942
- if (!match || measured.exitCode !== null && measured.exitCode !== 0 || Number(match[2]) !== 0) {
22497
+ const match = measured.stdout.match(
22498
+ new RegExp(`^${GIT_MEASURE_FRAME}\\t(\\d+)\\t(\\d+)\\t([0-9a-f]{64})$`)
22499
+ );
22500
+ if (!match || measured.exitCode !== null && measured.exitCode !== 0 || Number(match[1]) !== 0) {
21943
22501
  throw new ChannelAUnavailableError(
21944
22502
  "Workspace Git data is temporarily unavailable. Retry the operation."
21945
22503
  );
21946
22504
  }
21947
- const size = Number(match[1]);
22505
+ const size = Number(match[2]);
21948
22506
  if (!Number.isSafeInteger(size) || size < 0) {
21949
22507
  throw new ChannelAUnavailableError(
21950
22508
  "Workspace Git data is temporarily unavailable. Retry the operation."
21951
22509
  );
21952
22510
  }
21953
- return size;
22511
+ return { sizeBytes: size, sha256: match[3] };
21954
22512
  }
21955
22513
  /** Read an exact prefix of a command's output in chunks that remain below
21956
22514
  * every supported execCommand retained-output ceiling. The producer is
21957
22515
  * intentionally rerun per chunk; turn-end capture calls this only after the
21958
22516
  * durable mutation authority has quiesced the workspace. */
21959
- async readConfinedCommandPrefix(repo, command, byteLength2) {
21960
- if (byteLength2 === 0) return Buffer.alloc(0);
22517
+ async readConfinedCommandPrefix(repo, command, measurement, prefixByteLength = measurement.sizeBytes) {
22518
+ if (!Number.isSafeInteger(prefixByteLength) || prefixByteLength < 0 || prefixByteLength > measurement.sizeBytes) {
22519
+ throw new ChannelAUnavailableError(
22520
+ "Workspace Git data is temporarily unavailable. Retry the operation."
22521
+ );
22522
+ }
22523
+ if (prefixByteLength === 0) return Buffer.alloc(0);
21961
22524
  const chunks = [];
21962
- for (let offset = 0; offset < byteLength2; offset += GIT_COMMAND_CHUNK_BYTES) {
21963
- const expected = Math.min(GIT_COMMAND_CHUNK_BYTES, byteLength2 - offset);
22525
+ for (let offset = 0; offset < prefixByteLength; offset += GIT_COMMAND_CHUNK_BYTES) {
22526
+ const expected = Math.min(GIT_COMMAND_CHUNK_BYTES, prefixByteLength - offset);
21964
22527
  const chunk = await this.runInConfinedDirectory(repo, {
21965
22528
  cmd: [
21966
- `{ ${command}; } 2>/dev/null`,
21967
- `tail -c +${offset + 1}`,
21968
- `head -c ${expected}`,
21969
- "base64",
21970
- `tr -d '\\n'`
21971
- ].join(" | "),
22529
+ PORTABLE_SHA256_FILE_FUNCTION,
22530
+ "tmp=$(mktemp) || exit 70",
22531
+ `trap 'rm -f "$tmp"' EXIT`,
22532
+ `/bin/bash --noprofile --norc -c ${shellQuote7(command)} >"$tmp" 2>/dev/null`,
22533
+ "producer_status=$?",
22534
+ `bytes=$(wc -c <"$tmp" | tr -d ' \\n')`,
22535
+ `sha256=$(opengeni_sha256_file "$tmp") || exit 71`,
22536
+ `printf '${GIT_CHUNK_FRAME}\\t%s\\t%s\\t%s\\t%s\\t%s\\n' "$producer_status" "$bytes" "$sha256" ${offset} ${expected}`,
22537
+ `if [ "$producer_status" -eq 0 ]; then tail -c +${offset + 1} "$tmp" | head -c ${expected} | base64 | tr -d '\\n'; fi`,
22538
+ `printf '\\n${GIT_CHUNK_FRAME_END}'`
22539
+ ].join("; "),
21972
22540
  maxOutputTokens: Math.ceil(GIT_COMMAND_CHUNK_BYTES * 4 / 3) + 1024
21973
22541
  });
21974
22542
  if (chunk.exitCode !== null && chunk.exitCode !== 0) {
@@ -21976,7 +22544,21 @@ var SandboxChannelAService = class {
21976
22544
  "Workspace Git data is temporarily unavailable. Retry the operation."
21977
22545
  );
21978
22546
  }
21979
- const encoded = chunk.stdout.replace(/\s/g, "");
22547
+ const headerEnd = chunk.stdout.indexOf("\n");
22548
+ const trailer = `
22549
+ ${GIT_CHUNK_FRAME_END}`;
22550
+ if (headerEnd < 0 || !chunk.stdout.endsWith(trailer)) {
22551
+ throw new ChannelAUnavailableError(
22552
+ "Workspace Git data is temporarily unavailable. Retry the operation."
22553
+ );
22554
+ }
22555
+ const header = chunk.stdout.slice(0, headerEnd).split(" ");
22556
+ if (header.length !== 6 || header[0] !== GIT_CHUNK_FRAME || header[1] !== "0" || header[2] !== String(measurement.sizeBytes) || header[3] !== measurement.sha256 || header[4] !== String(offset) || header[5] !== String(expected)) {
22557
+ throw new ChannelAUnavailableError(
22558
+ "Workspace Git data changed during capture. Retry the operation."
22559
+ );
22560
+ }
22561
+ const encoded = chunk.stdout.slice(headerEnd + 1, -trailer.length);
21980
22562
  const bytes = Buffer.from(encoded, "base64");
21981
22563
  if (bytes.byteLength !== expected || bytes.toString("base64") !== encoded) {
21982
22564
  throw new ChannelAUnavailableError(
@@ -21985,35 +22567,61 @@ var SandboxChannelAService = class {
21985
22567
  }
21986
22568
  chunks.push(bytes);
21987
22569
  }
21988
- return Buffer.concat(chunks, byteLength2);
22570
+ return Buffer.concat(chunks, prefixByteLength);
21989
22571
  }
21990
22572
  async readConfinedCommandBytes(repo, command, maxBytes) {
21991
- const sizeBytes = await this.measureConfinedCommandBytes(repo, command);
21992
- if (sizeBytes > maxBytes) {
21993
- return { bytes: Buffer.alloc(0), sizeBytes, truncated: true };
22573
+ const measurement = await this.measureConfinedCommandBytes(repo, command);
22574
+ if (measurement.sizeBytes > maxBytes) {
22575
+ return { bytes: Buffer.alloc(0), sizeBytes: measurement.sizeBytes, truncated: true };
21994
22576
  }
21995
22577
  return {
21996
- bytes: await this.readConfinedCommandPrefix(repo, command, sizeBytes),
21997
- sizeBytes,
22578
+ bytes: await this.readConfinedCommandPrefix(repo, command, measurement),
22579
+ sizeBytes: measurement.sizeBytes,
21998
22580
  truncated: false
21999
22581
  };
22000
22582
  }
22583
+ /** Bind an untracked regular-file descriptor to its repository root and its
22584
+ * lstat identity before producing bytes. The final producer reads fd 3 rather
22585
+ * than reopening the path, so a check→read symlink swap cannot disclose a
22586
+ * target outside the repository (or substitute another in-repository inode). */
22587
+ confinedUntrackedRegularFileCommand(target, body) {
22588
+ const fileArg = target.startsWith("./") ? target : `./${target}`;
22589
+ return [
22590
+ PORTABLE_DESCRIPTOR_FUNCTIONS,
22591
+ `file=${shellQuote7(fileArg)}`,
22592
+ 'exec 3<"$file" || exit 66',
22593
+ 'exec 4<"$file" || exit 66',
22594
+ "root=$(pwd -P) || exit 66",
22595
+ "opengeni_set_fd_path 3 || exit 66",
22596
+ 'opened3="$opengeni_fd_path"',
22597
+ "opengeni_set_fd_path 4 || exit 66",
22598
+ 'opened4="$opengeni_fd_path"',
22599
+ 'case "$opened3" in "$root"|"$root"/*) ;; *) exit 67 ;; esac',
22600
+ 'case "$opened4" in "$root"|"$root"/*) ;; *) exit 67 ;; esac',
22601
+ 'test ! -L "$file" && test -f "$file" || exit 66',
22602
+ "opened3_identity=$(opengeni_fd_identity 3) || exit 66",
22603
+ "opened4_identity=$(opengeni_fd_identity 4) || exit 66",
22604
+ 'path_identity=$(opengeni_path_identity "$file") || exit 66',
22605
+ 'test "$opened3_identity" = "$opened4_identity" || exit 66',
22606
+ 'test "$opened3_identity" = "$path_identity" || exit 66',
22607
+ body
22608
+ ].join("; ");
22609
+ }
22001
22610
  /** Read a regular untracked file without routing its body through one large
22002
22611
  * execCommand response. Native provider reads are binary-safe; providers
22003
22612
  * without that surface use the same bounded chunk protocol as Git patches. */
22004
- async readUntrackedRegularFile(repo, target, byteLength2) {
22005
- if (byteLength2 === 0) return Buffer.alloc(0);
22613
+ async readUntrackedRegularFile(repo, target, prefixByteLength, sizeBytes) {
22006
22614
  const path = repo ? `${repo}/${target}` : target;
22007
22615
  assertSafeRelPath(path);
22008
22616
  if (this.session.readFile) {
22009
22617
  try {
22010
22618
  const raw = await this.session.readFile({
22011
22619
  path: this.joinRoot(path),
22012
- maxBytes: byteLength2,
22620
+ maxBytes: prefixByteLength,
22013
22621
  ...this.runAs ? { runAs: this.runAs } : {}
22014
22622
  });
22015
22623
  const bytes = typeof raw === "string" ? Buffer.from(raw, "utf8") : Buffer.from(raw);
22016
- if (bytes.byteLength !== byteLength2) {
22624
+ if (bytes.byteLength !== prefixByteLength) {
22017
22625
  throw new ChannelAUnavailableError(
22018
22626
  "Workspace Git data changed during capture. Retry the operation."
22019
22627
  );
@@ -22034,12 +22642,14 @@ var SandboxChannelAService = class {
22034
22642
  }
22035
22643
  }
22036
22644
  }
22037
- const fileArg = target.startsWith("./") ? target : `./${target}`;
22038
- return await this.readConfinedCommandPrefix(
22039
- repo,
22040
- `file=${shellQuote6(fileArg)}; test ! -L "$file" && test -f "$file" || exit 66; cat -- "$file"`,
22041
- byteLength2
22042
- );
22645
+ const command = this.confinedUntrackedRegularFileCommand(target, "cat <&3");
22646
+ const measurement = await this.measureConfinedCommandBytes(repo, command);
22647
+ if (measurement.sizeBytes !== sizeBytes) {
22648
+ throw new ChannelAUnavailableError(
22649
+ "Workspace Git data changed during capture. Retry the operation."
22650
+ );
22651
+ }
22652
+ return await this.readConfinedCommandPrefix(repo, command, measurement, prefixByteLength);
22043
22653
  }
22044
22654
  async gitStatus(req) {
22045
22655
  const repo = assertSafeRelPathOrRoot(req.path);
@@ -22068,24 +22678,24 @@ var SandboxChannelAService = class {
22068
22678
  "Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
22069
22679
  );
22070
22680
  }
22071
- return { ...parsePorcelainV2(status.bytes.toString("utf8")), revision: this.revision };
22681
+ return { ...parsePorcelainV2(decodeGitMetadataUtf8(status.bytes)), revision: this.revision };
22072
22682
  }
22073
22683
  async gitDiff(req) {
22074
22684
  const repo = assertSafeRelPathOrRoot(req.path);
22075
22685
  const ctx = req.contextLines;
22076
22686
  let range = "";
22077
- if (req.fromRef && req.toRef) range = `${shellQuote6(req.fromRef)} ${shellQuote6(req.toRef)}`;
22687
+ if (req.fromRef && req.toRef) range = `${shellQuote7(req.fromRef)} ${shellQuote7(req.toRef)}`;
22078
22688
  else if (req.fromRef) {
22079
22689
  if (req.fromRef === "HEAD") {
22080
22690
  const head = await this.runInConfinedDirectory(repo, {
22081
22691
  cmd: "if git rev-parse --verify --quiet HEAD >/dev/null; then printf 'present'; else printf 'unborn'; fi"
22082
22692
  });
22083
- range = head.stdout.trim() === "present" ? shellQuote6(req.fromRef) : "--cached";
22693
+ range = head.stdout.trim() === "present" ? shellQuote7(req.fromRef) : "--cached";
22084
22694
  } else {
22085
- range = shellQuote6(req.fromRef);
22695
+ range = shellQuote7(req.fromRef);
22086
22696
  }
22087
22697
  } else if (req.staged) range = "--cached";
22088
- const pathspec = req.pathspec.length ? ` -- ${req.pathspec.map(shellQuote6).join(" ")}` : "";
22698
+ const pathspec = req.pathspec.length ? ` -- ${req.pathspec.map(shellQuote7).join(" ")}` : "";
22089
22699
  const numstat = await this.readConfinedCommandBytes(
22090
22700
  repo,
22091
22701
  `git -c core.quotePath=false diff --no-color -z --numstat ${range}${pathspec}`.trim(),
@@ -22096,7 +22706,7 @@ var SandboxChannelAService = class {
22096
22706
  "Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
22097
22707
  );
22098
22708
  }
22099
- const stats = parseNumstatZ(numstat.bytes.toString("utf8"));
22709
+ const stats = parseNumstatZ(decodeGitMetadataUtf8(numstat.bytes));
22100
22710
  const files = [];
22101
22711
  for (const stat4 of stats) {
22102
22712
  const target = stat4.newPath;
@@ -22117,7 +22727,7 @@ var SandboxChannelAService = class {
22117
22727
  }
22118
22728
  const patch = await this.readConfinedCommandBytes(
22119
22729
  repo,
22120
- `git -c core.quotePath=false diff --no-color -U${ctx} ${range} -- ${shellQuote6(target)}`.trim(),
22730
+ `git -c core.quotePath=false diff --no-color -U${ctx} ${range} -- ${shellQuote7(target)}`.trim(),
22121
22731
  req.maxBytesPerFile
22122
22732
  );
22123
22733
  const parsed = patch.truncated ? { hunks: [], status: "modified" } : parseUnifiedPatch(patch.bytes.toString("utf8"));
@@ -22144,48 +22754,75 @@ var SandboxChannelAService = class {
22144
22754
  "Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
22145
22755
  );
22146
22756
  }
22147
- for (const target of untracked.bytes.toString("utf8").split(NUL).filter(Boolean)) {
22757
+ for (const target of decodeGitMetadataUtf8(untracked.bytes).split(NUL).filter(Boolean)) {
22148
22758
  const fileArg = target.startsWith("./") ? target : `./${target}`;
22149
- const read = await this.runInConfinedDirectory(repo, {
22150
- cmd: [
22151
- `file=${shellQuote6(fileArg)}`,
22152
- 'if [ -L "$file" ]; then printf "L\\t"; readlink -z -- "$file" | base64 | tr -d "\\n"; exit; fi',
22153
- 'size=$(wc -c < "$file") || exit 66',
22154
- 'line_count=$(wc -l < "$file") || exit 66',
22155
- 'if [ "$size" -gt 0 ]; then last_byte=$(tail -c 1 "$file" | od -An -tu1 | tr -d " \\n"); if [ "$last_byte" != "10" ]; then line_count=$((line_count + 1)); fi; fi',
22156
- 'printf "F\\t%s\\t%s" "$size" "$line_count"'
22157
- ].join("; ")
22158
- });
22159
- if (read.exitCode !== null && read.exitCode !== 0) {
22759
+ const kind = await this.readConfinedCommandBytes(
22760
+ repo,
22761
+ `file=${shellQuote7(fileArg)}; if [ -L "$file" ]; then printf L; elif [ -f "$file" ]; then printf F; else exit 66; fi`,
22762
+ 1
22763
+ );
22764
+ if (kind.truncated || kind.bytes[0] !== 76 && kind.bytes[0] !== 70) {
22160
22765
  throw new ChannelAUnavailableError(
22161
22766
  "Workspace Git data is temporarily unavailable. Retry the operation."
22162
22767
  );
22163
22768
  }
22164
- const [kind, first, second] = read.stdout.split(" ");
22165
22769
  let sampled = Buffer.alloc(0);
22166
22770
  let sizeBytes;
22167
22771
  let lineCount;
22168
- if (kind === "L") {
22169
- const encoded = (first ?? "").replace(/\s/g, "");
22170
- sampled = Buffer.from(encoded, "base64");
22171
- if (sampled.at(-1) !== 0) continue;
22772
+ if (kind.bytes[0] === 76) {
22773
+ const link = await this.readConfinedCommandBytes(
22774
+ repo,
22775
+ `file=${shellQuote7(fileArg)}; test -L "$file" || exit 66; readlink -n "$file" || exit 66; printf '\\0'`,
22776
+ GIT_METADATA_MAX_BYTES
22777
+ );
22778
+ if (link.truncated) {
22779
+ throw new ChannelAUnavailableError(
22780
+ "Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
22781
+ );
22782
+ }
22783
+ sampled = link.bytes;
22784
+ if (sampled.at(-1) !== 0) {
22785
+ throw new ChannelAUnavailableError(
22786
+ "Workspace Git data is temporarily unavailable. Retry the operation."
22787
+ );
22788
+ }
22172
22789
  sampled = sampled.subarray(0, -1);
22173
22790
  sizeBytes = sampled.length;
22174
22791
  lineCount = addedLines(sampled).length;
22175
22792
  } else {
22176
- if (kind !== "F") continue;
22177
- const parsedSize = safeInt(first);
22178
- const parsedLineCount = safeInt(second);
22179
- if (parsedSize === null || parsedSize < 0 || parsedLineCount === null || parsedLineCount < 0) {
22180
- continue;
22793
+ const metadata = await this.readConfinedCommandBytes(
22794
+ repo,
22795
+ this.confinedUntrackedRegularFileCommand(
22796
+ target,
22797
+ [
22798
+ "size=$(opengeni_fd_size 3) || exit 66",
22799
+ "line_count=$(wc -l <&3) || exit 66",
22800
+ 'if [ "$size" -gt 0 ]; then last_byte=$(tail -c 1 <&4 | od -An -tu1 | tr -d " \\n") || exit 66; if [ "$last_byte" != "10" ]; then line_count=$((line_count + 1)); fi; fi',
22801
+ 'printf "%s\\t%s" "$size" "$line_count"'
22802
+ ].join("; ")
22803
+ ),
22804
+ 128
22805
+ );
22806
+ if (metadata.truncated) {
22807
+ throw new ChannelAUnavailableError(
22808
+ "Workspace Git data is temporarily unavailable. Retry the operation."
22809
+ );
22810
+ }
22811
+ const frame = metadata.bytes.toString("ascii").match(/^(0|[1-9]\d*)\t(0|[1-9]\d*)$/);
22812
+ const parsedSize = safeInt(frame?.[1]);
22813
+ const parsedLineCount = safeInt(frame?.[2]);
22814
+ if (parsedSize === null || parsedLineCount === null) {
22815
+ throw new ChannelAUnavailableError(
22816
+ "Workspace Git data is temporarily unavailable. Retry the operation."
22817
+ );
22181
22818
  }
22182
22819
  sizeBytes = parsedSize;
22183
22820
  lineCount = parsedLineCount;
22184
22821
  const truncated2 = sizeBytes > req.maxBytesPerFile;
22185
22822
  const sampleSize = Math.min(sizeBytes, 8192);
22186
- sampled = await this.readUntrackedRegularFile(repo, target, sampleSize);
22823
+ sampled = await this.readUntrackedRegularFile(repo, target, sampleSize, sizeBytes);
22187
22824
  if (!sniffBinary(sampled) && !truncated2 && sampleSize < sizeBytes) {
22188
- sampled = await this.readUntrackedRegularFile(repo, target, sizeBytes);
22825
+ sampled = await this.readUntrackedRegularFile(repo, target, sizeBytes, sizeBytes);
22189
22826
  }
22190
22827
  }
22191
22828
  const truncated = sizeBytes > req.maxBytesPerFile || sampled.length > req.maxBytesPerFile;
@@ -22219,9 +22856,9 @@ var SandboxChannelAService = class {
22219
22856
  async gitLog(req) {
22220
22857
  const repo = assertSafeRelPathOrRoot(req.path);
22221
22858
  const fmt = `%H${US}%h${US}%P${US}%an${US}%ae${US}%at${US}%cn${US}%ce${US}%ct${US}%s${US}%b${RS}`;
22222
- const pathspec = req.pathspec.length ? ` -- ${req.pathspec.map(shellQuote6).join(" ")}` : "";
22859
+ const pathspec = req.pathspec.length ? ` -- ${req.pathspec.map(shellQuote7).join(" ")}` : "";
22223
22860
  const { stdout, exitCode } = await this.runInConfinedDirectory(repo, {
22224
- cmd: `git log --format=${shellQuote6(fmt)} -n${req.maxCount + 1} --skip=${req.skip} ${shellQuote6(req.ref)}${pathspec}`
22861
+ cmd: `git log --format=${shellQuote7(fmt)} -n${req.maxCount + 1} --skip=${req.skip} ${shellQuote7(req.ref)}${pathspec}`
22225
22862
  });
22226
22863
  if (exitCode !== null && exitCode !== 0) {
22227
22864
  return { commits: [], hasMore: false };
@@ -22248,7 +22885,7 @@ var SandboxChannelAService = class {
22248
22885
  const repo = assertSafeRelPathOrRoot(req.path);
22249
22886
  if (req.filePath) {
22250
22887
  const { stdout, exitCode } = await this.runInConfinedDirectory(repo, {
22251
- cmd: `git cat-file blob ${shellQuote6(`${req.ref}:${req.filePath}`)} 2>/dev/null | base64`
22888
+ cmd: `git cat-file blob ${shellQuote7(`${req.ref}:${req.filePath}`)} 2>/dev/null | base64`
22252
22889
  });
22253
22890
  if (exitCode !== null && exitCode !== 0 && stdout.trim() === "") {
22254
22891
  throw new ChannelANotFoundError(`blob not found: ${req.ref}:${req.filePath}`);
@@ -22521,19 +23158,28 @@ var SandboxChannelAService = class {
22521
23158
  const safe = assertSafeRelPathOrRoot(rel);
22522
23159
  const root = this.workspaceRoot || ".";
22523
23160
  const abs = this.joinRoot(safe);
22524
- const rejectLink = safe ? `test ! -L ${shellQuote6(abs)} || { printf '__OPENGENI_FS_SYMLINK__'; exit 68; }` : ":";
22525
- const script = [
22526
- `root=$(realpath -e -- ${shellQuote6(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
22527
- rejectLink,
22528
- `target=$(realpath -e -- ${shellQuote6(abs)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
22529
- `case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
22530
- `test -d "$target" || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
22531
- `cd -P -- "$target"`,
22532
- `printf '__OPENGENI_FS_CONFINED_OK__\\n'`,
22533
- args.cmd
22534
- ].join("; ");
22535
- const successPrefix = "__OPENGENI_FS_CONFINED_OK__\n";
23161
+ const rejectLink = safe ? `test ! -L ${shellQuote7(abs)} || { printf '__OPENGENI_FS_SYMLINK__'; exit 68; }` : ":";
22536
23162
  for (let attempt = 0; attempt < 2; attempt += 1) {
23163
+ const frameId = crypto.randomUUID().replaceAll("-", "");
23164
+ const successPrefix = `__OPENGENI_FS_CONFINED_${frameId}_OK__
23165
+ `;
23166
+ const successSuffixPrefix = `__OPENGENI_FS_CONFINED_${frameId}_END__:`;
23167
+ const successSuffixTerminator = "__";
23168
+ const script = [
23169
+ `root=$(realpath -e -- ${shellQuote7(root)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
23170
+ rejectLink,
23171
+ `target=$(realpath -e -- ${shellQuote7(abs)}) || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
23172
+ `case "$target" in "$root"|"$root"/*) ;; *) printf '__OPENGENI_FS_ESCAPE__'; exit 67 ;; esac`,
23173
+ `test -d "$target" || { printf '__OPENGENI_FS_NOT_FOUND__'; exit 66; }`,
23174
+ `cd -P -- "$target"`,
23175
+ `printf ${shellQuote7(successPrefix)}`,
23176
+ // Keep an operation-level `exit` inside the subshell so the trusted end
23177
+ // frame is emitted for every completed command.
23178
+ `( ${args.cmd} )`,
23179
+ `operation_status=$?`,
23180
+ `printf ${shellQuote7(`${successSuffixPrefix}%s${successSuffixTerminator}`)} "$operation_status"`,
23181
+ `exit "$operation_status"`
23182
+ ].join("; ");
22537
23183
  let result;
22538
23184
  try {
22539
23185
  result = await this.run({
@@ -22555,7 +23201,24 @@ var SandboxChannelAService = class {
22555
23201
  }
22556
23202
  const successIndex = result.stdout.indexOf(successPrefix);
22557
23203
  if (successIndex >= 0) {
22558
- return { ...result, stdout: result.stdout.slice(successIndex + successPrefix.length) };
23204
+ const payloadStart = successIndex + successPrefix.length;
23205
+ const suffixIndex = result.stdout.lastIndexOf(successSuffixPrefix);
23206
+ if (suffixIndex >= payloadStart) {
23207
+ const suffixEnd = result.stdout.indexOf(
23208
+ successSuffixTerminator,
23209
+ suffixIndex + successSuffixPrefix.length
23210
+ );
23211
+ const statusText = suffixEnd < 0 ? null : result.stdout.slice(suffixIndex + successSuffixPrefix.length, suffixEnd);
23212
+ if (statusText && /^(?:0|[1-9][0-9]{0,2})$/.test(statusText)) {
23213
+ const operationStatus = Number(statusText);
23214
+ if (operationStatus > 255) continue;
23215
+ return {
23216
+ ...result,
23217
+ stdout: result.stdout.slice(payloadStart, suffixIndex),
23218
+ exitCode: operationStatus
23219
+ };
23220
+ }
23221
+ }
22559
23222
  }
22560
23223
  if (result.stdout.includes("__OPENGENI_FS_ESCAPE__") || result.exitCode === 67) {
22561
23224
  throw new ChannelAValidationError(`path resolves outside workspace: ${safe || "."}`);
@@ -22640,6 +23303,15 @@ function sniffBinary(bytes) {
22640
23303
  for (let i = 0; i < n; i++) if (bytes[i] === 0) return true;
22641
23304
  return false;
22642
23305
  }
23306
+ function decodeGitMetadataUtf8(bytes) {
23307
+ const decoded = bytes.toString("utf8");
23308
+ if (!Buffer.from(decoded, "utf8").equals(bytes)) {
23309
+ throw new ChannelAUnavailableError(
23310
+ "Workspace Git paths are not valid UTF-8 and cannot be captured authoritatively."
23311
+ );
23312
+ }
23313
+ return decoded;
23314
+ }
22643
23315
  function addedLines(bytes) {
22644
23316
  if (bytes.length === 0) return [];
22645
23317
  const lines = bytes.toString("utf8").split("\n");
@@ -22668,11 +23340,11 @@ function assertSafeRelPath(p) {
22668
23340
  if (norm === "") throw new ChannelAValidationError("path is required");
22669
23341
  return norm;
22670
23342
  }
22671
- function shellQuote6(s) {
23343
+ function shellQuote7(s) {
22672
23344
  return `'${s.replace(/'/g, `'\\''`)}'`;
22673
23345
  }
22674
23346
  function internalBashCommand(script) {
22675
- return `env -u BASH_ENV bash --noprofile --norc -c ${shellQuote6(script)}`;
23347
+ return `env -u BASH_ENV bash --noprofile --norc -c ${shellQuote7(script)}`;
22676
23348
  }
22677
23349
  function assertSafePruneDirectoryName(name) {
22678
23350
  if (name.length > 255 || !/^[A-Za-z0-9._@+-]+$/.test(name) || name === "." || name === "..") {
@@ -23377,7 +24049,9 @@ function withDockerNetwork(client, network) {
23377
24049
  ...client.resume ? {
23378
24050
  resume: async (state) => await wrapSession(await client.resume(state))
23379
24051
  } : {},
23380
- ...client.delete ? { delete: async (state) => await client.delete(state) } : {},
24052
+ ...client.delete ? {
24053
+ delete: async (state) => await client.delete(state)
24054
+ } : {},
23381
24055
  ...client.serializeSessionState ? {
23382
24056
  serializeSessionState: async (state, options) => await client.serializeSessionState(state, options)
23383
24057
  } : {},
@@ -23447,55 +24121,9 @@ function readWorkspaceArchiveFromEnvelopeSessionState(sessionState) {
23447
24121
  return void 0;
23448
24122
  }
23449
24123
  }
23450
- var MODAL_SNAPSHOT_REF_PREFIXES = [
23451
- "MODAL_SANDBOX_FS_SNAPSHOT_V1\n",
23452
- "MODAL_SANDBOX_DIR_SNAPSHOT_V1\n"
23453
- ];
23454
24124
  function decodeModalSnapshotId(archive) {
23455
- let text;
23456
- try {
23457
- text = new TextDecoder().decode(archive);
23458
- } catch {
23459
- return void 0;
23460
- }
23461
- for (const prefix of MODAL_SNAPSHOT_REF_PREFIXES) {
23462
- if (!text.startsWith(prefix)) {
23463
- continue;
23464
- }
23465
- try {
23466
- const payload = JSON.parse(text.slice(prefix.length));
23467
- return typeof payload.snapshot_id === "string" && payload.snapshot_id.length > 0 ? payload.snapshot_id : void 0;
23468
- } catch {
23469
- return void 0;
23470
- }
23471
- }
23472
- return void 0;
23473
- }
23474
- async function deletePriorPersistedSnapshot(session, priorArchiveBase64) {
23475
- if (!priorArchiveBase64) {
23476
- return void 0;
23477
- }
23478
- let bytes;
23479
- try {
23480
- bytes = Uint8Array.from(Buffer.from(priorArchiveBase64, "base64"));
23481
- } catch {
23482
- return void 0;
23483
- }
23484
- const snapshotId = decodeModalSnapshotId(bytes);
23485
- if (!snapshotId) {
23486
- return void 0;
23487
- }
23488
- const modal = session.modal;
23489
- const del = modal?.images?.delete;
23490
- if (typeof del !== "function") {
23491
- return void 0;
23492
- }
23493
- try {
23494
- await del.call(modal.images, snapshotId);
23495
- return snapshotId;
23496
- } catch {
23497
- return void 0;
23498
- }
24125
+ const ref = decodeNativeSnapshotRef3(archive);
24126
+ return ref?.provider === "modal_snapshot_filesystem" || ref?.provider === "modal_snapshot_directory" ? ref.snapshotId : void 0;
23499
24127
  }
23500
24128
  async function deserializeSandboxSessionStateEnvelope(client, envelope) {
23501
24129
  if (!envelope || typeof envelope !== "object") {
@@ -23609,7 +24237,11 @@ async function establishSandboxSessionFromEnvelope(settings, envelope, opts) {
23609
24237
  const envelopeBackend = typeof envelope?.backendId === "string" ? envelope.backendId : void 0;
23610
24238
  const backend = opts.backendOverride ?? envelopeBackend ?? settings.sandboxBackend;
23611
24239
  const environment = opts.environment ?? collectSandboxEnvironment(settings);
23612
- const client = createSandboxClientForBackend(backend, settings, environment);
24240
+ const client = (opts.clientFactory ?? createSandboxClientForBackend)(
24241
+ backend,
24242
+ settings,
24243
+ environment
24244
+ );
23613
24245
  if (!client) {
23614
24246
  throw new SandboxConfigError(
23615
24247
  backend,
@@ -23702,20 +24334,22 @@ async function establishSandboxSessionFromEnvelope(settings, envelope, opts) {
23702
24334
  throw error;
23703
24335
  }
23704
24336
  }
23705
- try {
23706
- await verifyRestoredWorkspace(restored, workspaceArchive.descriptor);
23707
- } catch (error) {
23708
- await terminateCreatedSandbox(client, restored, restored.state);
23709
- if (error instanceof WorkspaceArchiveIntegrityError) throw error;
23710
- throw new WorkspaceArchiveIntegrityError(
23711
- "workspace_fingerprint_unavailable",
23712
- `failed to verify selected workspace archive revision ${workspaceArchive.descriptor.revision}`,
23713
- { retryable: true }
23714
- );
24337
+ if (workspaceArchive.kind === "tar") {
24338
+ try {
24339
+ await verifyRestoredWorkspace(restored, workspaceArchive.descriptor);
24340
+ } catch (error) {
24341
+ await terminateCreatedSandbox(client, restored, restored.state);
24342
+ if (error instanceof WorkspaceArchiveIntegrityError) throw error;
24343
+ throw new WorkspaceArchiveIntegrityError(
24344
+ "workspace_fingerprint_unavailable",
24345
+ `failed to verify selected workspace archive revision ${workspaceArchive.descriptor.revision}`,
24346
+ { retryable: true }
24347
+ );
24348
+ }
23715
24349
  }
23716
24350
  hydrationApplied = true;
23717
24351
  console.info(
23718
- `[sandbox] cold-restore verified workspace archive revision ${workspaceArchive.descriptor.revision}`
24352
+ `[sandbox] cold-restore applied ${workspaceArchive.kind === "provider_snapshot" ? "native snapshot receipt" : "verified tar archive"} revision ${workspaceArchive.descriptor.revision}`
23719
24353
  );
23720
24354
  }
23721
24355
  restoredState = restored.state;
@@ -23898,6 +24532,12 @@ export {
23898
24532
  modalSandboxAttributionEnvironment,
23899
24533
  modalSandboxAttributionTags,
23900
24534
  ensureModalRegistryImage,
24535
+ resolveModalCheckpointProviderBindingForSession,
24536
+ modalSessionMatchesCheckpointProviderBinding,
24537
+ resolveModalCheckpointProviderBinding,
24538
+ resolveModalCheckpointProviderBindingForLiveSandbox,
24539
+ inspectModalSandboxLifecycle,
24540
+ deleteModalCheckpointSnapshot,
23901
24541
  tagModalSandbox,
23902
24542
  terminateModalSandboxById,
23903
24543
  sweepModalOrphanSandboxes,
@@ -23956,13 +24596,16 @@ export {
23956
24596
  isProviderSandboxNotFoundError2 as isProviderSandboxNotFoundError,
23957
24597
  isProviderSandboxGoneDuringRoutedOperation,
23958
24598
  isProviderSandboxTransientError,
23959
- WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
23960
24599
  WorkspaceArchiveIntegrityError,
23961
- parseWorkspaceArchiveDescriptor,
24600
+ describeNativeSnapshotArchive,
24601
+ describeLegacyNativeSnapshotArchive,
23962
24602
  readVerifiedWorkspaceArchive,
23963
24603
  fingerprintSandboxWorkspace,
23964
24604
  captureVerifiedWorkspaceArchive,
23965
24605
  verifyRestoredWorkspace,
24606
+ WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION2 as WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
24607
+ decodeNativeSnapshotRef3 as decodeNativeSnapshotRef,
24608
+ parseWorkspaceArchiveDescriptor2 as parseWorkspaceArchiveDescriptor,
23966
24609
  selectBackend,
23967
24610
  backendSupportsOs,
23968
24611
  desktopCapableBackend,
@@ -24052,7 +24695,6 @@ export {
24052
24695
  restoredSandboxSessionStateFromEntry,
24053
24696
  readWorkspaceArchiveFromEnvelopeSessionState,
24054
24697
  decodeModalSnapshotId,
24055
- deletePriorPersistedSnapshot,
24056
24698
  deserializeSandboxSessionStateEnvelope,
24057
24699
  SandboxExecReadinessError,
24058
24700
  verifySandboxExecReadiness,
@@ -24065,4 +24707,4 @@ export {
24065
24707
  collectSandboxEnvironment2 as collectSandboxEnvironment,
24066
24708
  parseExposedPorts2 as parseExposedPorts
24067
24709
  };
24068
- //# sourceMappingURL=chunk-HHWIZHQM.js.map
24710
+ //# sourceMappingURL=chunk-GNEGANUF.js.map