@claxedo/sandbox-manager 0.9.0 → 0.10.1

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 (67) hide show
  1. package/README.md +233 -26
  2. package/dist/checkpoint-manager.d.ts +29 -4
  3. package/dist/checkpoint-manager.mjs +133 -24
  4. package/dist/command.d.ts +9 -2
  5. package/dist/command.mjs +8 -8
  6. package/dist/contract.d.ts +687 -0
  7. package/dist/driver-billing.d.ts +29 -0
  8. package/dist/driver-catalog.d.ts +42 -7
  9. package/dist/driver-catalog.mjs +115 -161
  10. package/dist/drivers/boat-client.d.ts +95 -0
  11. package/dist/drivers/boat-named-snapshots.d.ts +31 -0
  12. package/dist/drivers/boat-template.d.ts +49 -0
  13. package/dist/drivers/boat-template.mjs +1196 -0
  14. package/dist/drivers/boat.d.ts +64 -0
  15. package/dist/drivers/boat.mjs +990 -0
  16. package/dist/drivers/cloudflare.d.ts +3 -3
  17. package/dist/drivers/cloudflare.mjs +208 -147
  18. package/dist/drivers/docker.d.ts +4 -3
  19. package/dist/drivers/docker.mjs +154 -126
  20. package/dist/drivers/local-brokering.d.ts +14 -0
  21. package/dist/drivers/local-brokering.mjs +1029 -0
  22. package/dist/drivers/modal.d.ts +2 -2
  23. package/dist/drivers/modal.mjs +121 -111
  24. package/dist/drivers/transient-error.d.ts +2 -0
  25. package/dist/drivers/vercel.d.ts +3 -2
  26. package/dist/drivers/vercel.mjs +151 -115
  27. package/dist/egress-policy.d.ts +134 -0
  28. package/dist/egress-warnings.d.ts +22 -0
  29. package/dist/garbage-collect.d.ts +14 -0
  30. package/dist/hosted-network-policy.d.ts +9 -2
  31. package/dist/hosted-network-policy.mjs +218 -1
  32. package/dist/image-name.d.ts +12 -2
  33. package/dist/image-name.mjs +14 -5
  34. package/dist/image.d.ts +1 -20
  35. package/dist/image.mjs +11 -88
  36. package/dist/index.d.ts +8 -578
  37. package/dist/index.mjs +1379 -320
  38. package/dist/lease-failure.d.ts +173 -0
  39. package/dist/lease-lifecycle.d.ts +65 -0
  40. package/dist/lease-retry-wait.d.ts +8 -0
  41. package/dist/lease-start.d.ts +21 -0
  42. package/dist/lease-types.d.ts +4 -3
  43. package/dist/manager.d.ts +2 -0
  44. package/dist/runtime-env.d.ts +4 -2
  45. package/dist/runtime-env.mjs +37 -2
  46. package/dist/runtime-snapshot.d.ts +49 -0
  47. package/dist/runtime-version.d.ts +9 -0
  48. package/dist/runtime-version.mjs +2 -0
  49. package/dist/service-url-exposure.d.ts +0 -1
  50. package/dist/service-url-exposure.mjs +0 -9
  51. package/dist/start-fresh.d.ts +17 -0
  52. package/dist/start-telemetry.d.ts +37 -0
  53. package/dist/stores/memory.d.ts +1 -1
  54. package/dist/stores/memory.mjs +63 -52
  55. package/package.json +26 -42
  56. package/dist/daytona-allow-list.d.ts +0 -16
  57. package/dist/daytona-allow-list.mjs +0 -11
  58. package/dist/drivers/box.d.ts +0 -52
  59. package/dist/drivers/box.mjs +0 -574
  60. package/dist/drivers/daytona.d.ts +0 -163
  61. package/dist/drivers/daytona.mjs +0 -683
  62. package/dist/drivers/exe.d.ts +0 -26
  63. package/dist/drivers/exe.mjs +0 -492
  64. package/dist/drivers/fetch-bridge.d.ts +0 -10
  65. package/dist/drivers/fetch-bridge.mjs +0 -126
  66. package/dist/lease-policy.d.ts +0 -52
  67. package/dist/lease-policy.mjs +0 -290
@@ -1,4 +1,4 @@
1
- import type { SandboxDriver, SandboxDriverEnsureInput } from "..";
1
+ import type { SandboxDriver, SandboxDriverEnsureInput } from "../contract";
2
2
  import { type WorkspaceRuntimeControlEnv } from "../runtime-env";
3
3
  type ModalAppLike = unknown;
4
4
  type ModalImageLike = {
@@ -49,7 +49,7 @@ export type ModalSandboxDriverOptions = {
49
49
  runtimePort?: number;
50
50
  runtimeCommand?: string;
51
51
  workspaceDir?: string;
52
- runner?: string;
52
+ nativeHarness?: string;
53
53
  controlEnv?: WorkspaceRuntimeControlEnv;
54
54
  env?: (input: SandboxDriverEnsureInput, host: {
55
55
  id: string;
@@ -1,11 +1,41 @@
1
1
  // src/runtime-env.ts
2
+ var WORKSPACE_RUNTIME_IDENTITY_ENV_KEYS = [
3
+ "WORKSPACE_RUNTIME_WORKSPACE_ID",
4
+ "WORKSPACE_RUNTIME_HOST_ID",
5
+ "WORKSPACE_RUNTIME_RELAY_WORKSPACE_IDS"
6
+ ];
7
+ function workspaceRuntimeIdentityEnvConflicts(env) {
8
+ if (!env) return [];
9
+ return WORKSPACE_RUNTIME_IDENTITY_ENV_KEYS.filter((key) => env[key] !== void 0);
10
+ }
11
+ function assertWorkspaceRuntimeIdentityEnv(env) {
12
+ const conflicts = workspaceRuntimeIdentityEnvConflicts(env);
13
+ if (conflicts.length === 0) return;
14
+ throw new Error(
15
+ `sandbox env cannot set runtime identity ${conflicts.join(", ")}: the driver's placement owns the identity its target reports and the lease records`
16
+ );
17
+ }
18
+ var WORKSPACE_RUNTIME_PUBLIC_ENV_KEYS = /* @__PURE__ */ new Set([
19
+ ...WORKSPACE_RUNTIME_IDENTITY_ENV_KEYS,
20
+ "WORKSPACE_RUNTIME_DIRECTORY",
21
+ "WORKSPACE_RUNTIME_PORT",
22
+ "WORKSPACE_RUNTIME_HOST",
23
+ "WORKSPACE_RUNTIME_SOURCE_KIND",
24
+ "WORKSPACE_RUNTIME_GIT_REPO_URL",
25
+ "WORKSPACE_RUNTIME_GIT_BRANCH",
26
+ "WORKSPACE_RUNTIME_NATIVE_HARNESS",
27
+ "WORKSPACE_RUNTIME_RELAY_JWKS_URL",
28
+ "WORKSPACE_RUNTIME_MANAGEMENT_JWKS_URL",
29
+ "WORKSPACE_RUNTIME_SESSION_AUTHORITY_URL"
30
+ ]);
2
31
  function workspaceRuntimeBootEnv(input) {
32
+ assertWorkspaceRuntimeIdentityEnv(input.env);
3
33
  const env = {
4
34
  ...workspaceRuntimeTargetEnv(input),
5
35
  ...workspaceRuntimeSourceEnv(input),
6
36
  ...input.env
7
37
  };
8
- if (input.runner) env.WORKSPACE_RUNTIME_RUNNER = input.runner;
38
+ if (input.nativeHarness) env.WORKSPACE_RUNTIME_NATIVE_HARNESS = input.nativeHarness;
9
39
  if (input.controlEnv?.relayJwksUrl) env.WORKSPACE_RUNTIME_RELAY_JWKS_URL = input.controlEnv.relayJwksUrl;
10
40
  if (input.controlEnv?.relayVerifyPem) env.WORKSPACE_RUNTIME_RELAY_HOST_VERIFY_PEM = input.controlEnv.relayVerifyPem;
11
41
  if (input.controlEnv?.managementJwksUrl) env.WORKSPACE_RUNTIME_MANAGEMENT_JWKS_URL = input.controlEnv.managementJwksUrl;
@@ -58,61 +88,47 @@ function buildIdSuffix(buildId, env) {
58
88
  const id = (buildId ?? env.CLAXEDO_SANDBOX_BUILD_ID)?.trim();
59
89
  return id ? `-${snapshotVersion(id)}` : "";
60
90
  }
61
- function defaultSandboxImage(version = workspaceRuntimeVersion(), buildId, env = process.env) {
62
- return `${sandboxImageRepository(env)}:workspace-runtime-${snapshotVersion(version)}${buildIdSuffix(buildId, env)}-v${SNAPSHOT_SCHEMA_VERSION}`;
63
- }
64
- function defaultSnapshotName(version = workspaceRuntimeVersion(), buildId, env = process.env) {
65
- return `claxedo-workspace-runtime-${snapshotVersion(version)}${buildIdSuffix(buildId, env)}-v${SNAPSHOT_SCHEMA_VERSION}`;
66
- }
67
-
68
- // ../claxedo-helpers/dist/guards.mjs
69
- function isRecord(value) {
70
- return value !== null && typeof value === "object" && !Array.isArray(value);
71
- }
72
- function asRecord(value) {
73
- return isRecord(value) ? value : void 0;
74
- }
75
-
76
- // src/json.ts
77
- function num(input) {
78
- return typeof input === "number" ? input : void 0;
91
+ var AGENT_PLUGINS_TAG = "-agent-plugins";
92
+ function defaultSandboxImage(version = workspaceRuntimeVersion(), buildId, env = process.env, options = {}) {
93
+ const feature = options.agentPlugins ? AGENT_PLUGINS_TAG : "";
94
+ return `${sandboxImageRepository(env)}:workspace-runtime-${snapshotVersion(version)}${buildIdSuffix(buildId, env)}${feature}-v${SNAPSHOT_SCHEMA_VERSION}`;
79
95
  }
80
96
 
81
97
  // src/image.ts
82
98
  var SANDBOX_IMAGE_REPOSITORY = sandboxImageRepository();
83
99
  var SANDBOX_IMAGE = process.env.CLAXEDO_SANDBOX_IMAGE || defaultSandboxImage();
84
- var SNAPSHOT_NAME = process.env.CLAXEDO_SNAPSHOT_NAME || defaultSnapshotName();
85
100
 
86
- // src/hosted-network-policy.ts
87
- var SANDBOX_MODEL_PROVIDER_HOSTS = [
88
- "api.anthropic.com",
89
- "api.openai.com",
90
- "generativelanguage.googleapis.com",
91
- "openrouter.ai",
92
- // Model catalog + engine config, fetched on runner startup.
93
- "models.dev",
94
- "opencode.ai"
95
- ];
96
- var SANDBOX_PACKAGE_REGISTRY_HOSTS = [
97
- "registry.npmjs.org",
98
- "nodejs.org",
99
- "pypi.org",
100
- "files.pythonhosted.org",
101
- "crates.io",
102
- "static.crates.io",
103
- "index.crates.io",
104
- "proxy.golang.org",
105
- "sum.golang.org"
106
- ];
107
- var SANDBOX_BASELINE_EGRESS_HOSTS = [
108
- ...SANDBOX_MODEL_PROVIDER_HOSTS,
109
- ...SANDBOX_PACKAGE_REGISTRY_HOSTS
110
- ];
101
+ // src/driver-billing.ts
102
+ var HOUR_SECONDS = 3600;
103
+ var boatBilling = {
104
+ source: { url: "https://docs.boat.dev/pricing", readOn: "2026-10-12" },
105
+ meter: "Boat bills machine time per second while a sandbox runs, at an hourly rate per size; a stopped sandbox costs nothing.",
106
+ rates: {
107
+ small: { size: "small", vcpu: 2, memoryGb: 4, usdPerHour: 0.018 },
108
+ default: { size: "default", vcpu: 4, memoryGb: 8, usdPerHour: 0.036 },
109
+ large: { size: "large", vcpu: 8, memoryGb: 16, usdPerHour: 0.072 }
110
+ }
111
+ };
112
+ var CLOUDFLARE_USD_PER_GIB_SECOND_MEMORY = 25e-7;
113
+ var CLOUDFLARE_USD_PER_GB_SECOND_DISK = 7e-8;
114
+ var CLOUDFLARE_USD_PER_VCPU_SECOND_ACTIVE = 2e-5;
115
+ var CLOUDFLARE_STANDARD_1 = { size: "standard-1", vcpu: 0.5, memoryGb: 4, diskGb: 8 };
116
+ var cloudflareBilling = {
117
+ source: { url: "https://developers.cloudflare.com/containers/pricing/", readOn: "2026-10-12" },
118
+ meter: "Cloudflare bills a container for every 10 ms it runs: memory at $0.0000025 per GiB-second and disk at $0.00000007 per GB-second for the whole run, plus CPU at $0.00002 per vCPU-second of active use.",
119
+ rates: {
120
+ default: {
121
+ size: CLOUDFLARE_STANDARD_1.size,
122
+ vcpu: CLOUDFLARE_STANDARD_1.vcpu,
123
+ memoryGb: CLOUDFLARE_STANDARD_1.memoryGb,
124
+ usdPerHour: (CLOUDFLARE_STANDARD_1.memoryGb * CLOUDFLARE_USD_PER_GIB_SECOND_MEMORY + CLOUDFLARE_STANDARD_1.diskGb * CLOUDFLARE_USD_PER_GB_SECOND_DISK) * HOUR_SECONDS
125
+ }
126
+ },
127
+ excludes: `active CPU, billed at $${CLOUDFLARE_USD_PER_VCPU_SECOND_ACTIVE} per vCPU-second and not measured by Claxedo, and the monthly allowance a Workers Paid plan includes`
128
+ };
111
129
 
112
130
  // ../sandbox-contract/dist/index.mjs
113
131
  var sandboxDriverCredentialFields = {
114
- exe: [{ key: "api_token", label: "API Token", secret: true }],
115
- daytona: [{ key: "api_key", label: "API Key", secret: true }],
116
132
  modal: [
117
133
  { key: "token_id", label: "Token ID", secret: true },
118
134
  { key: "token_secret", label: "Token Secret", secret: true }
@@ -126,68 +142,26 @@ var sandboxDriverCredentialFields = {
126
142
  { key: "api_token", label: "API Token", secret: true },
127
143
  { key: "worker_url", label: "Worker URL" }
128
144
  ],
129
- box: [{ key: "api_key", label: "API Key", secret: true }],
145
+ boat: [{ key: "api_key", label: "API Key", secret: true }],
130
146
  docker: [{ key: "image", label: "Image" }]
131
147
  };
132
148
  var sandboxDriverLabels = {
133
- exe: "exe.dev",
134
- daytona: "Daytona",
135
149
  modal: "Modal",
136
150
  vercel: "Vercel",
137
151
  cloudflare: "Cloudflare",
138
- box: "Box",
152
+ boat: "Boat",
139
153
  docker: "Docker"
140
154
  };
141
155
 
142
156
  // src/driver-catalog.ts
143
157
  var sandboxDriverCatalog = {
144
- exe: {
145
- id: "exe",
146
- label: sandboxDriverLabels.exe,
147
- credentialFields: sandboxDriverCredentialFields.exe,
148
- metadata: {
149
- driverRunsIn: ["worker", "node"],
150
- hostStopBehavior: "not-supported",
151
- hostResumeBehavior: "same-host",
152
- targetAccess: "relay",
153
- secretBrokering: "none",
154
- egressControl: "none",
155
- persistence: {
156
- resume: "same-sandbox",
157
- capture: "none",
158
- clone: true,
159
- captureSource: "not-applicable",
160
- retention: "provider-managed",
161
- restoreMount: "same-resource"
162
- }
163
- }
164
- },
165
- daytona: {
166
- id: "daytona",
167
- label: sandboxDriverLabels.daytona,
168
- credentialFields: sandboxDriverCredentialFields.daytona,
169
- metadata: {
170
- driverRunsIn: ["worker", "node"],
171
- hostStopBehavior: "suspends-host",
172
- hostResumeBehavior: "same-host",
173
- targetAccess: "relay",
174
- secretBrokering: "native",
175
- // The driver translates names to domainAllowList, or addresses to networkAllowList.
176
- egressControl: "hosts-and-cidrs",
177
- persistence: {
178
- resume: "same-sandbox",
179
- capture: "filesystem",
180
- clone: false,
181
- captureSource: "preserved",
182
- retention: "provider-managed",
183
- restoreMount: "new-resource"
184
- }
185
- }
186
- },
187
158
  modal: {
188
159
  id: "modal",
189
160
  label: sandboxDriverLabels.modal,
190
161
  credentialFields: sandboxDriverCredentialFields.modal,
162
+ runtimeNetwork: { controlPlane: "direct", relay: "configured" },
163
+ runtimeEnv: "callback",
164
+ preparedImage: true,
191
165
  metadata: {
192
166
  driverRunsIn: ["node"],
193
167
  hostStopBehavior: "terminates-host",
@@ -210,6 +184,9 @@ var sandboxDriverCatalog = {
210
184
  id: "vercel",
211
185
  label: sandboxDriverLabels.vercel,
212
186
  credentialFields: sandboxDriverCredentialFields.vercel,
187
+ runtimeNetwork: { controlPlane: "direct", relay: "configured" },
188
+ runtimeEnv: "callback",
189
+ preparedImage: false,
213
190
  metadata: {
214
191
  driverRunsIn: ["node"],
215
192
  hostStopBehavior: "terminates-host",
@@ -232,30 +209,40 @@ var sandboxDriverCatalog = {
232
209
  id: "cloudflare",
233
210
  label: sandboxDriverLabels.cloudflare,
234
211
  credentialFields: sandboxDriverCredentialFields.cloudflare,
212
+ runtimeNetwork: { controlPlane: "direct", relay: "configured" },
213
+ runtimeEnv: "callback",
214
+ preparedImage: false,
215
+ billing: cloudflareBilling,
235
216
  metadata: {
236
217
  driverRunsIn: ["worker"],
237
- hostStopBehavior: "not-supported",
218
+ hostStopBehavior: "terminates-host",
238
219
  hostResumeBehavior: "same-host",
220
+ hostWatchesIdle: true,
239
221
  targetAccess: "relay",
240
222
  secretBrokering: "native",
241
223
  // Credential handlers do not restrict unrelated destinations.
242
224
  egressControl: "none",
225
+ // A container snapshot holds the whole root filesystem; the platform keeps it 30 days past its last restore and offers no deletion.
243
226
  persistence: {
244
227
  resume: "replacement-restore",
245
- capture: "directories",
228
+ capture: "filesystem",
246
229
  clone: false,
247
230
  captureSource: "preserved",
248
231
  retention: "provider-managed",
249
- restoreMount: "copy-on-write"
232
+ restoreMount: "new-resource"
250
233
  }
251
234
  }
252
235
  },
253
- box: {
254
- id: "box",
255
- label: sandboxDriverLabels.box,
256
- credentialFields: sandboxDriverCredentialFields.box,
236
+ boat: {
237
+ id: "boat",
238
+ label: sandboxDriverLabels.boat,
239
+ credentialFields: sandboxDriverCredentialFields.boat,
240
+ runtimeNetwork: { controlPlane: "direct", relay: "configured" },
241
+ runtimeEnv: "callback",
242
+ preparedImage: true,
243
+ billing: boatBilling,
257
244
  metadata: {
258
- driverRunsIn: ["node"],
245
+ driverRunsIn: ["worker", "node"],
259
246
  hostStopBehavior: "suspends-host",
260
247
  hostResumeBehavior: "same-host",
261
248
  targetAccess: "relay",
@@ -268,13 +255,17 @@ var sandboxDriverCatalog = {
268
255
  captureSource: "not-applicable",
269
256
  retention: "provider-managed",
270
257
  restoreMount: "same-resource"
271
- }
258
+ },
259
+ machineClasses: ["small", "default", "large"]
272
260
  }
273
261
  },
274
262
  docker: {
275
263
  id: "docker",
276
264
  label: sandboxDriverLabels.docker,
277
265
  credentialFields: sandboxDriverCredentialFields.docker,
266
+ runtimeNetwork: { controlPlane: "docker-host", relay: "configured" },
267
+ runtimeEnv: "callback",
268
+ preparedImage: true,
278
269
  metadata: {
279
270
  driverRunsIn: ["local"],
280
271
  hostStopBehavior: "terminates-host",
@@ -294,6 +285,19 @@ var sandboxDriverCatalog = {
294
285
  }
295
286
  };
296
287
 
288
+ // ../claxedo-helpers/dist/guards.mjs
289
+ function isRecord(value) {
290
+ return value !== null && typeof value === "object" && !Array.isArray(value);
291
+ }
292
+ function asRecord(value) {
293
+ return isRecord(value) ? value : void 0;
294
+ }
295
+
296
+ // src/json.ts
297
+ function num(input) {
298
+ return typeof input === "number" ? input : void 0;
299
+ }
300
+
297
301
  // src/drivers/transient-error.ts
298
302
  function textOf(input) {
299
303
  return typeof input === "string" ? input : "";
@@ -302,15 +306,18 @@ function driverErrorSignals(err) {
302
306
  const shaped = isRecord(err) ? err : {};
303
307
  const nested = isRecord(shaped.response) ? shaped.response : {};
304
308
  return {
305
- status: num(nested.status) ?? num(shaped.status),
309
+ // `response.status` is the axios shape; `statusCode` is what SDK-native
310
+ // error classes expose instead.
311
+ status: num(nested.status) ?? num(shaped.status) ?? num(shaped.statusCode),
306
312
  text: `${textOf(shaped.code)} ${textOf(shaped.name)} ${textOf(shaped.message)}`.toLowerCase()
307
313
  };
308
314
  }
309
315
  function isTransientDriverError(err, markers) {
310
- const { status, text: text2 } = driverErrorSignals(err);
316
+ const { status, text } = driverErrorSignals(err);
311
317
  if (status !== void 0 && status >= 500) return true;
312
- return markers.some((marker) => text2.includes(marker));
318
+ return markers.some((marker) => text.includes(marker));
313
319
  }
320
+ var TRANSIENT_DRIVER_RETRY_MS = 2e3;
314
321
 
315
322
  // src/drivers/modal.ts
316
323
  var DEFAULT_APP_NAME = "claxedo";
@@ -365,7 +372,7 @@ function createModalSandboxDriver(options) {
365
372
  host: "0.0.0.0",
366
373
  source: input.source,
367
374
  env: input.env,
368
- runner: options.runner,
375
+ nativeHarness: options.nativeHarness,
369
376
  controlEnv: options.controlEnv
370
377
  });
371
378
  }
@@ -383,10 +390,13 @@ function createModalSandboxDriver(options) {
383
390
  return { blockNetwork: true };
384
391
  }
385
392
  async function readyTarget(input, sandbox, hostId) {
386
- await sandbox.setTags(input.labels).catch(() => void 0);
387
- const tunnels = await sandbox.tunnels(tunnelTimeoutMs).catch(() => void 0);
393
+ await sandbox.setTags(input.labels);
394
+ const tunnels = await sandbox.tunnels(tunnelTimeoutMs).catch((error) => {
395
+ if (error instanceof Error && error.name === "SandboxTimeoutError") return void 0;
396
+ throw error;
397
+ });
388
398
  const tunnel = tunnels?.[runtimePort];
389
- if (!tunnel?.url) return { provisioning: true, retryAfterMs: 2e3 };
399
+ if (!tunnel?.url) return { provisioning: true, retryAfterMs: 0 };
390
400
  return {
391
401
  workspaceId: input.workspaceId,
392
402
  sandboxId: sandbox.sandboxId,
@@ -427,7 +437,7 @@ function createModalSandboxDriver(options) {
427
437
  if (transientDriverError(err)) return void 0;
428
438
  throw err;
429
439
  });
430
- if (!sandbox) return { provisioning: true, retryAfterMs: 2e3 };
440
+ if (!sandbox) return { provisioning: true, retryAfterMs: TRANSIENT_DRIVER_RETRY_MS };
431
441
  return readyTarget(input, sandbox, hostId);
432
442
  }
433
443
  async function sandboxById(target) {
@@ -9,3 +9,5 @@ export declare function driverErrorSignals(err: unknown): {
9
9
  * seen its own SDK produce.
10
10
  */
11
11
  export declare function isTransientDriverError(err: unknown, markers: readonly string[]): boolean;
12
+ /** How long a driver waits before asking a provider again after a failure `isTransientDriverError` admits, so a provider in trouble is not asked at once. */
13
+ export declare const TRANSIENT_DRIVER_RETRY_MS = 2000;
@@ -1,5 +1,6 @@
1
1
  import type { NetworkPolicy } from "@vercel/sandbox";
2
- import { type SandboxBrokeredSecret, type SandboxDriver, type SandboxDriverEnsureInput } from "..";
2
+ import { type SandboxDriver, type SandboxDriverEnsureInput } from "../contract";
3
+ import { type SandboxBrokeredSecret } from "../egress-policy";
3
4
  import { type WorkspaceRuntimeControlEnv } from "../runtime-env";
4
5
  type VercelSnapshotLike = {
5
6
  snapshotId: string;
@@ -80,7 +81,7 @@ export type VercelSandboxDriverOptions = {
80
81
  runtimePort?: number;
81
82
  runtimeCommand?: string;
82
83
  workspaceDir?: string;
83
- runner?: string;
84
+ nativeHarness?: string;
84
85
  controlEnv?: WorkspaceRuntimeControlEnv;
85
86
  env?: (input: SandboxDriverEnsureInput, host: {
86
87
  id: string;