@deepagents/context 6.0.0 → 6.1.2

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.
package/README.md CHANGED
@@ -32,6 +32,8 @@ with `createVirtualSandbox()`, `createDockerSandbox()`,
32
32
  `createDaytonaSandbox(client, options)`, or `createAgentOsSandbox()` depending
33
33
  on whether commands should run in memory, Docker, Apple Container lightweight
34
34
  VMs, Microsandbox microVMs, managed Daytona sandboxes, or Agent OS.
35
+ Virtual sandboxes can opt into in-process JavaScript execution with
36
+ `createVirtualSandbox({ javascript: true, ... })`.
35
37
 
36
38
  See the docs for the full API surface:
37
39
 
@@ -315,8 +317,9 @@ points.
315
317
  For `target: 'tool-output'`, use `toolOutput(...)` or inspect
316
318
  `ctx.toolOutcome`. The outcome is available after a tool reaches
317
319
  `output-available`, `output-error`, or `output-denied`, but before the next model
318
- generation. Assistant-history predicates such as `toolCalled(...)` only
319
- describe already persisted calls.
320
+ generation. Assistant-history predicates such as `toolCalled(...)` describe
321
+ tool parts visible in the current assistant segment; use `toolOutput(...)` when
322
+ you need the raw outcome currently being evaluated.
320
323
 
321
324
  ```ts
322
325
  import {
package/dist/index.js CHANGED
@@ -840,6 +840,7 @@ import { getErrorMessage } from "@ai-sdk/provider";
840
840
  import {
841
841
  convertToModelMessages as convertToModelMessages2,
842
842
  generateId as generateId5,
843
+ isStaticToolUIPart as isStaticToolUIPart2,
843
844
  validateUIMessages
844
845
  } from "ai";
845
846
 
@@ -3959,6 +3960,58 @@ function toolOutcomesFromStep(content) {
3959
3960
  }
3960
3961
  return outcomes;
3961
3962
  }
3963
+ function terminalToolPartsFromStep(content) {
3964
+ return content.flatMap((part) => {
3965
+ if (part.type === "tool-result" && part.dynamic !== true) {
3966
+ return [
3967
+ {
3968
+ type: `tool-${part.toolName}`,
3969
+ toolCallId: part.toolCallId,
3970
+ state: "output-available",
3971
+ input: part.input,
3972
+ output: part.output === void 0 ? null : part.output
3973
+ }
3974
+ ];
3975
+ }
3976
+ if (part.type === "tool-error" && part.dynamic !== true) {
3977
+ return [
3978
+ {
3979
+ type: `tool-${part.toolName}`,
3980
+ toolCallId: part.toolCallId,
3981
+ state: "output-error",
3982
+ input: part.input,
3983
+ errorText: getErrorMessage(part.error)
3984
+ }
3985
+ ];
3986
+ }
3987
+ if (part.type === "tool-approval-response" && part.approved === false && part.toolCall.dynamic !== true) {
3988
+ return [
3989
+ {
3990
+ type: `tool-${part.toolCall.toolName}`,
3991
+ toolCallId: part.toolCall.toolCallId,
3992
+ state: "output-denied",
3993
+ input: part.toolCall.input,
3994
+ approval: {
3995
+ id: part.approvalId,
3996
+ approved: false,
3997
+ ...part.reason === void 0 ? {} : { reason: part.reason }
3998
+ }
3999
+ }
4000
+ ];
4001
+ }
4002
+ return [];
4003
+ });
4004
+ }
4005
+ function mergeTerminalToolParts(message2, liveParts) {
4006
+ const remaining = new Map(liveParts);
4007
+ const parts = message2.parts.map((part) => {
4008
+ if (!isStaticToolUIPart2(part)) return part;
4009
+ remaining.delete(part.toolCallId);
4010
+ return part;
4011
+ });
4012
+ parts.push(...remaining.values());
4013
+ return { ...message2, parts };
4014
+ }
3962
4015
  var ContextEngine = class _ContextEngine {
3963
4016
  /** Non-message fragments (role, hints, etc.) - not persisted in graph */
3964
4017
  #fragments = [];
@@ -4371,12 +4424,24 @@ var ContextEngine = class _ContextEngine {
4371
4424
  const enableSteer = options.steer ?? true;
4372
4425
  const session = {
4373
4426
  firedOnceIds: /* @__PURE__ */ new Set(),
4374
- currentSegStart: 0
4427
+ terminalToolParts: /* @__PURE__ */ new Map(),
4428
+ segments: [],
4429
+ initialStepStarts: null,
4430
+ stepOffset: 0,
4431
+ lastStepNumber: null
4375
4432
  };
4376
4433
  this.#currentReminderSession = session;
4377
4434
  return async ({ steps, stepNumber, messages }) => {
4435
+ if (stepNumber === 0 && session.lastStepNumber !== null) {
4436
+ session.stepOffset += session.lastStepNumber + 1;
4437
+ }
4438
+ session.lastStepNumber = stepNumber;
4439
+ const completedSteps = session.stepOffset + stepNumber;
4378
4440
  const priorStep = stepNumber >= 1 ? steps[stepNumber - 1] : void 0;
4379
4441
  const hasSafeBoundary = (priorStep?.content?.length ?? 0) > 0;
4442
+ for (const part of terminalToolPartsFromStep(priorStep?.content ?? [])) {
4443
+ session.terminalToolParts.set(part.toolCallId, part);
4444
+ }
4380
4445
  const canFire = enableSteer && hasSafeBoundary;
4381
4446
  const steerConfigs = canFire ? this.#remindersFor("steer") : [];
4382
4447
  const outcomes = toolOutcomesFromStep(steps.at(-1)?.content ?? []);
@@ -4435,18 +4500,24 @@ var ContextEngine = class _ContextEngine {
4435
4500
  "createPrepareStep: expected an assistant message at chain head."
4436
4501
  );
4437
4502
  }
4438
- const currentSegmentId = session.currentSegId ?? head.id;
4503
+ const currentSegmentId = head.id;
4439
4504
  const currentSegment = await this.#store.getMessage(currentSegmentId);
4440
4505
  if (!currentSegment || currentSegment.name !== "assistant") {
4441
4506
  throw new Error(
4442
4507
  "createPrepareStep: expected the open assistant segment to be persisted."
4443
4508
  );
4444
4509
  }
4445
- const currentMessage = requireUIMessage(
4510
+ requireUIMessage(
4446
4511
  currentSegment.data,
4447
4512
  `Stored assistant message "${currentSegment.id}"`
4448
4513
  );
4449
4514
  const nextSegmentId = generateId5();
4515
+ if (session.segments.length === 0) {
4516
+ session.segments.push({
4517
+ id: currentSegmentId,
4518
+ startStep: 0
4519
+ });
4520
+ }
4450
4521
  for (const input of inputs) this.set(user(input));
4451
4522
  this.set(
4452
4523
  assistant({
@@ -4456,8 +4527,11 @@ var ContextEngine = class _ContextEngine {
4456
4527
  })
4457
4528
  );
4458
4529
  await this.save({ branch: false });
4459
- session.currentSegId = nextSegmentId;
4460
- session.currentSegStart += currentMessage.parts.length;
4530
+ session.segments.push({
4531
+ id: nextSegmentId,
4532
+ startStep: completedSteps
4533
+ });
4534
+ session.terminalToolParts.clear();
4461
4535
  return {
4462
4536
  messages: [...messages, ...inputModel]
4463
4537
  };
@@ -4482,14 +4556,81 @@ var ContextEngine = class _ContextEngine {
4482
4556
  );
4483
4557
  }
4484
4558
  const session = this.#currentReminderSession;
4485
- this.set(
4486
- assistant({
4487
- ...message2,
4488
- id: session?.currentSegId ?? head.id,
4489
- parts: message2.parts.slice(session?.currentSegStart ?? 0)
4490
- })
4491
- );
4492
- await this.save({ branch: false });
4559
+ let id = head.id;
4560
+ let parts = message2.parts;
4561
+ if (session) {
4562
+ if (session.initialStepStarts === null) {
4563
+ const initialId = session.segments[0]?.id ?? head.id;
4564
+ const initial = await this.#store.getMessage(initialId);
4565
+ if (!initial || initial.name !== "assistant") {
4566
+ throw new Error(
4567
+ `writeAssistantSegment: initial segment "${initialId}" was not found`
4568
+ );
4569
+ }
4570
+ session.initialStepStarts = requireUIMessage(
4571
+ initial.data,
4572
+ `Stored assistant message "${initial.id}"`
4573
+ ).parts.filter((part) => part.type === "step-start").length;
4574
+ }
4575
+ const streamStepStarts = message2.parts.flatMap(
4576
+ (part, index) => part.type === "step-start" ? [index] : []
4577
+ );
4578
+ const completedSteps = streamStepStarts.length - session.initialStepStarts;
4579
+ if (completedSteps < 0) {
4580
+ throw new Error(
4581
+ "writeAssistantSegment: response lost an existing step boundary"
4582
+ );
4583
+ }
4584
+ const segmentIndex = session.segments.findLastIndex(
4585
+ (candidate) => candidate.startStep < completedSteps
4586
+ );
4587
+ if (segmentIndex >= 0) {
4588
+ const segment = session.segments[segmentIndex];
4589
+ id = segment.id;
4590
+ if (segmentIndex > 0) {
4591
+ const start = streamStepStarts[session.initialStepStarts + segment.startStep];
4592
+ if (start === void 0) {
4593
+ throw new Error(
4594
+ `writeAssistantSegment: response is missing step ${segment.startStep + 1}`
4595
+ );
4596
+ }
4597
+ parts = message2.parts.slice(start);
4598
+ }
4599
+ } else {
4600
+ const lastSegment = session.segments.at(-1);
4601
+ if (lastSegment) {
4602
+ id = lastSegment.id;
4603
+ parts = [];
4604
+ }
4605
+ }
4606
+ }
4607
+ const fragment2 = assistant({
4608
+ ...message2,
4609
+ id,
4610
+ parts
4611
+ });
4612
+ if (!session) {
4613
+ this.set(fragment2);
4614
+ await this.save({ branch: false });
4615
+ return;
4616
+ }
4617
+ const stored = await this.#store.getMessage(id);
4618
+ if (!stored) {
4619
+ throw new Error(
4620
+ `writeAssistantSegment: reserved segment "${id}" was not found`
4621
+ );
4622
+ }
4623
+ if (!fragment2.codec) {
4624
+ throw new Error("writeAssistantSegment: assistant codec is missing");
4625
+ }
4626
+ await this.#store.addMessages([
4627
+ {
4628
+ ...stored,
4629
+ name: fragment2.name,
4630
+ type: fragment2.type,
4631
+ data: fragment2.codec.encode()
4632
+ }
4633
+ ]);
4493
4634
  }
4494
4635
  #remindersFor(target) {
4495
4636
  return this.#fragments.filter(isConditionalReminder).map((fragment2) => fragment2.metadata.reminder).filter((config) => config.target === target);
@@ -4590,8 +4731,16 @@ var ContextEngine = class _ContextEngine {
4590
4731
  "steer reminders require a user message earlier in the turn"
4591
4732
  );
4592
4733
  }
4734
+ const lastAssistantMessage = chain.lastAssistantMessage;
4735
+ if (!lastAssistantMessage) {
4736
+ throw new Error("steer reminders require a completed assistant step");
4737
+ }
4593
4738
  return {
4594
4739
  ...this.#buildWhenCtx(chain, currentMessage),
4740
+ lastAssistantMessage: mergeTerminalToolParts(
4741
+ lastAssistantMessage,
4742
+ session.terminalToolParts
4743
+ ),
4595
4744
  sandbox,
4596
4745
  firedOnceIds: /* @__PURE__ */ new Set([...chain.firedOnceIds, ...session.firedOnceIds])
4597
4746
  };
@@ -6557,7 +6706,7 @@ function startKernelProcess(os, command, options) {
6557
6706
  const stderr = new PassThrough();
6558
6707
  const onStdout = (chunk) => stdout.write(chunk);
6559
6708
  const onStderr = (chunk) => stderr.write(chunk);
6560
- const { pid } = os.spawn("sh", ["-c", command], {
6709
+ const { pid } = os.spawn("bash", ["-lc", command], {
6561
6710
  ...options,
6562
6711
  onStdout,
6563
6712
  onStderr
@@ -6610,6 +6759,25 @@ async function createAgentOsSandbox(options = {}) {
6610
6759
  const err = error instanceof Error ? error : new Error(String(error));
6611
6760
  throw new AgentOsCreationError(err.message, err);
6612
6761
  }
6762
+ try {
6763
+ const probe = startKernelProcess(os, ":", {});
6764
+ const [, stderr, exitCode] = await Promise.all([
6765
+ readAll(probe.stdout),
6766
+ readAll(probe.stderr),
6767
+ probe.exit
6768
+ ]);
6769
+ if (exitCode !== 0) {
6770
+ throw new Error(stderr.trim() || `exit code ${exitCode}`);
6771
+ }
6772
+ } catch (error) {
6773
+ await os.dispose().catch(() => {
6774
+ });
6775
+ const err = error instanceof Error ? error : new Error(String(error));
6776
+ throw new AgentOsCreationError(
6777
+ `Bash is required to execute sandbox commands but could not be started: ${err.message}`,
6778
+ err
6779
+ );
6780
+ }
6613
6781
  const sandbox = {
6614
6782
  async executeCommand(command, { signal } = {}) {
6615
6783
  if (signal?.aborted) {
@@ -7143,6 +7311,7 @@ var ContainerSandboxStrategy = class {
7143
7311
  await this.engine.ensureWorkdir(this.context.containerId, this.workdir);
7144
7312
  await this.configure();
7145
7313
  }
7314
+ await this.assertBashAvailable();
7146
7315
  } catch (error) {
7147
7316
  if (acquired && !acquired.attached) {
7148
7317
  await this.stopContainer(acquired.containerId);
@@ -7441,6 +7610,15 @@ var ContainerSandboxStrategy = class {
7441
7610
  };
7442
7611
  }
7443
7612
  }
7613
+ async assertBashAvailable() {
7614
+ const result = await this.exec(":");
7615
+ if (result.exitCode === 0) return;
7616
+ const detail = result.stderr.trim() || result.stdout.trim();
7617
+ throw this.engine.errors.generic(
7618
+ `Bash is required to execute sandbox commands but could not be started${detail ? `: ${detail}` : "."}`,
7619
+ this.context.containerId
7620
+ );
7621
+ }
7444
7622
  spawnProcess(command, options) {
7445
7623
  const child = childSpawn(
7446
7624
  this.engine.cli,
@@ -7632,7 +7810,7 @@ var appleEngine = {
7632
7810
  flags.push("--env", `${key}=${value}`);
7633
7811
  }
7634
7812
  }
7635
- return ["exec", ...flags, containerId, "sh", "-c", command];
7813
+ return ["exec", ...flags, containerId, "bash", "-lc", command];
7636
7814
  },
7637
7815
  inspectArgs(containerId) {
7638
7816
  return ["inspect", containerId];
@@ -7661,9 +7839,15 @@ var appleEngine = {
7661
7839
  return /already exists/i.test(message2);
7662
7840
  },
7663
7841
  async ensureWorkdir(containerId, workdir) {
7664
- await spawn3(CLI, ["exec", containerId, "sh", "-c", `mkdir -p ${workdir}`]);
7842
+ await spawn3(CLI, [
7843
+ "exec",
7844
+ containerId,
7845
+ "bash",
7846
+ "-lc",
7847
+ `mkdir -p ${shellQuote(workdir)}`
7848
+ ]);
7665
7849
  },
7666
- defaultImage: "docker.io/library/alpine:latest",
7850
+ defaultImage: "docker.io/library/bash:5.3-alpine3.24",
7667
7851
  createInstallerContext: createAppleInstallerContext,
7668
7852
  async imageExists(tag) {
7669
7853
  try {
@@ -7878,6 +8062,7 @@ var KNOWN_TOOLS = /* @__PURE__ */ new Set([
7878
8062
  "head",
7879
8063
  "html-to-markdown",
7880
8064
  "iconv",
8065
+ "js-exec",
7881
8066
  "join",
7882
8067
  "jq",
7883
8068
  "node",
@@ -8022,6 +8207,7 @@ async function createToolPrompt(sandbox, filenames, customPrompt) {
8022
8207
  const available = new Set(
8023
8208
  result.stdout.split("\n").filter((entry) => KNOWN_TOOLS.has(entry))
8024
8209
  );
8210
+ if (available.has("js-exec")) available.delete("node");
8025
8211
  if (available.size === 0) return "";
8026
8212
  const lines = [
8027
8213
  `Available tools: ${[...available].sort().join(", ")}, and more`
@@ -8311,6 +8497,7 @@ async function createDaytonaSandbox(client, options = {}) {
8311
8497
  } catch (error) {
8312
8498
  throw normalizeDaytonaError(error, sdk);
8313
8499
  }
8500
+ await assertDaytonaBash(sandbox, options.commandTimeout);
8314
8501
  const backend = createDaytonaSandboxMethods({
8315
8502
  sandbox,
8316
8503
  commandTimeout: options.commandTimeout
@@ -8326,6 +8513,24 @@ async function createDaytonaSandbox(client, options = {}) {
8326
8513
  }
8327
8514
  return backend;
8328
8515
  }
8516
+ async function assertDaytonaBash(sandbox, commandTimeout) {
8517
+ try {
8518
+ const result = await sandbox.process.executeCommand(
8519
+ "bash -lc ':'",
8520
+ void 0,
8521
+ void 0,
8522
+ commandTimeout
8523
+ );
8524
+ if (result.exitCode === void 0 || result.exitCode === 0) return;
8525
+ throw new Error(result.result || `exit code ${result.exitCode}`);
8526
+ } catch (error) {
8527
+ const err = toError(error);
8528
+ throw new DaytonaCreationError(
8529
+ `Bash is required to execute sandbox commands but could not be started: ${err.message}`,
8530
+ err
8531
+ );
8532
+ }
8533
+ }
8329
8534
  var UNRECOVERABLE_SANDBOX_STATES = /* @__PURE__ */ new Set([
8330
8535
  "error",
8331
8536
  "build_failed",
@@ -8462,7 +8667,7 @@ function createDaytonaSandboxMethods(args) {
8462
8667
  return abortedCommandResult();
8463
8668
  }
8464
8669
  const response = await sandbox.process.executeCommand(
8465
- command,
8670
+ `bash -lc ${shellQuote(command)}`,
8466
8671
  void 0,
8467
8672
  void 0,
8468
8673
  commandTimeout
@@ -8704,13 +8909,13 @@ function buildSessionCommand(command, options) {
8704
8909
  const env = options.env ?? {};
8705
8910
  const entries = Object.entries(env);
8706
8911
  if (entries.length === 0) {
8707
- return `sh -lc ${shellQuote(`${cwdPrefix}${command}`)}`;
8912
+ return `bash -lc ${shellQuote(`${cwdPrefix}${command}`)}`;
8708
8913
  }
8709
8914
  for (const [key] of entries) {
8710
8915
  validateEnvKey(key);
8711
8916
  }
8712
8917
  const exports = entries.map(([key, value]) => `export ${key}=${shellQuote(value)}`).join("; ");
8713
- return `sh -lc ${shellQuote(`${exports}; ${cwdPrefix}${command}`)}`;
8918
+ return `bash -lc ${shellQuote(`${exports}; ${cwdPrefix}${command}`)}`;
8714
8919
  }
8715
8920
  function validateEnvKey(key) {
8716
8921
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
@@ -8950,7 +9155,7 @@ var dockerEngine = {
8950
9155
  flags.push("-e", `${key}=${value}`);
8951
9156
  }
8952
9157
  }
8953
- return ["exec", ...flags, containerId, "sh", "-c", command];
9158
+ return ["exec", ...flags, containerId, "bash", "-lc", command];
8954
9159
  },
8955
9160
  inspectArgs(containerId) {
8956
9161
  return [
@@ -8993,7 +9198,7 @@ var dockerEngine = {
8993
9198
  },
8994
9199
  async ensureWorkdir() {
8995
9200
  },
8996
- defaultImage: "alpine:latest",
9201
+ defaultImage: "bash:5.3-alpine3.24",
8997
9202
  createInstallerContext,
8998
9203
  async imageExists(tag) {
8999
9204
  try {
@@ -9103,8 +9308,8 @@ var ComposeStrategy = class extends ContainerSandboxStrategy {
9103
9308
  "exec",
9104
9309
  "-T",
9105
9310
  this.service,
9106
- "sh",
9107
- "-c",
9311
+ "bash",
9312
+ "-lc",
9108
9313
  command
9109
9314
  ],
9110
9315
  { signal: options?.signal }
@@ -9130,8 +9335,8 @@ var ComposeStrategy = class extends ContainerSandboxStrategy {
9130
9335
  "-T",
9131
9336
  ...buildDockerExecFlags(options),
9132
9337
  this.service,
9133
- "sh",
9134
- "-c",
9338
+ "bash",
9339
+ "-lc",
9135
9340
  command
9136
9341
  ]);
9137
9342
  return toSandboxProcess(child, options?.signal);
@@ -9189,10 +9394,10 @@ import spawn6 from "nano-spawn";
9189
9394
  import { posix as posix2 } from "node:path";
9190
9395
  var STRACE_FLAGS = "-f -y -qq -e trace=%file,write,pwrite64,writev";
9191
9396
  function buildStraceCommand(command, traceFile, traceDir) {
9192
- return `mkdir -p ${shellQuote(traceDir)} 2>/dev/null; strace ${STRACE_FLAGS} -o ${shellQuote(traceFile)} -- sh -c ${shellQuote(command)}`;
9397
+ return `mkdir -p ${shellQuote(traceDir)} 2>/dev/null; strace ${STRACE_FLAGS} -o ${shellQuote(traceFile)} -- bash -lc ${shellQuote(command)}`;
9193
9398
  }
9194
9399
  function buildTracedCommand(command, traceFile, traceDir, sentinel) {
9195
- return `mkdir -p ${shellQuote(traceDir)} 2>/dev/null; strace ${STRACE_FLAGS} -o ${shellQuote(traceFile)} -- sh -c ${shellQuote(command)}; __dat_rc=$?; printf '\\n%s\\n' ${shellQuote(sentinel)}; base64 ${shellQuote(traceFile)} 2>/dev/null; rm -f ${shellQuote(traceFile)} 2>/dev/null; exit $__dat_rc`;
9400
+ return `mkdir -p ${shellQuote(traceDir)} 2>/dev/null; strace ${STRACE_FLAGS} -o ${shellQuote(traceFile)} -- bash -lc ${shellQuote(command)}; __dat_rc=$?; printf '\\n%s\\n' ${shellQuote(sentinel)}; base64 ${shellQuote(traceFile)} 2>/dev/null; rm -f ${shellQuote(traceFile)} 2>/dev/null; exit $__dat_rc`;
9196
9401
  }
9197
9402
  function splitTracedOutput(stdout, sentinel) {
9198
9403
  const marker = `
@@ -9815,7 +10020,7 @@ function formatVersion(version) {
9815
10020
  // packages/context/src/lib/sandbox/microsandbox-sandbox.ts
9816
10021
  import { randomUUID as randomUUID3 } from "node:crypto";
9817
10022
  var MICROSANDBOX_DEFAULT_DESTINATION = "/workspace";
9818
- var MICROSANDBOX_DEFAULT_IMAGE = "alpine";
10023
+ var MICROSANDBOX_DEFAULT_IMAGE = "bash:5.3-alpine3.24";
9819
10024
  var MICROSANDBOX_MAX_NAME_BYTES = 128;
9820
10025
  var COMMAND_TIMEOUT_EXIT_CODE = 124;
9821
10026
  var MicrosandboxSandboxError = class extends Error {
@@ -9855,8 +10060,17 @@ async function createMicrosandboxSandbox(options = {}) {
9855
10060
  let vm;
9856
10061
  try {
9857
10062
  vm = await acquireSandbox(sdk, { ...options, name, ephemeral, workdir });
10063
+ } catch (error) {
10064
+ throw normalizeMicrosandboxError(error, sdk);
10065
+ }
10066
+ try {
9858
10067
  await vm.fs().mkdir(workdir);
10068
+ await assertMicrosandboxBash(vm);
9859
10069
  } catch (error) {
10070
+ await vm.stop().catch(() => {
10071
+ });
10072
+ if (ephemeral) await sdk.Sandbox.remove(name).catch(() => {
10073
+ });
9860
10074
  throw normalizeMicrosandboxError(error, sdk);
9861
10075
  }
9862
10076
  const backend = createMicrosandboxMethods({
@@ -9930,10 +10144,24 @@ function buildSandbox(sdk, options) {
9930
10144
  if (options.memory !== void 0) builder = builder.memory(options.memory);
9931
10145
  if (options.env) builder = builder.envs(options.env);
9932
10146
  if (options.configure) builder = options.configure(builder);
9933
- return builder.create();
10147
+ return builder.shell("bash").create();
10148
+ }
10149
+ async function assertMicrosandboxBash(vm) {
10150
+ try {
10151
+ const result = await vm.exec("bash", ["-lc", ":"]);
10152
+ if (result.code === 0) return;
10153
+ throw new Error(result.stderr() || `exit code ${result.code}`);
10154
+ } catch (error) {
10155
+ const err = toError2(error);
10156
+ throw new MicrosandboxCreationError(
10157
+ `Bash is required to execute sandbox commands but could not be started: ${err.message}`,
10158
+ err
10159
+ );
10160
+ }
9934
10161
  }
9935
10162
  function normalizeMicrosandboxError(error, sdk) {
9936
10163
  const err = toError2(error);
10164
+ if (err instanceof MicrosandboxSandboxError) return err;
9937
10165
  if (err instanceof sdk.LibkrunfwNotFoundError) {
9938
10166
  return new MicrosandboxNotAvailableError(err);
9939
10167
  }
@@ -10048,7 +10276,7 @@ async function pumpExecStream(args) {
10048
10276
  }
10049
10277
  signal?.addEventListener("abort", abort, { once: true });
10050
10278
  try {
10051
- handle = await vm.execStreamWith("sh", (builder) => {
10279
+ handle = await vm.execStreamWith("bash", (builder) => {
10052
10280
  builder.args(["-lc", command]).stdinNull();
10053
10281
  if (options.cwd) builder.cwd(options.cwd);
10054
10282
  if (options.env) builder.envs(options.env);
@@ -10237,12 +10465,15 @@ function buildSubcommandRepair(name, subcommands) {
10237
10465
  }
10238
10466
 
10239
10467
  // packages/context/src/lib/sandbox/virtual-sandbox.ts
10240
- import { Bash } from "just-bash";
10468
+ import {
10469
+ Bash
10470
+ } from "just-bash";
10241
10471
  async function createVirtualSandbox(options) {
10242
10472
  const bash = new Bash({
10243
10473
  fs: options.fs,
10244
10474
  cwd: options.cwd,
10245
10475
  env: options.env,
10476
+ javascript: options.javascript,
10246
10477
  customCommands: options.customCommands
10247
10478
  });
10248
10479
  const sandbox = {