sandbox 3.0.2 → 3.1.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.
@@ -3102,13 +3102,13 @@ var require_ms = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/ms@2.1
3102
3102
  * @return {String}
3103
3103
  * @api private
3104
3104
  */
3105
- function fmtShort(ms$6) {
3106
- var msAbs = Math.abs(ms$6);
3107
- if (msAbs >= d) return Math.round(ms$6 / d) + "d";
3108
- if (msAbs >= h) return Math.round(ms$6 / h) + "h";
3109
- if (msAbs >= m) return Math.round(ms$6 / m) + "m";
3110
- if (msAbs >= s) return Math.round(ms$6 / s) + "s";
3111
- return ms$6 + "ms";
3105
+ function fmtShort(ms$7) {
3106
+ var msAbs = Math.abs(ms$7);
3107
+ if (msAbs >= d) return Math.round(ms$7 / d) + "d";
3108
+ if (msAbs >= h) return Math.round(ms$7 / h) + "h";
3109
+ if (msAbs >= m) return Math.round(ms$7 / m) + "m";
3110
+ if (msAbs >= s) return Math.round(ms$7 / s) + "s";
3111
+ return ms$7 + "ms";
3112
3112
  }
3113
3113
  /**
3114
3114
  * Long format for `ms`.
@@ -3117,20 +3117,20 @@ var require_ms = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/ms@2.1
3117
3117
  * @return {String}
3118
3118
  * @api private
3119
3119
  */
3120
- function fmtLong(ms$6) {
3121
- var msAbs = Math.abs(ms$6);
3122
- if (msAbs >= d) return plural(ms$6, msAbs, d, "day");
3123
- if (msAbs >= h) return plural(ms$6, msAbs, h, "hour");
3124
- if (msAbs >= m) return plural(ms$6, msAbs, m, "minute");
3125
- if (msAbs >= s) return plural(ms$6, msAbs, s, "second");
3126
- return ms$6 + " ms";
3120
+ function fmtLong(ms$7) {
3121
+ var msAbs = Math.abs(ms$7);
3122
+ if (msAbs >= d) return plural(ms$7, msAbs, d, "day");
3123
+ if (msAbs >= h) return plural(ms$7, msAbs, h, "hour");
3124
+ if (msAbs >= m) return plural(ms$7, msAbs, m, "minute");
3125
+ if (msAbs >= s) return plural(ms$7, msAbs, s, "second");
3126
+ return ms$7 + " ms";
3127
3127
  }
3128
3128
  /**
3129
3129
  * Pluralization helper.
3130
3130
  */
3131
- function plural(ms$6, msAbs, n, name) {
3131
+ function plural(ms$7, msAbs, n, name) {
3132
3132
  var isPlural = msAbs >= n * 1.5;
3133
- return Math.round(ms$6 / n) + " " + name + (isPlural ? "s" : "");
3133
+ return Math.round(ms$7 / n) + " " + name + (isPlural ? "s" : "");
3134
3134
  }
3135
3135
  }) });
3136
3136
 
@@ -7290,7 +7290,7 @@ const scope = {
7290
7290
 
7291
7291
  //#endregion
7292
7292
  //#region package.json
7293
- var version = "3.0.2";
7293
+ var version = "3.1.1";
7294
7294
 
7295
7295
  //#endregion
7296
7296
  //#region src/error.ts
@@ -11190,9 +11190,9 @@ function printCommand(command$1, args$5) {
11190
11190
 
11191
11191
  //#endregion
11192
11192
  //#region src/interactive-shell/extend-sandbox-timeout.ts
11193
- var import_ms$5 = /* @__PURE__ */ __toESM(require_ms());
11193
+ var import_ms$6 = /* @__PURE__ */ __toESM(require_ms());
11194
11194
  const debug$2 = createDebugger("sandbox:timeout");
11195
- const BUFFER = (0, import_ms$5.default)("10 seconds");
11195
+ const BUFFER = (0, import_ms$6.default)("10 seconds");
11196
11196
  async function extendSandboxTimeoutPeriodically(sandbox, signal) {
11197
11197
  const session = sandbox.currentSession();
11198
11198
  const timeout$1 = session.timeout;
@@ -11207,7 +11207,7 @@ async function extendSandboxTimeoutPeriodically(sandbox, signal) {
11207
11207
  debug$2(`sleeping for ${sleepMs}ms until next timeout extension`);
11208
11208
  await setTimeout$1(sleepMs, null, { signal });
11209
11209
  }
11210
- await sandbox.extendTimeout((0, import_ms$5.default)("5 minutes"));
11210
+ await sandbox.extendTimeout((0, import_ms$6.default)("5 minutes"));
11211
11211
  const updatedTimeout = session.timeout;
11212
11212
  if (updatedTimeout == null) return;
11213
11213
  const nextTick$1 = session.createdAt.getTime() + updatedTimeout;
@@ -11225,7 +11225,6 @@ const debugPty = createDebugger("sandbox:interactive-shell:pty");
11225
11225
  * That way, applications like `vim` and `nano` will work properly.
11226
11226
  */
11227
11227
  const TERM = "xterm-256color";
11228
- const neverResolvedPromise = new Promise(() => {});
11229
11228
  /**
11230
11229
  * Prepares the sandbox environment for interactive shell by installing required dependencies
11231
11230
  * and copying the TTY server script.
@@ -11234,18 +11233,17 @@ const neverResolvedPromise = new Promise(() => {});
11234
11233
  * @returns Promise that resolves when environment is ready
11235
11234
  */
11236
11235
  async function setupSandboxEnvironment(sandbox, ora$1) {
11236
+ let alreadyInstalled = false;
11237
11237
  try {
11238
- var _usingCtx$1 = _usingCtx();
11239
- const installed = _usingCtx$1.u(createAbortController(`Finished installation`));
11240
- const waitUntilInstalled = checkIfServerInstalled(sandbox, installed.signal).then((installed$1) => installed$1 ? void 0 : neverResolvedPromise, (err$1) => {
11241
- debug$1("Error checking if server is installed:", err$1);
11242
- });
11243
- await Promise.race([installServerBinary(sandbox, ora$1, installed.signal), waitUntilInstalled.then(() => debug$1("Server binary already installed"))]).catch(installed.ignoreInterruptions);
11244
- } catch (_) {
11245
- _usingCtx$1.e = _;
11246
- } finally {
11247
- _usingCtx$1.d();
11238
+ alreadyInstalled = await checkIfServerInstalled(sandbox);
11239
+ } catch (err$1) {
11240
+ debug$1("Error checking if server is installed:", err$1);
11248
11241
  }
11242
+ if (alreadyInstalled) {
11243
+ debug$1("Server binary already installed");
11244
+ return;
11245
+ }
11246
+ await installServerBinary(sandbox, ora$1);
11249
11247
  }
11250
11248
  async function checkIfServerInstalled(sandbox, signal) {
11251
11249
  return (await sandbox.runCommand({
@@ -11316,7 +11314,7 @@ async function startServerCommand(sandbox, _listener, execution, sudo, env$2, cw
11316
11314
  */
11317
11315
  async function startInteractiveShell(options) {
11318
11316
  try {
11319
- var _usingCtx3 = _usingCtx();
11317
+ var _usingCtx$1 = _usingCtx();
11320
11318
  const listener = createListener();
11321
11319
  let command$1 = null;
11322
11320
  let cleaned = false;
@@ -11332,14 +11330,14 @@ async function startInteractiveShell(options) {
11332
11330
  cleaned = true;
11333
11331
  };
11334
11332
  process.once("beforeExit", cleanup);
11335
- const _cleanup = _usingCtx3.u(defer(cleanup));
11336
- const progress = _usingCtx3.u(acquireRelease(() => ora({ discardStdin: false }).start(), (s$1) => s$1.clear()));
11333
+ const _cleanup = _usingCtx$1.u(defer(cleanup));
11334
+ const progress = _usingCtx$1.u(acquireRelease(() => ora({ discardStdin: false }).start(), (s$1) => s$1.stop()));
11337
11335
  progress.text = "Setting up sandbox environment";
11338
11336
  await setupSandboxEnvironment(options.sandbox, progress);
11339
11337
  progress.text = "Booting up interactive listener...";
11340
11338
  command$1 = await startServerCommand(options.sandbox, listener, options.execution, options.sudo, options.envVars, options.cwd);
11341
11339
  debug$1("startServerCommand completed, cmdId=%s, interactivePort=%s", command$1.cmdId, options.sandbox.interactivePort);
11342
- const waitForProcess = _usingCtx3.u(createAbortController("Connection established successfully"));
11340
+ const waitForProcess = _usingCtx$1.u(createAbortController("Connection established successfully"));
11343
11341
  listener.connection.then(() => {
11344
11342
  debug$1("listener.connection resolved");
11345
11343
  waitForProcess.abort();
@@ -11348,35 +11346,41 @@ async function startInteractiveShell(options) {
11348
11346
  if (waitForProcess.signal.aborted) return;
11349
11347
  listener.stdoutStream.destroy(err$1 instanceof Error ? err$1 : new Error(String(err$1)));
11350
11348
  });
11351
- await Promise.all([throwIfCommandPrematurelyExited(command$1, waitForProcess.signal), attach({
11349
+ await Promise.all([throwIfCommandPrematurelyExited(command$1, waitForProcess.signal).catch(waitForProcess.ignoreInterruptions), attach({
11352
11350
  sandbox: options.sandbox,
11353
11351
  progress,
11354
11352
  listener,
11355
11353
  skipExtendingTimeout: options.skipExtendingTimeout,
11356
11354
  printCommand: () => console.error(printCommand(options.execution[0], options.execution.slice(1)))
11357
- })]).catch(waitForProcess.ignoreInterruptions);
11355
+ })]);
11358
11356
  } catch (_) {
11359
- _usingCtx3.e = _;
11357
+ _usingCtx$1.e = _;
11360
11358
  } finally {
11361
- _usingCtx3.d();
11359
+ _usingCtx$1.d();
11362
11360
  }
11363
11361
  }
11364
11362
  async function throwIfCommandPrematurelyExited(command$1, signal) {
11363
+ let exitCode;
11365
11364
  try {
11366
- const { exitCode } = await command$1.wait({ signal });
11367
- throw new Error([
11368
- `Interactive shell failed to start (exit code: ${exitCode}).`,
11369
- `${source_default.bold("hint:")} The sandbox may have timed out or encountered an error.`,
11370
- "╰▶ Check sandbox status with `sandbox list` or view logs for details."
11371
- ].join("\n"));
11365
+ ({exitCode} = await command$1.wait({ signal }));
11372
11366
  } catch (err$1) {
11373
11367
  if (signal.aborted) return;
11374
11368
  throw err$1;
11375
11369
  }
11370
+ let serverError = "";
11371
+ try {
11372
+ serverError = (await command$1.stderr({ signal })).trim();
11373
+ } catch {}
11374
+ throw new Error([
11375
+ `Interactive shell failed to start (exit code: ${exitCode}).`,
11376
+ `${source_default.bold("hint:")} The sandbox may have timed out or encountered an error.`,
11377
+ ...serverError ? [source_default.dim(serverError)] : [],
11378
+ "╰▶ Check sandbox status with `sandbox list` or view logs for details."
11379
+ ].join("\n"));
11376
11380
  }
11377
11381
  async function attach({ progress, listener, printCommand: printCommand$1, sandbox, skipExtendingTimeout }) {
11378
11382
  try {
11379
- var _usingCtx4 = _usingCtx();
11383
+ var _usingCtx3 = _usingCtx();
11380
11384
  progress.text = "Waiting for connection...";
11381
11385
  const details = await listener.connection;
11382
11386
  assert(sandbox.interactivePort, "Sandbox interactive port is not defined");
@@ -11391,7 +11395,7 @@ async function attach({ progress, listener, printCommand: printCommand$1, sandbo
11391
11395
  return c$1;
11392
11396
  });
11393
11397
  progress.stop();
11394
- const extensionController = _usingCtx4.u(createAbortController("stopped extensions"));
11398
+ const extensionController = _usingCtx3.u(createAbortController("stopped extensions"));
11395
11399
  if (!skipExtendingTimeout) extendSandboxTimeoutPeriodically(sandbox, extensionController.signal).catch(extensionController.ignoreInterruptions);
11396
11400
  client.sendMessage({ type: "ready" });
11397
11401
  client.sendMessage({
@@ -11417,9 +11421,9 @@ async function attach({ progress, listener, printCommand: printCommand$1, sandbo
11417
11421
  client.close();
11418
11422
  console.error(source_default.dim(`\n╰▶ connection to ▲ ${sandbox.name} closed.`));
11419
11423
  } catch (_) {
11420
- _usingCtx4.e = _;
11424
+ _usingCtx3.e = _;
11421
11425
  } finally {
11422
- _usingCtx4.d();
11426
+ _usingCtx3.d();
11423
11427
  }
11424
11428
  }
11425
11429
  /**
@@ -11447,16 +11451,16 @@ async function* messageReader(stream) {
11447
11451
  */
11448
11452
  async function connect$1(command$1, listener, signal) {
11449
11453
  try {
11450
- var _usingCtx5 = _usingCtx();
11451
- const logs = _usingCtx5.u(command$1.logs({ signal }));
11452
- const stderrStream = _usingCtx5.u(getStderrStream());
11454
+ var _usingCtx4 = _usingCtx();
11455
+ const logs = _usingCtx4.u(command$1.logs({ signal }));
11456
+ const stderrStream = _usingCtx4.u(getStderrStream());
11453
11457
  for await (const chunk of logs) if (chunk.stream === "stdout") listener.stdoutStream.write(chunk.data);
11454
11458
  else stderrStream.write(chunk.data);
11455
11459
  listener.stdoutStream.end();
11456
11460
  } catch (_) {
11457
- _usingCtx5.e = _;
11461
+ _usingCtx4.e = _;
11458
11462
  } finally {
11459
- _usingCtx5.d();
11463
+ _usingCtx4.d();
11460
11464
  }
11461
11465
  }
11462
11466
  async function openWithRetry(create$1) {
@@ -11480,11 +11484,11 @@ async function openWithRetry(create$1) {
11480
11484
  factor: 0
11481
11485
  });
11482
11486
  }
11483
- function withTimeout(promise, ms$6) {
11487
+ function withTimeout(promise, ms$7) {
11484
11488
  promise.catch(() => {});
11485
11489
  let timer;
11486
11490
  const timeout$1 = new Promise((_, reject) => {
11487
- timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Operation timed out after ${ms$6}ms`)), ms$6);
11491
+ timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Operation timed out after ${ms$7}ms`)), ms$7);
11488
11492
  });
11489
11493
  return Promise.race([promise, timeout$1]).finally(() => {
11490
11494
  if (timer) clearTimeout(timer);
@@ -11545,6 +11549,7 @@ const ObjectFromKeyValue = import_cjs$18.extendType(import_cjs$18.array(KeyValue
11545
11549
  //#endregion
11546
11550
  //#region src/commands/exec.ts
11547
11551
  var import_cjs$17 = /* @__PURE__ */ __toESM(require_cjs());
11552
+ var import_ms$5 = /* @__PURE__ */ __toESM(require_ms());
11548
11553
  init_source();
11549
11554
  const args$4 = {
11550
11555
  sandbox: import_cjs$17.positional({ type: sandboxName }),
@@ -11595,18 +11600,25 @@ const args$4 = {
11595
11600
  type: ObjectFromKeyValue,
11596
11601
  description: "Environment variables to set for the command"
11597
11602
  }),
11603
+ timeout: import_cjs$17.option({
11604
+ long: "timeout",
11605
+ type: import_cjs$17.optional(Duration),
11606
+ description: "Maximum duration to wait for the command (e.g. 30s, 5m). On expiry the process is killed with SIGKILL. Cannot be combined with --interactive."
11607
+ }),
11598
11608
  scope
11599
11609
  };
11600
11610
  const exec = import_cjs$17.command({
11601
11611
  name: "exec",
11602
11612
  description: "Execute a command in an existing sandbox",
11603
11613
  args: args$4,
11604
- async handler({ command: command$1, cwd, args: args$5, asSudo, sandbox: sandboxName$1, scope: { token: token$1, team: team$1, project: project$1 }, interactive, envVars, skipExtendingTimeout }) {
11614
+ async handler({ command: command$1, cwd, args: args$5, asSudo, sandbox: sandboxName$1, scope: { token: token$1, team: team$1, project: project$1 }, interactive, envVars, skipExtendingTimeout, timeout: timeout$1 }) {
11615
+ if (interactive && timeout$1) throw new Error(["--timeout cannot be combined with --interactive.", `${source_default.bold("hint:")} Remove one of the two flags. Interactive sessions do not enforce a command timeout.`].join("\n"));
11605
11616
  const sandbox = typeof sandboxName$1 !== "string" ? sandboxName$1 : await sandboxClient.get({
11606
11617
  name: sandboxName$1,
11607
11618
  projectId: project$1,
11608
11619
  teamId: team$1,
11609
11620
  token: token$1,
11621
+ resume: true,
11610
11622
  __includeSystemRoutes: true
11611
11623
  });
11612
11624
  if (!interactive) {
@@ -11618,8 +11630,10 @@ const exec = import_cjs$17.command({
11618
11630
  stdout: process.stdout,
11619
11631
  sudo: asSudo,
11620
11632
  cwd,
11621
- env: envVars
11633
+ env: envVars,
11634
+ timeoutMs: timeout$1 ? (0, import_ms$5.default)(timeout$1) : void 0
11622
11635
  });
11636
+ if (timeout$1 && result.exitCode === 137) console.error(`${source_default.yellow("Command was killed (SIGKILL, exit code 137)")}.`);
11623
11637
  process.exitCode = result.exitCode;
11624
11638
  } else await startInteractiveShell({
11625
11639
  sandbox,
@@ -11889,7 +11903,8 @@ const create = import_cjs$15.command({
11889
11903
  command: "sh",
11890
11904
  interactive: true,
11891
11905
  tty: true,
11892
- sandbox
11906
+ sandbox,
11907
+ timeout: void 0
11893
11908
  });
11894
11909
  return sandbox;
11895
11910
  }
@@ -12010,7 +12025,8 @@ const fork = import_cjs$14.command({
12010
12025
  command: "sh",
12011
12026
  interactive: true,
12012
12027
  tty: true,
12013
- sandbox
12028
+ sandbox,
12029
+ timeout: void 0
12014
12030
  });
12015
12031
  return sandbox;
12016
12032
  }
@@ -12029,7 +12045,7 @@ function omit(obj, ...keys) {
12029
12045
  var import_cjs$13 = /* @__PURE__ */ __toESM(require_cjs());
12030
12046
  const args$1 = {
12031
12047
  ...args$3,
12032
- ...omit(args$4, "sandbox"),
12048
+ ...omit(args$4, "sandbox", "timeout"),
12033
12049
  removeAfterUse: import_cjs$13.flag({
12034
12050
  long: "rm",
12035
12051
  description: "Automatically remove the sandbox when the command exits."
@@ -12069,7 +12085,8 @@ const run = import_cjs$13.command({
12069
12085
  try {
12070
12086
  await exec.handler({
12071
12087
  ...rest$1,
12072
- sandbox
12088
+ sandbox,
12089
+ timeout: void 0
12073
12090
  });
12074
12091
  } finally {
12075
12092
  if (removeAfterUse) await sandbox.delete();
@@ -14798,10 +14815,10 @@ const snapshot = import_cjs$6.command({
14798
14815
  init_source();
14799
14816
  function formatExpires(expiresAt) {
14800
14817
  if (expiresAt === void 0) return source_default.gray("never");
14801
- const ms$6 = expiresAt - Date.now();
14802
- if (ms$6 <= 0) return source_default.red("expired");
14818
+ const ms$7 = expiresAt - Date.now();
14819
+ if (ms$7 <= 0) return source_default.red("expired");
14803
14820
  const formatted = timeAgo(expiresAt);
14804
- return ms$6 <= 3600 * 1e3 ? source_default.red(formatted) : source_default.green(formatted);
14821
+ return ms$7 <= 3600 * 1e3 ? source_default.red(formatted) : source_default.green(formatted);
14805
14822
  }
14806
14823
  function renderNode(id, expiresAt, isCurrent) {
14807
14824
  const bullet = isCurrent ? source_default.magenta.bold("●") : source_default.magenta("●");
@@ -15860,4 +15877,4 @@ const app = (opts) => (0, import_cjs.subcommands)({
15860
15877
 
15861
15878
  //#endregion
15862
15879
  export { source_exports as a, init_source as i, StyledError as n, require_cjs as r, app as t };
15863
- //# sourceMappingURL=app-C9tVyCZD.mjs.map
15880
+ //# sourceMappingURL=app-DWpJmO_S.mjs.map