import {
  assertProfilePromptWithinBudget,
  fingerprintAgentProfile
} from "./chunk-LWSJK546.js";
import {
  assertHarnessModelCompatible
} from "./chunk-CQZSAR77.js";
import {
  buildAppToolMcpServer
} from "./chunk-3EJ6SFJI.js";
import {
  base64UrlDecodeText,
  base64UrlEncodeText,
  constantTimeEqual,
  hmacSha256Base64Url
} from "./chunk-S5SRJJQG.js";
import {
  resolveTangleExecutionEnvironment,
  trimOrNull
} from "./chunk-JML7WKWU.js";

// src/sandbox/index.ts
import {
  Sandbox
} from "@tangle-network/sandbox";
import { createHash } from "crypto";

// src/sandbox/outcome.ts
var ok = (value) => ({ succeeded: true, value });
var fail = (error) => ({
  succeeded: false,
  error: error instanceof Error ? error : new Error(String(error))
});

// src/sandbox/binary-read.ts
function shellQuote(value) {
  return `'${value.replaceAll("'", `'"'"'`)}'`;
}
function base64ToBytes(base64) {
  const binary = atob(base64);
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);
  return bytes;
}
function execInSandbox(box, command, options) {
  return options?.sessionId ? box.exec(command, { sessionId: options.sessionId }) : box.exec(command);
}
async function statSandboxFileSize(box, absolutePath, options) {
  const quotedPath = shellQuote(absolutePath);
  let result;
  try {
    result = await execInSandbox(box, `wc -c < ${quotedPath}`, options);
  } catch (err) {
    return { succeeded: false, error: err instanceof Error ? err.message : String(err) };
  }
  if (result.exitCode !== 0) {
    return { succeeded: false, error: result.stderr || "unknown error" };
  }
  const size = Number.parseInt(result.stdout.trim(), 10);
  if (!Number.isFinite(size)) {
    return { succeeded: false, error: `could not parse file size from "${result.stdout.trim()}"` };
  }
  return { succeeded: true, value: size };
}
async function readSandboxBinaryBytes(box, absolutePath, expectedSize, options) {
  const quotedPath = shellQuote(absolutePath);
  let result;
  try {
    result = await execInSandbox(box, `base64 ${quotedPath}`, options);
  } catch (err) {
    return { succeeded: false, error: err instanceof Error ? err.message : String(err) };
  }
  if (result.exitCode !== 0) {
    return { succeeded: false, error: result.stderr || "unknown error" };
  }
  const cleaned = result.stdout.replace(/\s+/g, "");
  let bytes;
  try {
    bytes = base64ToBytes(cleaned);
  } catch (err) {
    return {
      succeeded: false,
      error: `could not decode file contents: ${err instanceof Error ? err.message : String(err)}`
    };
  }
  if (bytes.byteLength !== expectedSize) {
    return {
      succeeded: false,
      error: `read returned ${bytes.byteLength} bytes, expected ${expectedSize} \u2014 output truncated in transit`
    };
  }
  return { succeeded: true, value: { bytes, size: expectedSize } };
}

// src/sandbox/terminal-proxy-token.ts
var TERMINAL_PROXY_TOKEN_TTL_MS = 15 * 60 * 1e3;
async function mintTerminalProxyToken(secret, identity, ttlMs = TERMINAL_PROXY_TOKEN_TTL_MS, now = Date.now) {
  if (!secret) return fail(new Error("mintTerminalProxyToken: secret is required"));
  if (!identity.userId || !identity.workspaceId || !identity.sandboxId) {
    return fail(new Error("mintTerminalProxyToken: userId/workspaceId/sandboxId are required"));
  }
  const expiresAt = new Date(now() + ttlMs);
  const payload = { ...identity, exp: Math.floor(expiresAt.getTime() / 1e3) };
  const encoded = base64UrlEncodeText(JSON.stringify(payload));
  const sig = await hmacSha256Base64Url(encoded, secret);
  return ok({ token: `${encoded}.${sig}`, expiresAt });
}
async function verifyTerminalProxyToken(secret, token, expected, now = Date.now) {
  if (!secret) return false;
  const [encoded, sig, extra] = token.split(".");
  if (!encoded || !sig || extra !== void 0) return false;
  const expectedSig = await hmacSha256Base64Url(encoded, secret);
  if (!constantTimeEqual(sig, expectedSig)) return false;
  let payload;
  try {
    payload = JSON.parse(base64UrlDecodeText(encoded));
  } catch {
    return false;
  }
  return payload.userId === expected.userId && payload.workspaceId === expected.workspaceId && payload.sandboxId === expected.sandboxId && Number.isFinite(payload.exp) && payload.exp > Math.floor(now() / 1e3);
}

// src/sandbox/workspace-terminal.ts
function createWorkspaceSandboxManager(opts) {
  return {
    async ensureWorkspaceSandbox(workspaceId, userId, options) {
      if (!workspaceId) throw new Error("workspaceId is required");
      if (!userId) throw new Error("userId is required");
      const ctx = { workspaceId, userId };
      const client = await opts.getClient(ctx);
      const name = opts.nameForWorkspace(workspaceId, ctx);
      let listError;
      let existing = [];
      try {
        existing = await opts.listSandboxes(client, ctx);
      } catch (err) {
        listError = err;
        opts.onListError?.(err, ctx);
      }
      const found = existing.find((box) => box.name === name);
      if (found) {
        return await opts.prepareExisting?.(found, ctx, options) ?? found;
      }
      const created = await opts.createSandbox({
        client,
        ctx,
        name,
        options,
        listError
      });
      await opts.waitForRunning?.(created, ctx);
      return await opts.prepareCreated?.(created, ctx, options) ?? created;
    }
  };
}
var DEFAULT_TERMINAL_TOKEN_TTL_MS = 15 * 60 * 1e3;
var BEARER_SUBPROTOCOL_PREFIX = "bearer.";
var LEGACY_TERMINAL_TOKEN_PREFIX = "sbxt_";
async function createSandboxTerminalToken(subject, opts) {
  validateTerminalSubject(subject);
  const secret = opts.secret?.trim();
  if (!secret) throw new Error("terminal token secret is required");
  const now = opts.now ?? Date.now;
  const expiresInMs = opts.expiresInMs ?? DEFAULT_TERMINAL_TOKEN_TTL_MS;
  if (!Number.isFinite(expiresInMs) || expiresInMs <= 0) throw new Error("expiresInMs must be a positive number");
  const minted = await mintTerminalProxyToken(secret, subject, expiresInMs, now);
  if (!minted.succeeded) throw minted.error;
  return minted.value;
}
async function verifySandboxTerminalToken(token, expected, opts) {
  validateTerminalSubject(expected);
  const secret = opts.secret?.trim();
  const now = opts.now ?? Date.now;
  const normalized = token.startsWith(LEGACY_TERMINAL_TOKEN_PREFIX) ? token.slice(LEGACY_TERMINAL_TOKEN_PREFIX.length) : token;
  return verifyTerminalProxyToken(secret ?? "", normalized, expected, now);
}
function createWorkspaceSandboxConnectionHandler(opts) {
  return async function handleWorkspaceSandboxConnection({ request, params }) {
    const user = await opts.requireUser(request);
    const workspaceId = params.workspaceId;
    if (!workspaceId) return Response.json({ error: "workspaceId is required" }, { status: 400 });
    await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId });
    let box;
    try {
      box = await opts.ensureWorkspaceSandbox(workspaceId, user.id);
    } catch (err) {
      return Response.json(
        { error: err instanceof Error ? err.message : "Failed to provision workspace sandbox" },
        { status: 500 }
      );
    }
    const directSidecarUrl = box.connection?.sidecarUrl ?? box.connection?.runtimeUrl;
    const directSidecarToken = box.connection?.authToken ?? box.connection?.sidecarToken;
    const directSidecarExpiresAt = box.connection?.authTokenExpiresAt;
    if (opts.exposeDirectSidecar && directSidecarUrl && directSidecarToken && directSidecarExpiresAt) {
      return Response.json({
        runtimeUrl: directSidecarUrl,
        sidecarUrl: directSidecarUrl,
        token: directSidecarToken,
        expiresAt: directSidecarExpiresAt,
        status: box.status,
        sandboxId: box.id
      });
    }
    if (!directSidecarUrl) {
      return Response.json(
        {
          error: "Workspace sandbox runtime not ready. The sandbox is still initializing -- retry in a few seconds.",
          status: box.status
        },
        { status: 503 }
      );
    }
    const secret = typeof opts.tokenSecret === "function" ? opts.tokenSecret() : opts.tokenSecret;
    let scoped;
    try {
      scoped = await createSandboxTerminalToken(
        { userId: user.id, workspaceId, sandboxId: box.id },
        { secret, expiresInMs: opts.tokenExpiresInMs }
      );
    } catch (err) {
      return Response.json(
        { error: err instanceof Error ? err.message : "Failed to mint sandbox token" },
        { status: 503 }
      );
    }
    const runtimeUrl = opts.proxyRuntimeUrl ? opts.proxyRuntimeUrl({ request, workspaceId, sandboxId: box.id, box }) : `/api/workspaces/${encodeURIComponent(workspaceId)}/sandbox/runtime/${encodeURIComponent(box.id)}`;
    return Response.json({
      runtimeUrl,
      sidecarUrl: runtimeUrl,
      token: scoped.token,
      expiresAt: scoped.expiresAt.toISOString(),
      status: box.status,
      sandboxId: box.id
    });
  };
}
function createWorkspaceSandboxRuntimeProxyHandler(opts) {
  return async function handleWorkspaceSandboxRuntimeProxy({ request, params }) {
    const user = await opts.requireUser(request);
    const workspaceId = params.workspaceId;
    const sandboxId = params.sandboxId;
    const runtimePath = params["*"];
    if (!workspaceId || !sandboxId || !runtimePath) {
      return Response.json({ error: "workspaceId, sandboxId, and runtime path are required" }, { status: 400 });
    }
    const encodedRuntimePath = encodeSandboxRuntimePath(runtimePath);
    if (!encodedRuntimePath) return Response.json({ error: "Invalid sandbox runtime path" }, { status: 400 });
    await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId, sandboxId });
    const token = terminalTokenFromRequest(request.headers);
    const secret = typeof opts.tokenSecret === "function" ? opts.tokenSecret() : opts.tokenSecret;
    if (!token || !await verifySandboxTerminalToken(token, { userId: user.id, workspaceId, sandboxId }, { secret })) {
      return Response.json({ error: "Invalid terminal token" }, { status: 403 });
    }
    const requestUrl = new URL(request.url);
    const runtimeConnection = await opts.getSandboxRuntimeConnection?.({ request, userId: user.id, workspaceId, sandboxId });
    const directRuntimeConnection = runtimeConnection?.runtimeUrl && runtimeConnection.authToken ? runtimeConnection : null;
    const credentials = directRuntimeConnection ? null : await opts.getSandboxApiCredentials({ request, userId: user.id, workspaceId, sandboxId });
    const upstreamUrl = directRuntimeConnection ? new URL(encodedRuntimePath, `${directRuntimeConnection.runtimeUrl.replace(/\/+$/, "")}/`) : new URL(
      `/v1/sandboxes/${encodeURIComponent(sandboxId)}/runtime/${encodedRuntimePath}`,
      credentials.baseUrl
    );
    upstreamUrl.search = requestUrl.search;
    const headers = buildSandboxRuntimeProxyHeaders(
      request.headers,
      directRuntimeConnection?.authToken ?? credentials.apiKey,
      opts.forwardHeaders
    );
    const init = {
      method: request.method,
      headers,
      redirect: "manual"
    };
    if (request.method !== "GET" && request.method !== "HEAD" && request.body) {
      init.body = request.body;
      init.duplex = "half";
    }
    const fetchImpl = opts.fetch ?? fetch;
    const response = await fetchImpl(upstreamUrl, init);
    const responseHeaders = new Headers(response.headers);
    responseHeaders.delete("set-cookie");
    return new Response(response.body, {
      status: response.status,
      statusText: response.statusText,
      headers: responseHeaders
    });
  };
}
var SANDBOX_TERMINAL_WS_PATHNAME = /^\/api\/workspaces\/([^/]+)\/sandbox\/runtime\/([^/]+)\/(terminals\/[^/]+\/ws)$/;
function matchSandboxTerminalWsPath(pathname) {
  const m = SANDBOX_TERMINAL_WS_PATHNAME.exec(pathname);
  if (!m) return null;
  const [, workspaceId, sandboxId, subPath] = m;
  if (!workspaceId || !sandboxId || !subPath) return null;
  const decodedWorkspaceId = safeDecodeURIComponent(workspaceId);
  const decodedSandboxId = safeDecodeURIComponent(sandboxId);
  if (!decodedWorkspaceId || !decodedSandboxId) return null;
  return { workspaceId: decodedWorkspaceId, sandboxId: decodedSandboxId, subPath };
}
function isSandboxTerminalWsUpgrade(request) {
  if (request.headers.get("Upgrade")?.toLowerCase() !== "websocket") return false;
  try {
    return matchSandboxTerminalWsPath(new URL(request.url).pathname) !== null;
  } catch {
    return false;
  }
}
function createWorkspaceSandboxTerminalUpgradeHandler(opts) {
  return async function handleWorkspaceSandboxTerminalUpgrade(request) {
    if (request.headers.get("Upgrade")?.toLowerCase() !== "websocket") return null;
    let url;
    try {
      url = new URL(request.url);
    } catch {
      return null;
    }
    const match = matchSandboxTerminalWsPath(url.pathname);
    if (!match) return null;
    const { workspaceId, sandboxId, subPath } = match;
    let user;
    try {
      user = await opts.requireUser(request);
    } catch {
      return new Response("Unauthorized", { status: 401 });
    }
    try {
      await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId, sandboxId });
    } catch {
      return new Response("Forbidden", { status: 403 });
    }
    const token = terminalTokenFromRequest(request.headers);
    const secret = typeof opts.tokenSecret === "function" ? opts.tokenSecret() : opts.tokenSecret;
    if (!token || !await verifySandboxTerminalToken(token, { userId: user.id, workspaceId, sandboxId }, { secret })) {
      return new Response("Invalid terminal token", { status: 403 });
    }
    const runtimeConnection = await opts.getSandboxRuntimeConnection?.({ request, userId: user.id, workspaceId, sandboxId });
    const directRuntimeConnection = runtimeConnection?.runtimeUrl && runtimeConnection.authToken ? runtimeConnection : null;
    const credentials = directRuntimeConnection ? null : await opts.getSandboxApiCredentials({ request, userId: user.id, workspaceId, sandboxId });
    const upstreamUrl = directRuntimeConnection ? new URL(subPath, `${directRuntimeConnection.runtimeUrl.replace(/\/+$/, "")}/`) : new URL(`/v1/sandboxes/${encodeURIComponent(sandboxId)}/runtime/${subPath}`, credentials.baseUrl);
    upstreamUrl.search = url.search;
    const upstreamHeaders = new Headers(request.headers);
    const upstreamBearer = directRuntimeConnection?.authToken ?? credentials.apiKey;
    upstreamHeaders.set("Authorization", `Bearer ${upstreamBearer}`);
    upstreamHeaders.delete("host");
    stripBearerSubprotocol(upstreamHeaders);
    const fetchImpl = opts.fetch ?? fetch;
    return fetchImpl(upstreamUrl.toString(), { method: request.method, headers: upstreamHeaders });
  };
}
var DEFAULT_RUNTIME_PROXY_HEADERS = ["accept", "content-type", "last-event-id", "x-session-id"];
function buildSandboxRuntimeProxyHeaders(source, sandboxApiKey, forwardHeaders = DEFAULT_RUNTIME_PROXY_HEADERS) {
  const headers = new Headers();
  headers.set("Authorization", `Bearer ${sandboxApiKey}`);
  for (const name of forwardHeaders) {
    const value = source.get(name);
    if (value) headers.set(name, value);
  }
  return headers;
}
function encodeSandboxRuntimePath(runtimePath) {
  const segments = runtimePath.split("/");
  if (segments.some((segment) => !segment || segment === "." || segment === "..")) return null;
  return segments.map((segment) => encodeURIComponent(segment)).join("/");
}
function bearerToken(value) {
  if (!value) return null;
  const trimmed = value.trim();
  if (!trimmed) return null;
  if (trimmed.toLowerCase() === "bearer") return null;
  if (trimmed.toLowerCase().startsWith("bearer ")) {
    const token = trimmed.slice("bearer ".length).trim();
    return token || null;
  }
  return trimmed;
}
function bearerSubprotocolToken(value) {
  if (!value) return null;
  for (const part of value.split(",")) {
    const protocol = part.trim();
    if (!protocol.toLowerCase().startsWith(BEARER_SUBPROTOCOL_PREFIX)) continue;
    const encoded = protocol.slice(BEARER_SUBPROTOCOL_PREFIX.length);
    if (!encoded) return null;
    try {
      const token = base64UrlDecodeText(encoded).trim();
      return token || null;
    } catch {
      return null;
    }
  }
  return null;
}
function terminalTokenFromRequest(headers) {
  return bearerToken(headers.get("Authorization")) ?? bearerSubprotocolToken(headers.get("Sec-WebSocket-Protocol"));
}
function safeDecodeURIComponent(value) {
  try {
    return decodeURIComponent(value);
  } catch {
    return null;
  }
}
function stripBearerSubprotocol(headers) {
  const value = headers.get("Sec-WebSocket-Protocol");
  if (!value) return;
  const protocols = value.split(",").map((part) => part.trim()).filter((part) => part && !part.toLowerCase().startsWith(BEARER_SUBPROTOCOL_PREFIX));
  if (protocols.length) {
    headers.set("Sec-WebSocket-Protocol", protocols.join(", "));
  } else {
    headers.delete("Sec-WebSocket-Protocol");
  }
}
function validateTerminalSubject(subject) {
  if (!subject.userId) throw new Error("userId is required");
  if (!subject.workspaceId) throw new Error("workspaceId is required");
  if (!subject.sandboxId) throw new Error("sandboxId is required");
}

// src/sandbox/index.ts
var DEFAULT_SANDBOX_DIRECT_KEY_NAMES = [
  "TCLOUD_SANDBOX_API_KEY",
  "SANDBOX_API_KEY",
  "TANGLE_API_KEY"
];
var DEFAULT_SANDBOX_BASE_URL_NAMES = ["SANDBOX_GATEWAY_URL", "SANDBOX_API_URL"];
function normalizeBaseUrl(value) {
  return value.trim().replace(/\/v1\/?$/, "").replace(/\/+$/, "");
}
function processEnv() {
  return typeof process === "undefined" ? {} : process.env;
}
function directEnvCredentialsAllowed(environment, allow) {
  if (typeof allow === "function") return allow(environment);
  if (typeof allow === "boolean") return allow;
  return environment === "development" || environment === "test";
}
function resolveSandboxBaseUrl(env, names, defaultBaseUrl) {
  for (const name of names) {
    const value2 = trimOrNull(env[name]);
    if (value2) return normalizeBaseUrl(value2);
  }
  const value = trimOrNull(defaultBaseUrl);
  if (value) return normalizeBaseUrl(value);
  throw new Error(
    `Sandbox base URL is required (set one of ${names.join(", ")} or pass defaultBaseUrl).`
  );
}
function resolveDirectSandboxCredentials(env, keyNames, baseUrlNames, defaultBaseUrl) {
  for (const name of keyNames) {
    const apiKey = trimOrNull(env[name]);
    if (!apiKey) continue;
    return {
      apiKey,
      baseUrl: resolveSandboxBaseUrl(env, baseUrlNames, defaultBaseUrl)
    };
  }
  return null;
}
async function resolveSandboxClientCredentials(options = {}) {
  const env = options.env ?? processEnv();
  const environment = options.environment ?? resolveTangleExecutionEnvironment(env);
  const keyNames = options.directKeyNames ?? DEFAULT_SANDBOX_DIRECT_KEY_NAMES;
  const baseUrlNames = options.baseUrlNames ?? DEFAULT_SANDBOX_BASE_URL_NAMES;
  const directAllowed = directEnvCredentialsAllowed(environment, options.allowDirectEnvCredentials);
  const direct = () => directAllowed ? resolveDirectSandboxCredentials(env, keyNames, baseUrlNames, options.defaultBaseUrl) : null;
  if (environment === "development" || environment === "test") {
    const credentials2 = direct();
    if (credentials2) return credentials2;
  }
  const provisioned = await options.provision?.({ environment, env });
  if (provisioned) {
    return {
      apiKey: provisioned.apiKey,
      baseUrl: normalizeBaseUrl(provisioned.baseUrl)
    };
  }
  const credentials = direct();
  if (credentials) return credentials;
  const directHint = directAllowed ? ` or set one of ${keyNames.join(", ")}` : "";
  throw new Error(
    `Sandbox credentials are required for ${environment} (provide a provision callback${directHint}).`
  );
}
var DEFAULT_SANDBOX_RESOURCES = {
  image: "universal",
  cpuCores: 2,
  memoryMB: 4096,
  diskGB: 10,
  maxLifetimeSeconds: 86400,
  idleTimeoutSeconds: 3600
};
var _cached = null;
function getClientFromCreds(creds) {
  const fingerprint = `${creds.apiKey} ${creds.baseUrl}`;
  if (_cached && _cached.fingerprint === fingerprint) return _cached.client;
  const client = new Sandbox({ apiKey: creds.apiKey, baseUrl: creds.baseUrl });
  _cached = { client, fingerprint };
  return client;
}
function getClient(shell) {
  const creds = shell.credentials();
  if (creds && typeof creds.then === "function") {
    throw new Error("getClient: scoped (async) credentials require the async sandbox path");
  }
  if (!creds) throw new Error("sandbox credentials are required (apiKey/baseUrl)");
  return getClientFromCreds(creds);
}
function resetClientCache() {
  _cached = null;
}
function buildAppToolMcpServers(options) {
  const entries = {};
  for (const { tool, key, description } of options.tools) {
    entries[key] = buildAppToolMcpServer({
      tool,
      baseUrl: options.baseUrl,
      token: options.token,
      ctx: options.ctx,
      description,
      headerNames: options.headerNames
    });
  }
  return entries;
}
function shellSingleQuote(value) {
  return `'${value.replace(/'/g, `'\\''`)}'`;
}
var DEFAULT_SANDBOX_TOOL_BASE_DIR = "/home/agent/tools";
var SAFE_TOOL_SEGMENT = /^[A-Za-z0-9._-]+$/;
function normalizeSandboxToolSegment(value, label) {
  const segment = value.trim();
  if (!segment || segment === "." || segment === ".." || !SAFE_TOOL_SEGMENT.test(segment)) {
    throw new Error(`${label} must contain only letters, numbers, dots, underscores, or hyphens.`);
  }
  return segment;
}
function normalizeSandboxToolDir(value, label) {
  const dir = value.trim().replace(/\/+$/, "");
  if (!dir || !dir.startsWith("/") || dir.includes("\0") || dir.includes("\n")) {
    throw new Error(`${label} must be an absolute sandbox path.`);
  }
  return dir === "" ? "/" : dir;
}
function sandboxToolRootDir(options) {
  const appName = normalizeSandboxToolSegment(options.appName, "sandbox tool appName");
  const baseDir = normalizeSandboxToolDir(
    options.baseDir ?? DEFAULT_SANDBOX_TOOL_BASE_DIR,
    "sandbox tool baseDir"
  );
  return `${baseDir}/${appName}`;
}
function sandboxToolBinDir(options) {
  normalizeSandboxToolSegment(options.appName, "sandbox tool appName");
  if (options.binDir) return normalizeSandboxToolDir(options.binDir, "sandbox tool binDir");
  return `${sandboxToolRootDir(options)}/bin`;
}
function sandboxToolPath(options) {
  const toolName = normalizeSandboxToolSegment(options.toolName, "sandbox tool name");
  return `${sandboxToolBinDir(options)}/${toolName}`;
}
function buildSandboxToolFileMounts(options) {
  return options.tools.map((tool) => {
    const name = normalizeSandboxToolSegment(tool.name, "sandbox tool name");
    return {
      path: sandboxToolPath({ ...options, toolName: name }),
      resource: { kind: "inline", name, content: tool.content },
      executable: tool.executable ?? true
    };
  });
}
function buildSandboxToolPathSetupScript(options) {
  const binDir = sandboxToolBinDir(options);
  const exportLine = `export PATH=${binDir}:$PATH`;
  return [
    "set -eu",
    `mkdir -p ${shellSingleQuote(binDir)}`,
    `PATH=${shellSingleQuote(binDir)}:$PATH`,
    "export PATH",
    'for profile in "${HOME:-/home/agent}/.profile" "${HOME:-/home/agent}/.bashrc" "${HOME:-/home/agent}/.zshrc"; do',
    '  mkdir -p "$(dirname "$profile")"',
    '  touch "$profile"',
    `  grep -Fqx ${shellSingleQuote(exportLine)} "$profile" || printf '\\n%s\\n' ${shellSingleQuote(exportLine)} >> "$profile"`,
    "done"
  ].join("\n");
}
async function runSandboxToolPathSetup(box, options) {
  try {
    const res = await box.exec(buildSandboxToolPathSetupScript(options));
    if (res.exitCode !== 0) {
      return fail(
        new Error(
          `runSandboxToolPathSetup: failed to configure PATH for ${sandboxToolBinDir(options)} (exit ${res.exitCode}): ${res.stderr.slice(0, 500)}`
        )
      );
    }
    return ok(void 0);
  } catch (err) {
    return fail(new Error("runSandboxToolPathSetup: exec failed", { cause: err }));
  }
}
function shellPath(path) {
  if (path === "~") return '"$HOME"';
  if (path.startsWith("~/")) {
    const rest = path.slice(2);
    return rest ? `"$HOME"/${shellSingleQuote(rest)}` : '"$HOME"';
  }
  return shellSingleQuote(path);
}
function splitDeferredProfileFiles(profile) {
  const files = profile.resources?.files ?? [];
  const deferredFiles = [];
  const keptFiles = [];
  for (const mount of files) {
    if (mount.resource.kind === "inline") deferredFiles.push(mount);
    else keptFiles.push(mount);
  }
  if (deferredFiles.length === 0) return { leanProfile: profile, deferredFiles };
  const leanProfile = {
    ...profile,
    resources: { ...profile.resources ?? {}, files: keptFiles }
  };
  return { leanProfile, deferredFiles };
}
var PROFILE_WRITE_B64_CHUNK_CHARS = 3e3;
var PROFILE_WRITE_MAX_RETRIES = 4;
var PROFILE_WRITE_RETRY_BASE_MS = 250;
var PROFILE_WRITE_RETRY_MAX_MS = 2e3;
var PROFILE_WRITE_EXEC_TIMEOUT_MS = 3e4;
var PROFILE_WRITE_PACE_MS = 150;
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
var PROFILE_BIN_DIR_RE = /(^|\/)(s?bin)\//;
var ProfileWriteExecTimeoutError = class extends Error {
  constructor(timeoutMs) {
    super(`exec exceeded ${timeoutMs}ms (proxy hang/wedge)`);
    this.name = "ProfileWriteExecTimeoutError";
  }
};
function execWithTimeout(box, cmd, timeoutMs) {
  return new Promise((resolve, reject) => {
    let settled = false;
    const timer = setTimeout(() => {
      if (settled) return;
      settled = true;
      reject(new ProfileWriteExecTimeoutError(timeoutMs));
    }, timeoutMs);
    box.exec(cmd, { timeoutMs }).then(
      (res) => {
        if (settled) return;
        settled = true;
        clearTimeout(timer);
        resolve(res);
      },
      (err) => {
        if (settled) return;
        settled = true;
        clearTimeout(timer);
        reject(err);
      }
    );
  });
}
var TRANSIENT_EXEC_STATUS_CODES = /* @__PURE__ */ new Set([408, 409, 425, 429, 500, 502, 503, 504]);
var TRANSIENT_EXEC_CODE_RE = /^(ECONNRESET|ECONNREFUSED|ETIMEDOUT|EPIPE|ECONNABORTED)$/i;
var TRANSIENT_EXEC_MESSAGE_RE = /\b(408|409|425|429|500|502|503|504)\b|rate.?limit|too many requests|\bfetch failed\b|network error|connection reset|socket hang up|timed? out|service unavailable|bad gateway|gateway timeout|internal server error|\b(?:sidecar|runtime|exec(?:ution)?|terminal|sandbox|service|command(?:s)?|proxy)\b.{0,80}\bnot ready\b|\bnot ready\b.{0,80}\b(?:sidecar|runtime|exec(?:ution)?|terminal|sandbox|service|command(?:s)?|proxy)\b/i;
var RUNTIME_AUTH_REFRESH_SKEW_MS = 6e4;
function errorStatus(err) {
  const rawStatus = err.status ?? err.statusCode ?? (err.response && typeof err.response === "object" ? err.response.status : void 0);
  if (typeof rawStatus === "number") return rawStatus;
  if (typeof rawStatus === "string" && /^\d+$/.test(rawStatus)) return Number(rawStatus);
  return void 0;
}
function retryAfterMs(err, seen = /* @__PURE__ */ new Set()) {
  if (!err || typeof err !== "object") return void 0;
  if (seen.has(err)) return void 0;
  seen.add(err);
  const e = err;
  if (typeof e.retryAfterMs === "number") return e.retryAfterMs;
  return retryAfterMs(e.cause, seen);
}
function isTransientExecError(err, seen = /* @__PURE__ */ new Set()) {
  if (!err || typeof err !== "object") return false;
  if (seen.has(err)) return false;
  seen.add(err);
  const e = err;
  const status = errorStatus(e);
  if (status !== void 0 && TRANSIENT_EXEC_STATUS_CODES.has(status)) return true;
  if (typeof e.code === "string") {
    if (TRANSIENT_EXEC_CODE_RE.test(e.code)) return true;
    if (/rate.?limit|too.?many.?requests|429|server.?error|service.?unavailable/i.test(e.code)) return true;
  }
  if (typeof e.message === "string" && TRANSIENT_EXEC_MESSAGE_RE.test(e.message)) return true;
  return isTransientExecError(e.cause, seen);
}
function isRuntimeExecAuthError(err, seen = /* @__PURE__ */ new Set()) {
  if (!err || typeof err !== "object") return false;
  if (seen.has(err)) return false;
  seen.add(err);
  const e = err;
  if (errorStatus(e) === 401) return true;
  if (typeof e.code === "string" && /^(AUTH_ERROR|AUTHENTICATION_ERROR|UNAUTHORIZED|UNAUTHENTICATED|ERR_UNAUTHORIZED|ERR_UNAUTHENTICATED|401)$/i.test(e.code)) {
    return true;
  }
  if (typeof e.name === "string" && /^(AuthError|AuthenticationError|UnauthorizedError|UnauthenticatedError|SandboxAuthError)$/i.test(e.name)) {
    return true;
  }
  return isRuntimeExecAuthError(e.cause, seen);
}
function isRuntimeAuthRefreshDenied(err) {
  if (!err || typeof err !== "object") return false;
  return isRuntimeExecAuthError(err) || errorStatus(err) === 403;
}
function transientExecError(err) {
  if (err instanceof ProfileWriteExecTimeoutError) return { retryable: true };
  if (isTransientExecError(err)) return { retryable: true, retryAfterMs: retryAfterMs(err) };
  return { retryable: false };
}
function deferredProfileWriteFailed(stage, name, cause) {
  return new Error(`deferred file write failed on ${stage} box ${name}: ${cause.message}`, { cause });
}
var SandboxRuntimeAuthRefreshError = class extends Error {
  constructor(stage, name, detail, cause) {
    super(`${stage} sandbox auth refresh failed for ${name}: ${detail}`, { cause });
    this.name = "SandboxRuntimeAuthRefreshError";
  }
};
function fileApiTarget(mount) {
  if (mount.resource.kind !== "inline") return null;
  let rel;
  if (mount.path.startsWith("~/")) rel = mount.path.slice(2);
  else if (mount.path.startsWith("/home/agent/")) rel = mount.path.slice("/home/agent/".length);
  else if (mount.path.startsWith("/") || mount.path.startsWith("~")) return null;
  else rel = mount.path;
  if (rel.length === 0 || rel.startsWith("/") || rel.split("/").some((seg) => seg === ".." || seg === ".sidecar")) {
    return null;
  }
  return rel;
}
function isExecutableProfileFile(mount) {
  return mount.executable ?? PROFILE_BIN_DIR_RE.test(mount.path);
}
function profileFileMode(mount) {
  return isExecutableProfileFile(mount) ? 493 : void 0;
}
function fileApiSupportsMode(box) {
  const fs = box.fs;
  return fs?.supportsWriteMode === true;
}
async function writeProfileFilesToBox(box, files, options = {}) {
  const execTimeoutMs = options.execTimeoutMs ?? PROFILE_WRITE_EXEC_TIMEOUT_MS;
  const paceMs = options.paceMs ?? PROFILE_WRITE_PACE_MS;
  const maxRetries = options.maxRetries ?? PROFILE_WRITE_MAX_RETRIES;
  const fileApiAvailable = typeof box.fs?.writeMany === "function";
  const modeAwareFileApi = fileApiSupportsMode(box);
  const viaFileApi = [];
  const viaExec = [];
  for (const mount of files) {
    if (mount.resource.kind !== "inline") continue;
    const fileApiPath = fileApiAvailable ? fileApiTarget(mount) : null;
    const executable = isExecutableProfileFile(mount);
    if (fileApiPath !== null && (!executable || modeAwareFileApi)) {
      const mode = profileFileMode(mount);
      viaFileApi.push({
        path: fileApiPath,
        content: mount.resource.content ?? "",
        ...mode !== void 0 ? { mode } : {}
      });
    } else viaExec.push(mount);
  }
  if (viaFileApi.length > 0) {
    try {
      await box.fs.writeMany(viaFileApi, { paceMs, maxRetries });
    } catch (err) {
      return fail(new Error("writeProfileFilesToBox: file-API batch write failed", { cause: err }));
    }
  }
  let execStarted = false;
  const paceAndRetry = async (run, path) => {
    for (let attempt = 0; ; attempt++) {
      if (execStarted && paceMs > 0) await sleep(paceMs);
      execStarted = true;
      try {
        return ok(await run());
      } catch (err) {
        const { retryable, retryAfterMs: retryAfterMs2 } = transientExecError(err);
        if (retryable && attempt < maxRetries) {
          const backoff = Math.min(PROFILE_WRITE_RETRY_BASE_MS * 2 ** attempt, PROFILE_WRITE_RETRY_MAX_MS);
          await sleep(retryAfterMs2 ?? backoff);
          continue;
        }
        return fail(new Error(`writeProfileFilesToBox: exec failed for ${path}`, { cause: err }));
      }
    }
  };
  for (const mount of viaExec) {
    if (mount.resource.kind !== "inline") continue;
    const content = mount.resource.content ?? "";
    const path = mount.path;
    const b64 = Buffer.from(content, "utf8").toString("base64");
    const b64Chunks = [];
    for (let i = 0; i < b64.length; i += PROFILE_WRITE_B64_CHUNK_CHARS) {
      b64Chunks.push(b64.slice(i, i + PROFILE_WRITE_B64_CHUNK_CHARS));
    }
    const expectedSha256 = createHash("sha256").update(content, "utf8").digest("hex");
    const dir = path.replace(/\/[^/]*$/, "");
    const executable = isExecutableProfileFile(mount);
    const q = shellPath(path);
    const qb64 = shellPath(`${path}.b64`);
    const qtmp = shellPath(`${path}.tmp`);
    const qpartPrefix = shellPath(`${path}.b64.part.`);
    const step = async (cmd) => {
      const res2 = await paceAndRetry(() => execWithTimeout(box, cmd, execTimeoutMs), path);
      if (!res2.succeeded) return res2;
      const exec = res2.value;
      if (exec.exitCode !== 0) {
        return fail(
          new Error(
            `writeProfileFilesToBox: failed to write ${path} (exit ${exec.exitCode}): ${exec.stderr.slice(0, 500)}`
          )
        );
      }
      return ok(void 0);
    };
    const mkdir = dir && dir !== path ? `mkdir -p ${shellPath(dir)}` : ":";
    let res = await step(mkdir);
    if (!res.succeeded) return res;
    for (let i = 0; i < b64Chunks.length; i++) {
      const slice = b64Chunks[i];
      res = await step(`printf '%s' '${slice}' > ${shellPath(`${path}.b64.part.${i}`)}`);
      if (!res.succeeded) return res;
    }
    const chmod = executable ? `chmod +x ${q} || exit 1; ` : "";
    const checksumMismatch = shellSingleQuote(`writeProfileFilesToBox: checksum mismatch for ${path}`);
    const finalCmd = `expected='${expectedSha256}'; if [ -f ${q} ] && [ "$(sha256sum ${q} | awk '{print $1}')" = "$expected" ]; then ${chmod}rm -f ${qb64} ${qtmp}; i=0; while [ "$i" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done; exit 0; fi; : > ${qb64} && i=0; while [ "$i" -lt ${b64Chunks.length} ]; do cat ${qpartPrefix}$i >> ${qb64} || exit 1; i=$((i+1)); done && base64 -d ${qb64} > ${qtmp} && [ "$(sha256sum ${qtmp} | awk '{print $1}')" = "$expected" ] || { echo ${checksumMismatch} >&2; exit 1; }; mv ${qtmp} ${q} && ${executable ? `chmod +x ${q} && ` : ""}[ "$(sha256sum ${q} | awk '{print $1}')" = "$expected" ] || { echo ${checksumMismatch} >&2; exit 1; }; rm -f ${qb64} ${qtmp}; i=0; while [ "$i" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done`;
    res = await step(finalCmd);
    if (!res.succeeded) return res;
  }
  return ok(void 0);
}
var DEFERRED_CORPUS_HASH_KEY = "agentAppDeferredCorpusHash";
function deferredCorpusHash(files) {
  const norm = files.map((f) => ({
    p: f.path,
    c: f.resource.kind === "inline" ? f.resource.content ?? "" : `ref:${f.resource.kind}`
  })).sort((a, b) => a.p < b.p ? -1 : a.p > b.p ? 1 : 0);
  return createHash("sha256").update(JSON.stringify(norm), "utf8").digest("hex");
}
async function materializeDeferredFilesForExistingBox(shell, client, box, stage, name, workspaceId, userId, harness) {
  if (!shell.deferProfileFiles) return ok(box);
  const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId);
  const buildCtx = {
    workspaceId,
    connectedIntegrationIds,
    ...userId ? { userId } : {}
  };
  const files = await shell.files(buildCtx);
  const fullProfile = shell.profile({ extraFiles: files, harness });
  const { deferredFiles } = splitDeferredProfileFiles(fullProfile);
  if (deferredFiles.length === 0) return ok(box);
  const stampedHash = box.metadata?.[DEFERRED_CORPUS_HASH_KEY];
  if (typeof stampedHash === "string" && stampedHash === deferredCorpusHash(deferredFiles)) return ok(box);
  return writeDeferredFilesWithRuntimeAuthRefresh(client, box, deferredFiles, stage, name);
}
async function listRunning(client, name) {
  try {
    const running = await client.list({ status: "running" });
    return ok(running.find((s) => s.name === name) ?? null);
  } catch (err) {
    return fail(err);
  }
}
async function listStopped(client, name) {
  try {
    const stopped = await client.list({ status: "stopped" });
    return ok(stopped.find((s) => s.name === name) ?? null);
  } catch (err) {
    return fail(err);
  }
}
async function deleteBox(box) {
  try {
    await box.delete();
    return ok(void 0);
  } catch (err) {
    return fail(err);
  }
}
var SHELL_PROMPT_BUDGET_HINT = "If this prompt size is a decision you already made at compose time, mirror it on the shell as `promptBudget: { maxSystemPromptBytes, overBudgetReason }` \u2014 the shell gate is the one that sees the profile actually sent.";
var PROVISION_PAYLOAD_MAX_BYTES = 24e4;
var ENV_VALUE_MAX_BYTES = 12e4;
var ENV_TOTAL_MAX_BYTES = 2e5;
function utf8ByteLength(value) {
  return new TextEncoder().encode(typeof value === "string" ? value : JSON.stringify(value ?? null)).byteLength;
}
function assertProvisionPayloadWithinCap(payload) {
  const total = utf8ByteLength(payload);
  if (total <= PROVISION_PAYLOAD_MAX_BYTES) return;
  const profile = payload.backend?.profile;
  const files = (typeof profile === "string" ? void 0 : profile?.resources?.files) ?? [];
  const breakdown = `profile=${utf8ByteLength(profile ?? null)}B (files=${utf8ByteLength(files)}B), env=${utf8ByteLength(payload.env ?? {})}B, secrets=${utf8ByteLength(payload.secrets ?? [])}B`;
  throw new Error(
    `sandbox provision payload is ${total} bytes \u2014 over the ${PROVISION_PAYLOAD_MAX_BYTES}-byte gate (the platform caps the create body at 256 KiB; an over-cap payload can never create a sandbox). Breakdown: ${breakdown}. Hint: set deferProfileFiles: true or move content to resources.`
  );
}
function assertEnvWithinLimits(env) {
  let total = 0;
  let largest = null;
  for (const [name, value] of Object.entries(env)) {
    const bytes = utf8ByteLength(`${name}=${value}`);
    total += bytes;
    if (!largest || bytes > largest.bytes) largest = { name, bytes };
    if (bytes > ENV_VALUE_MAX_BYTES) {
      throw new Error(
        `sandbox env var ${name} is ${bytes} bytes \u2014 over the ${ENV_VALUE_MAX_BYTES}-byte gate (kernel MAX_ARG_STRLEN is 131072 bytes per env entry; anything larger E2BIGs every exec). Write large content to a file mount or resource instead of an env var.`
      );
    }
  }
  if (total > ENV_TOTAL_MAX_BYTES) {
    const worst = largest ? ` Largest: ${largest.name} (${largest.bytes}B).` : "";
    throw new Error(
      `sandbox env block is ${total} bytes total \u2014 over the ${ENV_TOTAL_MAX_BYTES}-byte gate.${worst} Write large content to a file mount or resource instead of env vars.`
    );
  }
}
async function isBoxAlive(box, harness, probe) {
  if (!probe) return true;
  const execTimeout = probe.execTimeoutMs ?? 5e3;
  const psTimeout = probe.psTimeoutMs ?? 3e3;
  const race = (p, ms, label) => Promise.race([
    p,
    new Promise((_, reject) => setTimeout(() => reject(new Error(label)), ms))
  ]);
  try {
    const alive = await race(box.exec("echo alive"), execTimeout, "alive check timeout");
    if (!alive.stdout.includes("alive")) return false;
    const pattern = probe.sidecarProcessPattern(harness);
    try {
      const ps = await race(
        box.exec(`pgrep -f ${shellSingleQuote(pattern)} || echo no-sidecar`),
        psTimeout,
        "ps check timeout"
      );
      if (ps.stdout.includes("no-sidecar")) return false;
    } catch {
    }
    return true;
  } catch {
    return false;
  }
}
var RUNTIME_CONNECTION_WAIT_MS = 3e4;
var RUNTIME_CONNECTION_POLL_MS = 1e3;
function sandboxRuntimeUrl(box) {
  const connection = box.connection;
  return connection?.sidecarUrl ?? connection?.runtimeUrl;
}
function runtimeAuthExpiresAtMs(value) {
  if (value instanceof Date) return value.getTime();
  if (typeof value === "number") return value;
  if (typeof value !== "string" || value.trim() === "") return void 0;
  const parsed = Date.parse(value);
  return Number.isNaN(parsed) ? void 0 : parsed;
}
function hasFreshRuntimeExecAuth(box, now = Date.now()) {
  const connection = box.connection;
  const token = connection?.authToken ?? connection?.sidecarToken;
  if (!sandboxRuntimeUrl(box) || !token) return false;
  const expiresAt = runtimeAuthExpiresAtMs(
    connection?.authTokenExpiresAt ?? connection?.sidecarTokenExpiresAt
  );
  return expiresAt === void 0 || expiresAt > now + RUNTIME_AUTH_REFRESH_SKEW_MS;
}
function sandboxEdgeFailed(box) {
  const connection = box.connection;
  return connection?.edgeStatus === "failed" || Boolean(connection?.edgeError);
}
async function refreshRuntimeConnection(client, box) {
  let current = box;
  if (sandboxRuntimeUrl(current)) return current;
  const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS;
  while (Date.now() < deadline) {
    try {
      await current.refresh();
      if (sandboxRuntimeUrl(current)) return current;
      const latest = await client.get(current.id);
      if (latest) current = latest;
      if (sandboxRuntimeUrl(current)) return current;
    } catch {
    }
    await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS));
  }
  return current;
}
async function bestEffortRefreshRuntimeExecAuth(client, box, stage, name) {
  let current = box;
  try {
    await current.refresh();
    if (hasFreshRuntimeExecAuth(current)) return ok(current);
  } catch (err) {
    if (isRuntimeAuthRefreshDenied(err)) {
      return fail(
        new SandboxRuntimeAuthRefreshError(
          stage,
          name,
          "runtime exec auth refresh was unauthorized",
          err
        )
      );
    }
  }
  try {
    const latest = await client.get(current.id);
    if (latest) current = latest;
    if (hasFreshRuntimeExecAuth(current)) return ok(current);
  } catch (err) {
    if (isRuntimeAuthRefreshDenied(err)) {
      return fail(
        new SandboxRuntimeAuthRefreshError(
          stage,
          name,
          "runtime exec auth re-fetch was unauthorized",
          err
        )
      );
    }
  }
  return ok(current);
}
async function refreshRuntimeExecAuth(client, box, stage, name) {
  let current = box;
  let lastError;
  const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS;
  while (Date.now() < deadline) {
    try {
      await current.refresh();
      if (hasFreshRuntimeExecAuth(current)) return ok(current);
      const latest = await client.get(current.id);
      if (latest) current = latest;
      if (hasFreshRuntimeExecAuth(current)) return ok(current);
    } catch (err) {
      lastError = err;
    }
    await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS));
  }
  const detail = sandboxRuntimeUrl(current) ? "runtime exec credentials are missing or expired after refresh" : "runtime connection is missing after refresh";
  return fail(new SandboxRuntimeAuthRefreshError(stage, name, detail, lastError));
}
async function writeDeferredFilesWithRuntimeAuthRefresh(client, box, files, stage, name) {
  let writeBox = box;
  if (!hasFreshRuntimeExecAuth(writeBox)) {
    const refreshed2 = await bestEffortRefreshRuntimeExecAuth(client, writeBox, stage, name);
    if (!refreshed2.succeeded) return fail(refreshed2.error);
    writeBox = refreshed2.value;
  }
  const first = await writeProfileFilesToBox(writeBox, files);
  if (first.succeeded) return ok(writeBox);
  if (!isRuntimeExecAuthError(first.error)) return fail(first.error);
  const refreshed = await refreshRuntimeExecAuth(client, writeBox, stage, name);
  if (!refreshed.succeeded) return fail(refreshed.error);
  const second = await writeProfileFilesToBox(refreshed.value, files);
  if (second.succeeded) return ok(refreshed.value);
  if (!isRuntimeExecAuthError(second.error)) return fail(second.error);
  return fail(
    new SandboxRuntimeAuthRefreshError(
      stage,
      name,
      "runtime exec remained unauthorized after auth refresh",
      second.error
    )
  );
}
async function isReusableBox(box, harness, probe) {
  if (sandboxEdgeFailed(box)) return false;
  if (!sandboxRuntimeUrl(box)) return false;
  return isBoxAlive(box, harness, probe);
}
async function resumeStoppedBox(box, timeoutMs, onProgress) {
  try {
    await box.resume();
    await box.waitFor("running", { timeoutMs, ...onProgress ? { onProgress } : {} });
    return ok(box);
  } catch (err) {
    return fail(err);
  }
}
async function resolveWorkspaceSandboxClient(shell, workspaceId, userId) {
  const scope = { workspaceId, ...userId ? { userId } : {} };
  const creds = await shell.credentials(scope);
  if (!creds) throw new Error("sandbox credentials are required (apiKey/baseUrl)");
  return {
    scope,
    client: getClientFromCreds(creds),
    name: shell.boxKey ? shell.boxKey(scope) : shell.name(workspaceId)
  };
}
async function peekWorkspaceSandbox(shell, options) {
  const { client, name } = await resolveWorkspaceSandboxClient(shell, options.workspaceId, options.userId);
  const displayName = shell.name(options.workspaceId);
  const boxes = await client.list();
  const match = boxes.find((box) => box.name === name) ?? boxes.find((box) => box.name === displayName);
  if (!match) return { status: "absent" };
  if (match.status !== "running") return { status: "not-running", state: match.status, box: match };
  return { status: "running", box: match };
}
async function ensureWorkspaceSandbox(shell, options) {
  const { workspaceId, userId, harness, forceNew, onProgress, billingOwnerId } = options;
  const resolved = await resolveWorkspaceSandboxClient(shell, workspaceId, userId);
  const { scope, client } = resolved;
  let name = resolved.name;
  let recoveryRestore;
  const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES;
  const resumeTimeout = 12e4;
  const existing = await listRunning(client, name);
  if (existing.succeeded && existing.value) {
    const found = existing.value;
    if (forceNew) {
      const dropped = await deleteBox(found);
      if (!dropped.succeeded) {
        throw new Error(`forceNew: sandbox ${name} could not be deleted`, { cause: dropped.error });
      }
    } else if (found.metadata?.harness === harness) {
      const ready = await refreshRuntimeConnection(client, found);
      if (await isReusableBox(ready, harness, shell.livenessProbe)) {
        const written = await materializeDeferredFilesForExistingBox(
          shell,
          client,
          ready,
          "reused",
          name,
          workspaceId,
          userId,
          harness
        );
        if (!written.succeeded) {
          throw deferredProfileWriteFailed("reused", name, written.error);
        }
        const reusedBox = written.value;
        if (shell.bootstrap) {
          const boot = await shell.bootstrap(reusedBox, scope);
          if (!boot.succeeded) {
            throw new Error(`bootstrap failed on reused box ${name}`, { cause: boot.error });
          }
        }
        return reusedBox;
      }
      const dropped = await deleteBox(ready);
      if (!dropped.succeeded) {
        throw new Error(
          `sandbox ${name} (was ${String(found.metadata?.harness ?? "unknown")}, want ${harness}, or unresponsive) could not be deleted`,
          { cause: dropped.error }
        );
      }
    } else {
      const dropped = await deleteBox(found);
      if (!dropped.succeeded) {
        throw new Error(
          `sandbox ${name} (was ${String(found.metadata?.harness ?? "unknown")}, want ${harness}, or unresponsive) could not be deleted`,
          { cause: dropped.error }
        );
      }
    }
  }
  if (!forceNew && shell.resumeStopped !== false) {
    const stopped = await listStopped(client, name);
    if (!stopped.succeeded) throw stopped.error;
    if (stopped.value) {
      const resumed = await resumeStoppedBox(stopped.value, resumeTimeout, onProgress);
      if (!resumed.succeeded) {
        if (!shell.recoverStoppedSandbox) throw resumed.error;
        const recovery = await shell.recoverStoppedSandbox({
          box: stopped.value,
          error: resumed.error,
          scope,
          boxKey: name
        });
        if (!recovery.succeeded) throw recovery.error;
        if (!recovery.value) throw resumed.error;
        const replacementBoxKey = recovery.value.replacementBoxKey.trim();
        if (!replacementBoxKey || replacementBoxKey === name) {
          throw new Error(
            `stopped sandbox recovery must return a fresh replacement box key for ${name}`,
            { cause: resumed.error }
          );
        }
        name = replacementBoxKey;
        recoveryRestore = recovery.value.restore;
      } else {
        const box2 = await refreshRuntimeConnection(client, resumed.value);
        if (await isReusableBox(box2, harness, shell.livenessProbe)) {
          const written = await materializeDeferredFilesForExistingBox(
            shell,
            client,
            box2,
            "resumed",
            name,
            workspaceId,
            userId,
            harness
          );
          if (!written.succeeded) {
            throw deferredProfileWriteFailed("resumed", name, written.error);
          }
          const resumedBox = written.value;
          if (shell.bootstrap) {
            const boot = await shell.bootstrap(resumedBox, scope);
            if (!boot.succeeded) {
              throw new Error(`bootstrap failed on resumed box ${name}`, { cause: boot.error });
            }
          }
          return resumedBox;
        }
        const dropped = await deleteBox(box2);
        if (!dropped.succeeded) {
          throw new Error(
            `resumed sandbox ${name} (was ${String(box2.metadata?.harness ?? "unknown")}, want ${harness}, or unresponsive) could not be deleted`,
            { cause: dropped.error }
          );
        }
      }
    }
  }
  const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId);
  const buildCtx = {
    workspaceId,
    connectedIntegrationIds,
    ...userId ? { userId } : {}
  };
  const [secrets, env, files] = await Promise.all([
    shell.secrets(workspaceId),
    shell.env(buildCtx),
    shell.files(buildCtx)
  ]);
  const fullProfile = shell.profile({ extraFiles: files, harness });
  const { leanProfile, deferredFiles } = shell.deferProfileFiles ? splitDeferredProfileFiles(fullProfile) : { leanProfile: fullProfile, deferredFiles: [] };
  const profile = leanProfile;
  const role = userId && shell.permissionRole ? shell.permissionRole("developer") : void 0;
  let model = shell.backendModelAtCreate ? resolveModel(shell.provider) : void 0;
  if (model && shell.childKeyMint && model.provider === "openai-compat") {
    const minted = await shell.childKeyMint(scope);
    if (minted.succeeded) model = { ...model, apiKey: minted.value };
    else {
      console.error(
        `[sandbox] childKeyMint failed for ${workspaceId}; using parent key:`,
        minted.error.message
      );
    }
  }
  const storage = shell.storage?.(buildCtx);
  const restore = recoveryRestore === void 0 ? shell.restore?.(buildCtx) : recoveryRestore;
  const payload = {
    name,
    image: resources.image,
    // Stamp the deferred-corpus hash so a later REUSE can skip re-writing an
    // unchanged skill corpus (materializeDeferredFilesForExistingBox reads it).
    metadata: {
      ...shell.metadata(harness),
      ...deferredFiles.length > 0 ? { [DEFERRED_CORPUS_HASH_KEY]: deferredCorpusHash(deferredFiles) } : {}
    },
    idempotencyKey: name,
    // Passed through untyped (the SDK payload type predates it); the platform
    // authz-gates it server-side and ignores it when unsupported.
    ...billingOwnerId ? { billingOwnerId } : {},
    ...userId ? { permissions: { initialUsers: [{ userId, role }] } } : {},
    env,
    secrets,
    backend: { type: harness, profile, ...model ? { model } : {} },
    ...storage ? { storage } : {},
    ...restore ? restore : {},
    ...shell.webTerminalEnabled ? { webTerminalEnabled: true } : {},
    maxLifetimeSeconds: resources.maxLifetimeSeconds,
    idleTimeoutSeconds: resources.idleTimeoutSeconds,
    resources: {
      cpuCores: resources.cpuCores,
      memoryMB: resources.memoryMB,
      diskGB: resources.diskGB
    }
  };
  assertEnvWithinLimits(env);
  assertProfilePromptWithinBudget(
    profile,
    shell.promptBudget ?? {},
    `provision profile systemPrompt for ${name}`,
    SHELL_PROMPT_BUDGET_HINT
  );
  assertProvisionPayloadWithinCap(payload ?? {});
  let box = await client.create(payload);
  await box.waitFor("running", { timeoutMs: 12e4, ...onProgress ? { onProgress } : {} });
  box = await refreshRuntimeConnection(client, box);
  if (deferredFiles.length > 0) {
    const written = await writeProfileFilesToBox(box, deferredFiles);
    if (!written.succeeded) {
      throw deferredProfileWriteFailed("new", name, written.error);
    }
  }
  if (shell.bootstrap) {
    const boot = await shell.bootstrap(box, scope);
    if (!boot.succeeded) {
      throw new Error(`bootstrap failed on new box ${name}`, { cause: boot.error });
    }
  }
  return box;
}
function resolveModel(config, override) {
  const c = config ?? {};
  const explicitBaseUrl = c.routerBaseUrl;
  const explicitApiKey = override?.modelApiKey ?? c.apiKey;
  const provider = c.providerName ?? (explicitApiKey ? "openai-compat" : c.openaiApiKey ? "openai" : void 0);
  const modelName = override?.model ?? c.modelName ?? (provider === "openai" || provider === "openai-compat" ? c.defaultModel : void 0);
  const apiKey = explicitApiKey ?? (provider === "openai" ? c.openaiApiKey : void 0);
  if (!provider || !modelName) return void 0;
  if (!apiKey && !c.allowKeylessModel) return void 0;
  return {
    model: modelName,
    provider,
    ...apiKey ? { apiKey } : {},
    ...explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}
  };
}
function historyTranscript(history) {
  return history.map((entry) => `${entry.role === "assistant" ? "Assistant" : "User"}: ${entry.content}`).join("\n\n");
}
function flattenHistory(message, history) {
  if (!history?.length) return message;
  return `${historyTranscript(history)}

User: ${message}`;
}
function mergeHistoryIntoParts(parts, history) {
  if (!history?.length) return parts;
  const textIndex = parts.findIndex((part) => part.type === "text");
  if (textIndex === -1) {
    throw new Error("mergeHistoryIntoParts requires at least one text part to carry the history");
  }
  const textPart = parts[textIndex];
  const merged = [...parts];
  merged[textIndex] = { ...textPart, text: `${historyTranscript(history)}

User: ${textPart.text}` };
  return merged;
}
function mergeExtraMcp(appToolMcp, baseProfileMcp, extra) {
  for (const key of Object.keys(extra ?? {})) {
    if (key in appToolMcp || key in baseProfileMcp) {
      throw new Error(`extraMcp key '${key}' collides with an existing profile MCP server`);
    }
  }
  return { ...appToolMcp, ...extra ?? {} };
}
function attachReasoningEffort(profile, harness, effort) {
  if (!effort || effort === "auto") return profile;
  return {
    ...profile,
    extensions: {
      ...profile.extensions ?? {},
      [harness]: {
        ...profile.extensions?.[harness] ?? {},
        reasoningEffort: effort
      }
    }
  };
}
async function* streamSandboxPrompt(shell, box, message, options) {
  const harness = options?.harness ?? "opencode";
  const model = resolveModel(shell.provider, {
    model: options?.model,
    modelApiKey: options?.modelApiKey
  });
  if (model?.model) assertHarnessModelCompatible(harness, model.model);
  const prompt = typeof message === "string" ? flattenHistory(message, options?.history) : mergeHistoryIntoParts(message, options?.history);
  const appToolMcp = options?.appToolMcp ?? {};
  const extraMcp = mergeExtraMcp(appToolMcp, options?.baseProfileMcp ?? {}, options?.extraMcp);
  const profile = shell.profile({ systemPrompt: options?.systemPrompt, extraMcp, harness });
  const profileWithEffort = attachReasoningEffort(profile, harness, options?.effort);
  assertProfilePromptWithinBudget(
    profileWithEffort,
    shell.promptBudget ?? {},
    "streamSandboxPrompt profile systemPrompt",
    SHELL_PROMPT_BUDGET_HINT
  );
  if (options?.onProfileResolved) {
    options.onProfileResolved(
      await fingerprintAgentProfile(profileWithEffort, { model: model?.model, harness })
    );
  }
  const stream = box.streamPrompt(prompt, {
    sessionId: options?.sessionId,
    executionId: options?.executionId,
    lastEventId: options?.lastEventId,
    ...options?.signal ? { signal: options.signal } : {},
    ...options?.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
    ...options?.requireVisibleAssistantOutput !== void 0 ? { requireVisibleAssistantOutput: options.requireVisibleAssistantOutput } : {},
    ...options?.detach ? { detach: true } : {},
    backend: {
      type: harness,
      profile: profileWithEffort,
      ...model ? { model } : {},
      ...options?.interactions ? { interactions: options.interactions } : {}
    }
  });
  let severedFinishReason = null;
  for await (const event of stream) {
    const step = classifySeveredStream(event);
    if (step) severedFinishReason = step.kind === "step-finish" && step.severed ? step.reason : null;
    if (severedFinishReason && isTerminalPromptEvent(event)) {
      throw new Error(`sandbox model stream severed mid-turn (reason="${severedFinishReason}")`);
    }
    if (options?.disallowQuestions) {
      const q = detectInteractiveQuestion(event);
      if (q) {
        throw new Error(`sandbox agent asked an interactive question during an autonomous run: ${q}`);
      }
    }
    yield event;
  }
  if (severedFinishReason) {
    throw new Error(`sandbox model stream severed mid-turn (reason="${severedFinishReason}")`);
  }
}
function textPartId(part, fallback) {
  for (const key of ["id", "partId", "messagePartId"]) {
    const value = part?.[key];
    if (typeof value === "string" && value.trim()) return value;
  }
  return fallback;
}
function dispatchedPromptTexts(message, history) {
  const raw = typeof message === "string" ? message : message.find((part) => part.type === "text")?.text ?? "";
  return [...new Set([raw, flattenHistory(raw, history)].map((text) => text.trim()))].filter(Boolean);
}
function lastNonPromptTextPart(parts, promptTexts) {
  const values = Array.from(parts.values()).map((value) => value.trim()).filter((value) => value && !promptTexts.includes(value));
  return values.at(-1) ?? "";
}
async function collectSandboxPromptText(events, message, history) {
  let finalText = "";
  const textParts = /* @__PURE__ */ new Map();
  let anonymousTextPart = 0;
  for await (const rawEvent of events) {
    const event = rawEvent;
    if (!event.type) continue;
    if (event.type === "message.part.updated") {
      const part = event.data?.part;
      const delta = typeof event.data?.delta === "string" ? event.data.delta : null;
      if (String(part?.type ?? "") === "text") {
        const partId = textPartId(part, delta ? "delta" : `text-${anonymousTextPart++}`);
        if (delta) textParts.set(partId, `${textParts.get(partId) ?? ""}${delta}`);
        else if (typeof part?.text === "string") textParts.set(partId, part.text);
      }
    } else if (event.type === "result") {
      const resultText = typeof event.data?.finalText === "string" ? event.data.finalText : null;
      if (resultText?.trim()) finalText = resultText;
    }
  }
  return finalText || lastNonPromptTextPart(textParts, dispatchedPromptTexts(message, history));
}
async function runSandboxPrompt(shell, box, message, options) {
  return collectSandboxPromptText(
    streamSandboxPrompt(shell, box, message, options),
    message,
    options?.history
  );
}
async function syncSandboxMemberAdd(box, seam, userId, role) {
  try {
    await box.permissions.add({ userId, role: seam.roleToSandboxRole(role) });
    return ok(void 0);
  } catch (err) {
    return fail(err);
  }
}
async function syncSandboxMemberRemove(box, userId) {
  try {
    await box.permissions.remove(userId, { preserveHomeDir: true });
    return ok(void 0);
  } catch (err) {
    return fail(err);
  }
}
async function syncSandboxMemberRole(box, seam, userId, role) {
  try {
    await box.permissions.update(userId, { role: seam.roleToSandboxRole(role) });
    return ok(void 0);
  } catch (err) {
    return fail(err);
  }
}
function secretStoreFromClient(shell) {
  const client = getClient(shell);
  return {
    create: async (name, value) => {
      await client.secrets.create(name, value);
    },
    update: async (name, value) => {
      await client.secrets.update(name, value);
    },
    get: (name) => client.secrets.get(name),
    delete: async (name) => {
      await client.secrets.delete(name);
    }
  };
}
async function storeSecret(store, name, value) {
  try {
    await store.create(name, value);
    return ok(void 0);
  } catch {
    try {
      await store.update(name, value);
      return ok(void 0);
    } catch (err) {
      return fail(new Error(`Failed to store sandbox secret ${name}`, { cause: err }));
    }
  }
}
async function readSecret(store, name) {
  try {
    return ok(await store.get(name));
  } catch (err) {
    return fail(err);
  }
}
async function deleteSecret(store, name) {
  try {
    await store.delete(name);
    return ok(void 0);
  } catch (err) {
    return fail(err);
  }
}
async function mintSandboxScopedToken(box, options) {
  try {
    const token = await box.mintScopedToken({
      scope: options.scope,
      ...options.sessionId ? { sessionId: options.sessionId } : {},
      ...options.ttlMinutes ? { ttlMinutes: options.ttlMinutes } : {}
    });
    return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope });
  } catch (err) {
    return fail(err);
  }
}
async function driveSandboxTurn(shell, box, message, options) {
  const harness = options.harness ?? "opencode";
  const model = resolveModel(shell.provider, {
    model: options.model,
    modelApiKey: options.modelApiKey
  });
  if (model?.model) assertHarnessModelCompatible(harness, model.model);
  const prompt = typeof message === "string" ? flattenHistory(message, options.history) : mergeHistoryIntoParts(message, options.history);
  const appToolMcp = options.appToolMcp ?? {};
  const extraMcp = mergeExtraMcp(appToolMcp, options.baseProfileMcp ?? {}, options.extraMcp);
  const profile = attachReasoningEffort(
    shell.profile({ systemPrompt: options.systemPrompt, extraMcp, harness }),
    harness,
    options.effort
  );
  assertProfilePromptWithinBudget(
    profile,
    shell.promptBudget ?? {},
    "driveSandboxTurn profile systemPrompt",
    SHELL_PROMPT_BUDGET_HINT
  );
  try {
    const drive = await box.driveTurn(prompt, {
      sessionId: options.sessionId,
      ...options.turnId ? { turnId: options.turnId } : {},
      ...options.wallCapMs !== void 0 ? { wallCapMs: options.wallCapMs } : {},
      ...options.executionId ? { executionId: options.executionId } : {},
      ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
      ...options.signal ? { signal: options.signal } : {},
      // Deliberately NO `interactions` here: detached turns (cron / mission steps) have
      // no consumer to answer a question. Interactive Q&A is streaming-path only.
      backend: { type: harness, profile, ...model ? { model } : {} }
    });
    return ok(drive);
  } catch (err) {
    return fail(err);
  }
}
var SEVERED_FINISH_REASONS = /* @__PURE__ */ new Set(["error", "other", "unknown"]);
function asPlainRecord(v) {
  return v && typeof v === "object" && !Array.isArray(v) ? v : null;
}
function classifySeveredStream(event) {
  const root = asPlainRecord(event);
  if (!root || root.type !== "message.part.updated") return null;
  const body = asPlainRecord(root.properties) ?? asPlainRecord(root.data) ?? root;
  const part = asPlainRecord(body.part);
  if (!part) return null;
  if (part.type === "step-start") return { kind: "step-start" };
  if (part.type !== "step-finish") return null;
  const reason = typeof part.reason === "string" && part.reason ? part.reason : "unknown";
  return { kind: "step-finish", reason, severed: SEVERED_FINISH_REASONS.has(reason) };
}
function isTerminalPromptEvent(event) {
  const t = asPlainRecord(event)?.type;
  return t === "result" || t === "done";
}
function detectInteractiveQuestion(event) {
  const root = asPlainRecord(event);
  if (!root) return null;
  const type = typeof root.type === "string" ? root.type : void 0;
  const data = asPlainRecord(root.data);
  const props = asPlainRecord(root.properties);
  const body = props ?? data ?? root;
  if (type === "question.asked" || type === "question") return firstQuestionText(body);
  if (type === "interaction" && body.kind === "question") return firstQuestionText(body);
  const part = asPlainRecord(data?.part) ?? asPlainRecord(body.part);
  const tool = typeof part?.tool === "string" && part.tool || typeof part?.name === "string" && part.name || typeof body.tool === "string" && body.tool || void 0;
  const isQ = type === "message.part.updated" && (tool === "question" || asPlainRecord(part)?.type === "question");
  if (!isQ) return null;
  const state = asPlainRecord(asPlainRecord(part)?.state);
  return firstQuestionText(asPlainRecord(state?.input) ?? state ?? part ?? body);
}
function firstQuestionText(value) {
  const arr = Array.isArray(value?.questions) ? value.questions : Array.isArray(asPlainRecord(value?.input)?.questions) ? asPlainRecord(value.input).questions : [];
  const first = asPlainRecord(arr[0]);
  const q = typeof first?.question === "string" && first.question || typeof first?.prompt === "string" && first.prompt || void 0;
  return q ?? "interactive question";
}

export {
  shellQuote,
  statSandboxFileSize,
  readSandboxBinaryBytes,
  mintTerminalProxyToken,
  verifyTerminalProxyToken,
  createWorkspaceSandboxManager,
  createSandboxTerminalToken,
  verifySandboxTerminalToken,
  createWorkspaceSandboxConnectionHandler,
  createWorkspaceSandboxRuntimeProxyHandler,
  matchSandboxTerminalWsPath,
  isSandboxTerminalWsUpgrade,
  createWorkspaceSandboxTerminalUpgradeHandler,
  buildSandboxRuntimeProxyHeaders,
  encodeSandboxRuntimePath,
  bearerToken,
  bearerSubprotocolToken,
  terminalTokenFromRequest,
  resolveSandboxClientCredentials,
  DEFAULT_SANDBOX_RESOURCES,
  getClient,
  resetClientCache,
  buildAppToolMcpServers,
  sandboxToolRootDir,
  sandboxToolBinDir,
  sandboxToolPath,
  buildSandboxToolFileMounts,
  buildSandboxToolPathSetupScript,
  runSandboxToolPathSetup,
  splitDeferredProfileFiles,
  SandboxRuntimeAuthRefreshError,
  writeProfileFilesToBox,
  deferredCorpusHash,
  PROVISION_PAYLOAD_MAX_BYTES,
  ENV_VALUE_MAX_BYTES,
  ENV_TOTAL_MAX_BYTES,
  assertProvisionPayloadWithinCap,
  assertEnvWithinLimits,
  peekWorkspaceSandbox,
  ensureWorkspaceSandbox,
  resolveModel,
  flattenHistory,
  mergeHistoryIntoParts,
  mergeExtraMcp,
  attachReasoningEffort,
  streamSandboxPrompt,
  collectSandboxPromptText,
  runSandboxPrompt,
  syncSandboxMemberAdd,
  syncSandboxMemberRemove,
  syncSandboxMemberRole,
  secretStoreFromClient,
  storeSecret,
  readSecret,
  deleteSecret,
  mintSandboxScopedToken,
  driveSandboxTurn,
  classifySeveredStream,
  isTerminalPromptEvent,
  detectInteractiveQuestion
};
//# sourceMappingURL=chunk-JXIQSGOV.js.map