@tangle-network/agent-app 0.43.6 → 0.43.7

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.
@@ -1188,7 +1188,8 @@ async function* streamSandboxPrompt(shell, box, message, options) {
1188
1188
  backend: {
1189
1189
  type: harness,
1190
1190
  profile: profileWithEffort,
1191
- ...model ? { model } : {}
1191
+ ...model ? { model } : {},
1192
+ ...options?.interactions ? { interactions: options.interactions } : {}
1192
1193
  }
1193
1194
  });
1194
1195
  let severedFinishReason = null;
@@ -1334,6 +1335,8 @@ async function driveSandboxTurn(shell, box, message, options) {
1334
1335
  ...options.executionId ? { executionId: options.executionId } : {},
1335
1336
  ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
1336
1337
  ...options.signal ? { signal: options.signal } : {},
1338
+ // Deliberately NO `interactions` here: detached turns (cron / mission steps) have
1339
+ // no consumer to answer a question. Interactive Q&A is streaming-path only.
1337
1340
  backend: { type: harness, profile, ...model ? { model } : {} }
1338
1341
  });
1339
1342
  if (!result.success) return fail(new Error(result.error ?? "sandbox turn failed"));
@@ -1369,6 +1372,7 @@ function detectInteractiveQuestion(event) {
1369
1372
  const props = asPlainRecord(root.properties);
1370
1373
  const body = props ?? data ?? root;
1371
1374
  if (type === "question.asked" || type === "question") return firstQuestionText(body);
1375
+ if (type === "interaction" && body.kind === "question") return firstQuestionText(body);
1372
1376
  const part = asPlainRecord(data?.part) ?? asPlainRecord(body.part);
1373
1377
  const tool = typeof part?.tool === "string" && part.tool || typeof part?.name === "string" && part.name || typeof body.tool === "string" && body.tool || void 0;
1374
1378
  const isQ = type === "message.part.updated" && (tool === "question" || asPlainRecord(part)?.type === "question");
@@ -1433,4 +1437,4 @@ export {
1433
1437
  isTerminalPromptEvent,
1434
1438
  detectInteractiveQuestion
1435
1439
  };
1436
- //# sourceMappingURL=chunk-67I332VJ.js.map
1440
+ //# sourceMappingURL=chunk-L3O65C27.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sandbox/index.ts","../src/sandbox/outcome.ts","../src/sandbox/terminal-proxy-token.ts","../src/sandbox/workspace-terminal.ts"],"sourcesContent":["import {\n Sandbox,\n type AgentProfile,\n type AgentProfileFileMount,\n type AgentProfileMcpServer,\n type ExecResult,\n type SandboxConnection,\n type SandboxInstance,\n type ScopedTokenScope,\n type StorageConfig,\n type PromptResult,\n type ProvisionEvent,\n} from '@tangle-network/sandbox'\nimport { createHash } from 'node:crypto'\nimport {\n buildAppToolMcpServer,\n type AppToolName,\n type AppToolContext,\n type ToolHeaderNames,\n} from '../tools/index'\nimport { assertHarnessModelCompatible, type Harness } from '../harness/index'\nimport {\n resolveTangleExecutionEnvironment,\n trimOrNull,\n type TangleExecutionEnvironment,\n} from '../runtime/model'\nimport { ok, fail, type Outcome } from './outcome'\n\nexport type { Outcome } from './outcome'\n\nexport interface SandboxClientCredentials {\n apiKey: string\n baseUrl: string\n}\n\n/**\n * Sandbox credential policy reuses the canonical execution-environment union\n * (development/test/staging/production) so env classification stays in one place\n * (see resolveTangleExecutionEnvironment in runtime/model).\n */\nexport type SandboxCredentialEnvironment = TangleExecutionEnvironment\n\nexport interface ResolveSandboxClientCredentialsOptions {\n /**\n * Environment object to read from. Defaults to process.env when available.\n */\n env?: Record<string, string | undefined>\n /**\n * Explicit environment classification. Defaults to APP_ENV/NODE_ENV derived\n * behavior: local/development/test use direct env credentials; staging/prod\n * require the provision callback unless allowDirectEnvCredentials opts in.\n */\n environment?: SandboxCredentialEnvironment\n /**\n * Env names that may carry a sandbox-compatible bearer. The first non-empty\n * value wins when direct env credentials are allowed.\n */\n directKeyNames?: readonly string[]\n /**\n * Env names that may carry the sandbox gateway URL. The first non-empty value\n * wins, then defaultBaseUrl.\n */\n baseUrlNames?: readonly string[]\n /**\n * Base URL used when none of baseUrlNames are present.\n */\n defaultBaseUrl?: string\n /**\n * Whether direct env credentials are allowed for this environment. Defaults\n * to true in development/test and false in staging/production.\n */\n allowDirectEnvCredentials?: boolean | ((environment: SandboxCredentialEnvironment) => boolean)\n /**\n * Product-owned provision path, usually minting a per-user sandbox key from a\n * linked platform account. Called before direct env credentials in\n * staging/production and after direct env credentials in development/test.\n */\n provision?: (\n context: {\n environment: SandboxCredentialEnvironment\n env: Record<string, string | undefined>\n },\n ) => SandboxClientCredentials | null | undefined | Promise<SandboxClientCredentials | null | undefined>\n}\n\nconst DEFAULT_SANDBOX_DIRECT_KEY_NAMES = [\n 'TCLOUD_SANDBOX_API_KEY',\n 'SANDBOX_API_KEY',\n 'TANGLE_API_KEY',\n] as const\nconst DEFAULT_SANDBOX_BASE_URL_NAMES = ['SANDBOX_GATEWAY_URL', 'SANDBOX_API_URL'] as const\n\nfunction normalizeBaseUrl(value: string): string {\n return value.trim().replace(/\\/v1\\/?$/, '').replace(/\\/+$/, '')\n}\n\nfunction processEnv(): Record<string, string | undefined> {\n return typeof process === 'undefined' ? {} : process.env\n}\n\nfunction directEnvCredentialsAllowed(\n environment: SandboxCredentialEnvironment,\n allow: ResolveSandboxClientCredentialsOptions['allowDirectEnvCredentials'],\n): boolean {\n if (typeof allow === 'function') return allow(environment)\n if (typeof allow === 'boolean') return allow\n return environment === 'development' || environment === 'test'\n}\n\nfunction resolveSandboxBaseUrl(\n env: Record<string, string | undefined>,\n names: readonly string[],\n defaultBaseUrl: string | undefined,\n): string {\n for (const name of names) {\n const value = trimOrNull(env[name])\n if (value) return normalizeBaseUrl(value)\n }\n const value = trimOrNull(defaultBaseUrl)\n if (value) return normalizeBaseUrl(value)\n throw new Error(\n `Sandbox base URL is required (set one of ${names.join(', ')} or pass defaultBaseUrl).`,\n )\n}\n\nfunction resolveDirectSandboxCredentials(\n env: Record<string, string | undefined>,\n keyNames: readonly string[],\n baseUrlNames: readonly string[],\n defaultBaseUrl: string | undefined,\n): SandboxClientCredentials | null {\n for (const name of keyNames) {\n const apiKey = trimOrNull(env[name])\n if (!apiKey) continue\n return {\n apiKey,\n baseUrl: resolveSandboxBaseUrl(env, baseUrlNames, defaultBaseUrl),\n }\n }\n return null\n}\n\nexport async function resolveSandboxClientCredentials(\n options: ResolveSandboxClientCredentialsOptions = {},\n): Promise<SandboxClientCredentials> {\n const env = options.env ?? processEnv()\n const environment = options.environment ?? resolveTangleExecutionEnvironment(env)\n const keyNames = options.directKeyNames ?? DEFAULT_SANDBOX_DIRECT_KEY_NAMES\n const baseUrlNames = options.baseUrlNames ?? DEFAULT_SANDBOX_BASE_URL_NAMES\n const directAllowed = directEnvCredentialsAllowed(environment, options.allowDirectEnvCredentials)\n const direct = () =>\n directAllowed\n ? resolveDirectSandboxCredentials(env, keyNames, baseUrlNames, options.defaultBaseUrl)\n : null\n\n if (environment === 'development' || environment === 'test') {\n const credentials = direct()\n if (credentials) return credentials\n }\n\n const provisioned = await options.provision?.({ environment, env })\n if (provisioned) {\n return {\n apiKey: provisioned.apiKey,\n baseUrl: normalizeBaseUrl(provisioned.baseUrl),\n }\n }\n\n const credentials = direct()\n if (credentials) return credentials\n\n const directHint = directAllowed\n ? ` or set one of ${keyNames.join(', ')}`\n : ''\n throw new Error(\n `Sandbox credentials are required for ${environment} (provide a provision callback${directHint}).`,\n )\n}\n\nexport interface SandboxResourceConfig {\n image: string\n cpuCores: number\n memoryMB: number\n diskGB: number\n maxLifetimeSeconds: number\n idleTimeoutSeconds: number\n}\n\nexport interface ProviderResolutionConfig {\n routerBaseUrl?: string\n apiKey?: string\n providerName?: string\n modelName?: string\n defaultModel?: string\n openaiApiKey?: string\n}\n\nexport interface SandboxBuildContext {\n workspaceId: string\n connectedIntegrationIds: string[]\n userId?: string\n}\n\n// SDK-typed snapshot storage config (re-exported for product seam closures).\nexport type { StorageConfig }\n\n// Scope handed to per-identity seams. workspaceId is always present; userId is\n// present when the lifecycle op carries one. Workspace-keyed products ignore userId.\nexport interface SandboxScope {\n workspaceId: string\n userId?: string\n}\n\n// Snapshot RESTORE-on-create. Returned alongside storage; undefined => fresh box.\nexport interface SandboxRestoreSpec {\n fromSnapshot: string\n fromSandboxId: string\n}\n\n// Reuse health gate + sidecar liveness. The exec+timeout-race is generic; the\n// sidecarProcessPattern is harness-specific (which process is the live sidecar),\n// so it is a closure. Absent => no liveness probe (reuse on metadata.harness match).\nexport interface LivenessProbeConfig {\n sidecarProcessPattern: (harness: Harness) => string\n execTimeoutMs?: number\n psTimeoutMs?: number\n}\n\nexport interface ProfileComposeOptions {\n systemPrompt?: string\n extraFiles?: AgentProfileFileMount[]\n extraMcp?: Record<string, AgentProfileMcpServer>\n name?: string\n}\n\nexport interface SandboxRuntimeConfig {\n // Widened to accept an optional scope and be async so a per-user key can be\n // minted. The sync, no-arg form still satisfies the type (back-compat).\n credentials: (\n scope?: SandboxScope,\n ) => SandboxClientCredentials | null | Promise<SandboxClientCredentials | null>\n name: (workspaceId: string) => string\n metadata: (harness: Harness) => Record<string, unknown>\n connectedIntegrationIds: (workspaceId: string) => Promise<string[]>\n env: (ctx: SandboxBuildContext) => Promise<Record<string, string>>\n files: (ctx: SandboxBuildContext) => Promise<AgentProfileFileMount[]>\n secrets: (workspaceId: string) => Promise<string[]>\n profile: (options: ProfileComposeOptions) => AgentProfile\n permissionRole?: (workspaceRole: string) => SandboxPermissionLevel\n resources?: SandboxResourceConfig\n provider?: ProviderResolutionConfig\n\n // BYOS3/R2 snapshot storage. Returns undefined => key omitted entirely\n // (fail-closed when creds absent). Product owns bucket/endpoint/credentials/prefix.\n storage?: (ctx: SandboxBuildContext) => StorageConfig | undefined\n // Snapshot RESTORE-on-create. undefined => fresh box.\n restore?: (ctx: SandboxBuildContext) => SandboxRestoreSpec | undefined\n // Per-identity box NAME. Defaults to name(scope.workspaceId) when absent.\n boxKey?: (scope: SandboxScope) => string\n // Per-workspace child-key mint: overrides the resolved model apiKey before create.\n // Applied only when a model is resolved and its provider is openai-compat.\n childKeyMint?: (scope: SandboxScope) => Promise<Outcome<string>>\n // One-shot post-running bootstrap, on BOTH create and reuse paths (idempotency\n // is the closure's job — it owns the marker check).\n bootstrap?: (box: SandboxInstance, scope: SandboxScope) => Promise<Outcome<void>>\n // Reuse health gate + sidecar liveness probe.\n livenessProbe?: LivenessProbeConfig\n // Enable browser terminal endpoints on newly-created sandboxes.\n webTerminalEnabled?: boolean\n // default true: try stopped-resume before create.\n resumeStopped?: boolean\n // default false: bake resolveModel() into backend.model at create.\n backendModelAtCreate?: boolean\n // default false: write the profile's `resources.files` INTO the box after it\n // reaches running (via `box.exec`), instead of inlining them in the create\n // payload. The orchestrator caps the provision body at 256 KiB; a large\n // file corpus (skills, tool scripts) blows that cap. Deferring it keeps the\n // provision body small and uncapped in corpus size, and lands real files on\n // disk — which is also the only path that works for harnesses whose backend\n // does not materialize the provider-neutral `resources.files` channel.\n //\n // Only `kind: 'inline'` files are deferred; non-inline refs (e.g. github)\n // stay in the create payload so the orchestrator resolves them. Runs on the\n // create AND resume/reuse paths (idempotent overwrite). Inline files are\n // STRIPPED from `resources.files` before create when this is set.\n deferProfileFiles?: boolean\n}\n\nexport const DEFAULT_SANDBOX_RESOURCES: SandboxResourceConfig = {\n image: 'universal',\n cpuCores: 2,\n memoryMB: 4096,\n diskGB: 10,\n maxLifetimeSeconds: 86400,\n idleTimeoutSeconds: 3600,\n}\n\ninterface ClientCacheEntry {\n client: Sandbox\n fingerprint: string\n}\n\nlet _cached: ClientCacheEntry | null = null\n\nfunction getClientFromCreds(creds: SandboxClientCredentials): Sandbox {\n const fingerprint = `${creds.apiKey} ${creds.baseUrl}`\n if (_cached && _cached.fingerprint === fingerprint) return _cached.client\n\n const client = new Sandbox({ apiKey: creds.apiKey, baseUrl: creds.baseUrl })\n _cached = { client, fingerprint }\n return client\n}\n\n// Sync client for non-scoped callers (secretStoreFromClient etc.). Resolves\n// credentials with no scope; throws if the seam returns a Promise — scoped\n// products must use the async ensureWorkspaceSandbox path.\nexport function getClient(shell: SandboxRuntimeConfig): Sandbox {\n const creds = shell.credentials()\n if (creds && typeof (creds as Promise<unknown>).then === 'function') {\n throw new Error('getClient: scoped (async) credentials require the async sandbox path')\n }\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n return getClientFromCreds(creds as SandboxClientCredentials)\n}\n\nexport function resetClientCache(): void {\n _cached = null\n}\n\nexport interface AppToolDescriptor {\n tool: AppToolName\n key: string\n description: string\n}\n\nexport interface BuildAppToolMcpServersOptions {\n tools: AppToolDescriptor[]\n baseUrl: string\n token: string\n ctx: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\nexport function buildAppToolMcpServers(\n options: BuildAppToolMcpServersOptions,\n): Record<string, AgentProfileMcpServer> {\n const entries: Record<string, AgentProfileMcpServer> = {}\n for (const { tool, key, description } of options.tools) {\n entries[key] = buildAppToolMcpServer({\n tool,\n baseUrl: options.baseUrl,\n token: options.token,\n ctx: options.ctx,\n description,\n headerNames: options.headerNames,\n }) as AgentProfileMcpServer\n }\n return entries\n}\n\nexport interface EnsureWorkspaceSandboxOptions {\n workspaceId: string\n userId?: string\n harness: Harness\n // When set, both the running-reuse and stopped-resume short-circuits are\n // skipped and any name-matched box is deleted before create.\n forceNew?: boolean\n // Real-time provisioning progress from the SDK's SSE stream, forwarded from\n // the `waitFor('running')` calls on the resume and cold-create paths. Callers\n // surface it as live \"warming up\" status. Only fires while a box is actually\n // being provisioned; a reused running box emits nothing.\n onProgress?: (event: ProvisionEvent) => void\n}\n\n// Single-quote a string for safe interpolation into a shell command.\nfunction shellSingleQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`\n}\n\nexport interface SandboxToolSpec {\n name: string\n content: string\n executable?: boolean\n}\n\nexport interface SandboxToolPathOptions {\n appName: string\n baseDir?: string\n binDir?: string\n}\n\nexport interface BuildSandboxToolFileMountsOptions extends SandboxToolPathOptions {\n tools: readonly SandboxToolSpec[]\n}\n\nconst DEFAULT_SANDBOX_TOOL_BASE_DIR = '/home/agent/tools'\nconst SAFE_TOOL_SEGMENT = /^[A-Za-z0-9._-]+$/\n\nfunction normalizeSandboxToolSegment(value: string, label: string): string {\n const segment = value.trim()\n if (!segment || segment === '.' || segment === '..' || !SAFE_TOOL_SEGMENT.test(segment)) {\n throw new Error(`${label} must contain only letters, numbers, dots, underscores, or hyphens.`)\n }\n return segment\n}\n\nfunction normalizeSandboxToolDir(value: string, label: string): string {\n const dir = value.trim().replace(/\\/+$/, '')\n if (!dir || !dir.startsWith('/') || dir.includes('\\0') || dir.includes('\\n')) {\n throw new Error(`${label} must be an absolute sandbox path.`)\n }\n return dir === '' ? '/' : dir\n}\n\nexport function sandboxToolRootDir(options: SandboxToolPathOptions): string {\n const appName = normalizeSandboxToolSegment(options.appName, 'sandbox tool appName')\n const baseDir = normalizeSandboxToolDir(\n options.baseDir ?? DEFAULT_SANDBOX_TOOL_BASE_DIR,\n 'sandbox tool baseDir',\n )\n return `${baseDir}/${appName}`\n}\n\nexport function sandboxToolBinDir(options: SandboxToolPathOptions): string {\n normalizeSandboxToolSegment(options.appName, 'sandbox tool appName')\n if (options.binDir) return normalizeSandboxToolDir(options.binDir, 'sandbox tool binDir')\n return `${sandboxToolRootDir(options)}/bin`\n}\n\nexport function sandboxToolPath(options: SandboxToolPathOptions & { toolName: string }): string {\n const toolName = normalizeSandboxToolSegment(options.toolName, 'sandbox tool name')\n return `${sandboxToolBinDir(options)}/${toolName}`\n}\n\nexport function buildSandboxToolFileMounts(\n options: BuildSandboxToolFileMountsOptions,\n): AgentProfileFileMount[] {\n return options.tools.map((tool) => {\n const name = normalizeSandboxToolSegment(tool.name, 'sandbox tool name')\n return {\n path: sandboxToolPath({ ...options, toolName: name }),\n resource: { kind: 'inline' as const, name, content: tool.content },\n executable: tool.executable ?? true,\n }\n })\n}\n\nexport function buildSandboxToolPathSetupScript(options: SandboxToolPathOptions): string {\n const binDir = sandboxToolBinDir(options)\n const exportLine = `export PATH=${binDir}:$PATH`\n return [\n 'set -eu',\n `mkdir -p ${shellSingleQuote(binDir)}`,\n `PATH=${shellSingleQuote(binDir)}:$PATH`,\n 'export PATH',\n 'for profile in \"${HOME:-/home/agent}/.profile\" \"${HOME:-/home/agent}/.bashrc\" \"${HOME:-/home/agent}/.zshrc\"; do',\n ' mkdir -p \"$(dirname \"$profile\")\"',\n ' touch \"$profile\"',\n ` grep -Fqx ${shellSingleQuote(exportLine)} \"$profile\" || printf '\\\\n%s\\\\n' ${shellSingleQuote(exportLine)} >> \"$profile\"`,\n 'done',\n ].join('\\n')\n}\n\nexport async function runSandboxToolPathSetup(\n box: SandboxInstance,\n options: SandboxToolPathOptions,\n): Promise<Outcome<void>> {\n try {\n const res = await box.exec(buildSandboxToolPathSetupScript(options))\n if (res.exitCode !== 0) {\n return fail(\n new Error(\n `runSandboxToolPathSetup: failed to configure PATH for ${sandboxToolBinDir(options)} ` +\n `(exit ${res.exitCode}): ${res.stderr.slice(0, 500)}`,\n ),\n )\n }\n return ok(undefined)\n } catch (err) {\n return fail(new Error('runSandboxToolPathSetup: exec failed', { cause: err }))\n }\n}\n\n// Build a shell-safe path token that preserves tilde-home semantics. A path\n// beginning `~/` (or a bare `~`) must resolve to the box user's real `$HOME`,\n// but single-quoting the whole path suppresses shell `~` expansion and lands\n// the file in a literal directory named `~`. Expand the leading `~` to an\n// UNQUOTED `\"$HOME\"` (so the shell expands it) and single-quote only the\n// remainder. Absolute and relative paths are single-quoted unchanged.\nfunction shellPath(path: string): string {\n if (path === '~') return '\"$HOME\"'\n if (path.startsWith('~/')) {\n const rest = path.slice(2)\n return rest ? `\"$HOME\"/${shellSingleQuote(rest)}` : '\"$HOME\"'\n }\n return shellSingleQuote(path)\n}\n\n// Split a profile's `resources.files` into the inline mounts that can be\n// written into a running box and the rest (non-inline refs that the\n// orchestrator must resolve, so they stay in the create payload). Returns the\n// inline set to defer and a profile copy with those inline files removed.\nexport function splitDeferredProfileFiles(\n profile: AgentProfile,\n): { leanProfile: AgentProfile; deferredFiles: AgentProfileFileMount[] } {\n const files = profile.resources?.files ?? []\n const deferredFiles: AgentProfileFileMount[] = []\n const keptFiles: AgentProfileFileMount[] = []\n for (const mount of files) {\n if (mount.resource.kind === 'inline') deferredFiles.push(mount)\n else keptFiles.push(mount)\n }\n if (deferredFiles.length === 0) return { leanProfile: profile, deferredFiles }\n const leanProfile: AgentProfile = {\n ...profile,\n resources: { ...(profile.resources ?? {}), files: keptFiles },\n }\n return { leanProfile, deferredFiles }\n}\n\n// The runtime exec proxy (`box.exec` → /terminals/commands) hangs (30s\n// timeout) on any request whose body crosses ~4096 bytes, and one oversized\n// exec wedges the channel so every later exec on the box hangs too. We slice\n// each file's base64 into appends whose full command string stays well under\n// that cap. 3000 chars of base64 leaves ~1000 bytes of headroom for the\n// surrounding `printf '%s' '<slice>' >> <path>.b64` command plus the proxy's\n// JSON request envelope — comfortably below 4096.\nconst PROFILE_WRITE_B64_CHUNK_CHARS = 3000\n\n// gtm's corpus is ~135 small execs; on a cold box the runtime exec proxy\n// hard-throttles (HTTP 429 after ~21 execs in ~34s) and, under sustained load,\n// SILENTLY HANGS instead of returning 429 — one parked exec wedges the channel\n// and `writeProfileFilesToBox` never returns, so `ensureWorkspaceSandbox`\n// parks the worker (~140s, no exception). These failures plus sidecar exec-plane\n// readiness/transport failures (5xx, reset, fetch/network errors) are transient:\n// retry the SAME exec with exponential backoff before failing loud. A non-zero\n// exit is a real command failure, never retried.\nconst PROFILE_WRITE_MAX_RETRIES = 4\nconst PROFILE_WRITE_RETRY_BASE_MS = 250\nconst PROFILE_WRITE_RETRY_MAX_MS = 2000\n\n// Client-side hard ceiling per exec. The proxy's own 30s timeout is unreliable\n// once the channel wedges (it can hang past it), so we race each exec against an\n// independent timer we control: a wedged exec is abandoned here and retried as a\n// transient transport error, never silently parked. We also pass timeoutMs to\n// the SDK as defense-in-depth, but the race is the guarantee.\nconst PROFILE_WRITE_EXEC_TIMEOUT_MS = 30_000\n\n// Pacing between execs to stay under the proxy throttle that triggers the hang.\n// The drill saw throttling at ~0.6 exec/s bursts; ~150ms between ~135 execs\n// adds well under a minute total and keeps the burst rate below the trip point.\n// On by default for the deferred path; overridable for tests/tuning.\nconst PROFILE_WRITE_PACE_MS = 150\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms))\n\n// A mount whose path sits in a bin directory is made executable. Shared so the\n// file-API eligibility check and the exec branch agree on \"executable by dir\".\nconst PROFILE_BIN_DIR_RE = /(^|\\/)(s?bin)\\//\n\n// Sentinel cause for a client-side per-exec timeout (a hung/wedged proxy exec).\n// Carried as the `.cause` of the fail-loud Outcome so callers see the wedged\n// command instead of an opaque infinite hang.\nclass ProfileWriteExecTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`exec exceeded ${timeoutMs}ms (proxy hang/wedge)`)\n this.name = 'ProfileWriteExecTimeoutError'\n }\n}\n\n// Run a box.exec, abandoning it if it does not settle within timeoutMs. The\n// returned promise rejects with ProfileWriteExecTimeoutError on timeout so the\n// retry loop treats a hang exactly like a transient transport error. We also\n// forward timeoutMs to the SDK so the underlying request is cancelled when the\n// SDK honors it; the race covers the case where it does not.\nfunction execWithTimeout(\n box: SandboxInstance,\n cmd: string,\n timeoutMs: number,\n): Promise<ExecResult> {\n return new Promise<ExecResult>((resolve, reject) => {\n let settled = false\n const timer = setTimeout(() => {\n if (settled) return\n settled = true\n reject(new ProfileWriteExecTimeoutError(timeoutMs))\n }, timeoutMs)\n box.exec(cmd, { timeoutMs }).then(\n (res) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n resolve(res)\n },\n (err) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n reject(err)\n },\n )\n })\n}\n\nconst TRANSIENT_EXEC_STATUS_CODES = new Set([408, 409, 425, 429, 500, 502, 503, 504])\nconst TRANSIENT_EXEC_CODE_RE = /^(ECONNRESET|ECONNREFUSED|ETIMEDOUT|EPIPE|ECONNABORTED)$/i\nconst TRANSIENT_EXEC_MESSAGE_RE =\n /\\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\nconst RUNTIME_AUTH_REFRESH_SKEW_MS = 60_000\n\nfunction errorStatus(err: { status?: unknown; statusCode?: unknown; response?: unknown }): number | undefined {\n const rawStatus = err.status ?? err.statusCode ?? (\n err.response && typeof err.response === 'object'\n ? (err.response as { status?: unknown }).status\n : undefined\n )\n if (typeof rawStatus === 'number') return rawStatus\n if (typeof rawStatus === 'string' && /^\\d+$/.test(rawStatus)) return Number(rawStatus)\n return undefined\n}\n\nfunction retryAfterMs(err: unknown, seen = new Set<object>()): number | undefined {\n if (!err || typeof err !== 'object') return undefined\n if (seen.has(err)) return undefined\n seen.add(err)\n const e = err as { retryAfterMs?: unknown; cause?: unknown }\n if (typeof e.retryAfterMs === 'number') return e.retryAfterMs\n return retryAfterMs(e.cause, seen)\n}\n\nfunction isTransientExecError(err: unknown, seen = new Set<object>()): boolean {\n if (!err || typeof err !== 'object') return false\n if (seen.has(err)) return false\n seen.add(err)\n const e = err as {\n status?: unknown\n statusCode?: unknown\n response?: unknown\n code?: unknown\n message?: unknown\n cause?: unknown\n }\n const status = errorStatus(e)\n if (status !== undefined && TRANSIENT_EXEC_STATUS_CODES.has(status)) return true\n if (typeof e.code === 'string') {\n if (TRANSIENT_EXEC_CODE_RE.test(e.code)) return true\n if (/rate.?limit|too.?many.?requests|429|server.?error|service.?unavailable/i.test(e.code)) return true\n }\n if (typeof e.message === 'string' && TRANSIENT_EXEC_MESSAGE_RE.test(e.message)) return true\n return isTransientExecError(e.cause, seen)\n}\n\nfunction isRuntimeExecAuthError(err: unknown, seen = new Set<object>()): boolean {\n if (!err || typeof err !== 'object') return false\n if (seen.has(err)) return false\n seen.add(err)\n const e = err as {\n status?: unknown\n statusCode?: unknown\n response?: unknown\n code?: unknown\n name?: unknown\n message?: unknown\n cause?: unknown\n }\n if (errorStatus(e) === 401) return true\n if (\n typeof e.code === 'string' &&\n /^(AUTH_ERROR|AUTHENTICATION_ERROR|UNAUTHORIZED|UNAUTHENTICATED|ERR_UNAUTHORIZED|ERR_UNAUTHENTICATED|401)$/i.test(e.code)\n ) {\n return true\n }\n if (\n typeof e.name === 'string' &&\n /^(AuthError|AuthenticationError|UnauthorizedError|UnauthenticatedError|SandboxAuthError)$/i.test(e.name)\n ) {\n return true\n }\n return isRuntimeExecAuthError(e.cause, seen)\n}\n\nfunction isRuntimeAuthRefreshDenied(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false\n return (\n isRuntimeExecAuthError(err) ||\n errorStatus(err as { status?: unknown; statusCode?: unknown; response?: unknown }) === 403\n )\n}\n\n// Classify an exec failure as transient-retryable. Retryable shapes share the\n// same backoff path: rate-limit (HTTP 429 + retryAfterMs), client-side timeout,\n// and transient sidecar/transport/readiness failures surfaced as SandboxError-\n// shaped objects, fetch errors, network resets, or 5xx-ish messages. Everything\n// else fails loud. Non-zero shell exits never reach this classifier.\nfunction transientExecError(err: unknown): { retryable: boolean; retryAfterMs?: number } {\n if (err instanceof ProfileWriteExecTimeoutError) return { retryable: true }\n if (isTransientExecError(err)) return { retryable: true, retryAfterMs: retryAfterMs(err) }\n return { retryable: false }\n}\n\nfunction deferredProfileWriteFailed(stage: 'new' | 'reused' | 'resumed', name: string, cause: Error): Error {\n return new Error(`deferred file write failed on ${stage} box ${name}: ${cause.message}`, { cause })\n}\n\ntype ExistingBoxStage = 'reused' | 'resumed'\n\nexport class SandboxRuntimeAuthRefreshError extends Error {\n constructor(stage: ExistingBoxStage, name: string, detail: string, cause?: unknown) {\n super(`${stage} sandbox auth refresh failed for ${name}: ${detail}`, { cause })\n this.name = 'SandboxRuntimeAuthRefreshError'\n }\n}\n\n// Materialize inline profile files into a running box via `box.exec`. Uses a\n// base64 pipe so arbitrary content (scripts, unicode, special chars) lands\n// byte-exact, and writes to ANY absolute path (e.g. /usr/local/bin) or a\n// `~`-relative path — the exec runs as the sidecar, which is not bound by the\n// safe-prefix allow-list the /files/write API enforces. Sets the executable\n// bit when the mount declares it OR the target is a bin directory.\n//\n// Each file is written in several small execs (mkdir, one append per base64\n// chunk, then a decode+cleanup) so no single exec request body trips the\n// ~4 KiB proxy cap. Writes are sequential; a single bad mount stops the batch\n// and the first failure is returned (fail-loud), the rest are not attempted.\n//\n// Each exec is bounded by a client-side hard timeout and retried with backoff\n// on transient rate-limit/readiness/transport failures, so one wedged or early\n// exec-plane request can never park the caller (and thus never park provisioning).\n// A small pace between execs keeps the burst rate below the proxy throttle that\n// triggers the hang.\nexport interface WriteProfileFilesOptions {\n // Hard ceiling per exec (ms). A hung/wedged exec is abandoned and retried.\n execTimeoutMs?: number\n // Delay between execs (ms) to stay under the proxy throttle. 0 disables it.\n paceMs?: number\n // Max retries for a transient exec before failing loud.\n maxRetries?: number\n}\n\n// The workspace-relative target for a deferred inline mount when it can be\n// materialized through the sidecar file API (`box.fs.writeMany` — FILES rate\n// group, 300/min, whole-file, auto-mkdir) instead of the chunked terminal-exec\n// path (50/min); null when it must stay on exec. The file API resolves relative\n// paths from the workspace root, so eligibility is: inline and a path that\n// resolves under the workspace root with no `..`/`.sidecar` segment. `~/…` and\n// `/home/agent/…` are home-relative; agent sandboxes set $HOME to the workspace\n// root, so both map to the same relative target. Other absolute (`/…`) and bare\n// `~`/`~user` mounts stay on exec.\nfunction fileApiTarget(mount: AgentProfileFileMount): string | null {\n if (mount.resource.kind !== 'inline') return null\n let rel: string\n if (mount.path.startsWith('~/')) rel = mount.path.slice(2)\n else if (mount.path.startsWith('/home/agent/')) rel = mount.path.slice('/home/agent/'.length)\n else if (mount.path.startsWith('/') || mount.path.startsWith('~')) return null\n else rel = mount.path\n if (rel.length === 0 || rel.startsWith('/') || rel.split('/').some((seg) => seg === '..' || seg === '.sidecar')) {\n return null\n }\n return rel\n}\n\nfunction isExecutableProfileFile(mount: AgentProfileFileMount): boolean {\n return mount.executable ?? PROFILE_BIN_DIR_RE.test(mount.path)\n}\n\nfunction profileFileMode(mount: AgentProfileFileMount): number | undefined {\n return isExecutableProfileFile(mount) ? 0o755 : undefined\n}\n\nfunction fileApiSupportsMode(box: SandboxInstance): boolean {\n const fs = box.fs as (SandboxInstance['fs'] & { supportsWriteMode?: boolean }) | undefined\n return fs?.supportsWriteMode === true\n}\n\nexport async function writeProfileFilesToBox(\n box: SandboxInstance,\n files: AgentProfileFileMount[],\n options: WriteProfileFilesOptions = {},\n): Promise<Outcome<void>> {\n const execTimeoutMs = options.execTimeoutMs ?? PROFILE_WRITE_EXEC_TIMEOUT_MS\n const paceMs = options.paceMs ?? PROFILE_WRITE_PACE_MS\n const maxRetries = options.maxRetries ?? PROFILE_WRITE_MAX_RETRIES\n // The bulk of a profile corpus (skills, `~/.claude/skills/…`, config) is\n // inline and workspace-relative — write it in ONE paced,\n // retry-aware batch via the SDK's file API (`box.fs.writeMany`, FILES rate\n // group 300/min). The SDK owns the pacing + transient-retry this module used\n // to hand-roll. Absolute / bare-`~` paths can't use the file API\n // (prefix-restricted), so they stay on the chunked exec path.\n // Capability-guarded: SDKs without `writeMany` route everything through\n // exec; SDKs before @tangle-network/sandbox 0.9.4 keep executable files on\n // exec because they do not expose `supportsWriteMode` or forward file modes.\n const fileApiAvailable = typeof box.fs?.writeMany === 'function'\n const modeAwareFileApi = fileApiSupportsMode(box)\n const viaFileApi: { path: string; content: string; mode?: number }[] = []\n const viaExec: AgentProfileFileMount[] = []\n for (const mount of files) {\n if (mount.resource.kind !== 'inline') continue\n const fileApiPath = fileApiAvailable ? fileApiTarget(mount) : null\n const executable = isExecutableProfileFile(mount)\n if (fileApiPath !== null && (!executable || modeAwareFileApi)) {\n const mode = profileFileMode(mount)\n viaFileApi.push({\n path: fileApiPath,\n content: mount.resource.content ?? '',\n ...(mode !== undefined ? { mode } : {}),\n })\n }\n else viaExec.push(mount)\n }\n if (viaFileApi.length > 0) {\n // `writeMany` is fail-loud on the first file it can't write. Preserve the\n // cause so the runtime-auth-refresh wrapper still detects a 401 — it\n // recurses `.cause` for an AuthError/401 shape (see isRuntimeExecAuthError).\n try {\n await box.fs.writeMany(viaFileApi, { paceMs, maxRetries })\n } catch (err) {\n return fail(new Error('writeProfileFilesToBox: file-API batch write failed', { cause: err }))\n }\n }\n\n // Pace BETWEEN execs, not before the first or after the last. Shared across\n // the exec mounts so the (now smaller) executable/edge-case set stays paced.\n let execStarted = false\n\n // Pace + transient-retry ONE exec attempt: backoff/pace/fail-loud in one place.\n // `run` must be idempotent under unknown-outcome retries (exec writes\n // deterministic parts). A transient error retries with backoff up to\n // maxRetries (honoring a server Retry-After); anything else, or exhausting\n // retries, fails loud with the cause.\n const paceAndRetry = async <T>(run: () => Promise<T>, path: string): Promise<Outcome<T>> => {\n for (let attempt = 0; ; attempt++) {\n if (execStarted && paceMs > 0) await sleep(paceMs)\n execStarted = true\n try {\n return ok(await run())\n } catch (err) {\n const { retryable, retryAfterMs } = transientExecError(err)\n if (retryable && attempt < maxRetries) {\n const backoff = Math.min(PROFILE_WRITE_RETRY_BASE_MS * 2 ** attempt, PROFILE_WRITE_RETRY_MAX_MS)\n await sleep(retryAfterMs ?? backoff)\n continue\n }\n return fail(new Error(`writeProfileFilesToBox: exec failed for ${path}`, { cause: err }))\n }\n }\n }\n\n for (const mount of viaExec) {\n if (mount.resource.kind !== 'inline') continue // always true (viaExec is inline) — narrows for TS\n const content = mount.resource.content ?? ''\n const path = mount.path\n\n const b64 = Buffer.from(content, 'utf8').toString('base64')\n const b64Chunks: string[] = []\n for (let i = 0; i < b64.length; i += PROFILE_WRITE_B64_CHUNK_CHARS) {\n b64Chunks.push(b64.slice(i, i + PROFILE_WRITE_B64_CHUNK_CHARS))\n }\n const expectedSha256 = createHash('sha256').update(content, 'utf8').digest('hex')\n const dir = path.replace(/\\/[^/]*$/, '')\n const executable = isExecutableProfileFile(mount)\n const q = shellPath(path)\n const qb64 = shellPath(`${path}.b64`)\n const qtmp = shellPath(`${path}.tmp`)\n const qpartPrefix = shellPath(`${path}.b64.part.`)\n\n // Run one exec step. Transport errors (incl. a wedged-proxy timeout) are\n // paced + retried by paceAndRetry; a non-zero exit is a REAL command failure\n // — surfaced immediately, never retried.\n const step = async (cmd: string): Promise<Outcome<void>> => {\n const res = await paceAndRetry(() => execWithTimeout(box, cmd, execTimeoutMs), path)\n if (!res.succeeded) return res\n const exec = res.value\n if (exec.exitCode !== 0) {\n return fail(\n new Error(\n `writeProfileFilesToBox: failed to write ${path} (exit ${exec.exitCode}): ${exec.stderr.slice(0, 500)}`,\n ),\n )\n }\n return ok(undefined)\n }\n\n // Ensure the target directory exists. Chunk/final commands below are\n // idempotent under unknown-outcome transport retries; this no-op/mkdir is too.\n const mkdir = dir && dir !== path ? `mkdir -p ${shellPath(dir)}` : ':'\n let res = await step(mkdir)\n if (!res.succeeded) return res\n\n // Write each deterministic part with overwrite, not append. If the server\n // writes a part but the HTTP response is lost, retrying the same step lands\n // the same bytes instead of duplicating them.\n for (let i = 0; i < b64Chunks.length; i++) {\n const slice = b64Chunks[i]!\n res = await step(`printf '%s' '${slice}' > ${shellPath(`${path}.b64.part.${i}`)}`)\n if (!res.succeeded) return res\n }\n\n // Materialize from deterministic parts into a temp file, verify its content\n // hash, then atomically move into place. If the final exec succeeds but its\n // response is lost, a retry first accepts an already-correct target and only\n // re-runs idempotent chmod/cleanup. Parts are cleaned only after the target\n // hash is known-good, so a retried final step can always reconstruct.\n const chmod = executable ? `chmod +x ${q} || exit 1; ` : ''\n const checksumMismatch = shellSingleQuote(`writeProfileFilesToBox: checksum mismatch for ${path}`)\n const finalCmd =\n `expected='${expectedSha256}'; ` +\n `if [ -f ${q} ] && [ \"$(sha256sum ${q} | awk '{print $1}')\" = \"$expected\" ]; then ` +\n `${chmod}rm -f ${qb64} ${qtmp}; i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done; exit 0; fi; ` +\n `: > ${qb64} && ` +\n `i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do cat ${qpartPrefix}$i >> ${qb64} || exit 1; i=$((i+1)); done && ` +\n `base64 -d ${qb64} > ${qtmp} && ` +\n `[ \"$(sha256sum ${qtmp} | awk '{print $1}')\" = \"$expected\" ] || { echo ${checksumMismatch} >&2; exit 1; }; ` +\n `mv ${qtmp} ${q} && ` +\n `${executable ? `chmod +x ${q} && ` : ''}` +\n `[ \"$(sha256sum ${q} | awk '{print $1}')\" = \"$expected\" ] || { echo ${checksumMismatch} >&2; exit 1; }; ` +\n `rm -f ${qb64} ${qtmp}; i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done`\n res = await step(finalCmd)\n if (!res.succeeded) return res\n }\n return ok(undefined)\n}\n\n// Resolve the shell's deferred (inline) profile files and write them into a\n// box that already exists (reuse/resume paths). No-op unless the shell opts\n// into deferProfileFiles. Idempotent overwrite — a redeploy with new skills\n// refreshes the corpus on the next ensure call.\nasync function materializeDeferredFilesForExistingBox(\n shell: SandboxRuntimeConfig,\n client: Sandbox,\n box: SandboxInstance,\n stage: ExistingBoxStage,\n name: string,\n workspaceId: string,\n userId: string | undefined,\n): Promise<Outcome<SandboxInstance>> {\n if (!shell.deferProfileFiles) return ok(box)\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = {\n workspaceId,\n connectedIntegrationIds,\n ...(userId ? { userId } : {}),\n }\n const files = await shell.files(buildCtx)\n const fullProfile = shell.profile({ extraFiles: files })\n const { deferredFiles } = splitDeferredProfileFiles(fullProfile)\n if (deferredFiles.length === 0) return ok(box)\n return writeDeferredFilesWithRuntimeAuthRefresh(client, box, deferredFiles, stage, name)\n}\n\nasync function listRunning(\n client: Sandbox,\n name: string,\n): Promise<Outcome<SandboxInstance | null>> {\n try {\n const running = await client.list({ status: 'running' })\n return ok(running.find((s) => s.name === name) ?? null)\n } catch (err) {\n return fail(err)\n }\n}\n\nasync function deleteBox(box: SandboxInstance): Promise<Outcome<void>> {\n try {\n await box.delete()\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\n// The SDK narrows `backend.type` to its own BackendType union and\n// `initialUsers[].role` to PermissionLevel — neither symbol is exported. The\n// create payload is assembled with the product's Harness/role strings, which\n// are a superset surface; the localized cast at the boundary is the only place\n// this widening is allowed, and the runtime contract (the sidecar boots the\n// named harness) is what enforces correctness.\ntype CreatePayload = Parameters<Sandbox['create']>[0]\n\n// Generic exec+sidecar liveness probe. Absent probe => always alive (the prior\n// reuse-on-metadata-match behavior). With a probe: the container must answer an\n// `echo alive` exec within execTimeoutMs, and the sidecar process must be found\n// by pgrep within psTimeoutMs (an inconclusive pgrep is treated as reusable).\nasync function isBoxAlive(\n box: SandboxInstance,\n harness: Harness,\n probe: LivenessProbeConfig | undefined,\n): Promise<boolean> {\n if (!probe) return true\n const execTimeout = probe.execTimeoutMs ?? 5000\n const psTimeout = probe.psTimeoutMs ?? 3000\n const race = <T>(p: Promise<T>, ms: number, label: string): Promise<T> =>\n Promise.race([\n p,\n new Promise<T>((_, reject) => setTimeout(() => reject(new Error(label)), ms)),\n ])\n try {\n const alive = await race(box.exec('echo alive'), execTimeout, 'alive check timeout')\n if (!alive.stdout.includes('alive')) return false\n const pattern = probe.sidecarProcessPattern(harness)\n try {\n const ps = await race(\n box.exec(`pgrep -f ${shellSingleQuote(pattern)} || echo no-sidecar`),\n psTimeout,\n 'ps check timeout',\n )\n if (ps.stdout.includes('no-sidecar')) return false\n } catch {\n // sidecar probe inconclusive — container is alive, treat as reusable\n }\n return true\n } catch {\n return false\n }\n}\n\nconst RUNTIME_CONNECTION_WAIT_MS = 30_000\nconst RUNTIME_CONNECTION_POLL_MS = 1_000\n\n// `sidecarUrl` is a product/forward-compat field the orchestrator may set on\n// the connection ahead of the SDK declaring it — the v0.6 `SandboxConnection`\n// exposes only `runtimeUrl`. Read it through a typed augmentation rather than an\n// ad-hoc cast (a plain `SandboxConnection` satisfies the optional field), and\n// fall back to the SDK runtime URL. The product-facing `WorkspaceSandboxInstanceLike`\n// carries the same field for consumers driving their own box types.\ntype RuntimeConnectionFields = SandboxConnection & {\n sidecarUrl?: string\n authToken?: string\n sidecarToken?: string\n authTokenExpiresAt?: string | number | Date\n sidecarTokenExpiresAt?: string | number | Date\n}\n\nfunction sandboxRuntimeUrl(box: SandboxInstance): string | undefined {\n const connection: RuntimeConnectionFields | undefined = box.connection\n return connection?.sidecarUrl ?? connection?.runtimeUrl\n}\n\nfunction runtimeAuthExpiresAtMs(value: string | number | Date | undefined): number | undefined {\n if (value instanceof Date) return value.getTime()\n if (typeof value === 'number') return value\n if (typeof value !== 'string' || value.trim() === '') return undefined\n const parsed = Date.parse(value)\n return Number.isNaN(parsed) ? undefined : parsed\n}\n\nfunction hasFreshRuntimeExecAuth(box: SandboxInstance, now = Date.now()): boolean {\n const connection: RuntimeConnectionFields | undefined = box.connection\n const token = connection?.authToken ?? connection?.sidecarToken\n if (!sandboxRuntimeUrl(box) || !token) return false\n const expiresAt = runtimeAuthExpiresAtMs(\n connection?.authTokenExpiresAt ?? connection?.sidecarTokenExpiresAt,\n )\n return expiresAt === undefined || expiresAt > now + RUNTIME_AUTH_REFRESH_SKEW_MS\n}\n\nfunction sandboxEdgeFailed(box: SandboxInstance): boolean {\n // `edgeStatus`/`edgeError` are declared on the SDK's `SandboxConnection`, so no cast.\n const connection = box.connection\n return connection?.edgeStatus === 'failed' || Boolean(connection?.edgeError)\n}\n\nasync function refreshRuntimeConnection(\n client: Sandbox,\n box: SandboxInstance,\n): Promise<SandboxInstance> {\n let current = box\n if (sandboxRuntimeUrl(current)) return current\n\n const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS\n while (Date.now() < deadline) {\n // Tolerate transient refresh/get failures (5xx, network blips) while the\n // orchestrator is still attaching the connection: swallow and retry. A box\n // that never surfaces a runtime URL is returned as-is so the caller's\n // readiness gate (isReusableBox) drops and recreates it — rather than this\n // poll throwing a hard provisioning failure on a recoverable hiccup.\n try {\n await current.refresh()\n if (sandboxRuntimeUrl(current)) return current\n\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (sandboxRuntimeUrl(current)) return current\n } catch {\n // transient — fall through to the poll delay and retry\n }\n\n await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS))\n }\n\n return current\n}\n\nasync function bestEffortRefreshRuntimeExecAuth(\n client: Sandbox,\n box: SandboxInstance,\n stage: ExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let current = box\n\n try {\n await current.refresh()\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n if (isRuntimeAuthRefreshDenied(err)) {\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec auth refresh was unauthorized',\n err,\n ),\n )\n }\n }\n\n try {\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n if (isRuntimeAuthRefreshDenied(err)) {\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec auth re-fetch was unauthorized',\n err,\n ),\n )\n }\n }\n\n return ok(current)\n}\n\nasync function refreshRuntimeExecAuth(\n client: Sandbox,\n box: SandboxInstance,\n stage: ExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let current = box\n let lastError: unknown\n const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS\n\n while (Date.now() < deadline) {\n try {\n await current.refresh()\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n lastError = err\n }\n\n await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS))\n }\n\n const detail = sandboxRuntimeUrl(current)\n ? 'runtime exec credentials are missing or expired after refresh'\n : 'runtime connection is missing after refresh'\n return fail(new SandboxRuntimeAuthRefreshError(stage, name, detail, lastError))\n}\n\nasync function writeDeferredFilesWithRuntimeAuthRefresh(\n client: Sandbox,\n box: SandboxInstance,\n files: AgentProfileFileMount[],\n stage: ExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let writeBox = box\n\n if (!hasFreshRuntimeExecAuth(writeBox)) {\n const refreshed = await bestEffortRefreshRuntimeExecAuth(client, writeBox, stage, name)\n if (!refreshed.succeeded) return fail(refreshed.error)\n writeBox = refreshed.value\n }\n\n const first = await writeProfileFilesToBox(writeBox, files)\n if (first.succeeded) return ok(writeBox)\n if (!isRuntimeExecAuthError(first.error)) return fail(first.error)\n\n const refreshed = await refreshRuntimeExecAuth(client, writeBox, stage, name)\n if (!refreshed.succeeded) return fail(refreshed.error)\n\n const second = await writeProfileFilesToBox(refreshed.value, files)\n if (second.succeeded) return ok(refreshed.value)\n if (!isRuntimeExecAuthError(second.error)) return fail(second.error)\n\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec remained unauthorized after auth refresh',\n second.error,\n ),\n )\n}\n\n// Decide whether an existing (reused or resumed) box is safe to hand back.\n// `refreshRuntimeConnection` has already polled for the runtime URL, so a box\n// that still has none never became connectable and must be recreated rather\n// than silently reused — downstream exec/terminal traffic would fail against\n// it. A failed edge is likewise unusable. Only when the connection is present\n// do we spend an exec round-trip on the liveness probe.\nasync function isReusableBox(\n box: SandboxInstance,\n harness: Harness,\n probe: LivenessProbeConfig | undefined,\n): Promise<boolean> {\n if (sandboxEdgeFailed(box)) return false\n if (!sandboxRuntimeUrl(box)) return false\n return isBoxAlive(box, harness, probe)\n}\n\n// Resume a name-matched stopped box and wait for it to reach running. Returns\n// ok(null) when no stopped box matches the name.\nasync function resumeStoppedBox(\n client: Sandbox,\n name: string,\n timeoutMs: number,\n onProgress?: (event: ProvisionEvent) => void,\n): Promise<Outcome<SandboxInstance | null>> {\n try {\n const stopped = await client.list({ status: 'stopped' })\n const match = stopped.find((s) => s.name === name) ?? null\n if (!match) return ok(null)\n await match.resume()\n await match.waitFor('running', { timeoutMs, ...(onProgress ? { onProgress } : {}) })\n return ok(match)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function ensureWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: EnsureWorkspaceSandboxOptions,\n): Promise<SandboxInstance> {\n const { workspaceId, userId, harness, forceNew, onProgress } = options\n const scope: SandboxScope = { workspaceId, ...(userId ? { userId } : {}) }\n const creds = await shell.credentials(scope)\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n const client = getClientFromCreds(creds)\n const name = shell.boxKey ? shell.boxKey(scope) : shell.name(workspaceId)\n const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES\n const resumeTimeout = 120_000\n\n // Stage 1 — running-box reuse (skipped on forceNew).\n const existing = await listRunning(client, name)\n if (existing.succeeded && existing.value) {\n const found = existing.value\n if (forceNew) {\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(`forceNew: sandbox ${name} could not be deleted`, { cause: dropped.error })\n }\n } else if (found.metadata?.harness === harness) {\n const ready = await refreshRuntimeConnection(client, found)\n if (await isReusableBox(ready, harness, shell.livenessProbe)) {\n const written = await materializeDeferredFilesForExistingBox(\n shell,\n client,\n ready,\n 'reused',\n name,\n workspaceId,\n userId,\n )\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('reused', name, written.error)\n }\n const reusedBox = written.value\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(reusedBox, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on reused box ${name}`, { cause: boot.error })\n }\n }\n return reusedBox\n }\n const dropped = await deleteBox(ready)\n if (!dropped.succeeded) {\n throw new Error(\n `sandbox ${name} ` +\n `(was ${String(found.metadata?.harness ?? 'unknown')}, want ${harness}, or unresponsive) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n } else {\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(\n `sandbox ${name} ` +\n `(was ${String(found.metadata?.harness ?? 'unknown')}, want ${harness}, or unresponsive) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n }\n }\n\n // Stage 2 — stopped-box resume (skipped on forceNew or resumeStopped===false).\n if (!forceNew && shell.resumeStopped !== false) {\n const resumed = await resumeStoppedBox(client, name, resumeTimeout, onProgress)\n if (resumed.succeeded && resumed.value) {\n const box = await refreshRuntimeConnection(client, resumed.value)\n if (await isReusableBox(box, harness, shell.livenessProbe)) {\n const written = await materializeDeferredFilesForExistingBox(\n shell,\n client,\n box,\n 'resumed',\n name,\n workspaceId,\n userId,\n )\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('resumed', name, written.error)\n }\n const resumedBox = written.value\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(resumedBox, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on resumed box ${name}`, { cause: boot.error })\n }\n }\n return resumedBox\n }\n const dropped = await deleteBox(box)\n if (!dropped.succeeded) {\n throw new Error(\n `resumed sandbox ${name} ` +\n `(was ${String(box.metadata?.harness ?? 'unknown')}, want ${harness}, or unresponsive) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n }\n }\n\n // Stage 3 — create fresh.\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = {\n workspaceId,\n connectedIntegrationIds,\n ...(userId ? { userId } : {}),\n }\n const [secrets, env, files] = await Promise.all([\n shell.secrets(workspaceId),\n shell.env(buildCtx),\n shell.files(buildCtx),\n ])\n const fullProfile = shell.profile({ extraFiles: files })\n // When deferring, strip inline files from the create payload and write them\n // into the box after it reaches running. Keeps the provision body under the\n // orchestrator's 256 KiB cap and lands real files on disk.\n const { leanProfile, deferredFiles } = shell.deferProfileFiles\n ? splitDeferredProfileFiles(fullProfile)\n : { leanProfile: fullProfile, deferredFiles: [] as AgentProfileFileMount[] }\n const profile = leanProfile\n\n const role = userId && shell.permissionRole ? shell.permissionRole('developer') : undefined\n\n // Bake the model at create when opted in. childKeyMint overrides the apiKey\n // per-workspace; a typed mint failure falls through to the parent key (logged).\n let model = shell.backendModelAtCreate ? resolveModel(shell.provider) : undefined\n if (model && shell.childKeyMint && model.provider === 'openai-compat') {\n const minted = await shell.childKeyMint(scope)\n if (minted.succeeded) model = { ...model, apiKey: minted.value }\n else {\n console.error(\n `[sandbox] childKeyMint failed for ${workspaceId}; using parent key:`,\n minted.error.message,\n )\n }\n }\n\n const storage = shell.storage?.(buildCtx)\n const restore = shell.restore?.(buildCtx)\n\n const payload = {\n name,\n image: resources.image,\n metadata: shell.metadata(harness),\n idempotencyKey: name,\n ...(userId ? { permissions: { initialUsers: [{ userId, role }] } } : {}),\n env,\n secrets,\n backend: { type: harness, profile, ...(model ? { model } : {}) },\n ...(storage ? { storage } : {}),\n ...(restore ? restore : {}),\n ...(shell.webTerminalEnabled ? { webTerminalEnabled: true } : {}),\n maxLifetimeSeconds: resources.maxLifetimeSeconds,\n idleTimeoutSeconds: resources.idleTimeoutSeconds,\n resources: {\n cpuCores: resources.cpuCores,\n memoryMB: resources.memoryMB,\n diskGB: resources.diskGB,\n },\n } as CreatePayload\n\n let box = await client.create(payload)\n\n await box.waitFor('running', { timeoutMs: 120_000, ...(onProgress ? { onProgress } : {}) })\n box = await refreshRuntimeConnection(client, box)\n\n if (deferredFiles.length > 0) {\n const written = await writeProfileFilesToBox(box, deferredFiles)\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('new', name, written.error)\n }\n }\n\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(box, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on new box ${name}`, { cause: boot.error })\n }\n }\n return box\n}\n\nexport interface ResolvedModel {\n model: string\n provider: string\n apiKey: string\n baseUrl?: string\n}\n\nexport function resolveModel(\n config: ProviderResolutionConfig | undefined,\n override?: { model?: string; modelApiKey?: string },\n): ResolvedModel | undefined {\n const c = config ?? {}\n const explicitBaseUrl = c.routerBaseUrl\n const explicitApiKey = override?.modelApiKey ?? c.apiKey\n const provider =\n c.providerName ?? (explicitApiKey ? 'openai-compat' : c.openaiApiKey ? 'openai' : undefined)\n const modelName =\n override?.model ??\n c.modelName ??\n (provider === 'openai' || provider === 'openai-compat' ? c.defaultModel : undefined)\n const apiKey = explicitApiKey ?? (provider === 'openai' ? c.openaiApiKey : undefined)\n if (!provider || !modelName || !apiKey) return undefined\n return {\n model: modelName,\n provider,\n apiKey,\n ...(explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}),\n }\n}\n\nexport function flattenHistory(\n message: string,\n history?: Array<{ role: 'user' | 'assistant'; content: string }>,\n): string {\n if (!history?.length) return message\n const transcript = history\n .map((entry) => `${entry.role === 'assistant' ? 'Assistant' : 'User'}: ${entry.content}`)\n .join('\\n\\n')\n return `${transcript}\\n\\nUser: ${message}`\n}\n\nexport function mergeExtraMcp(\n appToolMcp: Record<string, AgentProfileMcpServer>,\n baseProfileMcp: Record<string, AgentProfileMcpServer>,\n extra: Record<string, AgentProfileMcpServer> | undefined,\n): Record<string, AgentProfileMcpServer> {\n for (const key of Object.keys(extra ?? {})) {\n if (key in appToolMcp || key in baseProfileMcp) {\n throw new Error(`extraMcp key '${key}' collides with an existing profile MCP server`)\n }\n }\n return { ...appToolMcp, ...(extra ?? {}) }\n}\n\nexport function attachReasoningEffort(\n profile: AgentProfile,\n harness: Harness,\n effort: 'auto' | 'low' | 'medium' | 'high' | undefined,\n): AgentProfile {\n if (!effort || effort === 'auto') return profile\n return {\n ...profile,\n extensions: {\n ...(profile.extensions ?? {}),\n [harness]: {\n ...(profile.extensions?.[harness] ?? {}),\n reasoningEffort: effort,\n },\n },\n }\n}\n\nexport interface StreamSandboxPromptOptions {\n sessionId?: string\n executionId?: string\n lastEventId?: string\n systemPrompt?: string\n model?: string\n modelApiKey?: string\n history?: Array<{ role: 'user' | 'assistant'; content: string }>\n harness?: Harness\n effort?: 'auto' | 'low' | 'medium' | 'high'\n appToolMcp?: Record<string, AgentProfileMcpServer>\n baseProfileMcp?: Record<string, AgentProfileMcpServer>\n extraMcp?: Record<string, AgentProfileMcpServer>\n signal?: AbortSignal\n timeoutMs?: number\n requireVisibleAssistantOutput?: boolean\n // When true, an interactive question event throws instead of yielding —\n // detached (cron/mission-step) runs have no consumer to answer it.\n disallowQuestions?: boolean\n // Per-turn question/permission/plan channel toggles, forwarded VERBATIM into the\n // backend config. agent-app does not validate kinds per harness — the sidecar fails\n // session init loudly for unsupported ones; a local matrix would drift. Only honored\n // on the streaming path; the detached box.prompt path (driveSandboxTurn) never sets it.\n interactions?: { question?: boolean; permission?: boolean; plan?: boolean }\n}\n\ntype StreamPromptOptions = Parameters<SandboxInstance['streamPrompt']>[1]\n\nexport async function* streamSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options?: StreamSandboxPromptOptions,\n): AsyncGenerator<unknown> {\n const harness = options?.harness ?? 'opencode'\n const model = resolveModel(shell.provider, {\n model: options?.model,\n modelApiKey: options?.modelApiKey,\n })\n\n // Server-side enforcement of the harness↔model policy: a vendor-locked harness\n // (claude-code/codex/kimi-code) must not be sent a foreign-provider model, even\n // if the UI snap was bypassed. Provider-less ids pass (session's own config).\n if (model?.model) assertHarnessModelCompatible(harness, model.model)\n\n const prompt = flattenHistory(message, options?.history)\n\n const appToolMcp = options?.appToolMcp ?? {}\n const extraMcp = mergeExtraMcp(appToolMcp, options?.baseProfileMcp ?? {}, options?.extraMcp)\n\n const profile = shell.profile({ systemPrompt: options?.systemPrompt, extraMcp })\n const profileWithEffort = attachReasoningEffort(profile, harness, options?.effort)\n\n const stream = box.streamPrompt(prompt, {\n sessionId: options?.sessionId,\n executionId: options?.executionId,\n lastEventId: options?.lastEventId,\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options?.requireVisibleAssistantOutput !== undefined\n ? { requireVisibleAssistantOutput: options.requireVisibleAssistantOutput }\n : {}),\n backend: {\n type: harness,\n profile: profileWithEffort,\n ...(model ? { model } : {}),\n ...(options?.interactions ? { interactions: options.interactions } : {}),\n },\n } as StreamPromptOptions)\n\n let severedFinishReason: string | null = null\n for await (const event of stream) {\n const step = classifySeveredStream(event)\n if (step) severedFinishReason = step.kind === 'step-finish' && step.severed ? step.reason : null\n if (severedFinishReason && isTerminalPromptEvent(event)) {\n throw new Error(`sandbox model stream severed mid-turn (reason=\"${severedFinishReason}\")`)\n }\n if (options?.disallowQuestions) {\n const q = detectInteractiveQuestion(event)\n if (q) {\n throw new Error(`sandbox agent asked an interactive question during an autonomous run: ${q}`)\n }\n }\n yield event\n }\n // Reconnect-exhausted path: the stream ended on a severed step without a\n // terminal event. A truncated turn must fail loud, not return silently.\n if (severedFinishReason) {\n throw new Error(`sandbox model stream severed mid-turn (reason=\"${severedFinishReason}\")`)\n }\n}\n\nexport async function runSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options?: StreamSandboxPromptOptions,\n): Promise<string> {\n let fullText = ''\n let firstTextSeen = false\n\n for await (const rawEvent of streamSandboxPrompt(shell, box, message, options)) {\n const event = rawEvent as { type?: string; data?: Record<string, unknown> }\n if (!event.type) continue\n\n if (event.type === 'message.part.updated') {\n const part = event.data?.part as Record<string, unknown> | undefined\n const delta = typeof event.data?.delta === 'string' ? event.data.delta : null\n if (String(part?.type ?? '') === 'text') {\n if (!firstTextSeen) {\n firstTextSeen = true\n continue\n }\n if (delta) fullText += delta\n else if (typeof part?.text === 'string') fullText = part.text\n }\n } else if (event.type === 'result') {\n const finalText = typeof event.data?.finalText === 'string' ? event.data.finalText : null\n if (finalText) fullText = finalText\n }\n }\n\n return fullText\n}\n\n// Mirrors the SDK's PermissionLevel union (not re-exported by\n// @tangle-network/sandbox). The product's role-mapping seam must produce one of\n// these; binding the seam's return type to the union makes a wrong mapping a\n// compile error rather than a runtime 400 from the orchestrator.\nexport type SandboxPermissionLevel = 'owner' | 'admin' | 'developer' | 'viewer'\n\nexport interface MemberSyncSeam {\n roleToSandboxRole: (workspaceRole: string) => SandboxPermissionLevel\n}\n\nexport async function syncSandboxMemberAdd(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.add({ userId, role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRemove(\n box: SandboxInstance,\n userId: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.remove(userId, { preserveHomeDir: true })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRole(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.update(userId, { role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface SecretStore {\n create: (name: string, value: string) => Promise<void>\n update: (name: string, value: string) => Promise<void>\n get: (name: string) => Promise<string>\n delete: (name: string) => Promise<void>\n}\n\nexport function secretStoreFromClient(shell: SandboxRuntimeConfig): SecretStore {\n const client = getClient(shell)\n return {\n create: async (name, value) => {\n await client.secrets.create(name, value)\n },\n update: async (name, value) => {\n await client.secrets.update(name, value)\n },\n get: (name) => client.secrets.get(name),\n delete: async (name) => {\n await client.secrets.delete(name)\n },\n }\n}\n\nexport async function storeSecret(\n store: SecretStore,\n name: string,\n value: string,\n): Promise<Outcome<void>> {\n try {\n await store.create(name, value)\n return ok(undefined)\n } catch {\n try {\n await store.update(name, value)\n return ok(undefined)\n } catch (err) {\n return fail(new Error(`Failed to store sandbox secret ${name}`, { cause: err }))\n }\n }\n}\n\nexport async function readSecret(store: SecretStore, name: string): Promise<Outcome<string>> {\n try {\n return ok(await store.get(name))\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function deleteSecret(store: SecretStore, name: string): Promise<Outcome<void>> {\n try {\n await store.delete(name)\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface ScopedTokenResult {\n token: string\n expiresAt: Date\n scope: ScopedTokenScope\n}\n\n/**\n * Mint a scoped token for an already-provisioned box (e.g. to hand a terminal\n * proxy a narrowed credential). Uses the SDK's native `box.mintScopedToken`,\n * which normalizes `expiresAt` to a Date — no hand-rolled wire call.\n */\nexport async function mintSandboxScopedToken(\n box: SandboxInstance,\n options: { scope: ScopedTokenScope; sessionId?: string; ttlMinutes?: number },\n): Promise<Outcome<ScopedTokenResult>> {\n try {\n const token = await box.mintScopedToken({\n scope: options.scope,\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...(options.ttlMinutes ? { ttlMinutes: options.ttlMinutes } : {}),\n })\n return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope })\n } catch (err) {\n return fail(err)\n }\n}\n\n// Detached single-turn advance. The SDK SandboxInstance has no `driveTurn`; the\n// non-streaming sibling of streamPrompt is box.prompt(message, opts) -> PromptResult.\n// Returns a typed Outcome so a failed turn is inspected, not swallowed.\nexport async function driveSandboxTurn(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options: StreamSandboxPromptOptions & { sessionId: string },\n): Promise<Outcome<PromptResult>> {\n const harness = options.harness ?? 'opencode'\n const model = resolveModel(shell.provider, {\n model: options.model,\n modelApiKey: options.modelApiKey,\n })\n if (model?.model) assertHarnessModelCompatible(harness, model.model)\n const prompt = flattenHistory(message, options.history)\n const appToolMcp = options.appToolMcp ?? {}\n const extraMcp = mergeExtraMcp(appToolMcp, options.baseProfileMcp ?? {}, options.extraMcp)\n const profile = attachReasoningEffort(\n shell.profile({ systemPrompt: options.systemPrompt, extraMcp }),\n harness,\n options.effort,\n )\n try {\n const result = await box.prompt(prompt, {\n sessionId: options.sessionId,\n ...(options.executionId ? { executionId: options.executionId } : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n // Deliberately NO `interactions` here: detached turns (cron / mission steps) have\n // no consumer to answer a question. Interactive Q&A is streaming-path only.\n backend: { type: harness, profile, ...(model ? { model } : {}) },\n } as Parameters<SandboxInstance['prompt']>[1])\n if (!result.success) return fail(new Error(result.error ?? 'sandbox turn failed'))\n return ok(result)\n } catch (err) {\n return fail(err)\n }\n}\n\n// Severed-stream classifier. Generic to any router-backed harness: a final step\n// that finished with error/other/unknown is a truncated turn, not a completed one.\nconst SEVERED_FINISH_REASONS = new Set(['error', 'other', 'unknown'])\n\nexport type SandboxStepTransition =\n | { kind: 'step-start' }\n | { kind: 'step-finish'; reason: string; severed: boolean }\n\nfunction asPlainRecord(v: unknown): Record<string, unknown> | null {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : null\n}\n\nexport function classifySeveredStream(event: unknown): SandboxStepTransition | null {\n const root = asPlainRecord(event)\n if (!root || root.type !== 'message.part.updated') return null\n const body = asPlainRecord(root.properties) ?? asPlainRecord(root.data) ?? root\n const part = asPlainRecord(body.part)\n if (!part) return null\n if (part.type === 'step-start') return { kind: 'step-start' }\n if (part.type !== 'step-finish') return null\n const reason = typeof part.reason === 'string' && part.reason ? part.reason : 'unknown'\n return { kind: 'step-finish', reason, severed: SEVERED_FINISH_REASONS.has(reason) }\n}\n\nexport function isTerminalPromptEvent(event: unknown): boolean {\n const t = asPlainRecord(event)?.type\n return t === 'result' || t === 'done'\n}\n\n// Interactive-question detector. Returns the question text or null. Used by\n// streamSandboxPrompt when disallowQuestions is set.\nexport function detectInteractiveQuestion(event: unknown): string | null {\n const root = asPlainRecord(event)\n if (!root) return null\n const type = typeof root.type === 'string' ? root.type : undefined\n const data = asPlainRecord(root.data)\n const props = asPlainRecord(root.properties)\n const body = props ?? data ?? root\n if (type === 'question.asked' || type === 'question') return firstQuestionText(body)\n // Generic structured-interaction event (BackendConfig.interactions kinds surface as\n // `interaction` events with a `kind` discriminator); treat kind:\"question\" as a question.\n if (type === 'interaction' && body.kind === 'question') return firstQuestionText(body)\n const part = asPlainRecord(data?.part) ?? asPlainRecord(body.part)\n const tool =\n (typeof part?.tool === 'string' && part.tool) ||\n (typeof part?.name === 'string' && part.name) ||\n (typeof body.tool === 'string' && body.tool) ||\n undefined\n const isQ =\n type === 'message.part.updated' &&\n (tool === 'question' || asPlainRecord(part)?.type === 'question')\n if (!isQ) return null\n const state = asPlainRecord(asPlainRecord(part)?.state)\n return firstQuestionText(asPlainRecord(state?.input) ?? state ?? part ?? body)\n}\n\nfunction firstQuestionText(value: Record<string, unknown> | null): string {\n const arr = Array.isArray(value?.questions)\n ? value!.questions\n : Array.isArray(asPlainRecord(value?.input)?.questions)\n ? (asPlainRecord(value!.input)!.questions as unknown[])\n : []\n const first = asPlainRecord(arr[0])\n const q =\n (typeof first?.question === 'string' && first.question) ||\n (typeof first?.prompt === 'string' && first.prompt) ||\n undefined\n return q ?? 'interactive question'\n}\n// Workspace sandbox terminal handlers: WebSocket upgrade proxy, connection\n// + runtime-proxy handlers, and scoped terminal-token mint/verify.\nexport * from './terminal-proxy-token'\nexport * from './workspace-terminal'\n","// Shared Outcome triple for the sandbox modules. Lives in a dependency-free\n// leaf so both index.ts and terminal-proxy-token.ts import it instead of\n// re-declaring the type (index.ts re-exports * from terminal-proxy-token, so\n// the token module cannot import from index without a cycle).\nexport type Outcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: Error }\n\nexport const ok = <T>(value: T): Outcome<T> => ({ succeeded: true, value })\nexport const fail = (error: unknown): Outcome<never> => ({\n succeeded: false,\n error: error instanceof Error ? error : new Error(String(error)),\n})\n","import {\n base64UrlDecodeText,\n base64UrlEncodeText,\n constantTimeEqual,\n hmacSha256Base64Url,\n} from '../crypto/web-token'\nimport { ok, fail, type Outcome } from './outcome'\n\n// Terminal-proxy HMAC token. Identity tuple is generic; the secret comes from a\n// closure (fail-loud if absent).\nexport interface TerminalProxyIdentity {\n userId: string\n workspaceId: string\n sandboxId: string\n}\n\nconst TERMINAL_PROXY_TOKEN_TTL_MS = 15 * 60 * 1000\n\nexport async function mintTerminalProxyToken(\n secret: string,\n identity: TerminalProxyIdentity,\n ttlMs = TERMINAL_PROXY_TOKEN_TTL_MS,\n now: () => number = Date.now,\n): Promise<Outcome<{ token: string; expiresAt: Date }>> {\n if (!secret) return fail(new Error('mintTerminalProxyToken: secret is required'))\n if (!identity.userId || !identity.workspaceId || !identity.sandboxId) {\n return fail(new Error('mintTerminalProxyToken: userId/workspaceId/sandboxId are required'))\n }\n const expiresAt = new Date(now() + ttlMs)\n const payload = { ...identity, exp: Math.floor(expiresAt.getTime() / 1000) }\n const encoded = base64UrlEncodeText(JSON.stringify(payload))\n const sig = await hmacSha256Base64Url(encoded, secret)\n return ok({ token: `${encoded}.${sig}`, expiresAt })\n}\n\nexport async function verifyTerminalProxyToken(\n secret: string,\n token: string,\n expected: TerminalProxyIdentity,\n now: () => number = Date.now,\n): Promise<boolean> {\n if (!secret) return false\n const [encoded, sig, extra] = token.split('.')\n if (!encoded || !sig || extra !== undefined) return false\n const expectedSig = await hmacSha256Base64Url(encoded, secret)\n if (!constantTimeEqual(sig, expectedSig)) return false\n let payload: TerminalProxyIdentity & { exp: number }\n try {\n payload = JSON.parse(base64UrlDecodeText(encoded))\n } catch {\n return false\n }\n return (\n payload.userId === expected.userId &&\n payload.workspaceId === expected.workspaceId &&\n payload.sandboxId === expected.sandboxId &&\n Number.isFinite(payload.exp) &&\n payload.exp > Math.floor(now() / 1000)\n )\n}\n","import { base64UrlDecodeText } from '../crypto/web-token'\nimport {\n mintTerminalProxyToken,\n verifyTerminalProxyToken,\n type TerminalProxyIdentity,\n} from './terminal-proxy-token'\n\nexport interface WorkspaceSandboxInstanceLike {\n id: string\n name?: string\n status?: string\n connection?: {\n runtimeUrl?: string\n sidecarUrl?: string\n authToken?: string\n sidecarToken?: string\n authTokenExpiresAt?: string\n } | null\n}\n\n// Generic name-keyed sandbox lifecycle manager. A structural, substrate-free\n// helper for products that drive their own SDK/box types (distinct from the\n// concrete `ensureWorkspaceSandbox` in ./index, which is bound to the\n// @tangle-network/sandbox client). Kept as a public export — external\n// consumers compose it; removing it would be a breaking change.\nexport interface WorkspaceSandboxEnsureContext {\n workspaceId: string\n userId: string\n}\n\nexport interface WorkspaceSandboxManagerOptions<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {\n getClient: (ctx: WorkspaceSandboxEnsureContext) => Promise<TClient> | TClient\n nameForWorkspace: (workspaceId: string, ctx: WorkspaceSandboxEnsureContext) => string\n listSandboxes: (client: TClient, ctx: WorkspaceSandboxEnsureContext) => Promise<TBox[]>\n createSandbox: (args: {\n client: TClient\n ctx: WorkspaceSandboxEnsureContext\n name: string\n options: TEnsureOptions\n listError?: unknown\n }) => Promise<TBox>\n waitForRunning?: (box: TBox, ctx: WorkspaceSandboxEnsureContext) => Promise<void>\n prepareExisting?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>\n prepareCreated?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>\n onListError?: (error: unknown, ctx: WorkspaceSandboxEnsureContext) => void\n}\n\nexport interface WorkspaceSandboxManager<TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {\n ensureWorkspaceSandbox: (\n workspaceId: string,\n userId: string,\n options?: TEnsureOptions,\n ) => Promise<TBox>\n}\n\nexport function createWorkspaceSandboxManager<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void>(\n opts: WorkspaceSandboxManagerOptions<TClient, TBox, TEnsureOptions>,\n): WorkspaceSandboxManager<TBox, TEnsureOptions> {\n return {\n async ensureWorkspaceSandbox(workspaceId, userId, options) {\n if (!workspaceId) throw new Error('workspaceId is required')\n if (!userId) throw new Error('userId is required')\n const ctx = { workspaceId, userId }\n const client = await opts.getClient(ctx)\n const name = opts.nameForWorkspace(workspaceId, ctx)\n let listError: unknown\n let existing: TBox[] = []\n\n try {\n existing = await opts.listSandboxes(client, ctx)\n } catch (err) {\n listError = err\n opts.onListError?.(err, ctx)\n }\n\n const found = existing.find((box) => box.name === name)\n if (found) {\n return (await opts.prepareExisting?.(found, ctx, options as TEnsureOptions)) ?? found\n }\n\n const created = await opts.createSandbox({\n client,\n ctx,\n name,\n options: options as TEnsureOptions,\n listError,\n })\n await opts.waitForRunning?.(created, ctx)\n return (await opts.prepareCreated?.(created, ctx, options as TEnsureOptions)) ?? created\n },\n }\n}\n\nexport interface SandboxTerminalTokenOptions {\n secret?: string\n expiresInMs?: number\n now?: () => number\n}\n\nexport type SandboxTerminalTokenSubject = TerminalProxyIdentity\n\nexport interface SandboxTerminalTokenResult {\n token: string\n expiresAt: Date\n}\n\nconst DEFAULT_TERMINAL_TOKEN_TTL_MS = 15 * 60 * 1000\nconst BEARER_SUBPROTOCOL_PREFIX = 'bearer.'\n// Legacy `createSandboxTerminalToken` (pre proxy-token extraction) prefixed\n// minted tokens with `sbxt_` and signed the unprefixed payload. New tokens\n// carry no prefix. Strip it on verify so tokens minted by a prior deploy still\n// validate within their (default 15-min) TTL window — avoids a wave of 403s on\n// in-flight browser terminal sessions right after rollout.\nconst LEGACY_TERMINAL_TOKEN_PREFIX = 'sbxt_'\n\nexport async function createSandboxTerminalToken(\n subject: SandboxTerminalTokenSubject,\n opts: SandboxTerminalTokenOptions,\n): Promise<SandboxTerminalTokenResult> {\n validateTerminalSubject(subject)\n const secret = opts.secret?.trim()\n if (!secret) throw new Error('terminal token secret is required')\n const now = opts.now ?? Date.now\n const expiresInMs = opts.expiresInMs ?? DEFAULT_TERMINAL_TOKEN_TTL_MS\n if (!Number.isFinite(expiresInMs) || expiresInMs <= 0) throw new Error('expiresInMs must be a positive number')\n const minted = await mintTerminalProxyToken(secret, subject, expiresInMs, now)\n if (!minted.succeeded) throw minted.error\n return minted.value\n}\n\nexport async function verifySandboxTerminalToken(\n token: string,\n expected: SandboxTerminalTokenSubject,\n opts: SandboxTerminalTokenOptions,\n): Promise<boolean> {\n validateTerminalSubject(expected)\n const secret = opts.secret?.trim()\n const now = opts.now ?? Date.now\n const normalized = token.startsWith(LEGACY_TERMINAL_TOKEN_PREFIX)\n ? token.slice(LEGACY_TERMINAL_TOKEN_PREFIX.length)\n : token\n return verifyTerminalProxyToken(secret ?? '', normalized, expected, now)\n}\n\nexport interface AuthenticatedSandboxUser {\n id: string\n}\n\nexport interface WorkspaceSandboxConnectionHandlerOptions<TBox extends WorkspaceSandboxInstanceLike> {\n requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>\n requireWorkspaceAccess: (args: { request: Request; userId: string; workspaceId: string }) => Promise<void>\n ensureWorkspaceSandbox: (workspaceId: string, userId: string) => Promise<TBox>\n tokenSecret: string | (() => string | undefined)\n tokenExpiresInMs?: number\n proxyRuntimeUrl?: (args: { request: Request; workspaceId: string; sandboxId: string; box: TBox }) => string\n exposeDirectSidecar?: boolean\n}\n\nexport interface WorkspaceSandboxConnectionArgs {\n request: Request\n params: {\n workspaceId?: string\n }\n}\n\nexport function createWorkspaceSandboxConnectionHandler<TBox extends WorkspaceSandboxInstanceLike>(\n opts: WorkspaceSandboxConnectionHandlerOptions<TBox>,\n) {\n return async function handleWorkspaceSandboxConnection({ request, params }: WorkspaceSandboxConnectionArgs): Promise<Response> {\n const user = await opts.requireUser(request)\n const workspaceId = params.workspaceId\n if (!workspaceId) return Response.json({ error: 'workspaceId is required' }, { status: 400 })\n await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId })\n\n let box: TBox\n try {\n box = await opts.ensureWorkspaceSandbox(workspaceId, user.id)\n } catch (err) {\n return Response.json(\n { error: err instanceof Error ? err.message : 'Failed to provision workspace sandbox' },\n { status: 500 },\n )\n }\n\n const directSidecarUrl = box.connection?.sidecarUrl ?? box.connection?.runtimeUrl\n const directSidecarToken = box.connection?.authToken ?? box.connection?.sidecarToken\n const directSidecarExpiresAt = box.connection?.authTokenExpiresAt\n if (opts.exposeDirectSidecar && directSidecarUrl && directSidecarToken && directSidecarExpiresAt) {\n return Response.json({\n runtimeUrl: directSidecarUrl,\n sidecarUrl: directSidecarUrl,\n token: directSidecarToken,\n expiresAt: directSidecarExpiresAt,\n status: box.status,\n sandboxId: box.id,\n })\n }\n\n if (!directSidecarUrl) {\n return Response.json(\n {\n error: 'Workspace sandbox runtime not ready. The sandbox is still initializing -- retry in a few seconds.',\n status: box.status,\n },\n { status: 503 },\n )\n }\n\n const secret = typeof opts.tokenSecret === 'function' ? opts.tokenSecret() : opts.tokenSecret\n let scoped: SandboxTerminalTokenResult\n try {\n scoped = await createSandboxTerminalToken(\n { userId: user.id, workspaceId, sandboxId: box.id },\n { secret, expiresInMs: opts.tokenExpiresInMs },\n )\n } catch (err) {\n return Response.json(\n { error: err instanceof Error ? err.message : 'Failed to mint sandbox token' },\n { status: 503 },\n )\n }\n\n const runtimeUrl = opts.proxyRuntimeUrl\n ? opts.proxyRuntimeUrl({ request, workspaceId, sandboxId: box.id, box })\n : `/api/workspaces/${encodeURIComponent(workspaceId)}/sandbox/runtime/${encodeURIComponent(box.id)}`\n\n return Response.json({\n runtimeUrl,\n sidecarUrl: runtimeUrl,\n token: scoped.token,\n expiresAt: scoped.expiresAt.toISOString(),\n status: box.status,\n sandboxId: box.id,\n })\n }\n}\n\nexport interface SandboxApiCredentials {\n baseUrl: string\n apiKey: string\n}\n\nexport interface SandboxRuntimeConnection {\n runtimeUrl: string\n /** Server-side sidecar bearer. Must authorize terminal routes; never expose it to browser code. */\n authToken?: string\n}\n\nexport interface WorkspaceSandboxRuntimeProxyHandlerOptions {\n requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>\n requireWorkspaceAccess: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<void>\n getSandboxApiCredentials: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxApiCredentials>\n getSandboxRuntimeConnection?: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxRuntimeConnection | null | undefined>\n tokenSecret: string | (() => string | undefined)\n fetch?: typeof fetch\n forwardHeaders?: string[]\n}\n\nexport interface WorkspaceSandboxRuntimeProxyArgs {\n request: Request\n params: {\n workspaceId?: string\n sandboxId?: string\n '*'?: string\n }\n}\n\nexport function createWorkspaceSandboxRuntimeProxyHandler(opts: WorkspaceSandboxRuntimeProxyHandlerOptions) {\n return async function handleWorkspaceSandboxRuntimeProxy({ request, params }: WorkspaceSandboxRuntimeProxyArgs): Promise<Response> {\n const user = await opts.requireUser(request)\n const workspaceId = params.workspaceId\n const sandboxId = params.sandboxId\n const runtimePath = params['*']\n if (!workspaceId || !sandboxId || !runtimePath) {\n return Response.json({ error: 'workspaceId, sandboxId, and runtime path are required' }, { status: 400 })\n }\n const encodedRuntimePath = encodeSandboxRuntimePath(runtimePath)\n if (!encodedRuntimePath) return Response.json({ error: 'Invalid sandbox runtime path' }, { status: 400 })\n\n await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId, sandboxId })\n\n const token = terminalTokenFromRequest(request.headers)\n const secret = typeof opts.tokenSecret === 'function' ? opts.tokenSecret() : opts.tokenSecret\n if (!token || !(await verifySandboxTerminalToken(token, { userId: user.id, workspaceId, sandboxId }, { secret }))) {\n return Response.json({ error: 'Invalid terminal token' }, { status: 403 })\n }\n\n const requestUrl = new URL(request.url)\n const runtimeConnection = await opts.getSandboxRuntimeConnection?.({ request, userId: user.id, workspaceId, sandboxId })\n const directRuntimeConnection = runtimeConnection?.runtimeUrl && runtimeConnection.authToken ? runtimeConnection : null\n const credentials = directRuntimeConnection ? null : await opts.getSandboxApiCredentials({ request, userId: user.id, workspaceId, sandboxId })\n const upstreamUrl = directRuntimeConnection\n ? new URL(encodedRuntimePath, `${directRuntimeConnection.runtimeUrl.replace(/\\/+$/, '')}/`)\n : new URL(\n `/v1/sandboxes/${encodeURIComponent(sandboxId)}/runtime/${encodedRuntimePath}`,\n credentials!.baseUrl,\n )\n upstreamUrl.search = requestUrl.search\n\n const headers = buildSandboxRuntimeProxyHeaders(\n request.headers,\n directRuntimeConnection?.authToken ?? credentials!.apiKey,\n opts.forwardHeaders,\n )\n const init: RequestInit & { duplex?: 'half' } = {\n method: request.method,\n headers,\n redirect: 'manual',\n }\n if (request.method !== 'GET' && request.method !== 'HEAD' && request.body) {\n init.body = request.body\n init.duplex = 'half'\n }\n\n const fetchImpl = opts.fetch ?? fetch\n const response = await fetchImpl(upstreamUrl, init)\n const responseHeaders = new Headers(response.headers)\n responseHeaders.delete('set-cookie')\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n })\n }\n}\n\n// ---------------------------------------------------------------------------\n// Terminal WebSocket upgrade\n//\n// The interactive terminal is WebSocket-only on the current sidecar (the REST\n// `POST /terminals` create route was removed in the websocket-first migration).\n// `createWorkspaceSandboxRuntimeProxyHandler` runs inside a React Router\n// loader/action, which can only return a normal Response — never a 101 — so it\n// cannot perform the upgrade. The upgrade must be intercepted at the Worker\n// fetch entry (server.ts) BEFORE React Router, mirroring the session-stream WS\n// interceptor. This handler does exactly that: it auth-gates the upgrade (the\n// scoped terminal token rides in the `bearer.` subprotocol because browsers\n// can't set Authorization on a WS handshake) and forwards it to the sandbox API\n// runtime proxy with the server-to-server credential. Returning the upstream\n// 101 passes the live socket straight through to the browser — the same idiom\n// the sandbox API uses to reach the orchestrator.\n//\n// NOTE: this only runs under a WebSocket-capable runtime (Cloudflare Workers /\n// `wrangler`). `react-router dev` (Vite) never invokes the Worker fetch entry,\n// so the terminal WS is exercised under `wrangler dev` / production.\n// ---------------------------------------------------------------------------\n\nconst SANDBOX_TERMINAL_WS_PATHNAME =\n /^\\/api\\/workspaces\\/([^/]+)\\/sandbox\\/runtime\\/([^/]+)\\/(terminals\\/[^/]+\\/ws)$/\n\nexport interface SandboxTerminalWsMatch {\n workspaceId: string\n sandboxId: string\n subPath: string\n}\n\n/**\n * Parse a same-origin terminal-WS pathname into its parts, or `null` when the\n * path is not a sandbox terminal WebSocket. Matches the default `runtimeUrl`\n * convention emitted by {@link createWorkspaceSandboxConnectionHandler}\n * (`/api/workspaces/:workspaceId/sandbox/runtime/:sandboxId`) with a canonical\n * `terminals/:id/ws` sub-path. `subPath` is left URL-encoded for re-use in the\n * upstream URL; the ids are decoded for auth checks.\n */\nexport function matchSandboxTerminalWsPath(pathname: string): SandboxTerminalWsMatch | null {\n const m = SANDBOX_TERMINAL_WS_PATHNAME.exec(pathname)\n if (!m) return null\n const [, workspaceId, sandboxId, subPath] = m\n if (!workspaceId || !sandboxId || !subPath) return null\n const decodedWorkspaceId = safeDecodeURIComponent(workspaceId)\n const decodedSandboxId = safeDecodeURIComponent(sandboxId)\n if (!decodedWorkspaceId || !decodedSandboxId) return null\n return { workspaceId: decodedWorkspaceId, sandboxId: decodedSandboxId, subPath }\n}\n\n/** True when `request` is a WebSocket upgrade for a sandbox terminal path. */\nexport function isSandboxTerminalWsUpgrade(request: Request): boolean {\n if (request.headers.get('Upgrade')?.toLowerCase() !== 'websocket') return false\n try {\n return matchSandboxTerminalWsPath(new URL(request.url).pathname) !== null\n } catch {\n return false\n }\n}\n\nexport interface WorkspaceSandboxTerminalUpgradeHandlerOptions {\n requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>\n requireWorkspaceAccess: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<void>\n getSandboxApiCredentials: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxApiCredentials>\n getSandboxRuntimeConnection?: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxRuntimeConnection | null | undefined>\n tokenSecret: string | (() => string | undefined)\n fetch?: typeof fetch\n}\n\n/**\n * Build a Worker-entry handler that proxies a sandbox terminal WebSocket\n * upgrade to the sandbox API runtime proxy. Returns `null` when the request is\n * not a terminal WS upgrade, so the caller can fall through to its normal\n * request handler:\n *\n * ```ts\n * const handled = await handleSandboxTerminalUpgrade(request)\n * if (handled) return handled\n * ```\n */\nexport function createWorkspaceSandboxTerminalUpgradeHandler(opts: WorkspaceSandboxTerminalUpgradeHandlerOptions) {\n return async function handleWorkspaceSandboxTerminalUpgrade(request: Request): Promise<Response | null> {\n if (request.headers.get('Upgrade')?.toLowerCase() !== 'websocket') return null\n let url: URL\n try {\n url = new URL(request.url)\n } catch {\n return null\n }\n const match = matchSandboxTerminalWsPath(url.pathname)\n if (!match) return null\n const { workspaceId, sandboxId, subPath } = match\n\n let user: AuthenticatedSandboxUser\n try {\n user = await opts.requireUser(request)\n } catch {\n return new Response('Unauthorized', { status: 401 })\n }\n try {\n await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId, sandboxId })\n } catch {\n return new Response('Forbidden', { status: 403 })\n }\n\n const token = terminalTokenFromRequest(request.headers)\n const secret = typeof opts.tokenSecret === 'function' ? opts.tokenSecret() : opts.tokenSecret\n if (!token || !(await verifySandboxTerminalToken(token, { userId: user.id, workspaceId, sandboxId }, { secret }))) {\n return new Response('Invalid terminal token', { status: 403 })\n }\n\n const runtimeConnection = await opts.getSandboxRuntimeConnection?.({ request, userId: user.id, workspaceId, sandboxId })\n const directRuntimeConnection = runtimeConnection?.runtimeUrl && runtimeConnection.authToken ? runtimeConnection : null\n const credentials = directRuntimeConnection ? null : await opts.getSandboxApiCredentials({ request, userId: user.id, workspaceId, sandboxId })\n const upstreamUrl = directRuntimeConnection\n ? new URL(subPath, `${directRuntimeConnection.runtimeUrl.replace(/\\/+$/, '')}/`)\n : new URL(`/v1/sandboxes/${encodeURIComponent(sandboxId)}/runtime/${subPath}`, credentials!.baseUrl)\n upstreamUrl.search = url.search\n\n // Forward the upgrade verbatim — keep the Upgrade/Connection + Sec-WebSocket-*\n // headers the handshake needs, but strip the browser-only bearer subprotocol\n // and send the server-to-server sandbox credential only as Authorization.\n // Returning the upstream 101 passes the live socket straight through to the browser.\n const upstreamHeaders = new Headers(request.headers)\n const upstreamBearer = directRuntimeConnection?.authToken ?? credentials!.apiKey\n upstreamHeaders.set('Authorization', `Bearer ${upstreamBearer}`)\n upstreamHeaders.delete('host')\n stripBearerSubprotocol(upstreamHeaders)\n const fetchImpl = opts.fetch ?? fetch\n return fetchImpl(upstreamUrl.toString(), { method: request.method, headers: upstreamHeaders })\n }\n}\n\nconst DEFAULT_RUNTIME_PROXY_HEADERS = ['accept', 'content-type', 'last-event-id', 'x-session-id']\n\nexport function buildSandboxRuntimeProxyHeaders(source: Headers, sandboxApiKey: string, forwardHeaders = DEFAULT_RUNTIME_PROXY_HEADERS): Headers {\n const headers = new Headers()\n headers.set('Authorization', `Bearer ${sandboxApiKey}`)\n for (const name of forwardHeaders) {\n const value = source.get(name)\n if (value) headers.set(name, value)\n }\n return headers\n}\n\nexport function encodeSandboxRuntimePath(runtimePath: string): string | null {\n const segments = runtimePath.split('/')\n if (segments.some((segment) => !segment || segment === '.' || segment === '..')) return null\n return segments.map((segment) => encodeURIComponent(segment)).join('/')\n}\n\nexport function bearerToken(value: string | null): string | null {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n if (trimmed.toLowerCase() === 'bearer') return null\n if (trimmed.toLowerCase().startsWith('bearer ')) {\n const token = trimmed.slice('bearer '.length).trim()\n return token || null\n }\n return trimmed\n}\n\nexport function bearerSubprotocolToken(value: string | null): string | null {\n if (!value) return null\n for (const part of value.split(',')) {\n const protocol = part.trim()\n if (!protocol.toLowerCase().startsWith(BEARER_SUBPROTOCOL_PREFIX)) continue\n const encoded = protocol.slice(BEARER_SUBPROTOCOL_PREFIX.length)\n if (!encoded) return null\n try {\n const token = base64UrlDecodeText(encoded).trim()\n return token || null\n } catch {\n return null\n }\n }\n return null\n}\n\nexport function terminalTokenFromRequest(headers: Headers): string | null {\n return bearerToken(headers.get('Authorization')) ?? bearerSubprotocolToken(headers.get('Sec-WebSocket-Protocol'))\n}\n\nfunction safeDecodeURIComponent(value: string): string | null {\n try {\n return decodeURIComponent(value)\n } catch {\n return null\n }\n}\n\nfunction stripBearerSubprotocol(headers: Headers): void {\n const value = headers.get('Sec-WebSocket-Protocol')\n if (!value) return\n const protocols = value\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part && !part.toLowerCase().startsWith(BEARER_SUBPROTOCOL_PREFIX))\n if (protocols.length) {\n headers.set('Sec-WebSocket-Protocol', protocols.join(', '))\n } else {\n headers.delete('Sec-WebSocket-Protocol')\n }\n}\n\nfunction validateTerminalSubject(subject: SandboxTerminalTokenSubject): void {\n if (!subject.userId) throw new Error('userId is required')\n if (!subject.workspaceId) throw new Error('workspaceId is required')\n if (!subject.sandboxId) throw new Error('sandboxId is required')\n}\n"],"mappings":"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","names":["value","credentials","retryAfterMs","res","refreshed","box"]}
package/dist/index.js CHANGED
@@ -284,7 +284,7 @@ import {
284
284
  verifySandboxTerminalToken,
285
285
  verifyTerminalProxyToken,
286
286
  writeProfileFilesToBox
287
- } from "./chunk-67I332VJ.js";
287
+ } from "./chunk-L3O65C27.js";
288
288
  import {
289
289
  DEFAULT_HARNESS,
290
290
  KNOWN_HARNESSES,
@@ -410,6 +410,11 @@ interface StreamSandboxPromptOptions {
410
410
  timeoutMs?: number;
411
411
  requireVisibleAssistantOutput?: boolean;
412
412
  disallowQuestions?: boolean;
413
+ interactions?: {
414
+ question?: boolean;
415
+ permission?: boolean;
416
+ plan?: boolean;
417
+ };
413
418
  }
414
419
  declare function streamSandboxPrompt(shell: SandboxRuntimeConfig, box: SandboxInstance, message: string, options?: StreamSandboxPromptOptions): AsyncGenerator<unknown>;
415
420
  declare function runSandboxPrompt(shell: SandboxRuntimeConfig, box: SandboxInstance, message: string, options?: StreamSandboxPromptOptions): Promise<string>;
@@ -47,7 +47,7 @@ import {
47
47
  verifySandboxTerminalToken,
48
48
  verifyTerminalProxyToken,
49
49
  writeProfileFilesToBox
50
- } from "../chunk-67I332VJ.js";
50
+ } from "../chunk-L3O65C27.js";
51
51
  import "../chunk-E7QYOOON.js";
52
52
  import "../chunk-3II3AWHY.js";
53
53
  import "../chunk-7EVZUIHW.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.43.6",
3
+ "version": "0.43.7",
4
4
  "packageManager": "pnpm@10.33.4",
5
5
  "description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
6
6
  "keywords": [
@@ -353,7 +353,7 @@
353
353
  "@tangle-network/agent-knowledge": "^1.7.0",
354
354
  "@tangle-network/agent-runtime": "^0.79.3",
355
355
  "@tangle-network/brand": "^0.6.0",
356
- "@tangle-network/sandbox": "^0.9.5",
356
+ "@tangle-network/sandbox": "^0.9.7",
357
357
  "@tangle-network/sandbox-ui": "^0.60.0",
358
358
  "@tangle-network/ui": "^4.1.0",
359
359
  "@testing-library/dom": "^10.4.1",
@@ -388,7 +388,7 @@
388
388
  "@tangle-network/agent-knowledge": ">=1.7.0",
389
389
  "@tangle-network/agent-runtime": ">=0.79.3",
390
390
  "@tangle-network/brand": ">=0.6.0",
391
- "@tangle-network/sandbox": ">=0.9.4",
391
+ "@tangle-network/sandbox": ">=0.9.7",
392
392
  "@tangle-network/sandbox-ui": ">=0.60.0",
393
393
  "@xyflow/react": ">=12.0.0",
394
394
  "drizzle-orm": ">=0.36",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/sandbox/index.ts","../src/sandbox/outcome.ts","../src/sandbox/terminal-proxy-token.ts","../src/sandbox/workspace-terminal.ts"],"sourcesContent":["import {\n Sandbox,\n type AgentProfile,\n type AgentProfileFileMount,\n type AgentProfileMcpServer,\n type ExecResult,\n type SandboxConnection,\n type SandboxInstance,\n type ScopedTokenScope,\n type StorageConfig,\n type PromptResult,\n type ProvisionEvent,\n} from '@tangle-network/sandbox'\nimport { createHash } from 'node:crypto'\nimport {\n buildAppToolMcpServer,\n type AppToolName,\n type AppToolContext,\n type ToolHeaderNames,\n} from '../tools/index'\nimport { assertHarnessModelCompatible, type Harness } from '../harness/index'\nimport {\n resolveTangleExecutionEnvironment,\n trimOrNull,\n type TangleExecutionEnvironment,\n} from '../runtime/model'\nimport { ok, fail, type Outcome } from './outcome'\n\nexport type { Outcome } from './outcome'\n\nexport interface SandboxClientCredentials {\n apiKey: string\n baseUrl: string\n}\n\n/**\n * Sandbox credential policy reuses the canonical execution-environment union\n * (development/test/staging/production) so env classification stays in one place\n * (see resolveTangleExecutionEnvironment in runtime/model).\n */\nexport type SandboxCredentialEnvironment = TangleExecutionEnvironment\n\nexport interface ResolveSandboxClientCredentialsOptions {\n /**\n * Environment object to read from. Defaults to process.env when available.\n */\n env?: Record<string, string | undefined>\n /**\n * Explicit environment classification. Defaults to APP_ENV/NODE_ENV derived\n * behavior: local/development/test use direct env credentials; staging/prod\n * require the provision callback unless allowDirectEnvCredentials opts in.\n */\n environment?: SandboxCredentialEnvironment\n /**\n * Env names that may carry a sandbox-compatible bearer. The first non-empty\n * value wins when direct env credentials are allowed.\n */\n directKeyNames?: readonly string[]\n /**\n * Env names that may carry the sandbox gateway URL. The first non-empty value\n * wins, then defaultBaseUrl.\n */\n baseUrlNames?: readonly string[]\n /**\n * Base URL used when none of baseUrlNames are present.\n */\n defaultBaseUrl?: string\n /**\n * Whether direct env credentials are allowed for this environment. Defaults\n * to true in development/test and false in staging/production.\n */\n allowDirectEnvCredentials?: boolean | ((environment: SandboxCredentialEnvironment) => boolean)\n /**\n * Product-owned provision path, usually minting a per-user sandbox key from a\n * linked platform account. Called before direct env credentials in\n * staging/production and after direct env credentials in development/test.\n */\n provision?: (\n context: {\n environment: SandboxCredentialEnvironment\n env: Record<string, string | undefined>\n },\n ) => SandboxClientCredentials | null | undefined | Promise<SandboxClientCredentials | null | undefined>\n}\n\nconst DEFAULT_SANDBOX_DIRECT_KEY_NAMES = [\n 'TCLOUD_SANDBOX_API_KEY',\n 'SANDBOX_API_KEY',\n 'TANGLE_API_KEY',\n] as const\nconst DEFAULT_SANDBOX_BASE_URL_NAMES = ['SANDBOX_GATEWAY_URL', 'SANDBOX_API_URL'] as const\n\nfunction normalizeBaseUrl(value: string): string {\n return value.trim().replace(/\\/v1\\/?$/, '').replace(/\\/+$/, '')\n}\n\nfunction processEnv(): Record<string, string | undefined> {\n return typeof process === 'undefined' ? {} : process.env\n}\n\nfunction directEnvCredentialsAllowed(\n environment: SandboxCredentialEnvironment,\n allow: ResolveSandboxClientCredentialsOptions['allowDirectEnvCredentials'],\n): boolean {\n if (typeof allow === 'function') return allow(environment)\n if (typeof allow === 'boolean') return allow\n return environment === 'development' || environment === 'test'\n}\n\nfunction resolveSandboxBaseUrl(\n env: Record<string, string | undefined>,\n names: readonly string[],\n defaultBaseUrl: string | undefined,\n): string {\n for (const name of names) {\n const value = trimOrNull(env[name])\n if (value) return normalizeBaseUrl(value)\n }\n const value = trimOrNull(defaultBaseUrl)\n if (value) return normalizeBaseUrl(value)\n throw new Error(\n `Sandbox base URL is required (set one of ${names.join(', ')} or pass defaultBaseUrl).`,\n )\n}\n\nfunction resolveDirectSandboxCredentials(\n env: Record<string, string | undefined>,\n keyNames: readonly string[],\n baseUrlNames: readonly string[],\n defaultBaseUrl: string | undefined,\n): SandboxClientCredentials | null {\n for (const name of keyNames) {\n const apiKey = trimOrNull(env[name])\n if (!apiKey) continue\n return {\n apiKey,\n baseUrl: resolveSandboxBaseUrl(env, baseUrlNames, defaultBaseUrl),\n }\n }\n return null\n}\n\nexport async function resolveSandboxClientCredentials(\n options: ResolveSandboxClientCredentialsOptions = {},\n): Promise<SandboxClientCredentials> {\n const env = options.env ?? processEnv()\n const environment = options.environment ?? resolveTangleExecutionEnvironment(env)\n const keyNames = options.directKeyNames ?? DEFAULT_SANDBOX_DIRECT_KEY_NAMES\n const baseUrlNames = options.baseUrlNames ?? DEFAULT_SANDBOX_BASE_URL_NAMES\n const directAllowed = directEnvCredentialsAllowed(environment, options.allowDirectEnvCredentials)\n const direct = () =>\n directAllowed\n ? resolveDirectSandboxCredentials(env, keyNames, baseUrlNames, options.defaultBaseUrl)\n : null\n\n if (environment === 'development' || environment === 'test') {\n const credentials = direct()\n if (credentials) return credentials\n }\n\n const provisioned = await options.provision?.({ environment, env })\n if (provisioned) {\n return {\n apiKey: provisioned.apiKey,\n baseUrl: normalizeBaseUrl(provisioned.baseUrl),\n }\n }\n\n const credentials = direct()\n if (credentials) return credentials\n\n const directHint = directAllowed\n ? ` or set one of ${keyNames.join(', ')}`\n : ''\n throw new Error(\n `Sandbox credentials are required for ${environment} (provide a provision callback${directHint}).`,\n )\n}\n\nexport interface SandboxResourceConfig {\n image: string\n cpuCores: number\n memoryMB: number\n diskGB: number\n maxLifetimeSeconds: number\n idleTimeoutSeconds: number\n}\n\nexport interface ProviderResolutionConfig {\n routerBaseUrl?: string\n apiKey?: string\n providerName?: string\n modelName?: string\n defaultModel?: string\n openaiApiKey?: string\n}\n\nexport interface SandboxBuildContext {\n workspaceId: string\n connectedIntegrationIds: string[]\n userId?: string\n}\n\n// SDK-typed snapshot storage config (re-exported for product seam closures).\nexport type { StorageConfig }\n\n// Scope handed to per-identity seams. workspaceId is always present; userId is\n// present when the lifecycle op carries one. Workspace-keyed products ignore userId.\nexport interface SandboxScope {\n workspaceId: string\n userId?: string\n}\n\n// Snapshot RESTORE-on-create. Returned alongside storage; undefined => fresh box.\nexport interface SandboxRestoreSpec {\n fromSnapshot: string\n fromSandboxId: string\n}\n\n// Reuse health gate + sidecar liveness. The exec+timeout-race is generic; the\n// sidecarProcessPattern is harness-specific (which process is the live sidecar),\n// so it is a closure. Absent => no liveness probe (reuse on metadata.harness match).\nexport interface LivenessProbeConfig {\n sidecarProcessPattern: (harness: Harness) => string\n execTimeoutMs?: number\n psTimeoutMs?: number\n}\n\nexport interface ProfileComposeOptions {\n systemPrompt?: string\n extraFiles?: AgentProfileFileMount[]\n extraMcp?: Record<string, AgentProfileMcpServer>\n name?: string\n}\n\nexport interface SandboxRuntimeConfig {\n // Widened to accept an optional scope and be async so a per-user key can be\n // minted. The sync, no-arg form still satisfies the type (back-compat).\n credentials: (\n scope?: SandboxScope,\n ) => SandboxClientCredentials | null | Promise<SandboxClientCredentials | null>\n name: (workspaceId: string) => string\n metadata: (harness: Harness) => Record<string, unknown>\n connectedIntegrationIds: (workspaceId: string) => Promise<string[]>\n env: (ctx: SandboxBuildContext) => Promise<Record<string, string>>\n files: (ctx: SandboxBuildContext) => Promise<AgentProfileFileMount[]>\n secrets: (workspaceId: string) => Promise<string[]>\n profile: (options: ProfileComposeOptions) => AgentProfile\n permissionRole?: (workspaceRole: string) => SandboxPermissionLevel\n resources?: SandboxResourceConfig\n provider?: ProviderResolutionConfig\n\n // BYOS3/R2 snapshot storage. Returns undefined => key omitted entirely\n // (fail-closed when creds absent). Product owns bucket/endpoint/credentials/prefix.\n storage?: (ctx: SandboxBuildContext) => StorageConfig | undefined\n // Snapshot RESTORE-on-create. undefined => fresh box.\n restore?: (ctx: SandboxBuildContext) => SandboxRestoreSpec | undefined\n // Per-identity box NAME. Defaults to name(scope.workspaceId) when absent.\n boxKey?: (scope: SandboxScope) => string\n // Per-workspace child-key mint: overrides the resolved model apiKey before create.\n // Applied only when a model is resolved and its provider is openai-compat.\n childKeyMint?: (scope: SandboxScope) => Promise<Outcome<string>>\n // One-shot post-running bootstrap, on BOTH create and reuse paths (idempotency\n // is the closure's job — it owns the marker check).\n bootstrap?: (box: SandboxInstance, scope: SandboxScope) => Promise<Outcome<void>>\n // Reuse health gate + sidecar liveness probe.\n livenessProbe?: LivenessProbeConfig\n // Enable browser terminal endpoints on newly-created sandboxes.\n webTerminalEnabled?: boolean\n // default true: try stopped-resume before create.\n resumeStopped?: boolean\n // default false: bake resolveModel() into backend.model at create.\n backendModelAtCreate?: boolean\n // default false: write the profile's `resources.files` INTO the box after it\n // reaches running (via `box.exec`), instead of inlining them in the create\n // payload. The orchestrator caps the provision body at 256 KiB; a large\n // file corpus (skills, tool scripts) blows that cap. Deferring it keeps the\n // provision body small and uncapped in corpus size, and lands real files on\n // disk — which is also the only path that works for harnesses whose backend\n // does not materialize the provider-neutral `resources.files` channel.\n //\n // Only `kind: 'inline'` files are deferred; non-inline refs (e.g. github)\n // stay in the create payload so the orchestrator resolves them. Runs on the\n // create AND resume/reuse paths (idempotent overwrite). Inline files are\n // STRIPPED from `resources.files` before create when this is set.\n deferProfileFiles?: boolean\n}\n\nexport const DEFAULT_SANDBOX_RESOURCES: SandboxResourceConfig = {\n image: 'universal',\n cpuCores: 2,\n memoryMB: 4096,\n diskGB: 10,\n maxLifetimeSeconds: 86400,\n idleTimeoutSeconds: 3600,\n}\n\ninterface ClientCacheEntry {\n client: Sandbox\n fingerprint: string\n}\n\nlet _cached: ClientCacheEntry | null = null\n\nfunction getClientFromCreds(creds: SandboxClientCredentials): Sandbox {\n const fingerprint = `${creds.apiKey} ${creds.baseUrl}`\n if (_cached && _cached.fingerprint === fingerprint) return _cached.client\n\n const client = new Sandbox({ apiKey: creds.apiKey, baseUrl: creds.baseUrl })\n _cached = { client, fingerprint }\n return client\n}\n\n// Sync client for non-scoped callers (secretStoreFromClient etc.). Resolves\n// credentials with no scope; throws if the seam returns a Promise — scoped\n// products must use the async ensureWorkspaceSandbox path.\nexport function getClient(shell: SandboxRuntimeConfig): Sandbox {\n const creds = shell.credentials()\n if (creds && typeof (creds as Promise<unknown>).then === 'function') {\n throw new Error('getClient: scoped (async) credentials require the async sandbox path')\n }\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n return getClientFromCreds(creds as SandboxClientCredentials)\n}\n\nexport function resetClientCache(): void {\n _cached = null\n}\n\nexport interface AppToolDescriptor {\n tool: AppToolName\n key: string\n description: string\n}\n\nexport interface BuildAppToolMcpServersOptions {\n tools: AppToolDescriptor[]\n baseUrl: string\n token: string\n ctx: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\nexport function buildAppToolMcpServers(\n options: BuildAppToolMcpServersOptions,\n): Record<string, AgentProfileMcpServer> {\n const entries: Record<string, AgentProfileMcpServer> = {}\n for (const { tool, key, description } of options.tools) {\n entries[key] = buildAppToolMcpServer({\n tool,\n baseUrl: options.baseUrl,\n token: options.token,\n ctx: options.ctx,\n description,\n headerNames: options.headerNames,\n }) as AgentProfileMcpServer\n }\n return entries\n}\n\nexport interface EnsureWorkspaceSandboxOptions {\n workspaceId: string\n userId?: string\n harness: Harness\n // When set, both the running-reuse and stopped-resume short-circuits are\n // skipped and any name-matched box is deleted before create.\n forceNew?: boolean\n // Real-time provisioning progress from the SDK's SSE stream, forwarded from\n // the `waitFor('running')` calls on the resume and cold-create paths. Callers\n // surface it as live \"warming up\" status. Only fires while a box is actually\n // being provisioned; a reused running box emits nothing.\n onProgress?: (event: ProvisionEvent) => void\n}\n\n// Single-quote a string for safe interpolation into a shell command.\nfunction shellSingleQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`\n}\n\nexport interface SandboxToolSpec {\n name: string\n content: string\n executable?: boolean\n}\n\nexport interface SandboxToolPathOptions {\n appName: string\n baseDir?: string\n binDir?: string\n}\n\nexport interface BuildSandboxToolFileMountsOptions extends SandboxToolPathOptions {\n tools: readonly SandboxToolSpec[]\n}\n\nconst DEFAULT_SANDBOX_TOOL_BASE_DIR = '/home/agent/tools'\nconst SAFE_TOOL_SEGMENT = /^[A-Za-z0-9._-]+$/\n\nfunction normalizeSandboxToolSegment(value: string, label: string): string {\n const segment = value.trim()\n if (!segment || segment === '.' || segment === '..' || !SAFE_TOOL_SEGMENT.test(segment)) {\n throw new Error(`${label} must contain only letters, numbers, dots, underscores, or hyphens.`)\n }\n return segment\n}\n\nfunction normalizeSandboxToolDir(value: string, label: string): string {\n const dir = value.trim().replace(/\\/+$/, '')\n if (!dir || !dir.startsWith('/') || dir.includes('\\0') || dir.includes('\\n')) {\n throw new Error(`${label} must be an absolute sandbox path.`)\n }\n return dir === '' ? '/' : dir\n}\n\nexport function sandboxToolRootDir(options: SandboxToolPathOptions): string {\n const appName = normalizeSandboxToolSegment(options.appName, 'sandbox tool appName')\n const baseDir = normalizeSandboxToolDir(\n options.baseDir ?? DEFAULT_SANDBOX_TOOL_BASE_DIR,\n 'sandbox tool baseDir',\n )\n return `${baseDir}/${appName}`\n}\n\nexport function sandboxToolBinDir(options: SandboxToolPathOptions): string {\n normalizeSandboxToolSegment(options.appName, 'sandbox tool appName')\n if (options.binDir) return normalizeSandboxToolDir(options.binDir, 'sandbox tool binDir')\n return `${sandboxToolRootDir(options)}/bin`\n}\n\nexport function sandboxToolPath(options: SandboxToolPathOptions & { toolName: string }): string {\n const toolName = normalizeSandboxToolSegment(options.toolName, 'sandbox tool name')\n return `${sandboxToolBinDir(options)}/${toolName}`\n}\n\nexport function buildSandboxToolFileMounts(\n options: BuildSandboxToolFileMountsOptions,\n): AgentProfileFileMount[] {\n return options.tools.map((tool) => {\n const name = normalizeSandboxToolSegment(tool.name, 'sandbox tool name')\n return {\n path: sandboxToolPath({ ...options, toolName: name }),\n resource: { kind: 'inline' as const, name, content: tool.content },\n executable: tool.executable ?? true,\n }\n })\n}\n\nexport function buildSandboxToolPathSetupScript(options: SandboxToolPathOptions): string {\n const binDir = sandboxToolBinDir(options)\n const exportLine = `export PATH=${binDir}:$PATH`\n return [\n 'set -eu',\n `mkdir -p ${shellSingleQuote(binDir)}`,\n `PATH=${shellSingleQuote(binDir)}:$PATH`,\n 'export PATH',\n 'for profile in \"${HOME:-/home/agent}/.profile\" \"${HOME:-/home/agent}/.bashrc\" \"${HOME:-/home/agent}/.zshrc\"; do',\n ' mkdir -p \"$(dirname \"$profile\")\"',\n ' touch \"$profile\"',\n ` grep -Fqx ${shellSingleQuote(exportLine)} \"$profile\" || printf '\\\\n%s\\\\n' ${shellSingleQuote(exportLine)} >> \"$profile\"`,\n 'done',\n ].join('\\n')\n}\n\nexport async function runSandboxToolPathSetup(\n box: SandboxInstance,\n options: SandboxToolPathOptions,\n): Promise<Outcome<void>> {\n try {\n const res = await box.exec(buildSandboxToolPathSetupScript(options))\n if (res.exitCode !== 0) {\n return fail(\n new Error(\n `runSandboxToolPathSetup: failed to configure PATH for ${sandboxToolBinDir(options)} ` +\n `(exit ${res.exitCode}): ${res.stderr.slice(0, 500)}`,\n ),\n )\n }\n return ok(undefined)\n } catch (err) {\n return fail(new Error('runSandboxToolPathSetup: exec failed', { cause: err }))\n }\n}\n\n// Build a shell-safe path token that preserves tilde-home semantics. A path\n// beginning `~/` (or a bare `~`) must resolve to the box user's real `$HOME`,\n// but single-quoting the whole path suppresses shell `~` expansion and lands\n// the file in a literal directory named `~`. Expand the leading `~` to an\n// UNQUOTED `\"$HOME\"` (so the shell expands it) and single-quote only the\n// remainder. Absolute and relative paths are single-quoted unchanged.\nfunction shellPath(path: string): string {\n if (path === '~') return '\"$HOME\"'\n if (path.startsWith('~/')) {\n const rest = path.slice(2)\n return rest ? `\"$HOME\"/${shellSingleQuote(rest)}` : '\"$HOME\"'\n }\n return shellSingleQuote(path)\n}\n\n// Split a profile's `resources.files` into the inline mounts that can be\n// written into a running box and the rest (non-inline refs that the\n// orchestrator must resolve, so they stay in the create payload). Returns the\n// inline set to defer and a profile copy with those inline files removed.\nexport function splitDeferredProfileFiles(\n profile: AgentProfile,\n): { leanProfile: AgentProfile; deferredFiles: AgentProfileFileMount[] } {\n const files = profile.resources?.files ?? []\n const deferredFiles: AgentProfileFileMount[] = []\n const keptFiles: AgentProfileFileMount[] = []\n for (const mount of files) {\n if (mount.resource.kind === 'inline') deferredFiles.push(mount)\n else keptFiles.push(mount)\n }\n if (deferredFiles.length === 0) return { leanProfile: profile, deferredFiles }\n const leanProfile: AgentProfile = {\n ...profile,\n resources: { ...(profile.resources ?? {}), files: keptFiles },\n }\n return { leanProfile, deferredFiles }\n}\n\n// The runtime exec proxy (`box.exec` → /terminals/commands) hangs (30s\n// timeout) on any request whose body crosses ~4096 bytes, and one oversized\n// exec wedges the channel so every later exec on the box hangs too. We slice\n// each file's base64 into appends whose full command string stays well under\n// that cap. 3000 chars of base64 leaves ~1000 bytes of headroom for the\n// surrounding `printf '%s' '<slice>' >> <path>.b64` command plus the proxy's\n// JSON request envelope — comfortably below 4096.\nconst PROFILE_WRITE_B64_CHUNK_CHARS = 3000\n\n// gtm's corpus is ~135 small execs; on a cold box the runtime exec proxy\n// hard-throttles (HTTP 429 after ~21 execs in ~34s) and, under sustained load,\n// SILENTLY HANGS instead of returning 429 — one parked exec wedges the channel\n// and `writeProfileFilesToBox` never returns, so `ensureWorkspaceSandbox`\n// parks the worker (~140s, no exception). These failures plus sidecar exec-plane\n// readiness/transport failures (5xx, reset, fetch/network errors) are transient:\n// retry the SAME exec with exponential backoff before failing loud. A non-zero\n// exit is a real command failure, never retried.\nconst PROFILE_WRITE_MAX_RETRIES = 4\nconst PROFILE_WRITE_RETRY_BASE_MS = 250\nconst PROFILE_WRITE_RETRY_MAX_MS = 2000\n\n// Client-side hard ceiling per exec. The proxy's own 30s timeout is unreliable\n// once the channel wedges (it can hang past it), so we race each exec against an\n// independent timer we control: a wedged exec is abandoned here and retried as a\n// transient transport error, never silently parked. We also pass timeoutMs to\n// the SDK as defense-in-depth, but the race is the guarantee.\nconst PROFILE_WRITE_EXEC_TIMEOUT_MS = 30_000\n\n// Pacing between execs to stay under the proxy throttle that triggers the hang.\n// The drill saw throttling at ~0.6 exec/s bursts; ~150ms between ~135 execs\n// adds well under a minute total and keeps the burst rate below the trip point.\n// On by default for the deferred path; overridable for tests/tuning.\nconst PROFILE_WRITE_PACE_MS = 150\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms))\n\n// A mount whose path sits in a bin directory is made executable. Shared so the\n// file-API eligibility check and the exec branch agree on \"executable by dir\".\nconst PROFILE_BIN_DIR_RE = /(^|\\/)(s?bin)\\//\n\n// Sentinel cause for a client-side per-exec timeout (a hung/wedged proxy exec).\n// Carried as the `.cause` of the fail-loud Outcome so callers see the wedged\n// command instead of an opaque infinite hang.\nclass ProfileWriteExecTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`exec exceeded ${timeoutMs}ms (proxy hang/wedge)`)\n this.name = 'ProfileWriteExecTimeoutError'\n }\n}\n\n// Run a box.exec, abandoning it if it does not settle within timeoutMs. The\n// returned promise rejects with ProfileWriteExecTimeoutError on timeout so the\n// retry loop treats a hang exactly like a transient transport error. We also\n// forward timeoutMs to the SDK so the underlying request is cancelled when the\n// SDK honors it; the race covers the case where it does not.\nfunction execWithTimeout(\n box: SandboxInstance,\n cmd: string,\n timeoutMs: number,\n): Promise<ExecResult> {\n return new Promise<ExecResult>((resolve, reject) => {\n let settled = false\n const timer = setTimeout(() => {\n if (settled) return\n settled = true\n reject(new ProfileWriteExecTimeoutError(timeoutMs))\n }, timeoutMs)\n box.exec(cmd, { timeoutMs }).then(\n (res) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n resolve(res)\n },\n (err) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n reject(err)\n },\n )\n })\n}\n\nconst TRANSIENT_EXEC_STATUS_CODES = new Set([408, 409, 425, 429, 500, 502, 503, 504])\nconst TRANSIENT_EXEC_CODE_RE = /^(ECONNRESET|ECONNREFUSED|ETIMEDOUT|EPIPE|ECONNABORTED)$/i\nconst TRANSIENT_EXEC_MESSAGE_RE =\n /\\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\nconst RUNTIME_AUTH_REFRESH_SKEW_MS = 60_000\n\nfunction errorStatus(err: { status?: unknown; statusCode?: unknown; response?: unknown }): number | undefined {\n const rawStatus = err.status ?? err.statusCode ?? (\n err.response && typeof err.response === 'object'\n ? (err.response as { status?: unknown }).status\n : undefined\n )\n if (typeof rawStatus === 'number') return rawStatus\n if (typeof rawStatus === 'string' && /^\\d+$/.test(rawStatus)) return Number(rawStatus)\n return undefined\n}\n\nfunction retryAfterMs(err: unknown, seen = new Set<object>()): number | undefined {\n if (!err || typeof err !== 'object') return undefined\n if (seen.has(err)) return undefined\n seen.add(err)\n const e = err as { retryAfterMs?: unknown; cause?: unknown }\n if (typeof e.retryAfterMs === 'number') return e.retryAfterMs\n return retryAfterMs(e.cause, seen)\n}\n\nfunction isTransientExecError(err: unknown, seen = new Set<object>()): boolean {\n if (!err || typeof err !== 'object') return false\n if (seen.has(err)) return false\n seen.add(err)\n const e = err as {\n status?: unknown\n statusCode?: unknown\n response?: unknown\n code?: unknown\n message?: unknown\n cause?: unknown\n }\n const status = errorStatus(e)\n if (status !== undefined && TRANSIENT_EXEC_STATUS_CODES.has(status)) return true\n if (typeof e.code === 'string') {\n if (TRANSIENT_EXEC_CODE_RE.test(e.code)) return true\n if (/rate.?limit|too.?many.?requests|429|server.?error|service.?unavailable/i.test(e.code)) return true\n }\n if (typeof e.message === 'string' && TRANSIENT_EXEC_MESSAGE_RE.test(e.message)) return true\n return isTransientExecError(e.cause, seen)\n}\n\nfunction isRuntimeExecAuthError(err: unknown, seen = new Set<object>()): boolean {\n if (!err || typeof err !== 'object') return false\n if (seen.has(err)) return false\n seen.add(err)\n const e = err as {\n status?: unknown\n statusCode?: unknown\n response?: unknown\n code?: unknown\n name?: unknown\n message?: unknown\n cause?: unknown\n }\n if (errorStatus(e) === 401) return true\n if (\n typeof e.code === 'string' &&\n /^(AUTH_ERROR|AUTHENTICATION_ERROR|UNAUTHORIZED|UNAUTHENTICATED|ERR_UNAUTHORIZED|ERR_UNAUTHENTICATED|401)$/i.test(e.code)\n ) {\n return true\n }\n if (\n typeof e.name === 'string' &&\n /^(AuthError|AuthenticationError|UnauthorizedError|UnauthenticatedError|SandboxAuthError)$/i.test(e.name)\n ) {\n return true\n }\n return isRuntimeExecAuthError(e.cause, seen)\n}\n\nfunction isRuntimeAuthRefreshDenied(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false\n return (\n isRuntimeExecAuthError(err) ||\n errorStatus(err as { status?: unknown; statusCode?: unknown; response?: unknown }) === 403\n )\n}\n\n// Classify an exec failure as transient-retryable. Retryable shapes share the\n// same backoff path: rate-limit (HTTP 429 + retryAfterMs), client-side timeout,\n// and transient sidecar/transport/readiness failures surfaced as SandboxError-\n// shaped objects, fetch errors, network resets, or 5xx-ish messages. Everything\n// else fails loud. Non-zero shell exits never reach this classifier.\nfunction transientExecError(err: unknown): { retryable: boolean; retryAfterMs?: number } {\n if (err instanceof ProfileWriteExecTimeoutError) return { retryable: true }\n if (isTransientExecError(err)) return { retryable: true, retryAfterMs: retryAfterMs(err) }\n return { retryable: false }\n}\n\nfunction deferredProfileWriteFailed(stage: 'new' | 'reused' | 'resumed', name: string, cause: Error): Error {\n return new Error(`deferred file write failed on ${stage} box ${name}: ${cause.message}`, { cause })\n}\n\ntype ExistingBoxStage = 'reused' | 'resumed'\n\nexport class SandboxRuntimeAuthRefreshError extends Error {\n constructor(stage: ExistingBoxStage, name: string, detail: string, cause?: unknown) {\n super(`${stage} sandbox auth refresh failed for ${name}: ${detail}`, { cause })\n this.name = 'SandboxRuntimeAuthRefreshError'\n }\n}\n\n// Materialize inline profile files into a running box via `box.exec`. Uses a\n// base64 pipe so arbitrary content (scripts, unicode, special chars) lands\n// byte-exact, and writes to ANY absolute path (e.g. /usr/local/bin) or a\n// `~`-relative path — the exec runs as the sidecar, which is not bound by the\n// safe-prefix allow-list the /files/write API enforces. Sets the executable\n// bit when the mount declares it OR the target is a bin directory.\n//\n// Each file is written in several small execs (mkdir, one append per base64\n// chunk, then a decode+cleanup) so no single exec request body trips the\n// ~4 KiB proxy cap. Writes are sequential; a single bad mount stops the batch\n// and the first failure is returned (fail-loud), the rest are not attempted.\n//\n// Each exec is bounded by a client-side hard timeout and retried with backoff\n// on transient rate-limit/readiness/transport failures, so one wedged or early\n// exec-plane request can never park the caller (and thus never park provisioning).\n// A small pace between execs keeps the burst rate below the proxy throttle that\n// triggers the hang.\nexport interface WriteProfileFilesOptions {\n // Hard ceiling per exec (ms). A hung/wedged exec is abandoned and retried.\n execTimeoutMs?: number\n // Delay between execs (ms) to stay under the proxy throttle. 0 disables it.\n paceMs?: number\n // Max retries for a transient exec before failing loud.\n maxRetries?: number\n}\n\n// The workspace-relative target for a deferred inline mount when it can be\n// materialized through the sidecar file API (`box.fs.writeMany` — FILES rate\n// group, 300/min, whole-file, auto-mkdir) instead of the chunked terminal-exec\n// path (50/min); null when it must stay on exec. The file API resolves relative\n// paths from the workspace root, so eligibility is: inline and a path that\n// resolves under the workspace root with no `..`/`.sidecar` segment. `~/…` and\n// `/home/agent/…` are home-relative; agent sandboxes set $HOME to the workspace\n// root, so both map to the same relative target. Other absolute (`/…`) and bare\n// `~`/`~user` mounts stay on exec.\nfunction fileApiTarget(mount: AgentProfileFileMount): string | null {\n if (mount.resource.kind !== 'inline') return null\n let rel: string\n if (mount.path.startsWith('~/')) rel = mount.path.slice(2)\n else if (mount.path.startsWith('/home/agent/')) rel = mount.path.slice('/home/agent/'.length)\n else if (mount.path.startsWith('/') || mount.path.startsWith('~')) return null\n else rel = mount.path\n if (rel.length === 0 || rel.startsWith('/') || rel.split('/').some((seg) => seg === '..' || seg === '.sidecar')) {\n return null\n }\n return rel\n}\n\nfunction isExecutableProfileFile(mount: AgentProfileFileMount): boolean {\n return mount.executable ?? PROFILE_BIN_DIR_RE.test(mount.path)\n}\n\nfunction profileFileMode(mount: AgentProfileFileMount): number | undefined {\n return isExecutableProfileFile(mount) ? 0o755 : undefined\n}\n\nfunction fileApiSupportsMode(box: SandboxInstance): boolean {\n const fs = box.fs as (SandboxInstance['fs'] & { supportsWriteMode?: boolean }) | undefined\n return fs?.supportsWriteMode === true\n}\n\nexport async function writeProfileFilesToBox(\n box: SandboxInstance,\n files: AgentProfileFileMount[],\n options: WriteProfileFilesOptions = {},\n): Promise<Outcome<void>> {\n const execTimeoutMs = options.execTimeoutMs ?? PROFILE_WRITE_EXEC_TIMEOUT_MS\n const paceMs = options.paceMs ?? PROFILE_WRITE_PACE_MS\n const maxRetries = options.maxRetries ?? PROFILE_WRITE_MAX_RETRIES\n // The bulk of a profile corpus (skills, `~/.claude/skills/…`, config) is\n // inline and workspace-relative — write it in ONE paced,\n // retry-aware batch via the SDK's file API (`box.fs.writeMany`, FILES rate\n // group 300/min). The SDK owns the pacing + transient-retry this module used\n // to hand-roll. Absolute / bare-`~` paths can't use the file API\n // (prefix-restricted), so they stay on the chunked exec path.\n // Capability-guarded: SDKs without `writeMany` route everything through\n // exec; SDKs before @tangle-network/sandbox 0.9.4 keep executable files on\n // exec because they do not expose `supportsWriteMode` or forward file modes.\n const fileApiAvailable = typeof box.fs?.writeMany === 'function'\n const modeAwareFileApi = fileApiSupportsMode(box)\n const viaFileApi: { path: string; content: string; mode?: number }[] = []\n const viaExec: AgentProfileFileMount[] = []\n for (const mount of files) {\n if (mount.resource.kind !== 'inline') continue\n const fileApiPath = fileApiAvailable ? fileApiTarget(mount) : null\n const executable = isExecutableProfileFile(mount)\n if (fileApiPath !== null && (!executable || modeAwareFileApi)) {\n const mode = profileFileMode(mount)\n viaFileApi.push({\n path: fileApiPath,\n content: mount.resource.content ?? '',\n ...(mode !== undefined ? { mode } : {}),\n })\n }\n else viaExec.push(mount)\n }\n if (viaFileApi.length > 0) {\n // `writeMany` is fail-loud on the first file it can't write. Preserve the\n // cause so the runtime-auth-refresh wrapper still detects a 401 — it\n // recurses `.cause` for an AuthError/401 shape (see isRuntimeExecAuthError).\n try {\n await box.fs.writeMany(viaFileApi, { paceMs, maxRetries })\n } catch (err) {\n return fail(new Error('writeProfileFilesToBox: file-API batch write failed', { cause: err }))\n }\n }\n\n // Pace BETWEEN execs, not before the first or after the last. Shared across\n // the exec mounts so the (now smaller) executable/edge-case set stays paced.\n let execStarted = false\n\n // Pace + transient-retry ONE exec attempt: backoff/pace/fail-loud in one place.\n // `run` must be idempotent under unknown-outcome retries (exec writes\n // deterministic parts). A transient error retries with backoff up to\n // maxRetries (honoring a server Retry-After); anything else, or exhausting\n // retries, fails loud with the cause.\n const paceAndRetry = async <T>(run: () => Promise<T>, path: string): Promise<Outcome<T>> => {\n for (let attempt = 0; ; attempt++) {\n if (execStarted && paceMs > 0) await sleep(paceMs)\n execStarted = true\n try {\n return ok(await run())\n } catch (err) {\n const { retryable, retryAfterMs } = transientExecError(err)\n if (retryable && attempt < maxRetries) {\n const backoff = Math.min(PROFILE_WRITE_RETRY_BASE_MS * 2 ** attempt, PROFILE_WRITE_RETRY_MAX_MS)\n await sleep(retryAfterMs ?? backoff)\n continue\n }\n return fail(new Error(`writeProfileFilesToBox: exec failed for ${path}`, { cause: err }))\n }\n }\n }\n\n for (const mount of viaExec) {\n if (mount.resource.kind !== 'inline') continue // always true (viaExec is inline) — narrows for TS\n const content = mount.resource.content ?? ''\n const path = mount.path\n\n const b64 = Buffer.from(content, 'utf8').toString('base64')\n const b64Chunks: string[] = []\n for (let i = 0; i < b64.length; i += PROFILE_WRITE_B64_CHUNK_CHARS) {\n b64Chunks.push(b64.slice(i, i + PROFILE_WRITE_B64_CHUNK_CHARS))\n }\n const expectedSha256 = createHash('sha256').update(content, 'utf8').digest('hex')\n const dir = path.replace(/\\/[^/]*$/, '')\n const executable = isExecutableProfileFile(mount)\n const q = shellPath(path)\n const qb64 = shellPath(`${path}.b64`)\n const qtmp = shellPath(`${path}.tmp`)\n const qpartPrefix = shellPath(`${path}.b64.part.`)\n\n // Run one exec step. Transport errors (incl. a wedged-proxy timeout) are\n // paced + retried by paceAndRetry; a non-zero exit is a REAL command failure\n // — surfaced immediately, never retried.\n const step = async (cmd: string): Promise<Outcome<void>> => {\n const res = await paceAndRetry(() => execWithTimeout(box, cmd, execTimeoutMs), path)\n if (!res.succeeded) return res\n const exec = res.value\n if (exec.exitCode !== 0) {\n return fail(\n new Error(\n `writeProfileFilesToBox: failed to write ${path} (exit ${exec.exitCode}): ${exec.stderr.slice(0, 500)}`,\n ),\n )\n }\n return ok(undefined)\n }\n\n // Ensure the target directory exists. Chunk/final commands below are\n // idempotent under unknown-outcome transport retries; this no-op/mkdir is too.\n const mkdir = dir && dir !== path ? `mkdir -p ${shellPath(dir)}` : ':'\n let res = await step(mkdir)\n if (!res.succeeded) return res\n\n // Write each deterministic part with overwrite, not append. If the server\n // writes a part but the HTTP response is lost, retrying the same step lands\n // the same bytes instead of duplicating them.\n for (let i = 0; i < b64Chunks.length; i++) {\n const slice = b64Chunks[i]!\n res = await step(`printf '%s' '${slice}' > ${shellPath(`${path}.b64.part.${i}`)}`)\n if (!res.succeeded) return res\n }\n\n // Materialize from deterministic parts into a temp file, verify its content\n // hash, then atomically move into place. If the final exec succeeds but its\n // response is lost, a retry first accepts an already-correct target and only\n // re-runs idempotent chmod/cleanup. Parts are cleaned only after the target\n // hash is known-good, so a retried final step can always reconstruct.\n const chmod = executable ? `chmod +x ${q} || exit 1; ` : ''\n const checksumMismatch = shellSingleQuote(`writeProfileFilesToBox: checksum mismatch for ${path}`)\n const finalCmd =\n `expected='${expectedSha256}'; ` +\n `if [ -f ${q} ] && [ \"$(sha256sum ${q} | awk '{print $1}')\" = \"$expected\" ]; then ` +\n `${chmod}rm -f ${qb64} ${qtmp}; i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done; exit 0; fi; ` +\n `: > ${qb64} && ` +\n `i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do cat ${qpartPrefix}$i >> ${qb64} || exit 1; i=$((i+1)); done && ` +\n `base64 -d ${qb64} > ${qtmp} && ` +\n `[ \"$(sha256sum ${qtmp} | awk '{print $1}')\" = \"$expected\" ] || { echo ${checksumMismatch} >&2; exit 1; }; ` +\n `mv ${qtmp} ${q} && ` +\n `${executable ? `chmod +x ${q} && ` : ''}` +\n `[ \"$(sha256sum ${q} | awk '{print $1}')\" = \"$expected\" ] || { echo ${checksumMismatch} >&2; exit 1; }; ` +\n `rm -f ${qb64} ${qtmp}; i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done`\n res = await step(finalCmd)\n if (!res.succeeded) return res\n }\n return ok(undefined)\n}\n\n// Resolve the shell's deferred (inline) profile files and write them into a\n// box that already exists (reuse/resume paths). No-op unless the shell opts\n// into deferProfileFiles. Idempotent overwrite — a redeploy with new skills\n// refreshes the corpus on the next ensure call.\nasync function materializeDeferredFilesForExistingBox(\n shell: SandboxRuntimeConfig,\n client: Sandbox,\n box: SandboxInstance,\n stage: ExistingBoxStage,\n name: string,\n workspaceId: string,\n userId: string | undefined,\n): Promise<Outcome<SandboxInstance>> {\n if (!shell.deferProfileFiles) return ok(box)\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = {\n workspaceId,\n connectedIntegrationIds,\n ...(userId ? { userId } : {}),\n }\n const files = await shell.files(buildCtx)\n const fullProfile = shell.profile({ extraFiles: files })\n const { deferredFiles } = splitDeferredProfileFiles(fullProfile)\n if (deferredFiles.length === 0) return ok(box)\n return writeDeferredFilesWithRuntimeAuthRefresh(client, box, deferredFiles, stage, name)\n}\n\nasync function listRunning(\n client: Sandbox,\n name: string,\n): Promise<Outcome<SandboxInstance | null>> {\n try {\n const running = await client.list({ status: 'running' })\n return ok(running.find((s) => s.name === name) ?? null)\n } catch (err) {\n return fail(err)\n }\n}\n\nasync function deleteBox(box: SandboxInstance): Promise<Outcome<void>> {\n try {\n await box.delete()\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\n// The SDK narrows `backend.type` to its own BackendType union and\n// `initialUsers[].role` to PermissionLevel — neither symbol is exported. The\n// create payload is assembled with the product's Harness/role strings, which\n// are a superset surface; the localized cast at the boundary is the only place\n// this widening is allowed, and the runtime contract (the sidecar boots the\n// named harness) is what enforces correctness.\ntype CreatePayload = Parameters<Sandbox['create']>[0]\n\n// Generic exec+sidecar liveness probe. Absent probe => always alive (the prior\n// reuse-on-metadata-match behavior). With a probe: the container must answer an\n// `echo alive` exec within execTimeoutMs, and the sidecar process must be found\n// by pgrep within psTimeoutMs (an inconclusive pgrep is treated as reusable).\nasync function isBoxAlive(\n box: SandboxInstance,\n harness: Harness,\n probe: LivenessProbeConfig | undefined,\n): Promise<boolean> {\n if (!probe) return true\n const execTimeout = probe.execTimeoutMs ?? 5000\n const psTimeout = probe.psTimeoutMs ?? 3000\n const race = <T>(p: Promise<T>, ms: number, label: string): Promise<T> =>\n Promise.race([\n p,\n new Promise<T>((_, reject) => setTimeout(() => reject(new Error(label)), ms)),\n ])\n try {\n const alive = await race(box.exec('echo alive'), execTimeout, 'alive check timeout')\n if (!alive.stdout.includes('alive')) return false\n const pattern = probe.sidecarProcessPattern(harness)\n try {\n const ps = await race(\n box.exec(`pgrep -f ${shellSingleQuote(pattern)} || echo no-sidecar`),\n psTimeout,\n 'ps check timeout',\n )\n if (ps.stdout.includes('no-sidecar')) return false\n } catch {\n // sidecar probe inconclusive — container is alive, treat as reusable\n }\n return true\n } catch {\n return false\n }\n}\n\nconst RUNTIME_CONNECTION_WAIT_MS = 30_000\nconst RUNTIME_CONNECTION_POLL_MS = 1_000\n\n// `sidecarUrl` is a product/forward-compat field the orchestrator may set on\n// the connection ahead of the SDK declaring it — the v0.6 `SandboxConnection`\n// exposes only `runtimeUrl`. Read it through a typed augmentation rather than an\n// ad-hoc cast (a plain `SandboxConnection` satisfies the optional field), and\n// fall back to the SDK runtime URL. The product-facing `WorkspaceSandboxInstanceLike`\n// carries the same field for consumers driving their own box types.\ntype RuntimeConnectionFields = SandboxConnection & {\n sidecarUrl?: string\n authToken?: string\n sidecarToken?: string\n authTokenExpiresAt?: string | number | Date\n sidecarTokenExpiresAt?: string | number | Date\n}\n\nfunction sandboxRuntimeUrl(box: SandboxInstance): string | undefined {\n const connection: RuntimeConnectionFields | undefined = box.connection\n return connection?.sidecarUrl ?? connection?.runtimeUrl\n}\n\nfunction runtimeAuthExpiresAtMs(value: string | number | Date | undefined): number | undefined {\n if (value instanceof Date) return value.getTime()\n if (typeof value === 'number') return value\n if (typeof value !== 'string' || value.trim() === '') return undefined\n const parsed = Date.parse(value)\n return Number.isNaN(parsed) ? undefined : parsed\n}\n\nfunction hasFreshRuntimeExecAuth(box: SandboxInstance, now = Date.now()): boolean {\n const connection: RuntimeConnectionFields | undefined = box.connection\n const token = connection?.authToken ?? connection?.sidecarToken\n if (!sandboxRuntimeUrl(box) || !token) return false\n const expiresAt = runtimeAuthExpiresAtMs(\n connection?.authTokenExpiresAt ?? connection?.sidecarTokenExpiresAt,\n )\n return expiresAt === undefined || expiresAt > now + RUNTIME_AUTH_REFRESH_SKEW_MS\n}\n\nfunction sandboxEdgeFailed(box: SandboxInstance): boolean {\n // `edgeStatus`/`edgeError` are declared on the SDK's `SandboxConnection`, so no cast.\n const connection = box.connection\n return connection?.edgeStatus === 'failed' || Boolean(connection?.edgeError)\n}\n\nasync function refreshRuntimeConnection(\n client: Sandbox,\n box: SandboxInstance,\n): Promise<SandboxInstance> {\n let current = box\n if (sandboxRuntimeUrl(current)) return current\n\n const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS\n while (Date.now() < deadline) {\n // Tolerate transient refresh/get failures (5xx, network blips) while the\n // orchestrator is still attaching the connection: swallow and retry. A box\n // that never surfaces a runtime URL is returned as-is so the caller's\n // readiness gate (isReusableBox) drops and recreates it — rather than this\n // poll throwing a hard provisioning failure on a recoverable hiccup.\n try {\n await current.refresh()\n if (sandboxRuntimeUrl(current)) return current\n\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (sandboxRuntimeUrl(current)) return current\n } catch {\n // transient — fall through to the poll delay and retry\n }\n\n await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS))\n }\n\n return current\n}\n\nasync function bestEffortRefreshRuntimeExecAuth(\n client: Sandbox,\n box: SandboxInstance,\n stage: ExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let current = box\n\n try {\n await current.refresh()\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n if (isRuntimeAuthRefreshDenied(err)) {\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec auth refresh was unauthorized',\n err,\n ),\n )\n }\n }\n\n try {\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n if (isRuntimeAuthRefreshDenied(err)) {\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec auth re-fetch was unauthorized',\n err,\n ),\n )\n }\n }\n\n return ok(current)\n}\n\nasync function refreshRuntimeExecAuth(\n client: Sandbox,\n box: SandboxInstance,\n stage: ExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let current = box\n let lastError: unknown\n const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS\n\n while (Date.now() < deadline) {\n try {\n await current.refresh()\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n lastError = err\n }\n\n await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS))\n }\n\n const detail = sandboxRuntimeUrl(current)\n ? 'runtime exec credentials are missing or expired after refresh'\n : 'runtime connection is missing after refresh'\n return fail(new SandboxRuntimeAuthRefreshError(stage, name, detail, lastError))\n}\n\nasync function writeDeferredFilesWithRuntimeAuthRefresh(\n client: Sandbox,\n box: SandboxInstance,\n files: AgentProfileFileMount[],\n stage: ExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let writeBox = box\n\n if (!hasFreshRuntimeExecAuth(writeBox)) {\n const refreshed = await bestEffortRefreshRuntimeExecAuth(client, writeBox, stage, name)\n if (!refreshed.succeeded) return fail(refreshed.error)\n writeBox = refreshed.value\n }\n\n const first = await writeProfileFilesToBox(writeBox, files)\n if (first.succeeded) return ok(writeBox)\n if (!isRuntimeExecAuthError(first.error)) return fail(first.error)\n\n const refreshed = await refreshRuntimeExecAuth(client, writeBox, stage, name)\n if (!refreshed.succeeded) return fail(refreshed.error)\n\n const second = await writeProfileFilesToBox(refreshed.value, files)\n if (second.succeeded) return ok(refreshed.value)\n if (!isRuntimeExecAuthError(second.error)) return fail(second.error)\n\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec remained unauthorized after auth refresh',\n second.error,\n ),\n )\n}\n\n// Decide whether an existing (reused or resumed) box is safe to hand back.\n// `refreshRuntimeConnection` has already polled for the runtime URL, so a box\n// that still has none never became connectable and must be recreated rather\n// than silently reused — downstream exec/terminal traffic would fail against\n// it. A failed edge is likewise unusable. Only when the connection is present\n// do we spend an exec round-trip on the liveness probe.\nasync function isReusableBox(\n box: SandboxInstance,\n harness: Harness,\n probe: LivenessProbeConfig | undefined,\n): Promise<boolean> {\n if (sandboxEdgeFailed(box)) return false\n if (!sandboxRuntimeUrl(box)) return false\n return isBoxAlive(box, harness, probe)\n}\n\n// Resume a name-matched stopped box and wait for it to reach running. Returns\n// ok(null) when no stopped box matches the name.\nasync function resumeStoppedBox(\n client: Sandbox,\n name: string,\n timeoutMs: number,\n onProgress?: (event: ProvisionEvent) => void,\n): Promise<Outcome<SandboxInstance | null>> {\n try {\n const stopped = await client.list({ status: 'stopped' })\n const match = stopped.find((s) => s.name === name) ?? null\n if (!match) return ok(null)\n await match.resume()\n await match.waitFor('running', { timeoutMs, ...(onProgress ? { onProgress } : {}) })\n return ok(match)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function ensureWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: EnsureWorkspaceSandboxOptions,\n): Promise<SandboxInstance> {\n const { workspaceId, userId, harness, forceNew, onProgress } = options\n const scope: SandboxScope = { workspaceId, ...(userId ? { userId } : {}) }\n const creds = await shell.credentials(scope)\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n const client = getClientFromCreds(creds)\n const name = shell.boxKey ? shell.boxKey(scope) : shell.name(workspaceId)\n const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES\n const resumeTimeout = 120_000\n\n // Stage 1 — running-box reuse (skipped on forceNew).\n const existing = await listRunning(client, name)\n if (existing.succeeded && existing.value) {\n const found = existing.value\n if (forceNew) {\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(`forceNew: sandbox ${name} could not be deleted`, { cause: dropped.error })\n }\n } else if (found.metadata?.harness === harness) {\n const ready = await refreshRuntimeConnection(client, found)\n if (await isReusableBox(ready, harness, shell.livenessProbe)) {\n const written = await materializeDeferredFilesForExistingBox(\n shell,\n client,\n ready,\n 'reused',\n name,\n workspaceId,\n userId,\n )\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('reused', name, written.error)\n }\n const reusedBox = written.value\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(reusedBox, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on reused box ${name}`, { cause: boot.error })\n }\n }\n return reusedBox\n }\n const dropped = await deleteBox(ready)\n if (!dropped.succeeded) {\n throw new Error(\n `sandbox ${name} ` +\n `(was ${String(found.metadata?.harness ?? 'unknown')}, want ${harness}, or unresponsive) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n } else {\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(\n `sandbox ${name} ` +\n `(was ${String(found.metadata?.harness ?? 'unknown')}, want ${harness}, or unresponsive) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n }\n }\n\n // Stage 2 — stopped-box resume (skipped on forceNew or resumeStopped===false).\n if (!forceNew && shell.resumeStopped !== false) {\n const resumed = await resumeStoppedBox(client, name, resumeTimeout, onProgress)\n if (resumed.succeeded && resumed.value) {\n const box = await refreshRuntimeConnection(client, resumed.value)\n if (await isReusableBox(box, harness, shell.livenessProbe)) {\n const written = await materializeDeferredFilesForExistingBox(\n shell,\n client,\n box,\n 'resumed',\n name,\n workspaceId,\n userId,\n )\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('resumed', name, written.error)\n }\n const resumedBox = written.value\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(resumedBox, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on resumed box ${name}`, { cause: boot.error })\n }\n }\n return resumedBox\n }\n const dropped = await deleteBox(box)\n if (!dropped.succeeded) {\n throw new Error(\n `resumed sandbox ${name} ` +\n `(was ${String(box.metadata?.harness ?? 'unknown')}, want ${harness}, or unresponsive) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n }\n }\n\n // Stage 3 — create fresh.\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = {\n workspaceId,\n connectedIntegrationIds,\n ...(userId ? { userId } : {}),\n }\n const [secrets, env, files] = await Promise.all([\n shell.secrets(workspaceId),\n shell.env(buildCtx),\n shell.files(buildCtx),\n ])\n const fullProfile = shell.profile({ extraFiles: files })\n // When deferring, strip inline files from the create payload and write them\n // into the box after it reaches running. Keeps the provision body under the\n // orchestrator's 256 KiB cap and lands real files on disk.\n const { leanProfile, deferredFiles } = shell.deferProfileFiles\n ? splitDeferredProfileFiles(fullProfile)\n : { leanProfile: fullProfile, deferredFiles: [] as AgentProfileFileMount[] }\n const profile = leanProfile\n\n const role = userId && shell.permissionRole ? shell.permissionRole('developer') : undefined\n\n // Bake the model at create when opted in. childKeyMint overrides the apiKey\n // per-workspace; a typed mint failure falls through to the parent key (logged).\n let model = shell.backendModelAtCreate ? resolveModel(shell.provider) : undefined\n if (model && shell.childKeyMint && model.provider === 'openai-compat') {\n const minted = await shell.childKeyMint(scope)\n if (minted.succeeded) model = { ...model, apiKey: minted.value }\n else {\n console.error(\n `[sandbox] childKeyMint failed for ${workspaceId}; using parent key:`,\n minted.error.message,\n )\n }\n }\n\n const storage = shell.storage?.(buildCtx)\n const restore = shell.restore?.(buildCtx)\n\n const payload = {\n name,\n image: resources.image,\n metadata: shell.metadata(harness),\n idempotencyKey: name,\n ...(userId ? { permissions: { initialUsers: [{ userId, role }] } } : {}),\n env,\n secrets,\n backend: { type: harness, profile, ...(model ? { model } : {}) },\n ...(storage ? { storage } : {}),\n ...(restore ? restore : {}),\n ...(shell.webTerminalEnabled ? { webTerminalEnabled: true } : {}),\n maxLifetimeSeconds: resources.maxLifetimeSeconds,\n idleTimeoutSeconds: resources.idleTimeoutSeconds,\n resources: {\n cpuCores: resources.cpuCores,\n memoryMB: resources.memoryMB,\n diskGB: resources.diskGB,\n },\n } as CreatePayload\n\n let box = await client.create(payload)\n\n await box.waitFor('running', { timeoutMs: 120_000, ...(onProgress ? { onProgress } : {}) })\n box = await refreshRuntimeConnection(client, box)\n\n if (deferredFiles.length > 0) {\n const written = await writeProfileFilesToBox(box, deferredFiles)\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('new', name, written.error)\n }\n }\n\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(box, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on new box ${name}`, { cause: boot.error })\n }\n }\n return box\n}\n\nexport interface ResolvedModel {\n model: string\n provider: string\n apiKey: string\n baseUrl?: string\n}\n\nexport function resolveModel(\n config: ProviderResolutionConfig | undefined,\n override?: { model?: string; modelApiKey?: string },\n): ResolvedModel | undefined {\n const c = config ?? {}\n const explicitBaseUrl = c.routerBaseUrl\n const explicitApiKey = override?.modelApiKey ?? c.apiKey\n const provider =\n c.providerName ?? (explicitApiKey ? 'openai-compat' : c.openaiApiKey ? 'openai' : undefined)\n const modelName =\n override?.model ??\n c.modelName ??\n (provider === 'openai' || provider === 'openai-compat' ? c.defaultModel : undefined)\n const apiKey = explicitApiKey ?? (provider === 'openai' ? c.openaiApiKey : undefined)\n if (!provider || !modelName || !apiKey) return undefined\n return {\n model: modelName,\n provider,\n apiKey,\n ...(explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}),\n }\n}\n\nexport function flattenHistory(\n message: string,\n history?: Array<{ role: 'user' | 'assistant'; content: string }>,\n): string {\n if (!history?.length) return message\n const transcript = history\n .map((entry) => `${entry.role === 'assistant' ? 'Assistant' : 'User'}: ${entry.content}`)\n .join('\\n\\n')\n return `${transcript}\\n\\nUser: ${message}`\n}\n\nexport function mergeExtraMcp(\n appToolMcp: Record<string, AgentProfileMcpServer>,\n baseProfileMcp: Record<string, AgentProfileMcpServer>,\n extra: Record<string, AgentProfileMcpServer> | undefined,\n): Record<string, AgentProfileMcpServer> {\n for (const key of Object.keys(extra ?? {})) {\n if (key in appToolMcp || key in baseProfileMcp) {\n throw new Error(`extraMcp key '${key}' collides with an existing profile MCP server`)\n }\n }\n return { ...appToolMcp, ...(extra ?? {}) }\n}\n\nexport function attachReasoningEffort(\n profile: AgentProfile,\n harness: Harness,\n effort: 'auto' | 'low' | 'medium' | 'high' | undefined,\n): AgentProfile {\n if (!effort || effort === 'auto') return profile\n return {\n ...profile,\n extensions: {\n ...(profile.extensions ?? {}),\n [harness]: {\n ...(profile.extensions?.[harness] ?? {}),\n reasoningEffort: effort,\n },\n },\n }\n}\n\nexport interface StreamSandboxPromptOptions {\n sessionId?: string\n executionId?: string\n lastEventId?: string\n systemPrompt?: string\n model?: string\n modelApiKey?: string\n history?: Array<{ role: 'user' | 'assistant'; content: string }>\n harness?: Harness\n effort?: 'auto' | 'low' | 'medium' | 'high'\n appToolMcp?: Record<string, AgentProfileMcpServer>\n baseProfileMcp?: Record<string, AgentProfileMcpServer>\n extraMcp?: Record<string, AgentProfileMcpServer>\n signal?: AbortSignal\n timeoutMs?: number\n requireVisibleAssistantOutput?: boolean\n // When true, an interactive question event throws instead of yielding —\n // detached (cron/mission-step) runs have no consumer to answer it.\n disallowQuestions?: boolean\n}\n\ntype StreamPromptOptions = Parameters<SandboxInstance['streamPrompt']>[1]\n\nexport async function* streamSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options?: StreamSandboxPromptOptions,\n): AsyncGenerator<unknown> {\n const harness = options?.harness ?? 'opencode'\n const model = resolveModel(shell.provider, {\n model: options?.model,\n modelApiKey: options?.modelApiKey,\n })\n\n // Server-side enforcement of the harness↔model policy: a vendor-locked harness\n // (claude-code/codex/kimi-code) must not be sent a foreign-provider model, even\n // if the UI snap was bypassed. Provider-less ids pass (session's own config).\n if (model?.model) assertHarnessModelCompatible(harness, model.model)\n\n const prompt = flattenHistory(message, options?.history)\n\n const appToolMcp = options?.appToolMcp ?? {}\n const extraMcp = mergeExtraMcp(appToolMcp, options?.baseProfileMcp ?? {}, options?.extraMcp)\n\n const profile = shell.profile({ systemPrompt: options?.systemPrompt, extraMcp })\n const profileWithEffort = attachReasoningEffort(profile, harness, options?.effort)\n\n const stream = box.streamPrompt(prompt, {\n sessionId: options?.sessionId,\n executionId: options?.executionId,\n lastEventId: options?.lastEventId,\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options?.requireVisibleAssistantOutput !== undefined\n ? { requireVisibleAssistantOutput: options.requireVisibleAssistantOutput }\n : {}),\n backend: {\n type: harness,\n profile: profileWithEffort,\n ...(model ? { model } : {}),\n },\n } as StreamPromptOptions)\n\n let severedFinishReason: string | null = null\n for await (const event of stream) {\n const step = classifySeveredStream(event)\n if (step) severedFinishReason = step.kind === 'step-finish' && step.severed ? step.reason : null\n if (severedFinishReason && isTerminalPromptEvent(event)) {\n throw new Error(`sandbox model stream severed mid-turn (reason=\"${severedFinishReason}\")`)\n }\n if (options?.disallowQuestions) {\n const q = detectInteractiveQuestion(event)\n if (q) {\n throw new Error(`sandbox agent asked an interactive question during an autonomous run: ${q}`)\n }\n }\n yield event\n }\n // Reconnect-exhausted path: the stream ended on a severed step without a\n // terminal event. A truncated turn must fail loud, not return silently.\n if (severedFinishReason) {\n throw new Error(`sandbox model stream severed mid-turn (reason=\"${severedFinishReason}\")`)\n }\n}\n\nexport async function runSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options?: StreamSandboxPromptOptions,\n): Promise<string> {\n let fullText = ''\n let firstTextSeen = false\n\n for await (const rawEvent of streamSandboxPrompt(shell, box, message, options)) {\n const event = rawEvent as { type?: string; data?: Record<string, unknown> }\n if (!event.type) continue\n\n if (event.type === 'message.part.updated') {\n const part = event.data?.part as Record<string, unknown> | undefined\n const delta = typeof event.data?.delta === 'string' ? event.data.delta : null\n if (String(part?.type ?? '') === 'text') {\n if (!firstTextSeen) {\n firstTextSeen = true\n continue\n }\n if (delta) fullText += delta\n else if (typeof part?.text === 'string') fullText = part.text\n }\n } else if (event.type === 'result') {\n const finalText = typeof event.data?.finalText === 'string' ? event.data.finalText : null\n if (finalText) fullText = finalText\n }\n }\n\n return fullText\n}\n\n// Mirrors the SDK's PermissionLevel union (not re-exported by\n// @tangle-network/sandbox). The product's role-mapping seam must produce one of\n// these; binding the seam's return type to the union makes a wrong mapping a\n// compile error rather than a runtime 400 from the orchestrator.\nexport type SandboxPermissionLevel = 'owner' | 'admin' | 'developer' | 'viewer'\n\nexport interface MemberSyncSeam {\n roleToSandboxRole: (workspaceRole: string) => SandboxPermissionLevel\n}\n\nexport async function syncSandboxMemberAdd(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.add({ userId, role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRemove(\n box: SandboxInstance,\n userId: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.remove(userId, { preserveHomeDir: true })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRole(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.update(userId, { role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface SecretStore {\n create: (name: string, value: string) => Promise<void>\n update: (name: string, value: string) => Promise<void>\n get: (name: string) => Promise<string>\n delete: (name: string) => Promise<void>\n}\n\nexport function secretStoreFromClient(shell: SandboxRuntimeConfig): SecretStore {\n const client = getClient(shell)\n return {\n create: async (name, value) => {\n await client.secrets.create(name, value)\n },\n update: async (name, value) => {\n await client.secrets.update(name, value)\n },\n get: (name) => client.secrets.get(name),\n delete: async (name) => {\n await client.secrets.delete(name)\n },\n }\n}\n\nexport async function storeSecret(\n store: SecretStore,\n name: string,\n value: string,\n): Promise<Outcome<void>> {\n try {\n await store.create(name, value)\n return ok(undefined)\n } catch {\n try {\n await store.update(name, value)\n return ok(undefined)\n } catch (err) {\n return fail(new Error(`Failed to store sandbox secret ${name}`, { cause: err }))\n }\n }\n}\n\nexport async function readSecret(store: SecretStore, name: string): Promise<Outcome<string>> {\n try {\n return ok(await store.get(name))\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function deleteSecret(store: SecretStore, name: string): Promise<Outcome<void>> {\n try {\n await store.delete(name)\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface ScopedTokenResult {\n token: string\n expiresAt: Date\n scope: ScopedTokenScope\n}\n\n/**\n * Mint a scoped token for an already-provisioned box (e.g. to hand a terminal\n * proxy a narrowed credential). Uses the SDK's native `box.mintScopedToken`,\n * which normalizes `expiresAt` to a Date — no hand-rolled wire call.\n */\nexport async function mintSandboxScopedToken(\n box: SandboxInstance,\n options: { scope: ScopedTokenScope; sessionId?: string; ttlMinutes?: number },\n): Promise<Outcome<ScopedTokenResult>> {\n try {\n const token = await box.mintScopedToken({\n scope: options.scope,\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...(options.ttlMinutes ? { ttlMinutes: options.ttlMinutes } : {}),\n })\n return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope })\n } catch (err) {\n return fail(err)\n }\n}\n\n// Detached single-turn advance. The SDK SandboxInstance has no `driveTurn`; the\n// non-streaming sibling of streamPrompt is box.prompt(message, opts) -> PromptResult.\n// Returns a typed Outcome so a failed turn is inspected, not swallowed.\nexport async function driveSandboxTurn(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string,\n options: StreamSandboxPromptOptions & { sessionId: string },\n): Promise<Outcome<PromptResult>> {\n const harness = options.harness ?? 'opencode'\n const model = resolveModel(shell.provider, {\n model: options.model,\n modelApiKey: options.modelApiKey,\n })\n if (model?.model) assertHarnessModelCompatible(harness, model.model)\n const prompt = flattenHistory(message, options.history)\n const appToolMcp = options.appToolMcp ?? {}\n const extraMcp = mergeExtraMcp(appToolMcp, options.baseProfileMcp ?? {}, options.extraMcp)\n const profile = attachReasoningEffort(\n shell.profile({ systemPrompt: options.systemPrompt, extraMcp }),\n harness,\n options.effort,\n )\n try {\n const result = await box.prompt(prompt, {\n sessionId: options.sessionId,\n ...(options.executionId ? { executionId: options.executionId } : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n backend: { type: harness, profile, ...(model ? { model } : {}) },\n } as Parameters<SandboxInstance['prompt']>[1])\n if (!result.success) return fail(new Error(result.error ?? 'sandbox turn failed'))\n return ok(result)\n } catch (err) {\n return fail(err)\n }\n}\n\n// Severed-stream classifier. Generic to any router-backed harness: a final step\n// that finished with error/other/unknown is a truncated turn, not a completed one.\nconst SEVERED_FINISH_REASONS = new Set(['error', 'other', 'unknown'])\n\nexport type SandboxStepTransition =\n | { kind: 'step-start' }\n | { kind: 'step-finish'; reason: string; severed: boolean }\n\nfunction asPlainRecord(v: unknown): Record<string, unknown> | null {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : null\n}\n\nexport function classifySeveredStream(event: unknown): SandboxStepTransition | null {\n const root = asPlainRecord(event)\n if (!root || root.type !== 'message.part.updated') return null\n const body = asPlainRecord(root.properties) ?? asPlainRecord(root.data) ?? root\n const part = asPlainRecord(body.part)\n if (!part) return null\n if (part.type === 'step-start') return { kind: 'step-start' }\n if (part.type !== 'step-finish') return null\n const reason = typeof part.reason === 'string' && part.reason ? part.reason : 'unknown'\n return { kind: 'step-finish', reason, severed: SEVERED_FINISH_REASONS.has(reason) }\n}\n\nexport function isTerminalPromptEvent(event: unknown): boolean {\n const t = asPlainRecord(event)?.type\n return t === 'result' || t === 'done'\n}\n\n// Interactive-question detector. Returns the question text or null. Used by\n// streamSandboxPrompt when disallowQuestions is set.\nexport function detectInteractiveQuestion(event: unknown): string | null {\n const root = asPlainRecord(event)\n if (!root) return null\n const type = typeof root.type === 'string' ? root.type : undefined\n const data = asPlainRecord(root.data)\n const props = asPlainRecord(root.properties)\n const body = props ?? data ?? root\n if (type === 'question.asked' || type === 'question') return firstQuestionText(body)\n const part = asPlainRecord(data?.part) ?? asPlainRecord(body.part)\n const tool =\n (typeof part?.tool === 'string' && part.tool) ||\n (typeof part?.name === 'string' && part.name) ||\n (typeof body.tool === 'string' && body.tool) ||\n undefined\n const isQ =\n type === 'message.part.updated' &&\n (tool === 'question' || asPlainRecord(part)?.type === 'question')\n if (!isQ) return null\n const state = asPlainRecord(asPlainRecord(part)?.state)\n return firstQuestionText(asPlainRecord(state?.input) ?? state ?? part ?? body)\n}\n\nfunction firstQuestionText(value: Record<string, unknown> | null): string {\n const arr = Array.isArray(value?.questions)\n ? value!.questions\n : Array.isArray(asPlainRecord(value?.input)?.questions)\n ? (asPlainRecord(value!.input)!.questions as unknown[])\n : []\n const first = asPlainRecord(arr[0])\n const q =\n (typeof first?.question === 'string' && first.question) ||\n (typeof first?.prompt === 'string' && first.prompt) ||\n undefined\n return q ?? 'interactive question'\n}\n// Workspace sandbox terminal handlers: WebSocket upgrade proxy, connection\n// + runtime-proxy handlers, and scoped terminal-token mint/verify.\nexport * from './terminal-proxy-token'\nexport * from './workspace-terminal'\n","// Shared Outcome triple for the sandbox modules. Lives in a dependency-free\n// leaf so both index.ts and terminal-proxy-token.ts import it instead of\n// re-declaring the type (index.ts re-exports * from terminal-proxy-token, so\n// the token module cannot import from index without a cycle).\nexport type Outcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: Error }\n\nexport const ok = <T>(value: T): Outcome<T> => ({ succeeded: true, value })\nexport const fail = (error: unknown): Outcome<never> => ({\n succeeded: false,\n error: error instanceof Error ? error : new Error(String(error)),\n})\n","import {\n base64UrlDecodeText,\n base64UrlEncodeText,\n constantTimeEqual,\n hmacSha256Base64Url,\n} from '../crypto/web-token'\nimport { ok, fail, type Outcome } from './outcome'\n\n// Terminal-proxy HMAC token. Identity tuple is generic; the secret comes from a\n// closure (fail-loud if absent).\nexport interface TerminalProxyIdentity {\n userId: string\n workspaceId: string\n sandboxId: string\n}\n\nconst TERMINAL_PROXY_TOKEN_TTL_MS = 15 * 60 * 1000\n\nexport async function mintTerminalProxyToken(\n secret: string,\n identity: TerminalProxyIdentity,\n ttlMs = TERMINAL_PROXY_TOKEN_TTL_MS,\n now: () => number = Date.now,\n): Promise<Outcome<{ token: string; expiresAt: Date }>> {\n if (!secret) return fail(new Error('mintTerminalProxyToken: secret is required'))\n if (!identity.userId || !identity.workspaceId || !identity.sandboxId) {\n return fail(new Error('mintTerminalProxyToken: userId/workspaceId/sandboxId are required'))\n }\n const expiresAt = new Date(now() + ttlMs)\n const payload = { ...identity, exp: Math.floor(expiresAt.getTime() / 1000) }\n const encoded = base64UrlEncodeText(JSON.stringify(payload))\n const sig = await hmacSha256Base64Url(encoded, secret)\n return ok({ token: `${encoded}.${sig}`, expiresAt })\n}\n\nexport async function verifyTerminalProxyToken(\n secret: string,\n token: string,\n expected: TerminalProxyIdentity,\n now: () => number = Date.now,\n): Promise<boolean> {\n if (!secret) return false\n const [encoded, sig, extra] = token.split('.')\n if (!encoded || !sig || extra !== undefined) return false\n const expectedSig = await hmacSha256Base64Url(encoded, secret)\n if (!constantTimeEqual(sig, expectedSig)) return false\n let payload: TerminalProxyIdentity & { exp: number }\n try {\n payload = JSON.parse(base64UrlDecodeText(encoded))\n } catch {\n return false\n }\n return (\n payload.userId === expected.userId &&\n payload.workspaceId === expected.workspaceId &&\n payload.sandboxId === expected.sandboxId &&\n Number.isFinite(payload.exp) &&\n payload.exp > Math.floor(now() / 1000)\n )\n}\n","import { base64UrlDecodeText } from '../crypto/web-token'\nimport {\n mintTerminalProxyToken,\n verifyTerminalProxyToken,\n type TerminalProxyIdentity,\n} from './terminal-proxy-token'\n\nexport interface WorkspaceSandboxInstanceLike {\n id: string\n name?: string\n status?: string\n connection?: {\n runtimeUrl?: string\n sidecarUrl?: string\n authToken?: string\n sidecarToken?: string\n authTokenExpiresAt?: string\n } | null\n}\n\n// Generic name-keyed sandbox lifecycle manager. A structural, substrate-free\n// helper for products that drive their own SDK/box types (distinct from the\n// concrete `ensureWorkspaceSandbox` in ./index, which is bound to the\n// @tangle-network/sandbox client). Kept as a public export — external\n// consumers compose it; removing it would be a breaking change.\nexport interface WorkspaceSandboxEnsureContext {\n workspaceId: string\n userId: string\n}\n\nexport interface WorkspaceSandboxManagerOptions<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {\n getClient: (ctx: WorkspaceSandboxEnsureContext) => Promise<TClient> | TClient\n nameForWorkspace: (workspaceId: string, ctx: WorkspaceSandboxEnsureContext) => string\n listSandboxes: (client: TClient, ctx: WorkspaceSandboxEnsureContext) => Promise<TBox[]>\n createSandbox: (args: {\n client: TClient\n ctx: WorkspaceSandboxEnsureContext\n name: string\n options: TEnsureOptions\n listError?: unknown\n }) => Promise<TBox>\n waitForRunning?: (box: TBox, ctx: WorkspaceSandboxEnsureContext) => Promise<void>\n prepareExisting?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>\n prepareCreated?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>\n onListError?: (error: unknown, ctx: WorkspaceSandboxEnsureContext) => void\n}\n\nexport interface WorkspaceSandboxManager<TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {\n ensureWorkspaceSandbox: (\n workspaceId: string,\n userId: string,\n options?: TEnsureOptions,\n ) => Promise<TBox>\n}\n\nexport function createWorkspaceSandboxManager<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void>(\n opts: WorkspaceSandboxManagerOptions<TClient, TBox, TEnsureOptions>,\n): WorkspaceSandboxManager<TBox, TEnsureOptions> {\n return {\n async ensureWorkspaceSandbox(workspaceId, userId, options) {\n if (!workspaceId) throw new Error('workspaceId is required')\n if (!userId) throw new Error('userId is required')\n const ctx = { workspaceId, userId }\n const client = await opts.getClient(ctx)\n const name = opts.nameForWorkspace(workspaceId, ctx)\n let listError: unknown\n let existing: TBox[] = []\n\n try {\n existing = await opts.listSandboxes(client, ctx)\n } catch (err) {\n listError = err\n opts.onListError?.(err, ctx)\n }\n\n const found = existing.find((box) => box.name === name)\n if (found) {\n return (await opts.prepareExisting?.(found, ctx, options as TEnsureOptions)) ?? found\n }\n\n const created = await opts.createSandbox({\n client,\n ctx,\n name,\n options: options as TEnsureOptions,\n listError,\n })\n await opts.waitForRunning?.(created, ctx)\n return (await opts.prepareCreated?.(created, ctx, options as TEnsureOptions)) ?? created\n },\n }\n}\n\nexport interface SandboxTerminalTokenOptions {\n secret?: string\n expiresInMs?: number\n now?: () => number\n}\n\nexport type SandboxTerminalTokenSubject = TerminalProxyIdentity\n\nexport interface SandboxTerminalTokenResult {\n token: string\n expiresAt: Date\n}\n\nconst DEFAULT_TERMINAL_TOKEN_TTL_MS = 15 * 60 * 1000\nconst BEARER_SUBPROTOCOL_PREFIX = 'bearer.'\n// Legacy `createSandboxTerminalToken` (pre proxy-token extraction) prefixed\n// minted tokens with `sbxt_` and signed the unprefixed payload. New tokens\n// carry no prefix. Strip it on verify so tokens minted by a prior deploy still\n// validate within their (default 15-min) TTL window — avoids a wave of 403s on\n// in-flight browser terminal sessions right after rollout.\nconst LEGACY_TERMINAL_TOKEN_PREFIX = 'sbxt_'\n\nexport async function createSandboxTerminalToken(\n subject: SandboxTerminalTokenSubject,\n opts: SandboxTerminalTokenOptions,\n): Promise<SandboxTerminalTokenResult> {\n validateTerminalSubject(subject)\n const secret = opts.secret?.trim()\n if (!secret) throw new Error('terminal token secret is required')\n const now = opts.now ?? Date.now\n const expiresInMs = opts.expiresInMs ?? DEFAULT_TERMINAL_TOKEN_TTL_MS\n if (!Number.isFinite(expiresInMs) || expiresInMs <= 0) throw new Error('expiresInMs must be a positive number')\n const minted = await mintTerminalProxyToken(secret, subject, expiresInMs, now)\n if (!minted.succeeded) throw minted.error\n return minted.value\n}\n\nexport async function verifySandboxTerminalToken(\n token: string,\n expected: SandboxTerminalTokenSubject,\n opts: SandboxTerminalTokenOptions,\n): Promise<boolean> {\n validateTerminalSubject(expected)\n const secret = opts.secret?.trim()\n const now = opts.now ?? Date.now\n const normalized = token.startsWith(LEGACY_TERMINAL_TOKEN_PREFIX)\n ? token.slice(LEGACY_TERMINAL_TOKEN_PREFIX.length)\n : token\n return verifyTerminalProxyToken(secret ?? '', normalized, expected, now)\n}\n\nexport interface AuthenticatedSandboxUser {\n id: string\n}\n\nexport interface WorkspaceSandboxConnectionHandlerOptions<TBox extends WorkspaceSandboxInstanceLike> {\n requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>\n requireWorkspaceAccess: (args: { request: Request; userId: string; workspaceId: string }) => Promise<void>\n ensureWorkspaceSandbox: (workspaceId: string, userId: string) => Promise<TBox>\n tokenSecret: string | (() => string | undefined)\n tokenExpiresInMs?: number\n proxyRuntimeUrl?: (args: { request: Request; workspaceId: string; sandboxId: string; box: TBox }) => string\n exposeDirectSidecar?: boolean\n}\n\nexport interface WorkspaceSandboxConnectionArgs {\n request: Request\n params: {\n workspaceId?: string\n }\n}\n\nexport function createWorkspaceSandboxConnectionHandler<TBox extends WorkspaceSandboxInstanceLike>(\n opts: WorkspaceSandboxConnectionHandlerOptions<TBox>,\n) {\n return async function handleWorkspaceSandboxConnection({ request, params }: WorkspaceSandboxConnectionArgs): Promise<Response> {\n const user = await opts.requireUser(request)\n const workspaceId = params.workspaceId\n if (!workspaceId) return Response.json({ error: 'workspaceId is required' }, { status: 400 })\n await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId })\n\n let box: TBox\n try {\n box = await opts.ensureWorkspaceSandbox(workspaceId, user.id)\n } catch (err) {\n return Response.json(\n { error: err instanceof Error ? err.message : 'Failed to provision workspace sandbox' },\n { status: 500 },\n )\n }\n\n const directSidecarUrl = box.connection?.sidecarUrl ?? box.connection?.runtimeUrl\n const directSidecarToken = box.connection?.authToken ?? box.connection?.sidecarToken\n const directSidecarExpiresAt = box.connection?.authTokenExpiresAt\n if (opts.exposeDirectSidecar && directSidecarUrl && directSidecarToken && directSidecarExpiresAt) {\n return Response.json({\n runtimeUrl: directSidecarUrl,\n sidecarUrl: directSidecarUrl,\n token: directSidecarToken,\n expiresAt: directSidecarExpiresAt,\n status: box.status,\n sandboxId: box.id,\n })\n }\n\n if (!directSidecarUrl) {\n return Response.json(\n {\n error: 'Workspace sandbox runtime not ready. The sandbox is still initializing -- retry in a few seconds.',\n status: box.status,\n },\n { status: 503 },\n )\n }\n\n const secret = typeof opts.tokenSecret === 'function' ? opts.tokenSecret() : opts.tokenSecret\n let scoped: SandboxTerminalTokenResult\n try {\n scoped = await createSandboxTerminalToken(\n { userId: user.id, workspaceId, sandboxId: box.id },\n { secret, expiresInMs: opts.tokenExpiresInMs },\n )\n } catch (err) {\n return Response.json(\n { error: err instanceof Error ? err.message : 'Failed to mint sandbox token' },\n { status: 503 },\n )\n }\n\n const runtimeUrl = opts.proxyRuntimeUrl\n ? opts.proxyRuntimeUrl({ request, workspaceId, sandboxId: box.id, box })\n : `/api/workspaces/${encodeURIComponent(workspaceId)}/sandbox/runtime/${encodeURIComponent(box.id)}`\n\n return Response.json({\n runtimeUrl,\n sidecarUrl: runtimeUrl,\n token: scoped.token,\n expiresAt: scoped.expiresAt.toISOString(),\n status: box.status,\n sandboxId: box.id,\n })\n }\n}\n\nexport interface SandboxApiCredentials {\n baseUrl: string\n apiKey: string\n}\n\nexport interface SandboxRuntimeConnection {\n runtimeUrl: string\n /** Server-side sidecar bearer. Must authorize terminal routes; never expose it to browser code. */\n authToken?: string\n}\n\nexport interface WorkspaceSandboxRuntimeProxyHandlerOptions {\n requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>\n requireWorkspaceAccess: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<void>\n getSandboxApiCredentials: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxApiCredentials>\n getSandboxRuntimeConnection?: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxRuntimeConnection | null | undefined>\n tokenSecret: string | (() => string | undefined)\n fetch?: typeof fetch\n forwardHeaders?: string[]\n}\n\nexport interface WorkspaceSandboxRuntimeProxyArgs {\n request: Request\n params: {\n workspaceId?: string\n sandboxId?: string\n '*'?: string\n }\n}\n\nexport function createWorkspaceSandboxRuntimeProxyHandler(opts: WorkspaceSandboxRuntimeProxyHandlerOptions) {\n return async function handleWorkspaceSandboxRuntimeProxy({ request, params }: WorkspaceSandboxRuntimeProxyArgs): Promise<Response> {\n const user = await opts.requireUser(request)\n const workspaceId = params.workspaceId\n const sandboxId = params.sandboxId\n const runtimePath = params['*']\n if (!workspaceId || !sandboxId || !runtimePath) {\n return Response.json({ error: 'workspaceId, sandboxId, and runtime path are required' }, { status: 400 })\n }\n const encodedRuntimePath = encodeSandboxRuntimePath(runtimePath)\n if (!encodedRuntimePath) return Response.json({ error: 'Invalid sandbox runtime path' }, { status: 400 })\n\n await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId, sandboxId })\n\n const token = terminalTokenFromRequest(request.headers)\n const secret = typeof opts.tokenSecret === 'function' ? opts.tokenSecret() : opts.tokenSecret\n if (!token || !(await verifySandboxTerminalToken(token, { userId: user.id, workspaceId, sandboxId }, { secret }))) {\n return Response.json({ error: 'Invalid terminal token' }, { status: 403 })\n }\n\n const requestUrl = new URL(request.url)\n const runtimeConnection = await opts.getSandboxRuntimeConnection?.({ request, userId: user.id, workspaceId, sandboxId })\n const directRuntimeConnection = runtimeConnection?.runtimeUrl && runtimeConnection.authToken ? runtimeConnection : null\n const credentials = directRuntimeConnection ? null : await opts.getSandboxApiCredentials({ request, userId: user.id, workspaceId, sandboxId })\n const upstreamUrl = directRuntimeConnection\n ? new URL(encodedRuntimePath, `${directRuntimeConnection.runtimeUrl.replace(/\\/+$/, '')}/`)\n : new URL(\n `/v1/sandboxes/${encodeURIComponent(sandboxId)}/runtime/${encodedRuntimePath}`,\n credentials!.baseUrl,\n )\n upstreamUrl.search = requestUrl.search\n\n const headers = buildSandboxRuntimeProxyHeaders(\n request.headers,\n directRuntimeConnection?.authToken ?? credentials!.apiKey,\n opts.forwardHeaders,\n )\n const init: RequestInit & { duplex?: 'half' } = {\n method: request.method,\n headers,\n redirect: 'manual',\n }\n if (request.method !== 'GET' && request.method !== 'HEAD' && request.body) {\n init.body = request.body\n init.duplex = 'half'\n }\n\n const fetchImpl = opts.fetch ?? fetch\n const response = await fetchImpl(upstreamUrl, init)\n const responseHeaders = new Headers(response.headers)\n responseHeaders.delete('set-cookie')\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n })\n }\n}\n\n// ---------------------------------------------------------------------------\n// Terminal WebSocket upgrade\n//\n// The interactive terminal is WebSocket-only on the current sidecar (the REST\n// `POST /terminals` create route was removed in the websocket-first migration).\n// `createWorkspaceSandboxRuntimeProxyHandler` runs inside a React Router\n// loader/action, which can only return a normal Response — never a 101 — so it\n// cannot perform the upgrade. The upgrade must be intercepted at the Worker\n// fetch entry (server.ts) BEFORE React Router, mirroring the session-stream WS\n// interceptor. This handler does exactly that: it auth-gates the upgrade (the\n// scoped terminal token rides in the `bearer.` subprotocol because browsers\n// can't set Authorization on a WS handshake) and forwards it to the sandbox API\n// runtime proxy with the server-to-server credential. Returning the upstream\n// 101 passes the live socket straight through to the browser — the same idiom\n// the sandbox API uses to reach the orchestrator.\n//\n// NOTE: this only runs under a WebSocket-capable runtime (Cloudflare Workers /\n// `wrangler`). `react-router dev` (Vite) never invokes the Worker fetch entry,\n// so the terminal WS is exercised under `wrangler dev` / production.\n// ---------------------------------------------------------------------------\n\nconst SANDBOX_TERMINAL_WS_PATHNAME =\n /^\\/api\\/workspaces\\/([^/]+)\\/sandbox\\/runtime\\/([^/]+)\\/(terminals\\/[^/]+\\/ws)$/\n\nexport interface SandboxTerminalWsMatch {\n workspaceId: string\n sandboxId: string\n subPath: string\n}\n\n/**\n * Parse a same-origin terminal-WS pathname into its parts, or `null` when the\n * path is not a sandbox terminal WebSocket. Matches the default `runtimeUrl`\n * convention emitted by {@link createWorkspaceSandboxConnectionHandler}\n * (`/api/workspaces/:workspaceId/sandbox/runtime/:sandboxId`) with a canonical\n * `terminals/:id/ws` sub-path. `subPath` is left URL-encoded for re-use in the\n * upstream URL; the ids are decoded for auth checks.\n */\nexport function matchSandboxTerminalWsPath(pathname: string): SandboxTerminalWsMatch | null {\n const m = SANDBOX_TERMINAL_WS_PATHNAME.exec(pathname)\n if (!m) return null\n const [, workspaceId, sandboxId, subPath] = m\n if (!workspaceId || !sandboxId || !subPath) return null\n const decodedWorkspaceId = safeDecodeURIComponent(workspaceId)\n const decodedSandboxId = safeDecodeURIComponent(sandboxId)\n if (!decodedWorkspaceId || !decodedSandboxId) return null\n return { workspaceId: decodedWorkspaceId, sandboxId: decodedSandboxId, subPath }\n}\n\n/** True when `request` is a WebSocket upgrade for a sandbox terminal path. */\nexport function isSandboxTerminalWsUpgrade(request: Request): boolean {\n if (request.headers.get('Upgrade')?.toLowerCase() !== 'websocket') return false\n try {\n return matchSandboxTerminalWsPath(new URL(request.url).pathname) !== null\n } catch {\n return false\n }\n}\n\nexport interface WorkspaceSandboxTerminalUpgradeHandlerOptions {\n requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>\n requireWorkspaceAccess: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<void>\n getSandboxApiCredentials: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxApiCredentials>\n getSandboxRuntimeConnection?: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxRuntimeConnection | null | undefined>\n tokenSecret: string | (() => string | undefined)\n fetch?: typeof fetch\n}\n\n/**\n * Build a Worker-entry handler that proxies a sandbox terminal WebSocket\n * upgrade to the sandbox API runtime proxy. Returns `null` when the request is\n * not a terminal WS upgrade, so the caller can fall through to its normal\n * request handler:\n *\n * ```ts\n * const handled = await handleSandboxTerminalUpgrade(request)\n * if (handled) return handled\n * ```\n */\nexport function createWorkspaceSandboxTerminalUpgradeHandler(opts: WorkspaceSandboxTerminalUpgradeHandlerOptions) {\n return async function handleWorkspaceSandboxTerminalUpgrade(request: Request): Promise<Response | null> {\n if (request.headers.get('Upgrade')?.toLowerCase() !== 'websocket') return null\n let url: URL\n try {\n url = new URL(request.url)\n } catch {\n return null\n }\n const match = matchSandboxTerminalWsPath(url.pathname)\n if (!match) return null\n const { workspaceId, sandboxId, subPath } = match\n\n let user: AuthenticatedSandboxUser\n try {\n user = await opts.requireUser(request)\n } catch {\n return new Response('Unauthorized', { status: 401 })\n }\n try {\n await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId, sandboxId })\n } catch {\n return new Response('Forbidden', { status: 403 })\n }\n\n const token = terminalTokenFromRequest(request.headers)\n const secret = typeof opts.tokenSecret === 'function' ? opts.tokenSecret() : opts.tokenSecret\n if (!token || !(await verifySandboxTerminalToken(token, { userId: user.id, workspaceId, sandboxId }, { secret }))) {\n return new Response('Invalid terminal token', { status: 403 })\n }\n\n const runtimeConnection = await opts.getSandboxRuntimeConnection?.({ request, userId: user.id, workspaceId, sandboxId })\n const directRuntimeConnection = runtimeConnection?.runtimeUrl && runtimeConnection.authToken ? runtimeConnection : null\n const credentials = directRuntimeConnection ? null : await opts.getSandboxApiCredentials({ request, userId: user.id, workspaceId, sandboxId })\n const upstreamUrl = directRuntimeConnection\n ? new URL(subPath, `${directRuntimeConnection.runtimeUrl.replace(/\\/+$/, '')}/`)\n : new URL(`/v1/sandboxes/${encodeURIComponent(sandboxId)}/runtime/${subPath}`, credentials!.baseUrl)\n upstreamUrl.search = url.search\n\n // Forward the upgrade verbatim — keep the Upgrade/Connection + Sec-WebSocket-*\n // headers the handshake needs, but strip the browser-only bearer subprotocol\n // and send the server-to-server sandbox credential only as Authorization.\n // Returning the upstream 101 passes the live socket straight through to the browser.\n const upstreamHeaders = new Headers(request.headers)\n const upstreamBearer = directRuntimeConnection?.authToken ?? credentials!.apiKey\n upstreamHeaders.set('Authorization', `Bearer ${upstreamBearer}`)\n upstreamHeaders.delete('host')\n stripBearerSubprotocol(upstreamHeaders)\n const fetchImpl = opts.fetch ?? fetch\n return fetchImpl(upstreamUrl.toString(), { method: request.method, headers: upstreamHeaders })\n }\n}\n\nconst DEFAULT_RUNTIME_PROXY_HEADERS = ['accept', 'content-type', 'last-event-id', 'x-session-id']\n\nexport function buildSandboxRuntimeProxyHeaders(source: Headers, sandboxApiKey: string, forwardHeaders = DEFAULT_RUNTIME_PROXY_HEADERS): Headers {\n const headers = new Headers()\n headers.set('Authorization', `Bearer ${sandboxApiKey}`)\n for (const name of forwardHeaders) {\n const value = source.get(name)\n if (value) headers.set(name, value)\n }\n return headers\n}\n\nexport function encodeSandboxRuntimePath(runtimePath: string): string | null {\n const segments = runtimePath.split('/')\n if (segments.some((segment) => !segment || segment === '.' || segment === '..')) return null\n return segments.map((segment) => encodeURIComponent(segment)).join('/')\n}\n\nexport function bearerToken(value: string | null): string | null {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n if (trimmed.toLowerCase() === 'bearer') return null\n if (trimmed.toLowerCase().startsWith('bearer ')) {\n const token = trimmed.slice('bearer '.length).trim()\n return token || null\n }\n return trimmed\n}\n\nexport function bearerSubprotocolToken(value: string | null): string | null {\n if (!value) return null\n for (const part of value.split(',')) {\n const protocol = part.trim()\n if (!protocol.toLowerCase().startsWith(BEARER_SUBPROTOCOL_PREFIX)) continue\n const encoded = protocol.slice(BEARER_SUBPROTOCOL_PREFIX.length)\n if (!encoded) return null\n try {\n const token = base64UrlDecodeText(encoded).trim()\n return token || null\n } catch {\n return null\n }\n }\n return null\n}\n\nexport function terminalTokenFromRequest(headers: Headers): string | null {\n return bearerToken(headers.get('Authorization')) ?? bearerSubprotocolToken(headers.get('Sec-WebSocket-Protocol'))\n}\n\nfunction safeDecodeURIComponent(value: string): string | null {\n try {\n return decodeURIComponent(value)\n } catch {\n return null\n }\n}\n\nfunction stripBearerSubprotocol(headers: Headers): void {\n const value = headers.get('Sec-WebSocket-Protocol')\n if (!value) return\n const protocols = value\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part && !part.toLowerCase().startsWith(BEARER_SUBPROTOCOL_PREFIX))\n if (protocols.length) {\n headers.set('Sec-WebSocket-Protocol', protocols.join(', '))\n } else {\n headers.delete('Sec-WebSocket-Protocol')\n }\n}\n\nfunction validateTerminalSubject(subject: SandboxTerminalTokenSubject): void {\n if (!subject.userId) throw new Error('userId is required')\n if (!subject.workspaceId) throw new Error('workspaceId is required')\n if (!subject.sandboxId) throw new Error('sandboxId is required')\n}\n"],"mappings":"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","names":["value","credentials","retryAfterMs","res","refreshed","box"]}