@mastra/platform-workspace 1.4.1 → 1.5.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/LICENSE.md +6 -4
- package/README.md +40 -9
- package/dist/address-registry.d.ts.map +1 -1
- package/dist/client.d.ts +3 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/filesystem.d.ts.map +1 -1
- package/dist/index.cjs +388 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +392 -24
- package/dist/index.js.map +1 -1
- package/dist/private-net-exec.d.ts.map +1 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/repo-template.d.ts +69 -0
- package/dist/repo-template.d.ts.map +1 -0
- package/dist/sandbox.d.ts +60 -0
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/template.d.ts +95 -0
- package/dist/template.d.ts.map +1 -0
- package/package.json +7 -6
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["#map"],"sources":["../src/client.ts","../src/filesystem.ts","../src/direct-exec.ts","../src/e2b-exec.ts","../src/private-net-exec.ts","../src/sandbox.ts","../src/provider.ts","../src/address-registry.ts"],"sourcesContent":["export interface PlatformClientOptions {\n accessToken?: string;\n projectId?: string;\n actingUserId?: string;\n /**\n * Advisory correlation id for the factory session driving this client.\n * Sent as `x-mastra-session-id` on every proxy request so proxy-side logs\n * can be joined back to the calling session without a multi-store hand-join\n * (`threadId → sessionId → sandboxId → providerResourceId`). Never used for\n * authorization — the Bearer token remains the only credential.\n */\n sessionId?: string;\n /**\n * Advisory correlation id for the factory thread, sent as\n * `x-mastra-thread-id` when present. See {@link PlatformClientOptions.sessionId}.\n */\n threadId?: string;\n fetch?: typeof fetch;\n}\n\nexport interface PlatformRequestOptions extends RequestInit {\n query?: Record<string, string | number | boolean | undefined>;\n}\n\nexport type SandboxProvider = 'railway' | 'e2b';\n\nconst DEFAULT_PROXY_URL = 'https://workspaces.mastra.ai';\n\n/**\n * Default per-request timeout for calls to the workspace proxy. Applied only\n * when the caller doesn't already pass an `AbortSignal`. Long-running routes\n * (e.g. `POST /sandbox/:id/exec`) pass their own longer signal.\n */\nconst DEFAULT_REQUEST_TIMEOUT_MS = 60_000;\n\nexport function requireOption(value: string | undefined, name: string): string {\n if (!value) throw new Error(`${name} is required`);\n return value;\n}\n\nfunction resolveSandboxProvider(value: string | undefined): SandboxProvider {\n const provider = value?.trim() || 'railway';\n if (provider !== 'railway' && provider !== 'e2b') {\n throw new Error('SANDBOX_PROVIDER must be either \"railway\" or \"e2b\"');\n }\n return provider;\n}\n\nexport function resolvePlatformOptions(options: PlatformClientOptions) {\n const configuredSandboxProvider = process.env.SANDBOX_PROVIDER?.trim();\n\n return {\n accessToken: requireOption(options.accessToken ?? process.env.MASTRA_PLATFORM_ACCESS_TOKEN, 'accessToken'),\n projectId: requireOption(options.projectId ?? process.env.MASTRA_PROJECT_ID, 'projectId'),\n actingUserId: options.actingUserId?.trim() || undefined,\n proxyUrl: (process.env.MASTRA_WORKSPACE_PROXY_URL ?? DEFAULT_PROXY_URL).replace(/\\/$/, ''),\n sandboxProvider: resolveSandboxProvider(configuredSandboxProvider),\n useLegacyRoutes: !configuredSandboxProvider,\n sessionId: options.sessionId,\n threadId: options.threadId,\n fetch: options.fetch ?? fetch,\n };\n}\n\n/**\n * Structured error shape returned by the workspace proxy. All routes emit\n * `{ error: { message, type } }` on failure — see servers/workspace-proxy in\n * the Platform repo. Kept as a wire-level type so callers can switch on\n * `error.code` without re-parsing `error.body`.\n */\nexport interface PlatformProxyError {\n message: string;\n /** Machine-readable error kind, e.g. `not_found`, `invalid_request`, `authentication_error`. */\n type: string;\n}\n\nfunction parseProxyError(body: string): PlatformProxyError | undefined {\n if (!body) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n return undefined;\n }\n if (typeof parsed !== 'object' || parsed === null) return undefined;\n const err = (parsed as { error?: unknown }).error;\n if (typeof err !== 'object' || err === null) return undefined;\n const { message, type } = err as { message?: unknown; type?: unknown };\n if (typeof message !== 'string' || typeof type !== 'string') return undefined;\n return { message, type };\n}\n\nexport class PlatformApiError extends Error {\n readonly status: number;\n readonly body: string;\n /** Machine-readable proxy error kind (e.g. `not_found`), when the response body matches `{ error: { message, type } }`. */\n readonly code: string | undefined;\n /** Human-readable proxy error message, when the response body matches `{ error: { message, type } }`. */\n readonly proxyMessage: string | undefined;\n\n constructor(status: number, body: string) {\n const parsed = parseProxyError(body);\n const summary = parsed ? `${parsed.type}: ${parsed.message}` : body;\n super(`Platform proxy request failed with ${status}${summary ? `: ${summary}` : ''}`);\n this.name = 'PlatformApiError';\n this.status = status;\n this.body = body;\n this.code = parsed?.type;\n this.proxyMessage = parsed?.message;\n }\n}\n\nexport class PlatformClient {\n readonly accessToken: string;\n readonly projectId: string;\n readonly actingUserId: string | undefined;\n readonly proxyUrl: string;\n readonly sandboxProvider: SandboxProvider;\n private readonly useLegacyRoutes: boolean;\n /** Advisory session correlation id — see {@link PlatformClientOptions.sessionId}. */\n readonly sessionId: string | undefined;\n /** Advisory thread correlation id — see {@link PlatformClientOptions.threadId}. */\n readonly threadId: string | undefined;\n readonly fetch: typeof fetch;\n\n constructor(options: PlatformClientOptions) {\n const resolved = resolvePlatformOptions(options);\n this.accessToken = resolved.accessToken;\n this.projectId = resolved.projectId;\n this.actingUserId = resolved.actingUserId;\n this.proxyUrl = resolved.proxyUrl;\n this.sandboxProvider = resolved.sandboxProvider;\n this.useLegacyRoutes = resolved.useLegacyRoutes;\n this.sessionId = resolved.sessionId;\n this.threadId = resolved.threadId;\n this.fetch = resolved.fetch;\n }\n\n async request(path: string, options: PlatformRequestOptions = {}): Promise<Response> {\n const providerPath = this.useLegacyRoutes ? '' : `/${this.sandboxProvider}`;\n const url = new URL(`${this.proxyUrl}/v1${providerPath}/projects/${encodeURIComponent(this.projectId)}${path}`);\n for (const [key, value] of Object.entries(options.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value));\n }\n\n const headers = new Headers(options.headers);\n headers.set('authorization', `Bearer ${this.accessToken}`);\n if (this.actingUserId) headers.set('x-acting-user-id', this.actingUserId);\n // Advisory correlation headers — the proxy folds them into its log lines\n // so proxy-side events can be joined back to the calling factory session\n // without a cross-store hand-join. Unknown headers are passthrough for\n // older proxies; these are never used for authorization.\n if (this.sessionId) headers.set('x-mastra-session-id', this.sessionId);\n if (this.threadId) headers.set('x-mastra-thread-id', this.threadId);\n\n // Strip our helper-only field so the underlying fetch sees a valid RequestInit.\n const { query: _query, ...fetchOptions } = options;\n // Apply a default timeout only when the caller didn't already supply an\n // AbortSignal — long-running routes (exec) provide their own longer signal.\n const signal = fetchOptions.signal ?? AbortSignal.timeout(DEFAULT_REQUEST_TIMEOUT_MS);\n const response = await this.fetch(url, { ...fetchOptions, headers, signal });\n if (!response.ok) {\n throw new PlatformApiError(response.status, await response.text());\n }\n return response;\n }\n}\n","import { Buffer } from 'node:buffer';\nimport nodePath from 'node:path';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type {\n CopyOptions,\n FileContent,\n FileEntry,\n FileStat,\n FilesystemIcon,\n FilesystemInfo,\n InstructionsOption,\n ListOptions,\n MastraFilesystemOptions,\n ProviderStatus,\n ReadOptions,\n RemoveOptions,\n WriteOptions,\n} from '@mastra/core/workspace';\nimport { FileExistsError, FileNotFoundError, MastraFilesystem, WorkspaceReadOnlyError } from '@mastra/core/workspace';\nimport type { PlatformClientOptions } from './client.js';\nimport { PlatformClient } from './client.js';\n\ninterface ProxyListResponse {\n contents?: Array<{ key?: string; size?: number; lastModified?: string }>;\n commonPrefixes?: string[];\n}\n\nexport interface PlatformFilesystemOptions extends PlatformClientOptions, MastraFilesystemOptions {\n id?: string;\n bucketName?: string;\n readOnly?: boolean;\n displayName?: string;\n icon?: FilesystemIcon;\n description?: string;\n instructions?: InstructionsOption;\n}\n\nfunction normalizePath(input: string): string {\n if (!input || input === '.') return '/';\n let normalized = input.startsWith('/') ? input : `/${input}`;\n normalized = nodePath.posix.normalize(normalized);\n return normalized === '.' ? '/' : normalized;\n}\n\nfunction keyFromPath(path: string): string {\n const normalized = normalizePath(path);\n return normalized === '/' ? '' : normalized.slice(1);\n}\n\n/**\n * Encode each `/`-delimited segment of an object key with `encodeURIComponent`\n * so reserved URL characters (`?`, `#`, `%`, `&`, `+`, spaces, etc.) are\n * treated as part of the key instead of URL syntax. Kept segment-aware so\n * `/` continues to act as a path separator on the wire.\n */\nfunction encodeKeyPath(key: string): string {\n return key.split('/').map(encodeURIComponent).join('/');\n}\n\nfunction nameFromPath(path: string): string {\n const normalized = normalizePath(path);\n if (normalized === '/') return '';\n return normalized.slice(normalized.lastIndexOf('/') + 1);\n}\n\nfunction contentToBody(content: FileContent): string | Buffer {\n if (typeof content === 'string') return content;\n return Buffer.from(content);\n}\n\nfunction headerDate(headers: Headers, name: string): Date {\n const value = headers.get(name);\n return value ? new Date(value) : new Date(0);\n}\n\nfunction headerSize(headers: Headers): number {\n const value = headers.get('content-length');\n return value ? Number(value) : 0;\n}\n\nfunction isNotFound(error: unknown): boolean {\n return typeof error === 'object' && error !== null && 'status' in error && error.status === 404;\n}\n\nexport class PlatformFilesystem extends MastraFilesystem {\n readonly id: string;\n readonly name = 'PlatformFilesystem';\n readonly provider = 'platform';\n readonly readOnly?: boolean;\n readonly displayName?: string;\n readonly icon: FilesystemIcon;\n readonly description?: string;\n status: ProviderStatus = 'pending';\n\n private readonly _client: PlatformClient;\n private readonly _bucketName: string;\n private readonly _instructionsOverride?: InstructionsOption;\n\n constructor(options: PlatformFilesystemOptions = {}) {\n super({ ...options, name: 'PlatformFilesystem' });\n this.id = options.id ?? this.generateId();\n this._bucketName = options.bucketName ?? process.env.MASTRA_PLATFORM_BUCKET_NAME ?? '';\n if (!this._bucketName) throw new Error('bucketName is required');\n this.readOnly = options.readOnly;\n this.displayName = options.displayName;\n this.icon = options.icon ?? 'cloud';\n this.description = options.description;\n this._instructionsOverride = options.instructions;\n this._client = new PlatformClient(options);\n }\n\n private generateId(): string {\n return `platform-fs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n async readFile(path: string, options?: ReadOptions): Promise<string | Buffer> {\n await this.ensureReady();\n let response: Response;\n try {\n response = await this._client.request(\n `/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`,\n );\n } catch (error) {\n if (isNotFound(error)) throw new FileNotFoundError(path);\n throw error;\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n return options?.encoding ? buffer.toString(options.encoding) : buffer;\n }\n\n async writeFile(path: string, content: FileContent, options?: WriteOptions): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('writeFile');\n const headers: Record<string, string> = {};\n if (options?.mimeType) headers['content-type'] = options.mimeType;\n if (options?.overwrite === false) headers['if-none-match'] = '*';\n try {\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`, {\n method: 'PUT',\n headers,\n body: contentToBody(content),\n });\n } catch (error) {\n if (typeof error === 'object' && error !== null && 'status' in error && error.status === 412) {\n throw new FileExistsError(path);\n }\n throw error;\n }\n }\n\n /**\n * Append bytes to a file.\n *\n * **Not atomic.** Object storage behind the workspace proxy has no native\n * append or compare-and-swap primitive, so this implementation is a\n * read-modify-write: it reads the current contents, concatenates the new\n * bytes, and PUTs the whole object back. Concurrent `appendFile` calls to\n * the same path can overwrite each other's writes (\"last write wins\").\n * Use `writeFile` with distinct keys for concurrent writers.\n */\n async appendFile(path: string, content: FileContent): Promise<void> {\n const existing = (await this.exists(path)) ? await this.readFile(path) : Buffer.alloc(0);\n await this.writeFile(\n path,\n Buffer.concat([Buffer.isBuffer(existing) ? existing : Buffer.from(existing), Buffer.from(content)]),\n );\n }\n\n async deleteFile(path: string, options?: RemoveOptions): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('deleteFile');\n try {\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`, {\n method: 'DELETE',\n query: { recursive: options?.recursive },\n });\n } catch (error) {\n if (isNotFound(error) && options?.force) return;\n if (isNotFound(error)) throw new FileNotFoundError(path);\n throw error;\n }\n }\n\n async copyFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('copyFile');\n // The workspace proxy's `?op=copy` route always overwrites the destination;\n // there's no conditional wire field to prevent it. Reject the option\n // explicitly instead of silently overwriting when the caller asked us not to.\n if (options?.overwrite === false) {\n throw new Error('PlatformFilesystem.copyFile does not support overwrite: false — the proxy always overwrites.');\n }\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(src))}`, {\n method: 'POST',\n query: { op: 'copy' },\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ destination: keyFromPath(dest) }),\n });\n }\n\n async moveFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('moveFile');\n // Same rationale as copyFile: `?op=rename` always overwrites.\n if (options?.overwrite === false) {\n throw new Error('PlatformFilesystem.moveFile does not support overwrite: false — the proxy always overwrites.');\n }\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(src))}`, {\n method: 'POST',\n query: { op: 'rename' },\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ destination: keyFromPath(dest) }),\n });\n }\n\n async mkdir(path: string, _options?: { recursive?: boolean }): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('mkdir');\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`, {\n method: 'POST',\n query: { op: 'mkdir' },\n });\n }\n\n async rmdir(path: string, options?: RemoveOptions): Promise<void> {\n await this.deleteFile(path.endsWith('/') ? path : `${path}/`, { recursive: true, force: options?.force });\n }\n\n async readdir(path: string, options?: ListOptions): Promise<FileEntry[]> {\n await this.ensureReady();\n const prefix = keyFromPath(path);\n const response = await this._client.request(\n `/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(prefix)}`,\n {\n query: {\n delimiter: options?.recursive ? undefined : '/',\n prefix: prefix ? `${prefix.replace(/\\/$/, '')}/` : undefined,\n },\n },\n );\n const json = (await response.json()) as ProxyListResponse;\n return [\n ...(json.commonPrefixes ?? []).map(prefix => ({\n name: nameFromPath(prefix.replace(/\\/$/, '')),\n type: 'directory' as const,\n })),\n ...(json.contents ?? [])\n .filter(object => object.key && !object.key.endsWith('/'))\n .map(object => ({\n name: nameFromPath(object.key!),\n type: 'file' as const,\n size: object.size,\n })),\n ].filter(\n entry => !options?.extension || entry.type === 'directory' || matchesExtension(entry.name, options.extension),\n );\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n await this.stat(path);\n return true;\n } catch (error) {\n if (isNotFound(error) || error instanceof FileNotFoundError) return false;\n throw error;\n }\n }\n\n async stat(path: string): Promise<FileStat> {\n await this.ensureReady();\n const normalized = normalizePath(path);\n if (normalized === '/') {\n return { name: '', path: '/', type: 'directory', size: 0, createdAt: new Date(0), modifiedAt: new Date(0) };\n }\n let response: Response;\n try {\n response = await this._client.request(\n `/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`,\n {\n method: 'HEAD',\n },\n );\n } catch (error) {\n if (isNotFound(error)) throw new FileNotFoundError(path);\n throw error;\n }\n return {\n name: nameFromPath(path),\n path: normalized,\n type: normalized.endsWith('/') ? 'directory' : 'file',\n size: headerSize(response.headers),\n createdAt: headerDate(response.headers, 'last-modified'),\n modifiedAt: headerDate(response.headers, 'last-modified'),\n mimeType: response.headers.get('content-type') ?? undefined,\n };\n }\n\n realpath(path: string): Promise<string> {\n return Promise.resolve(normalizePath(path));\n }\n\n getInstructions(opts?: { requestContext?: RequestContext }): string {\n const defaultInstructions = `Platform filesystem backed by Mastra Platform bucket ${this._bucketName}. Use absolute workspace paths.`;\n if (typeof this._instructionsOverride === 'function') {\n return this._instructionsOverride({ defaultInstructions, requestContext: opts?.requestContext });\n }\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return defaultInstructions;\n }\n\n getInfo(): FilesystemInfo<{ bucketName: string; displayName?: string; description?: string }> {\n return {\n id: this.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n readOnly: this.readOnly,\n icon: this.icon,\n metadata: {\n bucketName: this._bucketName,\n ...(this.displayName && { displayName: this.displayName }),\n ...(this.description && { description: this.description }),\n },\n };\n }\n}\n\nfunction matchesExtension(name: string, extension: string | string[]): boolean {\n const extensions = Array.isArray(extension) ? extension : [extension];\n return extensions.some(ext => name.endsWith(ext));\n}\n","/**\n * Direct exec client — opens Railway's tcp-proxy exec WebSocket directly using\n * a short-lived JWT minted by the workspace proxy's exec-lease endpoint. This\n * removes the platform data plane from the exec stdout/stderr path entirely\n * (see `docs/factory/direct-sandbox-connection.md` in the Platform repo),\n * cutting payload-scaled Cloud Run egress and RTT for commands like\n * `pnpm install` that stream tens of MB of output.\n *\n * The frame protocol below mirrors `connectExecWs()` in `railway@3.5.5`\n * (`workspaces/railway/node_modules/railway/dist/index.js`). The `railway`\n * SDK's version is pinned on both sides (platform + here); a version bump\n * signals the protocol may have drifted and this module must be revisited.\n */\n\n/** Byte-0 tag on binary WS frames for stdout output. */\nconst STDOUT_FRAME = 1;\n/** Byte-0 tag on binary WS frames for stderr output. */\nconst STDERR_FRAME = 3;\n/**\n * Upper bound on how long we'll wait for the WebSocket to open when the\n * caller didn't supply a `timeoutMs`. Guards against a stalled TLS/WS\n * handshake leaving the promise unresolved forever. Not applied once the\n * socket has opened — a caller with no timeout has opted in to unbounded\n * command runtime, just not to unbounded connection setup.\n */\nconst HANDSHAKE_DEADLINE_MS = 30_000;\n\n/**\n * Minimal WebSocket surface this module depends on. Matches both the browser\n * `WebSocket` global and Node 22+'s built-in `WebSocket`. Extracted so tests\n * can inject a fake without pulling in `ws` or jsdom.\n */\nexport interface DirectExecWebSocket {\n binaryType: 'blob' | 'arraybuffer';\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code: number; reason: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n}\n\n/**\n * Factory that opens a WebSocket to `endpoint` with the given subprotocols.\n * Defaults to the global `WebSocket` when omitted, which works on Node 22+\n * (the package's minimum) and in the browser. Tests inject a fake here.\n */\nexport type DirectExecWebSocketFactory = (endpoint: string, subprotocols: string[]) => DirectExecWebSocket;\n\n/** Lease payload returned by `POST /v1/:provider/projects/:projectId/sandbox/:sandboxId/exec-lease`. */\nexport interface ExecLease {\n jwt: string;\n wsEndpoint: string;\n subprotocol: string;\n /** ISO-8601 UTC. Null when the provider issues a JWT without an `exp` claim. */\n expiresAt: string | null;\n}\n\n/** Inputs to a direct exec invocation. Mirrors the shape of the `/exec` route body. */\nexport interface DirectExecOptions {\n command: string;\n cwd?: string;\n env?: Record<string, string>;\n /**\n * Wall-clock cap for the exec. When elapsed, we close the socket and\n * return `{timedOut: true, exitCode: 124}` matching the semantics of the\n * proxy's `/exec` route.\n */\n timeoutMs?: number;\n onStdout?: (chunk: string) => void;\n onStderr?: (chunk: string) => void;\n /** Injected for tests. Defaults to `globalThis.WebSocket`. */\n webSocketFactory?: DirectExecWebSocketFactory;\n}\n\n/**\n * Result of a direct exec. Shape matches the workspace-proxy `/exec` response\n * so the caller (`PlatformSandbox.executeCommand`) can hand it back with no\n * translation.\n *\n * `exitCode` is `null` when the socket closed without an `exit` frame AND the\n * exec did not time out (rare — usually a mid-stream network drop). Callers\n * currently coerce `null` to `1` upstream; kept nullable here to preserve the\n * distinction for future observability.\n */\nexport interface DirectExecResult {\n exitCode: number | null;\n stdout: string;\n stderr: string;\n truncated: boolean;\n timedOut: boolean;\n /**\n * WebSocket close metadata. Populated on any close (normal or transport\n * failure). `opened` distinguishes handshake failures (never opened) from\n * mid-stream drops. Callers use this for diagnostic logging; not part of\n * the CommandResult contract.\n */\n closeCode?: number;\n closeReason?: string;\n opened?: boolean;\n}\n\nconst DEFAULT_WS_FACTORY: DirectExecWebSocketFactory = (endpoint, subprotocols) => {\n const WS = (globalThis as { WebSocket?: unknown }).WebSocket as\n | (new (url: string, protocols: string[]) => DirectExecWebSocket)\n | undefined;\n if (!WS) {\n throw new Error(\n 'Direct exec requires a WebSocket implementation. Node 22+ provides one globally; on older runtimes, pass webSocketFactory explicitly.',\n );\n }\n return new WS(endpoint, subprotocols);\n};\n\n/**\n * Open the provider exec WebSocket using `lease`, run `command`, and resolve\n * with the accumulated stdout/stderr + exit code. See the module docstring\n * for the wire protocol reference.\n *\n * The client sends `stdin_close` immediately after `init_exec`, matching the\n * SDK's own one-shot exec behavior — we never stream stdin from the caller.\n */\nexport function execViaLease(lease: ExecLease, options: DirectExecOptions): Promise<DirectExecResult> {\n const factory = options.webSocketFactory ?? DEFAULT_WS_FACTORY;\n const stdoutDecoder = new TextDecoder();\n const stderrDecoder = new TextDecoder();\n\n return new Promise<DirectExecResult>(resolve => {\n let stdout = '';\n let stderr = '';\n let exitCode: number | null = null;\n let timedOut = false;\n let settled = false;\n let opened = false;\n let closeCode: number | undefined;\n let closeReason: string | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let handshakeTimer: ReturnType<typeof setTimeout> | undefined;\n\n const settle = () => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n if (handshakeTimer) clearTimeout(handshakeTimer);\n // Flush any bytes still buffered in the decoders. A stream:true decode\n // holds trailing partial multi-byte sequences until the next chunk, so\n // without a flush the final char(s) of a UTF-8 stream can be dropped.\n const stdoutTail = stdoutDecoder.decode();\n if (stdoutTail) {\n stdout += stdoutTail;\n options.onStdout?.(stdoutTail);\n }\n const stderrTail = stderrDecoder.decode();\n if (stderrTail) {\n stderr += stderrTail;\n options.onStderr?.(stderrTail);\n }\n try {\n socket.close(1000, '');\n } catch {\n /* already closed */\n }\n resolve({\n exitCode,\n stdout,\n stderr,\n truncated: false,\n timedOut,\n ...(closeCode !== undefined && { closeCode }),\n ...(closeReason !== undefined && { closeReason }),\n opened,\n });\n };\n\n // Arm the timeout BEFORE we open the socket so a stalled handshake can't\n // leave the promise pending. Callers with a positive `timeoutMs` get the\n // wall-clock cap they asked for; callers without one still get a\n // connect-only deadline that clears once the socket opens.\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) {\n timer = setTimeout(() => {\n timedOut = true;\n // 124 matches the proxy's `/exec` semantics (coreutils `timeout`\n // exit code) so callers that switch on exitCode see the same value.\n if (exitCode === null) exitCode = 124;\n settle();\n }, options.timeoutMs);\n } else {\n handshakeTimer = setTimeout(() => {\n // Never opened → treat as a transport failure. Leave exitCode=null\n // so the caller can distinguish this from a normal exit; do not\n // set timedOut (that flag is reserved for the wall-clock case).\n if (!opened) settle();\n }, HANDSHAKE_DEADLINE_MS);\n }\n\n const socket = factory(lease.wsEndpoint, [lease.subprotocol, lease.jwt]);\n socket.binaryType = 'arraybuffer';\n\n socket.onopen = () => {\n opened = true;\n if (handshakeTimer) {\n clearTimeout(handshakeTimer);\n handshakeTimer = undefined;\n }\n const data: Record<string, unknown> = { command: options.command };\n if (options.cwd) data.cwd = options.cwd;\n if (options.env && Object.keys(options.env).length > 0) data.env = options.env;\n socket.send(JSON.stringify({ type: 'init_exec', data }));\n // We never stream stdin for one-shot exec; the SDK does this too, and\n // omitting it can leave the exec hanging waiting on EOF.\n socket.send(JSON.stringify({ type: 'stdin_close' }));\n };\n\n socket.onmessage = event => {\n const { data } = event;\n if (data instanceof ArrayBuffer) {\n handleBinaryFrame(data);\n } else if (typeof data === 'string') {\n handleTextFrame(data);\n }\n };\n\n socket.onclose = event => {\n closeCode = event.code;\n closeReason = event.reason;\n if (!opened) {\n // Never opened — surface as a failure via exitCode=null,\n // truncated=false, timedOut=false so the caller can distinguish\n // it from a normal exit-0 by inspecting `exitCode === null`.\n settle();\n return;\n }\n // Preserve any info captured before close; if the server sent an\n // `exit` frame this is a no-op because settle() already ran.\n settle();\n };\n\n socket.onerror = () => {\n if (settled) return;\n if (!opened) {\n settle();\n }\n // If we're mid-stream and the socket errors, wait for onclose to fire\n // so we settle with whatever output we did receive.\n };\n\n function handleBinaryFrame(buffer: ArrayBuffer) {\n const view = new Uint8Array(buffer);\n if (view.length <= 1) return;\n if (view[0] === STDOUT_FRAME) {\n const chunk = stdoutDecoder.decode(view.subarray(1), { stream: true });\n stdout += chunk;\n options.onStdout?.(chunk);\n } else if (view[0] === STDERR_FRAME) {\n const chunk = stderrDecoder.decode(view.subarray(1), { stream: true });\n stderr += chunk;\n options.onStderr?.(chunk);\n }\n }\n\n function handleTextFrame(text: string) {\n let frame: { type?: string; data?: { exit_code?: number } };\n try {\n frame = JSON.parse(text) as { type?: string; data?: { exit_code?: number } };\n } catch {\n return;\n }\n if (frame.type === 'exit') {\n exitCode = frame.data?.exit_code ?? 0;\n settle();\n }\n // `durable_session` frames are intentionally ignored — we don't reattach\n // or expose session names on the one-shot exec path.\n }\n });\n}\n","import { CommandExitError, Sandbox, TimeoutError } from 'e2b';\n\nimport type { DirectExecOptions, DirectExecResult, ExecLease } from './direct-exec.js';\n\nconst E2B_ENVD_VERSION = '0.4.0';\n\nexport interface E2BExecLease extends ExecLease {\n sandboxId: string;\n}\n\nexport type E2BExecRunner = (lease: E2BExecLease, options: DirectExecOptions) => Promise<DirectExecResult>;\n\nexport const execViaE2BLease: E2BExecRunner = async (lease, options) => {\n const stdoutChunks: string[] = [];\n const stderrChunks: string[] = [];\n const onStdout = (data: string) => {\n stdoutChunks.push(data);\n options.onStdout?.(data);\n };\n const onStderr = (data: string) => {\n stderrChunks.push(data);\n options.onStderr?.(data);\n };\n\n try {\n const sandbox = new Sandbox({\n sandboxId: lease.sandboxId,\n envdVersion: E2B_ENVD_VERSION,\n envdAccessToken: lease.jwt,\n sandboxUrl: lease.wsEndpoint,\n validateApiKey: false,\n });\n const result = await sandbox.commands.run(options.command, {\n cwd: options.cwd,\n envs: options.env,\n timeoutMs: options.timeoutMs,\n onStdout,\n onStderr,\n });\n return {\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n truncated: false,\n timedOut: false,\n opened: true,\n };\n } catch (error) {\n if (error instanceof CommandExitError) {\n return {\n exitCode: error.exitCode,\n stdout: error.stdout,\n stderr: error.stderr,\n truncated: false,\n timedOut: false,\n opened: true,\n };\n }\n return {\n exitCode: null,\n stdout: stdoutChunks.join(''),\n stderr: stderrChunks.join(''),\n truncated: false,\n timedOut: error instanceof TimeoutError,\n closeReason: error instanceof Error ? error.message : String(error),\n opened: true,\n };\n }\n};\n","/**\n * Private-network exec client — dials the in-sandbox sidecar HTTP server\n * directly over Railway's private IPv6 network, bypassing the workspace-proxy\n * exec lease and the public tcp-proxy WebSocket entirely.\n *\n * Wire spec (matches the sidecar's `POST /exec` route, see\n * `.scratch/factory-deploy/issue-sandbox-sidecar-agent-in-base-image.md` in\n * the Platform repo):\n *\n * - Request: `POST ${instanceUrl}/exec` with JSON body\n * `{command, cwd?, env?, timeoutMs?}`.\n * - Response: `text/plain` NDJSON, one JSON object per line, terminated by an\n * `exit` frame:\n * `{\"type\":\"stdout\",\"data\":\"…\"}`\n * `{\"type\":\"stderr\",\"data\":\"…\"}`\n * `{\"type\":\"exit\",\"code\":<number>}`\n *\n * Auth is *network position* — the private ULA IPv6 space is only reachable\n * from workloads inside this Railway environment, and every workload there is\n * our own code. A bearer secret adds no boundary today so we do not send one;\n * `bearerToken` is accepted here as a defense-in-depth hook for when\n * untrusted-tenant sandboxes eventually share a private network.\n *\n * Return shape mirrors {@link ../direct-exec.ts}'s `DirectExecResult` so the\n * caller in `sandbox.ts` can hand results back with no translation regardless\n * of which transport served the exec.\n */\n\n/**\n * Minimal fetch surface this module depends on. Matches the global `fetch`\n * exposed by Node 22+ (undici) and the browser. Extracted so tests can inject\n * a fake without spinning up a real HTTP server.\n */\nexport type PrivateNetFetch = typeof fetch;\n\n/** Inputs to a private-network exec invocation. Mirrors {@link DirectExecOptions}. */\nexport interface PrivateNetExecOptions {\n command: string;\n cwd?: string;\n env?: Record<string, string>;\n /**\n * Wall-clock cap for the exec. When elapsed, we abort the request and\n * return `{timedOut: true, exitCode: 124}` matching the semantics of\n * `direct-exec.ts` (and the proxy's `/exec` route before it).\n */\n timeoutMs?: number;\n onStdout?: (chunk: string) => void;\n onStderr?: (chunk: string) => void;\n /** Injected for tests. Defaults to `globalThis.fetch`. */\n fetch?: PrivateNetFetch;\n /**\n * Optional bearer secret forwarded as `Authorization: Bearer <token>`.\n * Not required today (network position is the boundary). Present so we can\n * flip on per-sandbox secrets in a follow-up without a client-side reshape.\n */\n bearerToken?: string;\n}\n\n/**\n * Result of a private-network exec. Same shape as `DirectExecResult` — the\n * caller does not care which transport produced it.\n *\n * `exitCode` is `null` when the response body ended without an `exit` frame\n * AND the exec did not time out. That is a transport-level failure (the\n * sidecar died mid-stream or the socket was cut) and callers should treat it\n * as such (invalidate the cached `instanceUrl`, fall back to the lease path).\n */\nexport interface PrivateNetExecResult {\n exitCode: number | null;\n stdout: string;\n stderr: string;\n timedOut: boolean;\n /**\n * True when we got a full HTTP response (status + at least the response\n * headers), even if the stream later dropped. False when we could not\n * establish the connection or the sidecar refused the request outright.\n * Used by the caller to distinguish \"sidecar unreachable\" (invalidate\n * cache) from \"sidecar answered but the stream broke\" (still invalidate,\n * but log differently).\n */\n opened: boolean;\n /** HTTP status when we got a response. Undefined on connection failure. */\n status?: number;\n /** Populated when we could not even open the request (DNS/connect/TLS). */\n transportErrorMessage?: string;\n}\n\n/**\n * Thrown by {@link execViaPrivateNetwork} when the sidecar returns a non-2xx\n * HTTP response. This is an *application* error, not a transport error — the\n * sidecar is reachable and answered, it just refused the exec. Callers should\n * fall back to the lease path for this one call but MUST NOT invalidate the\n * cached `instanceUrl` (the address is still good).\n */\nexport class PrivateNetExecHttpError extends Error {\n readonly status: number;\n readonly body: string;\n\n constructor(status: number, body: string) {\n super(`Sidecar /exec returned ${status}${body ? `: ${body.slice(0, 200)}` : ''}`);\n this.name = 'PrivateNetExecHttpError';\n this.status = status;\n this.body = body;\n }\n}\n\nconst DEFAULT_FETCH: PrivateNetFetch = (input, init) => {\n const f = (globalThis as { fetch?: typeof fetch }).fetch;\n if (!f) {\n throw new Error(\n 'Private-network exec requires a fetch implementation. Node 22+ provides one globally; on older runtimes, pass fetch explicitly.',\n );\n }\n return f(input, init);\n};\n\n/**\n * Wire frame shapes accepted from the sidecar. Anything else on the stream\n * is ignored so a future sidecar can add new frame types without breaking\n * older clients.\n */\ntype SidecarFrame =\n | { type: 'stdout'; data: string }\n | { type: 'stderr'; data: string }\n | { type: 'exit'; code: number };\n\n/**\n * Dial `${instanceUrl}/exec` and stream the response, resolving with the\n * accumulated stdout/stderr + exit code.\n *\n * Errors:\n * - Connection failure (DNS, refused, reset) → resolves with\n * `{opened:false, exitCode:null, transportErrorMessage}`. Never throws for\n * transport failures — the shape matches the lease-path result so the\n * caller can treat both transports uniformly.\n * - Non-2xx HTTP response from the sidecar → throws {@link PrivateNetExecHttpError}.\n * Application-level; caller decides whether to fall back.\n * - Stream ends without an `exit` frame → resolves with\n * `{opened:true, exitCode:null}`, matching the lease-path semantics for a\n * mid-stream drop.\n * - `timeoutMs` elapsed → aborts the request, resolves with\n * `{timedOut:true, exitCode:124}`.\n */\nexport async function execViaPrivateNetwork(\n instanceUrl: string,\n options: PrivateNetExecOptions,\n): Promise<PrivateNetExecResult> {\n const fetchImpl = options.fetch ?? DEFAULT_FETCH;\n const url = `${instanceUrl.replace(/\\/$/, '')}/exec`;\n\n const controller = new AbortController();\n let timedOut = false;\n let timeoutTimer: ReturnType<typeof setTimeout> | undefined;\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) {\n timeoutTimer = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, options.timeoutMs);\n }\n\n const body: Record<string, unknown> = { command: options.command };\n if (options.cwd) body.cwd = options.cwd;\n if (options.env && Object.keys(options.env).length > 0) body.env = options.env;\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) body.timeoutMs = options.timeoutMs;\n\n const headers: Record<string, string> = { 'content-type': 'application/json' };\n if (options.bearerToken) headers.authorization = `Bearer ${options.bearerToken}`;\n\n let response: Response;\n try {\n response = await fetchImpl(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (error) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n // AbortError from our own timeout → treat as timeout, not transport error.\n if (timedOut) {\n return {\n exitCode: 124,\n stdout: '',\n stderr: '',\n timedOut: true,\n opened: false,\n };\n }\n return {\n exitCode: null,\n stdout: '',\n stderr: '',\n timedOut: false,\n opened: false,\n transportErrorMessage: error instanceof Error ? error.message : String(error),\n };\n }\n\n if (!response.ok) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n const text = await response.text().catch(() => '');\n throw new PrivateNetExecHttpError(response.status, text);\n }\n\n if (!response.body) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n // A 200 without a body is a broken sidecar. Treat as mid-stream drop\n // (opened=true, no exit frame) so the caller invalidates cache.\n return {\n exitCode: null,\n stdout: '',\n stderr: '',\n timedOut: false,\n opened: true,\n status: response.status,\n };\n }\n\n let stdout = '';\n let stderr = '';\n let exitCode: number | null = null;\n const decoder = new TextDecoder();\n let buffer = '';\n\n const handleLine = (line: string): void => {\n if (!line) return;\n let frame: SidecarFrame | undefined;\n try {\n frame = JSON.parse(line) as SidecarFrame;\n } catch {\n // Unknown / malformed frame — ignore. A well-behaved sidecar only emits\n // JSON objects, but tolerating garbage protects against a partial write.\n return;\n }\n if (!frame || typeof frame !== 'object') return;\n if (frame.type === 'stdout' && typeof frame.data === 'string') {\n stdout += frame.data;\n options.onStdout?.(frame.data);\n } else if (frame.type === 'stderr' && typeof frame.data === 'string') {\n stderr += frame.data;\n options.onStderr?.(frame.data);\n } else if (frame.type === 'exit' && typeof frame.code === 'number') {\n exitCode = frame.code;\n }\n // Any other frame type is intentionally ignored (see SidecarFrame jsdoc).\n };\n\n try {\n const reader = response.body.getReader();\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n // NDJSON: split on newline; last piece stays in buffer for the next chunk.\n let newlineIdx = buffer.indexOf('\\n');\n while (newlineIdx !== -1) {\n const line = buffer.slice(0, newlineIdx).trim();\n buffer = buffer.slice(newlineIdx + 1);\n handleLine(line);\n newlineIdx = buffer.indexOf('\\n');\n }\n }\n // Flush the decoder + any trailing (no-newline) line at EOF.\n buffer += decoder.decode();\n const trailing = buffer.trim();\n if (trailing) handleLine(trailing);\n } catch (error) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n if (timedOut) {\n return {\n exitCode: 124,\n stdout,\n stderr,\n timedOut: true,\n opened: true,\n status: response.status,\n };\n }\n // Mid-stream failure. Return whatever we accumulated with exitCode=null\n // so the caller sees this as a transport failure and can invalidate.\n return {\n exitCode,\n stdout,\n stderr,\n timedOut: false,\n opened: true,\n status: response.status,\n transportErrorMessage: error instanceof Error ? error.message : String(error),\n };\n } finally {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n }\n\n return {\n exitCode,\n stdout,\n stderr,\n timedOut: false,\n opened: true,\n status: response.status,\n };\n}\n","import type { RequestContext } from '@mastra/core/di';\nimport type {\n CommandResult,\n ExecuteCommandOptions,\n InstructionsOption,\n MastraSandboxOptions,\n ProcessInfo,\n ProviderStatus,\n SandboxCloneOptions,\n SandboxInfo,\n SandboxStartResult,\n SpawnProcessOptions,\n} from '@mastra/core/workspace';\nimport {\n MastraSandbox,\n ProcessHandle,\n UnsupportedStdinCloseError,\n SandboxNotReadyError,\n SandboxProcessManager,\n} from '@mastra/core/workspace';\nimport type { PlatformClientOptions } from './client.js';\nimport { PlatformApiError, PlatformClient } from './client.js';\nimport type { DirectExecWebSocketFactory, ExecLease } from './direct-exec.js';\nimport { execViaLease } from './direct-exec.js';\nimport type { E2BExecRunner } from './e2b-exec.js';\nimport { execViaE2BLease } from './e2b-exec.js';\nimport type { PrivateNetExecOptions, PrivateNetExecResult, PrivateNetFetch } from './private-net-exec.js';\nimport { execViaPrivateNetwork, PrivateNetExecHttpError } from './private-net-exec.js';\n\nexport type PlatformSandboxNetworkIsolation = 'ISOLATED' | 'PRIVATE';\n\n/**\n * In-process `sandboxId → instanceUrl` map that lets\n * {@link PlatformSandbox.executeCommand} dial the in-sandbox sidecar over\n * Railway's private network instead of paying for a lease + WebSocket\n * round-trip through Railway's public control plane.\n *\n * The workspace proxy discovers each sandbox's IPv6 during\n * `POST /v1/:provider/projects/:pid/sandbox` and returns it as `instanceUrl` on the\n * create + get responses (see the platform inline-discovery issue). The\n * `PlatformSandbox` client copies that field into this registry from both\n * {@link PlatformSandbox.start} branches (fresh provision + reattach), evicts\n * on {@link PlatformSandbox.destroy}, and evicts again on any observed\n * transport failure so the next exec falls back to the lease path cleanly.\n *\n * See:\n * - `.scratch/factory-deploy/issue-runtime-sandbox-address-discovery.md`\n * - `.scratch/factory-deploy/issue-platform-sandbox-exec-via-private-network.md`\n */\nexport interface SandboxAddressRegistry {\n set(sandboxId: string, instanceUrl: string): void;\n get(sandboxId: string): string | undefined;\n delete(sandboxId: string): void;\n}\n\nexport interface PlatformSandboxOptions extends Omit<MastraSandboxOptions, 'processes'>, PlatformClientOptions {\n id?: string;\n environmentId?: string;\n sandboxId?: string;\n /** Boot-only fallback checkpoint for a fresh sandbox whose primary recovery key has no state. */\n seedCheckpointName?: string;\n idleTimeoutMinutes?: number;\n networkIsolation?: PlatformSandboxNetworkIsolation;\n env?: Record<string, string>;\n timeout?: number;\n instructions?: InstructionsOption;\n /**\n * Injected WebSocket factory used by the direct-exec code path. Defaults to\n * the global `WebSocket` (available on Node 22+, this package's minimum) and\n * only exists so tests can drive the exec state machine deterministically\n * without a real network socket.\n */\n webSocketFactory?: DirectExecWebSocketFactory;\n /** Injected E2B direct-exec implementation used by tests. */\n e2bExecRunner?: E2BExecRunner;\n /**\n * Injected fetch implementation used by the private-network exec code path\n * to dial the in-sandbox sidecar. Defaults to `globalThis.fetch` and only\n * exists so tests can drive that transport without a real HTTP server.\n * Note: this is separate from the `fetch` on {@link PlatformClientOptions},\n * which is used for calls to the workspace proxy.\n */\n privateNetFetch?: PrivateNetFetch;\n /**\n * Registry that maps `sandboxId → instanceUrl` for the private-network\n * exec path. When set, {@link PlatformSandbox.start} populates it from the\n * `instanceUrl` field workspace-proxy returns on create + get responses,\n * and {@link PlatformSandbox.executeCommand} looks it up before every exec\n * and tries the private-network transport first, falling back to the lease\n * path on any transport failure (and invalidating the registry entry so\n * the next call goes to the lease path cleanly). When absent, all execs\n * go straight to the lease path — this is the pre-existing behavior and\n * the expected mode outside the shipyard runtime. See\n * {@link SandboxAddressRegistry}.\n */\n addressRegistry?: SandboxAddressRegistry;\n}\n\ninterface ExecLeaseResponse {\n provider: string;\n sandboxId: string;\n providerResourceId: string;\n jwt: string;\n wsEndpoint: string;\n subprotocol: string;\n expiresAt: string | null;\n}\n\ninterface CachedExecLease extends ExecLease {\n provider: string;\n sandboxId: string;\n providerResourceId: string;\n expiresAtMs: number | null;\n}\n\n/**\n * How long before a lease's stated `expiresAt` we should treat it as\n * expired. Avoids a race where the JWT is valid at cache-hit time but the\n * server rejects it by the time the WebSocket handshake completes.\n */\nconst LEASE_REFRESH_MARGIN_MS = 60_000;\n\ninterface CreateSandboxResponse {\n id: string;\n providerResourceId?: string | null;\n status?: string;\n createdAt?: string;\n destroyedAt?: string | null;\n /**\n * Full sidecar URL (`http://[<ipv6>]:<port>`) the runtime can dial over\n * Railway's private network to reach the in-sandbox exec sidecar. The\n * workspace proxy discovers the sandbox's IPv6 during `Sandbox.create()`\n * via one `sandbox.exec(\"awk … /proc/net/if_inet6\")` and stores it in\n * `environment_sandboxes.instance_url`; the same field is echoed on\n * `GET /sandbox/:id`. `null` when discovery failed (returned by the proxy\n * so the runtime knows to skip private-net dial for this sandbox rather\n * than fall back on a missing-field ambiguity).\n */\n instanceUrl?: string | null;\n}\n\n/** Max attempts for `POST /sandbox` when the proxy returns transient 5xx errors. */\nconst CREATE_MAX_ATTEMPTS = 3;\n/** Base delay between create retries; multiplied by the attempt number. */\nconst CREATE_RETRY_BASE_DELAY_MS = 2_000;\n\n/**\n * How long to wait for the in-sandbox sidecar's `/health` endpoint to respond\n * before giving up and leaving the address registry unpopulated (execs fall\n * back to the lease path). This bounds the fire-and-forget probe that runs\n * after `start()` resolves; the sandbox is usable immediately — the probe\n * only controls whether early execs go via private-net or lease.\n */\nconst SIDECAR_PROBE_TIMEOUT_MS = 30_000;\n/** Delay between sidecar probe attempts. */\nconst SIDECAR_PROBE_INTERVAL_MS = 250;\n/**\n * How long `executeCommand` waits for the transport to become ready before\n * falling back to the lease path. This is much shorter than\n * `SIDECAR_PROBE_TIMEOUT_MS` because we want execs to proceed quickly if\n * the sidecar is slow to boot — the probe continues in the background and\n * later execs will use private-net once it succeeds.\n */\nconst TRANSPORT_READY_WAIT_MS = 5_000;\n\n/**\n * Diagnostic error thrown when the direct-exec WebSocket transport fails\n * twice in a row (opening handshake refused or socket closed mid-stream\n * without an `exit` frame). Distinguishes \"the sandbox transport is broken\"\n * from \"your command failed\" so callers can decide whether to retry at a\n * higher level (e.g. reprovision the sandbox) or surface the error.\n *\n * `opened` is `true` when the WebSocket completed its handshake at least\n * once before closing; `false` when Railway refused the upgrade outright.\n */\nexport class SandboxExecTransportError extends Error {\n readonly sandboxId: string | undefined;\n readonly command: string;\n readonly attempts: number;\n readonly opened: boolean;\n readonly closeCode: number | undefined;\n readonly closeReason: string | undefined;\n readonly wsEndpoint: string;\n\n constructor(\n message: string,\n diagnostics: {\n sandboxId?: string;\n command: string;\n attempts: number;\n opened: boolean;\n closeCode?: number;\n closeReason?: string;\n wsEndpoint: string;\n },\n ) {\n super(message);\n this.name = 'SandboxExecTransportError';\n this.sandboxId = diagnostics.sandboxId;\n this.command = diagnostics.command;\n this.attempts = diagnostics.attempts;\n this.opened = diagnostics.opened;\n this.closeCode = diagnostics.closeCode;\n this.closeReason = diagnostics.closeReason;\n this.wsEndpoint = diagnostics.wsEndpoint;\n }\n}\n\n/**\n * Outcome of {@link PlatformSandbox.captureCheckpoint}. Mirrors the shape of\n * the OSS `@mastra/railway` `RailwaySandbox.captureCheckpoint()` return so a\n * caller (e.g. the factory fleet) can branch on `status`/`reason` uniformly\n * across providers without knowing which one is underneath.\n *\n * `captured` and `coalesced` both represent a successful capture the caller\n * can persist against — they carry the checkpoint name inline so callers\n * don't have to reach back into the sandbox instance to learn what was\n * written. `skipped` carries a machine-readable `reason` so the discriminant\n * set stays extensible.\n *\n * Note: the platform proxy's own `skipped` (returned when the upstream\n * sandbox is already destroyed) is mapped to `sandbox-not-running` here to\n * keep the discriminant identical to the OSS provider. The diagnostic\n * distinction (pre-flight vs post-hoc discovery) is preserved in log lines,\n * not the return type — see {@link PlatformSandbox.captureCheckpoint}.\n */\nexport type CaptureCheckpointResult =\n | { status: 'captured'; checkpointName: string }\n | { status: 'coalesced'; checkpointName: string }\n | { status: 'skipped'; reason: 'no-checkpoint-name-configured' | 'sandbox-not-running' };\n\n/**\n * Thrown when `/exec-lease` returns 410 Gone — the sandbox has been destroyed\n * (Railway destroy, quota reclamation, etc.). The client cannot recover from\n * this on its own because it does not own the binding store; only the fleet\n * layer can clear the stale sandbox id and provision a fresh one. Callers\n * (typically `SandboxFleet`) must catch this and reprovision-and-replay.\n *\n * When this is thrown the cached `_lease` and `_sandboxId` on the sandbox\n * instance are cleared, so the next `ensureRunning()` on a reused instance\n * will re-provision cleanly.\n */\nexport class SandboxDestroyedError extends Error {\n readonly sandboxId: string | undefined;\n readonly command: string;\n readonly attempts: number;\n\n constructor(message: string, diagnostics: { sandboxId?: string; command: string; attempts: number }) {\n super(message);\n this.name = 'SandboxDestroyedError';\n this.sandboxId = diagnostics.sandboxId;\n this.command = diagnostics.command;\n this.attempts = diagnostics.attempts;\n }\n}\n\n/**\n * Compose a shell command line from a `command` string and optional `args`.\n *\n * IMPORTANT: `command` is treated as a **shell string** and passed to the\n * remote shell verbatim so callers can use pipes, redirects, and chaining\n * (`ls -la | grep foo`). This matches the contract of {@link MastraSandbox}\n * and the local sandbox implementation. `args` are always shell-quoted so\n * they cannot inject syntax.\n *\n * Callers MUST NOT pass untrusted input as `command`. Untrusted values must\n * be passed via `args`, where they are safely quoted. Passing untrusted\n * input as `command` allows arbitrary shell syntax execution on the remote\n * sandbox.\n */\nfunction buildCommand(command: string, args?: string[]): string {\n return args?.length ? `${command} ${args.map(shellQuote).join(' ')}` : command;\n}\n\nfunction shellQuote(arg: string): string {\n if (/^[a-zA-Z0-9._\\-/=:@]+$/.test(arg)) return arg;\n return `'${arg.replace(/'/g, `'\\\\''`)}'`;\n}\n\nclass PlatformProcessHandle extends ProcessHandle {\n readonly pid: string;\n private readonly resultPromise: Promise<CommandResult>;\n private exitCodeValue: number | undefined;\n\n constructor(pid: string, resultPromise: Promise<CommandResult>, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this.resultPromise = resultPromise.then(result => {\n this.exitCodeValue = result.exitCode;\n if (result.stdout) this.emitStdout(result.stdout);\n if (result.stderr) this.emitStderr(result.stderr);\n return result;\n });\n }\n\n get exitCode(): number | undefined {\n return this.exitCodeValue;\n }\n\n async wait(): Promise<CommandResult> {\n return this.resultPromise;\n }\n\n async kill(): Promise<boolean> {\n // The workspace proxy has no cancel-exec endpoint; each `executeCommand`\n // is a synchronous round-trip that has already completed (or timed out)\n // by the time a handle exists to kill. Making this explicit avoids\n // callers silently believing they cancelled a still-running process.\n throw new Error('Platform sandbox command execution does not support killing individual processes');\n }\n\n async sendStdin(): Promise<void> {\n throw new Error('Platform sandbox command execution does not support stdin');\n }\n\n async closeStdin(): Promise<void> {\n throw new UnsupportedStdinCloseError('Platform sandbox command execution does not support closing stdin');\n }\n}\n\nclass PlatformProcessManager extends SandboxProcessManager<PlatformSandbox> {\n private spawnCounter = 0;\n\n /**\n * Spawn a process on the remote sandbox.\n *\n * `command` is interpreted as a shell string by the remote shell, matching\n * the {@link MastraSandbox} contract. See {@link PlatformSandbox.executeCommand}\n * for the untrusted-input caveat: never pass untrusted values as `command`.\n */\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n const pid = `platform-proc-${Date.now().toString(36)}-${(this.spawnCounter++).toString(36)}`;\n const resultPromise = this.sandbox.executeCommand(command, undefined, options);\n const handle = new PlatformProcessHandle(pid, resultPromise, options);\n this._tracked.set(handle.pid, handle);\n return handle;\n }\n\n async list(): Promise<ProcessInfo[]> {\n return Array.from(this._tracked.values()).map(handle => ({\n pid: handle.pid,\n command: handle.command,\n running: handle.exitCode === undefined,\n ...(handle.exitCode !== undefined && { exitCode: handle.exitCode }),\n }));\n }\n}\n\nexport class PlatformSandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'PlatformSandbox';\n readonly provider = 'platform';\n status: ProviderStatus = 'pending';\n declare readonly processes: PlatformProcessManager;\n\n private readonly _client: PlatformClient;\n private readonly _environmentId: string;\n private _sandboxId?: string;\n private readonly _seedCheckpointName?: string;\n private readonly _idleTimeoutMinutes?: number;\n private readonly _networkIsolation?: PlatformSandboxNetworkIsolation;\n private readonly _env: Record<string, string>;\n private readonly _timeout?: number;\n private readonly _instructionsOverride?: InstructionsOption;\n private _createdAt: Date | null = null;\n private readonly _webSocketFactory?: DirectExecWebSocketFactory;\n private readonly _e2bExecRunner: E2BExecRunner;\n private readonly _privateNetFetch?: PrivateNetFetch;\n /**\n * Registry that maps `sandboxId → instanceUrl` for the private-network\n * exec path. Injected by the composition site via\n * {@link PlatformSandboxOptions.addressRegistry} and populated by this\n * class itself in `start()` when the workspace-proxy's create/reattach\n * response includes an `instanceUrl` field. The registry IS the cache —\n * there is no per-instance mirror on `PlatformSandbox`, so every exec is\n * a `Map.get()` (in the default in-process impl) against the live view.\n * When absent, executes go straight to the lease path with no extra\n * round-trip.\n */\n private readonly _addressRegistry?: SandboxAddressRegistry;\n /**\n * Cached exec lease for this sandbox. `null` before the first exec and\n * after {@link destroy}. Refreshed when `expiresAt - LEASE_REFRESH_MARGIN_MS < now`\n * (see {@link _ensureLease}); a lease without a disclosed `expiresAt`\n * is refreshed on every call.\n */\n private _lease: CachedExecLease | null = null;\n /**\n * In-flight mint request; concurrent `_ensureLease` callers on a cold or\n * near-expiry cache all await this single promise so we don't burn N\n * `POST /exec-lease` round-trips when the sandbox is doing N parallel execs.\n * Cleared (regardless of success or failure) when the request settles.\n */\n private _leaseInFlight: Promise<CachedExecLease> | null = null;\n /**\n * True when this sandbox was constructed with a caller-supplied `id` (the\n * recovery key the proxy hashes into an on-provider checkpoint name).\n * `captureCheckpoint()` needs this to distinguish \"no checkpoint intent\"\n * (auto-generated random id — capture would land under a name no future\n * boot would look for) from \"capture on demand\". Cloned sandboxes route\n * `checkpointName` through `id`, so both entry points set this the same\n * way.\n */\n private readonly _hasRecoveryKey: boolean;\n /**\n * In-flight `captureCheckpoint()` request. Concurrent callers on the same\n * instance coalesce onto this single promise so we don't burn N `POST\n * /checkpoint` round-trips when the fleet fires several turn-end captures\n * before the first one resolves. Cleared when the request settles.\n */\n private _captureInFlight: Promise<CaptureCheckpointResult> | null = null;\n /**\n * Generation token for the sidecar probe. Incremented on every `start()`\n * and on teardown. The probe captures this value when it begins; if the\n * generation has changed by the time the probe succeeds, the probe skips\n * the `set()` to avoid re-populating a deleted or superseded sandbox entry.\n */\n private _probeGeneration = 0;\n /**\n * In-flight sidecar probe promise. Concurrent `executeCommand` callers that\n * arrive before the registry is populated all await this single promise so\n * we don't fire N independent lease requests during the sidecar boot window.\n * Once the probe resolves (success or timeout), callers check the registry\n * and proceed — either via private-net (probe succeeded) or via lease (probe\n * failed/timed out, but now coalesced via `_leaseInFlight`).\n */\n private _transportReadyPromise: Promise<void> | null = null;\n /**\n * The sidecar address of the most recent `start()`, kept so a timed-out\n * probe can be restarted by a later exec ({@link _awaitTransportReady})\n * instead of pinning the sandbox to the lease path for its lifetime.\n */\n private _probeTarget: { sandboxId: string; instanceUrl: string } | null = null;\n\n constructor(options: PlatformSandboxOptions = {}) {\n super({ ...options, name: 'PlatformSandbox', processes: new PlatformProcessManager() });\n this._hasRecoveryKey = options.id !== undefined;\n this.id = options.id ?? this.generateId();\n this._client = new PlatformClient(options);\n this._environmentId = options.environmentId ?? process.env.MASTRA_ENVIRONMENT_ID ?? '';\n if (!this._environmentId && !options.sandboxId) throw new Error('environmentId is required');\n this._sandboxId = options.sandboxId;\n this._seedCheckpointName = options.seedCheckpointName;\n this._idleTimeoutMinutes = options.idleTimeoutMinutes;\n this._networkIsolation = options.networkIsolation;\n this._env = options.env ?? {};\n this._timeout = options.timeout;\n this._instructionsOverride = options.instructions;\n this._webSocketFactory = options.webSocketFactory;\n this._e2bExecRunner = options.e2bExecRunner ?? execViaE2BLease;\n this._privateNetFetch = options.privateNetFetch;\n this._addressRegistry = options.addressRegistry;\n }\n\n private generateId(): string {\n return `platform-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n /**\n * Construct a sibling {@link PlatformSandbox} that inherits this sandbox's\n * credentials and defaults (access token, project, environment, network\n * isolation, timeout, instructions, env, idle timeout) with per-instance\n * overrides from `options`.\n *\n * Performs no I/O and does not require this sandbox to be started — the\n * returned sandbox is not started and provisions (or reattaches, when\n * `sandboxId` is set) on its own `start()`. Use it when one configured\n * sandbox acts as the template for a fleet of independent sandboxes\n * (e.g. one per project).\n */\n clone(options: SandboxCloneOptions = {}): PlatformSandbox {\n // The proxy hashes `body.id` on POST /sandbox to look up a prior\n // checkpoint. A stable `checkpointName` is only useful if it round-trips\n // to `body.id`, so route it through the sandbox id when the caller\n // didn't pick one explicitly. Without this, every clone gets a random\n // id and no boot ever hits its captured checkpoint (see\n // issue-platform-sandbox-clone-drops-checkpoint-name.md).\n const id = options.id ?? options.checkpointName;\n const seedCheckpointName =\n options.seedCheckpointName ??\n (this._client.sandboxProvider === 'e2b' ? options.checkpointName : undefined) ??\n this._seedCheckpointName;\n return new PlatformSandbox({\n ...(id !== undefined && { id }),\n accessToken: this._client.accessToken,\n projectId: this._client.projectId,\n actingUserId: options.actingUserId ?? this._client.actingUserId,\n ...(this._client.sessionId !== undefined && { sessionId: this._client.sessionId }),\n ...(this._client.threadId !== undefined && { threadId: this._client.threadId }),\n fetch: this._client.fetch,\n environmentId: this._environmentId,\n ...(options.sandboxId !== undefined && { sandboxId: options.sandboxId }),\n ...(seedCheckpointName !== undefined && { seedCheckpointName }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n env: options.env ?? this._env,\n ...(this._timeout !== undefined && { timeout: this._timeout }),\n ...(this._instructionsOverride !== undefined && { instructions: this._instructionsOverride }),\n ...(this._webSocketFactory !== undefined && { webSocketFactory: this._webSocketFactory }),\n e2bExecRunner: this._e2bExecRunner,\n ...(this._privateNetFetch !== undefined && { privateNetFetch: this._privateNetFetch }),\n // Propagate the registry — the clone is a different sandbox with a\n // different id, so it will `get()` its OWN address (or nothing) out\n // of the shared registry, not the parent's. See\n // `.scratch/factory-deploy/issue-platform-sandbox-exec-via-private-network.md`.\n ...(this._addressRegistry !== undefined && { addressRegistry: this._addressRegistry }),\n });\n }\n\n /**\n * Start the sandbox: reattach to a known provider `sandboxId` when one is\n * set and still live, otherwise provision a fresh sandbox via the proxy.\n *\n * Concurrent-caller coalescing lives in the `MastraSandbox` base class\n * (constructor-wrapped `start()`): joined callers share one attempt and\n * observe its result; the in-flight slot is cleared on settle so a failed\n * attempt is not a permanent latch.\n *\n * Reports `outcome: 'connected'` on reattach and `outcome: 'created'` on provision.\n * Note: a `POST /sandbox` seeded from an id-keyed checkpoint is still a\n * fresh VM and reports `outcome: 'created'`.\n */\n async start(): Promise<SandboxStartResult> {\n const startedAt = Date.now();\n if (this._sandboxId) {\n try {\n const requestStartedAt = Date.now();\n const response = await this._client.request(`/sandbox/${encodeURIComponent(this._sandboxId)}`);\n const requestMs = Date.now() - requestStartedAt;\n const json = (await response.json()) as CreateSandboxResponse;\n // A destroyed record (idle GC, manual delete) is not reattachable —\n // treat it like a missing sandbox so we fall through to a fresh\n // provision instead of pointing exec at a dead resource.\n if (!json.destroyedAt) {\n this._createdAt = json.createdAt ? new Date(json.createdAt) : new Date();\n this._populateAddressFromResponse(json);\n this._logStartComplete(json.id, startedAt, requestMs, 'reattach');\n return { outcome: 'connected' };\n }\n this._sandboxId = undefined;\n } catch (error) {\n if (!(error instanceof PlatformApiError) || error.status !== 404) throw error;\n this._sandboxId = undefined;\n }\n }\n\n if (!this._environmentId) throw new Error('environmentId is required');\n\n const body = JSON.stringify({\n // Sent so the platform can associate the provisioned resource with a\n // caller-stable identifier (used for opt-in checkpoint recovery). The\n // platform treats it as an advisory key: unknown values fall through\n // to a fresh sandbox, matching pre-existing behavior.\n id: this.id,\n seedCheckpointName: this._seedCheckpointName,\n environmentId: this._environmentId,\n idleTimeoutMinutes: this._idleTimeoutMinutes,\n networkIsolation: this._networkIsolation,\n env: this._env,\n });\n // Provisioning is observed to fail intermittently with proxy 500s while\n // the provider is under load. A create either succeeds (201) or fails\n // without allocating a caller-visible resource, so retrying transient\n // 5xx responses with a short backoff is safe and keeps a single flaky\n // window from killing the caller's whole workflow.\n let response: Response | undefined;\n const requestStartedAt = Date.now();\n for (let attempt = 1; ; attempt++) {\n try {\n response = await this._client.request('/sandbox', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body,\n });\n break;\n } catch (error) {\n const transient = error instanceof PlatformApiError && error.status >= 500;\n if (!transient || attempt >= CREATE_MAX_ATTEMPTS) throw error;\n await new Promise(resolve => setTimeout(resolve, CREATE_RETRY_BASE_DELAY_MS * attempt));\n }\n }\n const requestMs = Date.now() - requestStartedAt;\n const json = (await response.json()) as CreateSandboxResponse;\n this._sandboxId = json.id;\n this._createdAt = json.createdAt ? new Date(json.createdAt) : new Date();\n this._populateAddressFromResponse(json);\n this._logStartComplete(json.id, startedAt, requestMs, 'provision');\n return { outcome: 'created' };\n }\n\n /**\n * One timing summary per completed `start()` — the whole\n * `PlatformSandbox`-visible boot in a single greppable line.\n *\n * `requestMs` is the proxy round-trip (`GET /sandbox/:id` on reattach,\n * `POST /sandbox` including transient-5xx retries on provision) — a black\n * box from this side that rolls up Railway RPC, sidecar launch, and the\n * proxy's discovery exec. Sidecar probe cost is intentionally NOT here: the\n * probe is fire-and-forget and outlives `start()` by design, so its\n * duration lands on the `platform-workspace probe ok` line instead.\n */\n private _logStartComplete(sandboxId: string, startedAt: number, requestMs: number, mode: string): void {\n this.logger.info('platform-workspace start complete', {\n sandboxId,\n sessionId: this._client.sessionId,\n mode,\n totalMs: Date.now() - startedAt,\n requestMs,\n });\n }\n\n /**\n * Copy `response.instanceUrl` into the injected {@link SandboxAddressRegistry}\n * when both are present. Called from both {@link start} branches (fresh\n * provision + reattach) with the workspace-proxy response for this sandbox.\n *\n * The proxy discovers the IPv6 during `Sandbox.create()` and stores it in\n * `environment_sandboxes.instance_url`; both the create response and\n * `GET /sandbox/:id` echo the same field. The runtime does not do any\n * discovery of its own — it only mirrors the field into an in-process map\n * so {@link executeCommand} can `Map.get()` before every exec without an\n * HTTP round-trip.\n *\n * `null`/absent `instanceUrl` (proxy discovery failed, or an older proxy\n * that predates the field) evicts any stale registry address and leaves\n * executes on the lease path.\n */\n private _populateAddressFromResponse(json: CreateSandboxResponse): void {\n if (!this._addressRegistry) return;\n if (!json.instanceUrl) {\n // A later start() without an address must not keep probing the previous\n // sidecar or reuse a leftover registry URL. Invalidate any in-flight\n // probe, drop the remembered target, and evict the stale entry.\n this._probeGeneration++;\n this._probeTarget = null;\n this._transportReadyPromise = null;\n this._addressRegistry.delete(json.id);\n return;\n }\n // Clear any stale entry before probing. On reattach, the registry may have\n // the old sandbox's address; execs should fall back to lease until the new\n // probe succeeds rather than dialing the stale address.\n this._addressRegistry.delete(json.id);\n // Start the sidecar probe and expose it so executeCommand can await it.\n // Early execs wait for the probe (up to TRANSPORT_READY_WAIT_MS) rather\n // than all racing to the lease path independently.\n const generation = ++this._probeGeneration;\n // Remember the probe target so a later exec can restart the probe if this\n // one times out, instead of falling back to the lease path forever.\n this._probeTarget = { sandboxId: json.id, instanceUrl: json.instanceUrl };\n this._transportReadyPromise = this._probeSidecarThenRegister(json.id, json.instanceUrl, generation);\n }\n\n /**\n * Fire-and-forget probe that polls the sidecar's `/health` endpoint until\n * it responds, then populates the address registry. Runs detached from\n * `start()` so sandbox provision latency is unchanged; early execs simply\n * fall back to the lease path until the probe succeeds.\n *\n * If the sidecar never comes up within {@link SIDECAR_PROBE_TIMEOUT_MS},\n * the registry stays unpopulated, `_transportReadyPromise` is cleared,\n * and a later {@link _awaitTransportReady} call restarts the probe\n * instead of pinning this sandbox to the lease path.\n *\n * @param generation - The probe generation captured at call time. If this\n * no longer matches `_probeGeneration` when the probe succeeds, the probe\n * was superseded by a teardown or a new `start()`, so we skip the `set()`.\n */\n private async _probeSidecarThenRegister(sandboxId: string, instanceUrl: string, generation: number): Promise<void> {\n const probeStartedAt = Date.now();\n const deadline = probeStartedAt + SIDECAR_PROBE_TIMEOUT_MS;\n const fetchFn = this._privateNetFetch ?? fetch;\n let attempts = 0;\n while (Date.now() < deadline) {\n // Teardown or new start() superseded this probe — bail out early.\n if (generation !== this._probeGeneration) return;\n attempts++;\n try {\n const res = await fetchFn(`${instanceUrl}/health`, {\n method: 'GET',\n signal: AbortSignal.timeout(1_000),\n });\n const ok = res.ok;\n // Release the response body so the connection returns to the pool.\n await res.body?.cancel().catch(() => {});\n if (ok) {\n // A ~1-attempt probe means the sidecar was ready when the proxy\n // returned; hundreds of ms means it was still booting — the exact\n // window that used to silently fall back to the lease path.\n this.logger.info('platform-workspace probe ok', {\n sandboxId,\n sessionId: this._client.sessionId,\n probeDurationMs: Date.now() - probeStartedAt,\n attempts,\n });\n // Sidecar is listening. Only populate if this probe is still current.\n if (generation === this._probeGeneration && this._sandboxId === sandboxId) {\n this._addressRegistry?.set(sandboxId, instanceUrl);\n }\n return;\n }\n } catch {\n // Connection refused / timeout — keep polling.\n }\n await new Promise(r => setTimeout(r, SIDECAR_PROBE_INTERVAL_MS));\n }\n // Sidecar never came up within this probe's window. Leave the registry\n // entry unset (execs go via lease) but clear the ready promise so a later\n // exec can restart the probe rather than pinning this sandbox to the\n // lease path for its lifetime.\n if (generation === this._probeGeneration && this._transportReadyPromise) {\n this._transportReadyPromise = null;\n }\n this.logger.warn('platform-workspace probe timed out', {\n sandboxId,\n sessionId: this._client.sessionId,\n timeoutMs: SIDECAR_PROBE_TIMEOUT_MS,\n attempts,\n });\n }\n\n /**\n * Wait for the transport to become ready (sidecar probe succeeds) or time\n * out. Concurrent callers all await the same probe promise, coalescing the\n * cold-start storm into a single warmup attempt.\n *\n * If no probe is in flight (no registry, or registry already populated),\n * this returns immediately. After the wait (success or timeout), callers\n * check the registry and proceed — either via private-net or lease. The\n * lease path is still coalesced via `_leaseInFlight`, so even if the probe\n * times out, we only mint one lease for all concurrent execs.\n */\n private async _awaitTransportReady(): Promise<void> {\n // Fast path: registry already has an entry, transport is warm.\n if (this._sandboxId && this._addressRegistry?.get(this._sandboxId)) {\n return;\n }\n // No probe in flight. If a previous probe timed out for the current\n // sandbox, restart it — the sidecar may just have been slow to boot, and\n // one exec paying a short wait beats every exec going via lease forever.\n if (!this._transportReadyPromise) {\n const target = this._probeTarget;\n if (!target || this._sandboxId !== target.sandboxId) return;\n const generation = ++this._probeGeneration;\n this._transportReadyPromise = this._probeSidecarThenRegister(target.sandboxId, target.instanceUrl, generation);\n }\n // Race the probe against a timeout. We don't want to block execs forever\n // if the sidecar is slow to boot — they can proceed via lease after a\n // short wait, and later execs will use private-net once the probe succeeds.\n await Promise.race([this._transportReadyPromise, new Promise<void>(r => setTimeout(r, TRANSPORT_READY_WAIT_MS))]);\n }\n\n /**\n * Stop the sandbox while **preserving its recovery checkpoint**.\n *\n * Semantic parity with `@mastra/railway` `RailwaySandbox.stop()`: the VM\n * is released but the on-provider checkpoint survives, so a subsequent\n * `start()` on a sandbox constructed with the same `id` can restore from\n * it. Any in-flight capture is awaited first so the preserved checkpoint\n * reflects the latest disk state we asked for.\n *\n * Corresponds to `DELETE /v1/:provider/projects/:pid/sandbox/:sandboxId` on\n * workspace-proxy, which by contract does not touch the checkpoint. Use\n * {@link destroy} when you want the checkpoint released too.\n */\n async stop(): Promise<void> {\n // Await any in-flight capture so the preserved checkpoint reflects the\n // latest capture the caller triggered. Never rethrow — a failing capture\n // must not block teardown; the proxy's safety-net refresh timer is a\n // fallback for the checkpoint state.\n if (this._captureInFlight) {\n await this._captureInFlight.catch(error => {\n this.logger.warn(`stop(): failed to flush in-flight capture before teardown:`, error);\n });\n }\n await this._teardownSandbox();\n }\n\n /**\n * Destroy the sandbox **and release its recovery checkpoint**.\n *\n * Semantic parity with `@mastra/railway` `RailwaySandbox.destroy()`:\n * cancels any in-flight capture (the checkpoint is about to be deleted\n * — no reason to burn a capture on state we're releasing), asks the\n * proxy to delete the checkpoint, then releases the VM. Both remote\n * operations are best-effort logged failures — a stray checkpoint or a\n * transient proxy error must not leave the caller with a half-torn-down\n * sandbox they can't safely retry.\n *\n * Railway requires a caller-supplied recovery `id` before it can have a\n * checkpoint to delete. E2B also permits capture with the automatic id, so\n * destroy releases that named snapshot even when no recovery id was supplied.\n */\n async destroy(): Promise<void> {\n if (!this._sandboxId) return;\n const destroyedSandboxId = this._sandboxId;\n\n // Drop the in-flight capture promise — we're about to delete the\n // checkpoint, so completing an in-flight capture is at best a wasted\n // round-trip and at worst races with the delete. Callers get whatever\n // resolution the pending capture already had; we don't rethrow.\n this._captureInFlight = null;\n\n if (this._hasRecoveryKey || this._client.sandboxProvider === 'e2b') {\n // Body mirrors the POST /checkpoint shape (`{ id }`) so the proxy\n // can hash the same recovery key into the same checkpoint name.\n // Best-effort: a proxy 404/410 means the checkpoint is already\n // absent (idle GC, prior delete) and we can proceed with the VM\n // teardown; other failures are surfaced in logs but do not abort\n // — the VM DELETE below is the operation the caller most needs.\n try {\n await this._client.request(`/sandbox/${encodeURIComponent(destroyedSandboxId)}/checkpoint`, {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: this.id }),\n });\n } catch (error) {\n if (error instanceof PlatformApiError && (error.status === 404 || error.status === 410)) {\n this.logger.debug(`destroy(): checkpoint already absent upstream (status=${error.status})`);\n } else {\n this.logger.warn(`destroy(): failed to delete checkpoint upstream:`, error);\n }\n }\n }\n\n await this._teardownSandbox();\n }\n\n /**\n * Release the remote sandbox VM and clear the local state pointing at it.\n *\n * Shared body of {@link stop} and {@link destroy} — both funnel through\n * here after they've dealt with the checkpoint (preserve vs release).\n * The VM DELETE is safe to issue in either mode: the proxy's DELETE\n * route does not touch the checkpoint on its own, so `stop()` correctly\n * leaves the checkpoint intact and `destroy()` has already removed it\n * before this call.\n */\n private async _teardownSandbox(): Promise<void> {\n if (!this._sandboxId) return;\n const destroyedSandboxId = this._sandboxId;\n // Invalidate any in-flight probe so it doesn't re-populate the registry\n // after we've deleted the entry below. The probe checks this generation\n // before calling set(). Also drop the re-probe target so later execs\n // don't restart a probe against the deleted sandbox's address.\n this._probeGeneration++;\n this._probeTarget = null;\n this._transportReadyPromise = null;\n await this._client.request(`/sandbox/${encodeURIComponent(destroyedSandboxId)}`, { method: 'DELETE' });\n // Clear local state so a subsequent start() creates a fresh remote sandbox\n // instead of taking the reattach branch and pointing exec at a deleted resource.\n this._sandboxId = undefined;\n this._createdAt = null;\n // Drop the exec lease with the sandbox — the JWT is tied to the provider\n // instance id and would be rejected against a fresh one.\n this._lease = null;\n // Evict the sidecar address from the registry explicitly. Destroy\n // deallocates the IPv6, so any stale entry would be a dial-to-nowhere;\n // clearing here prevents a transport-failure round-trip on the next\n // exec against a reused instance. A subsequent start() (fresh provision\n // or reattach) will re-populate the entry from the workspace-proxy's\n // response.\n this._addressRegistry?.delete(destroyedSandboxId);\n }\n\n /** Persist the configured recovery checkpoint when available. */\n async snapshot(): Promise<void> {\n await this.captureCheckpoint();\n }\n\n /** Snapshots persist real checkpoints that can seed future sandboxes. */\n readonly supportsCheckpoints: boolean = true;\n\n /**\n * Capture the sandbox's checkpoint on demand, outside any refresh timer the\n * workspace-proxy owns internally.\n *\n * Intended for callers (e.g. a factory-side scheduler) that want to refresh\n * the recovery checkpoint at semantic moments — turn end, session-idle,\n * pre-teardown — rather than only just before the upstream's idle destroy.\n *\n * Mirrors the OSS `@mastra/railway` `RailwaySandbox.captureCheckpoint()`\n * shape so factory can call `sandbox.captureCheckpoint()` uniformly and\n * branch on `status`/`reason` without knowing which provider is underneath.\n * Both `captured` and `coalesced` carry the checkpoint name inline so the\n * caller can persist a session→checkpoint binding atomically with the\n * awaited capture.\n *\n * Skip semantics:\n * - No caller-supplied `id`: returns `{ status: 'skipped', reason:\n * 'no-checkpoint-name-configured' }`. An auto-generated random id is\n * never a meaningful recovery key (no future boot would look for a\n * checkpoint under it), so capturing would silently produce dead data.\n * - Not started (no `_sandboxId`): returns `{ status: 'skipped', reason:\n * 'sandbox-not-running' }` without a round-trip.\n * - Upstream 410 (workspace-proxy or Railway reports the sandbox is\n * already destroyed): returns the same `sandbox-not-running` skip so\n * the discriminant matches the pre-flight case. Local state\n * (`_sandboxId`, `_lease`, sidecar address) is cleared as a side\n * effect so the next `start()` provisions fresh instead of reattaching\n * to a dead id. The diagnostic distinction (pre-flight vs post-hoc)\n * is preserved in log level: debug for the expected pre-flight skip,\n * warn for the surprise upstream destroy.\n *\n * Concurrent callers on the same instance coalesce onto a single in-flight\n * `POST /checkpoint` so N simultaneous turn-end fires (e.g. several tabs)\n * do not each round-trip the proxy. Both the originator and joiners\n * receive `{ status: 'coalesced', ... }` for the joined result — the\n * outer contract does not distinguish who started the request, only that\n * one upstream capture was made.\n *\n * Never throws for expected outcomes. Transport failures (5xx, 4xx other\n * than 410) propagate as {@link PlatformApiError}; a 410 is normalized\n * to a skip as described above.\n */\n async captureCheckpoint(): Promise<CaptureCheckpointResult> {\n if (!this._hasRecoveryKey && this._client.sandboxProvider !== 'e2b') {\n this.logger.debug(\n `captureCheckpoint skipped: no recovery key configured for sandbox ${this._sandboxId ?? '(unstarted)'}`,\n );\n return { status: 'skipped', reason: 'no-checkpoint-name-configured' };\n }\n\n if (!this._sandboxId) {\n this.logger.debug(`captureCheckpoint skipped: sandbox not running (local pre-flight, id=${this.id})`);\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n\n if (this._captureInFlight) {\n return this._captureInFlight;\n }\n\n const sandboxId = this._sandboxId;\n const capture = this._doCaptureCheckpoint(sandboxId).finally(() => {\n if (this._captureInFlight === capture) {\n this._captureInFlight = null;\n }\n });\n this._captureInFlight = capture;\n return capture;\n }\n\n /**\n * The single `POST /checkpoint` attempt behind {@link captureCheckpoint}.\n *\n * Split out so the coalescing wrapper can install a shared in-flight\n * promise without inlining the transport + response-mapping logic.\n * Joined callers observe `{ status: 'coalesced', ... }` — the initiator\n * sees the underlying `captured` / `coalesced` / `skipped` result the\n * proxy returned. Both are legitimate: the OSS mirror uses the same\n * \"initiator sees the truth, joiners see coalesced\" split.\n */\n private async _doCaptureCheckpoint(sandboxId: string): Promise<CaptureCheckpointResult> {\n let response: Response;\n try {\n response = await this._client.request(`/sandbox/${encodeURIComponent(sandboxId)}/checkpoint`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: this.id }),\n });\n } catch (error) {\n if (error instanceof PlatformApiError && error.status === 410) {\n this.logger.warn(`captureCheckpoint skipped: sandbox destroyed upstream (proxy 410, sandboxId=${sandboxId})`);\n this._clearDestroyedState(sandboxId);\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n throw error;\n }\n const json = (await response.json()) as { checkpointName: string; status: 'captured' | 'coalesced' | 'skipped' };\n if (json.status === 'skipped') {\n // Proxy's own `skipped` means the upstream sandbox is already\n // destroyed — same actionable outcome as a 410, so normalize to\n // the same discriminant + clear local state.\n this.logger.warn(\n `captureCheckpoint skipped: sandbox destroyed upstream (proxy reported skipped, sandboxId=${sandboxId})`,\n );\n this._clearDestroyedState(sandboxId);\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n return { status: json.status, checkpointName: json.checkpointName };\n }\n\n /**\n * Clear local state that would otherwise let the caller keep exec'ing\n * against a sandbox the upstream has already destroyed. Mirrors what\n * `destroy()` does minus the outbound DELETE — the sandbox is already\n * gone, so all that remains is to stop pointing at it.\n *\n * Also resets `status` to `'pending'` so a subsequent `_start()` on this\n * reused instance re-runs provisioning instead of short-circuiting on\n * the cached `'running'` state (see `MastraSandbox._start`).\n */\n private _clearDestroyedState(destroyedSandboxId: string): void {\n this._probeGeneration++;\n this._probeTarget = null;\n this._transportReadyPromise = null;\n this._sandboxId = undefined;\n this._createdAt = null;\n this._lease = null;\n this._addressRegistry?.delete(destroyedSandboxId);\n this.status = 'pending';\n }\n\n /**\n * Execute a command on the remote sandbox.\n *\n * `command` is a **shell string**: it is concatenated verbatim into the\n * command line sent to the remote shell, which lets callers use pipes,\n * redirects, and chaining (`ls -la | grep foo`). This matches the contract\n * of {@link MastraSandbox} and the local sandbox implementation.\n *\n * `args`, when provided, are always shell-quoted so they cannot inject\n * additional shell syntax.\n *\n * Security: callers MUST NOT pass untrusted input as `command`. If any part\n * of the invocation is derived from an untrusted source, pass it through\n * `args` (which is safely quoted) or shell-quote it yourself before\n * inclusion. Untrusted `command` values allow arbitrary shell syntax\n * execution on the remote sandbox.\n */\n async executeCommand(command: string, args?: string[], options?: ExecuteCommandOptions): Promise<CommandResult> {\n await this.ensureRunning();\n if (!this._sandboxId) throw new SandboxNotReadyError(this.id);\n\n const started = Date.now();\n const fullCommand = buildCommand(command, args);\n // Nullish check so an explicit `timeout: 0` still overrides the instance\n // default. `_runDirectExec` omits `timeoutMs` from the exec payload when\n // the value is 0, which disables the client-side timer entirely.\n const effectiveTimeout = options?.timeout ?? this._timeout;\n\n // Merge the sandbox env under per-call env once, up front — every exec\n // transport below (private network, WebSocket lease, E2B lease) receives\n // these options, and none of them route through the process manager.\n const sandboxEnv = this.getEnv();\n const execCallOptions =\n Object.keys(sandboxEnv).length > 0 ? { ...options, env: { ...sandboxEnv, ...options?.env } } : options;\n\n // Wait for the transport to become ready before proceeding. During the\n // sidecar boot window (immediately after start()), concurrent execs all\n // await the same probe promise rather than each independently racing to\n // the lease path — this coalesces the cold-start storm into a single\n // warmup attempt. Once the probe resolves (or times out after\n // TRANSPORT_READY_WAIT_MS), we check the registry and proceed.\n await this._awaitTransportReady();\n\n // Preferred path: dial the in-sandbox sidecar over Railway's private\n // network (~16 ms p50). No GraphQL, no lease mint, no public tcp-proxy.\n // Available only when the in-process address registry has an entry for\n // this sandboxId — populated by start() from the workspace-proxy's\n // create/reattach response when the proxy discloses `instanceUrl`. On\n // any transport failure (connection refused, mid-stream drop, no exit\n // frame) we invalidate the registry entry and fall through to the lease\n // path — application-level failures (sidecar returns 5xx) still fall\n // back for this call but do NOT invalidate the entry. See\n // `.scratch/factory-deploy/issue-platform-sandbox-exec-via-private-network.md`.\n const instanceUrl = this._addressRegistry?.get(this._sandboxId);\n if (instanceUrl) {\n const privateNet = await this._tryExecViaPrivateNetwork(\n instanceUrl,\n fullCommand,\n effectiveTimeout,\n execCallOptions,\n );\n if (privateNet) {\n const privateExit = privateNet.exitCode ?? 124;\n return {\n success: privateExit === 0,\n exitCode: privateExit,\n stdout: privateNet.stdout,\n stderr: privateNet.stderr,\n timedOut: privateNet.timedOut,\n command: fullCommand,\n executionTimeMs: Date.now() - started,\n };\n }\n // Fall through — `_tryExecViaPrivateNetwork` already evicted the\n // registry entry if this was a transport failure.\n }\n\n // Fallback: WebSocket direct-exec via `/exec-lease`. `_runDirectExec`\n // handles single-shot transport retry and throws typed errors on\n // unrecoverable failure: `SandboxDestroyedError` when `/exec-lease`\n // returns 410 (fleet must reprovision), `SandboxExecTransportError`\n // when the WebSocket transport fails twice against a live sandbox,\n // `PlatformApiError` for other `/exec-lease` errors (404/500/501).\n // See ./direct-exec.ts and `docs/factory/direct-sandbox-connection.md`\n // in the Platform repo.\n const result = await this._runDirectExec(fullCommand, effectiveTimeout, execCallOptions);\n // `_runDirectExec` throws on transport failure (see its jsdoc), so a\n // `null` exitCode here can only mean `timedOut: true` — the sandbox\n // never got to send an exit frame because we cut the command short.\n // Use 124 for that (the conventional timeout exit code). We are NOT\n // coercing transport-failure nulls to fake exit codes — those throw.\n const exitCode = result.exitCode ?? 124;\n return {\n success: exitCode === 0,\n exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n timedOut: result.timedOut,\n command: fullCommand,\n executionTimeMs: Date.now() - started,\n };\n }\n\n /**\n * Run a single exec against the direct-exec transport, with one in-flight\n * retry on WebSocket transport failure (socket closed without an `exit`\n * frame and the exec did not time out). The retry mints a fresh lease\n * — the failure could be a stale JWT — and reopens a new WebSocket.\n *\n * Error taxonomy:\n * - **410 on `/exec-lease`** (either attempt) → the sandbox is gone.\n * Nulls the cached `_lease` and `_sandboxId` and throws\n * {@link SandboxDestroyedError}. Callers (typically `SandboxFleet`) must\n * catch this, clear the stale binding, and reprovision + replay.\n * - **Persistent transport failure** (both WS attempts close without an\n * `exit` frame against a live sandbox) → {@link SandboxExecTransportError}\n * with WebSocket close diagnostics.\n * - **Other `PlatformApiError`s** (404/500/501) propagate directly.\n * - **Real command result** (exit code from Railway's exit frame, or\n * `timedOut: true`) returns normally.\n *\n * Returns a result with a real `exitCode` OR `timedOut: true`. Never\n * returns `{ exitCode: null, timedOut: false }` — that case throws.\n */\n private async _runDirectExec(\n fullCommand: string,\n effectiveTimeout: number | undefined,\n options: ExecuteCommandOptions | undefined,\n ): Promise<{ exitCode: number | null; stdout: string; stderr: string; timedOut: boolean }> {\n // Filter undefined values out of the env overlay so we match the\n // Record<string, string> shape execViaLease expects. `ExecuteCommandOptions.env`\n // is NodeJS.ProcessEnv (string | undefined).\n const filteredEnv = options?.env\n ? Object.fromEntries(\n Object.entries(options.env).filter((entry): entry is [string, string] => entry[1] !== undefined),\n )\n : undefined;\n\n let lastResult: Awaited<ReturnType<typeof execViaLease>> | undefined;\n let lastLease: CachedExecLease | undefined;\n let attemptsMade = 0;\n // Two attempts: initial + one retry. On the second attempt we drop the\n // cached lease so we don't reuse a JWT that may itself be the cause of\n // the transport failure — but only if the cache still holds the same\n // lease we just failed against. A concurrent exec sharing this instance\n // may have already cached a fresh, unrelated lease in between, and we\n // must not discard that.\n for (let attempt = 0; attempt < 2; attempt++) {\n if (attempt > 0 && lastLease && this._lease === lastLease) this._lease = null;\n let lease: CachedExecLease;\n try {\n lease = await this._ensureLease();\n } catch (error) {\n // 410 → sandbox has been destroyed. Clear all cached state so a\n // reused instance re-provisions cleanly, then hand off to the fleet\n // layer via a typed error. Other PlatformApiErrors (404/500/501)\n // propagate as-is — those are configuration or platform errors, not\n // a \"reprovision me\" signal.\n if (error instanceof PlatformApiError && error.status === 410) {\n this._lease = null;\n const priorSandboxId = this._sandboxId;\n this._sandboxId = undefined;\n // Reset lifecycle status too: the next `ensureRunning()` must re-run\n // the full start lifecycle (acquisition + `onStart` hook) so a\n // replacement VM is set up, not just leased.\n this.status = 'stopped';\n throw new SandboxDestroyedError(\n `Sandbox ${priorSandboxId ?? '(unknown)'} was destroyed; /exec-lease returned 410`,\n {\n ...(priorSandboxId && { sandboxId: priorSandboxId }),\n command: fullCommand,\n attempts: attempt + 1,\n },\n );\n }\n throw error;\n }\n lastLease = lease;\n attemptsMade = attempt + 1;\n const execOptions = {\n command: fullCommand,\n ...(options?.cwd !== undefined && { cwd: options.cwd }),\n ...(filteredEnv !== undefined && { env: filteredEnv }),\n ...(effectiveTimeout != null && effectiveTimeout > 0 && { timeoutMs: effectiveTimeout }),\n ...(this._webSocketFactory && { webSocketFactory: this._webSocketFactory }),\n };\n const result =\n lease.provider === 'e2b'\n ? await this._e2bExecRunner(lease, execOptions)\n : await execViaLease(lease, execOptions);\n lastResult = result;\n // `null` exitCode with `timedOut: false` means the socket closed\n // without an exit frame — a transport failure (handshake stalled,\n // mid-stream drop, expired token). Any other outcome (real exit code\n // or timed-out) is a valid result and we return it.\n if (result.exitCode !== null || result.timedOut) return result;\n }\n\n // Both attempts failed at the transport layer against a live sandbox.\n // Surface a loud, typed error with close diagnostics so callers can\n // distinguish \"your command failed\" from \"the sandbox transport is\n // broken.\"\n const result = lastResult!;\n const lease = lastLease!;\n // The lease from the failed second attempt is still cached; drop it so\n // the next `executeCommand` doesn't waste its first attempt on the same\n // implicated JWT before minting fresh. Identity-check first so a\n // concurrent exec that has already cached a fresh, unrelated lease\n // isn't collateral-damaged.\n if (this._lease === lease) this._lease = null;\n throw new SandboxExecTransportError(\n `Direct-exec transport failed for sandbox ${this._sandboxId ?? '(unknown)'} after ${attemptsMade} attempt(s)` +\n (result.closeCode !== undefined\n ? ` (close ${result.closeCode}${result.closeReason ? ` ${result.closeReason}` : ''})`\n : ''),\n {\n ...(this._sandboxId && { sandboxId: this._sandboxId }),\n command: fullCommand,\n attempts: attemptsMade,\n opened: result.opened ?? false,\n ...(result.closeCode !== undefined && { closeCode: result.closeCode }),\n ...(result.closeReason !== undefined && { closeReason: result.closeReason }),\n wsEndpoint: lease.wsEndpoint,\n },\n );\n }\n\n /**\n * Try to run the exec against the in-sandbox sidecar over Railway's private\n * network. Returns the result on success (including non-zero exit codes and\n * timeouts — those are real command results, not failures). Returns\n * `undefined` when the caller should fall back to the lease path:\n *\n * - Transport failure (connection refused, mid-stream drop, no `exit`\n * frame). The registry entry is evicted so subsequent execs skip the\n * private-net dial until the sidecar re-registers.\n * - Sidecar answered with a non-2xx HTTP status. Registry is left intact —\n * the address is still valid; something else is wrong (bad request,\n * sidecar bug). Only this specific exec falls back.\n */\n private async _tryExecViaPrivateNetwork(\n instanceUrl: string,\n fullCommand: string,\n effectiveTimeout: number | undefined,\n options: ExecuteCommandOptions | undefined,\n ): Promise<PrivateNetExecResult | undefined> {\n // Match the env-filter dance in `_runDirectExec`: ExecuteCommandOptions.env\n // is NodeJS.ProcessEnv (string | undefined) but the wire body wants a\n // Record<string, string>.\n const filteredEnv = options?.env\n ? Object.fromEntries(\n Object.entries(options.env).filter((entry): entry is [string, string] => entry[1] !== undefined),\n )\n : undefined;\n\n const execOptions: PrivateNetExecOptions = {\n command: fullCommand,\n ...(options?.cwd !== undefined && { cwd: options.cwd }),\n ...(filteredEnv !== undefined && { env: filteredEnv }),\n ...(effectiveTimeout != null && effectiveTimeout > 0 && { timeoutMs: effectiveTimeout }),\n ...(this._privateNetFetch && { fetch: this._privateNetFetch }),\n };\n\n let result: PrivateNetExecResult;\n try {\n result = await execViaPrivateNetwork(instanceUrl, execOptions);\n } catch (error) {\n if (error instanceof PrivateNetExecHttpError) {\n // Application-level failure from a reachable sidecar. Fall back for\n // this call, but do NOT evict the registry entry — future calls\n // should still prefer the private-network path.\n return undefined;\n }\n // Anything else escaping is unexpected (e.g. options validation). Treat\n // it like a transport failure so we don't wedge the caller.\n this._invalidateAddress();\n return undefined;\n }\n\n // A timeout is always the caller's answer, never a lease-fallback trigger:\n // the sidecar may already be running the command, so re-executing on the\n // lease path would double-run non-idempotent work (rm, git push, DB\n // migrations) and return the second result instead of `timedOut: true`.\n // If we never opened the response (pre-headers abort), the address is\n // still evicted so subsequent execs skip a dial we already know is slow —\n // but the timed-out result itself flows back to the caller unchanged.\n if (result.timedOut) {\n if (!result.opened) this._invalidateAddress();\n return result;\n }\n\n // A completed exec (real exit code) is a valid result — hand it back even\n // if exitCode is non-zero. Only evict when the transport itself failed:\n // never opened, or opened without an exit frame. `opened=false` here\n // means connection refused (no timeout to disambiguate).\n const transportFailed = !result.opened || result.exitCode === null;\n if (transportFailed) {\n this._invalidateAddress();\n return undefined;\n }\n\n return result;\n }\n\n /**\n * Evict this sandbox's entry from the address registry after an observed\n * transport failure. The entry stays gone until the next start() re-reads\n * `instanceUrl` from a workspace-proxy response — until then, execs skip\n * the private-net dial and go straight to the lease path.\n */\n private _invalidateAddress(): void {\n if (this._sandboxId) this._addressRegistry?.delete(this._sandboxId);\n }\n\n /**\n * Return a cached exec lease, minting a fresh one when the cache is empty\n * or the JWT is within {@link LEASE_REFRESH_MARGIN_MS} of `expiresAt`.\n *\n * Callers are expected to be on the \"sandbox is running\" path; we don't\n * re-check `_sandboxId` here because `executeCommand` already gated on it.\n */\n private async _ensureLease(): Promise<CachedExecLease> {\n const now = Date.now();\n // Cache hit only when we know the expiry AND we're comfortably before it.\n // A null `expiresAtMs` means the provider didn't disclose a TTL — treat\n // that as \"refresh every call\" rather than \"cache forever\", so a token\n // that turns out to be short-lived can't wedge the sandbox until restart.\n if (this._lease && this._lease.expiresAtMs !== null && this._lease.expiresAtMs - LEASE_REFRESH_MARGIN_MS > now) {\n return this._lease;\n }\n // Coalesce concurrent mints on a cold/expired cache.\n if (this._leaseInFlight) return this._leaseInFlight;\n if (!this._sandboxId) throw new SandboxNotReadyError(this.id);\n const sandboxId = this._sandboxId;\n const inFlight = (async () => {\n const response = await this._client.request(`/sandbox/${encodeURIComponent(sandboxId)}/exec-lease`, {\n method: 'POST',\n });\n const json = (await response.json()) as ExecLeaseResponse;\n const expiresAtMs = json.expiresAt ? Date.parse(json.expiresAt) : null;\n const lease: CachedExecLease = {\n provider: json.provider,\n sandboxId: json.sandboxId,\n providerResourceId: json.providerResourceId,\n jwt: json.jwt,\n wsEndpoint: json.wsEndpoint,\n subprotocol: json.subprotocol,\n expiresAt: json.expiresAt,\n // Guard against `Date.parse` returning NaN for malformed values by\n // treating them as \"no expiry known\", which forces a mint every call\n // rather than silently caching a broken lease forever.\n expiresAtMs: expiresAtMs !== null && !Number.isNaN(expiresAtMs) ? expiresAtMs : null,\n };\n this._lease = lease;\n return lease;\n })();\n this._leaseInFlight = inFlight;\n try {\n return await inFlight;\n } finally {\n // Clear on both success and failure so a failed mint doesn't wedge\n // future callers into awaiting the same rejected promise forever.\n if (this._leaseInFlight === inFlight) this._leaseInFlight = null;\n }\n }\n\n async getInfo(): Promise<SandboxInfo> {\n if (!this._sandboxId) {\n return {\n id: this.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n createdAt: this._createdAt ?? new Date(),\n };\n }\n // Skip the workspace-proxy round-trip when the address registry has an\n // entry for this sandbox — a live entry is proof that start() saw an\n // `instanceUrl` on the create/reattach response and that no exec since\n // has evicted it via a transport failure. Serving `getInfo()` from\n // local state here removes the per-poll `GET /sandbox/:id` hit that\n // otherwise triggers a Railway GraphQL call + `sandboxExec` awk on\n // `/proc/net/if_inet6` inside the proxy.\n //\n // Note: this does NOT probe the sidecar. If the sandbox has been\n // destroyed out-of-band the next exec will fail transport, evict the\n // registry entry, and a subsequent getInfo() will fall through to the\n // proxy below and observe the true status.\n if (this._addressRegistry?.get(this._sandboxId)) {\n return {\n id: this._sandboxId,\n name: this.name,\n provider: this.provider,\n status: this.status,\n createdAt: this._createdAt ?? new Date(),\n metadata: {\n sandboxId: this._sandboxId,\n },\n };\n }\n const response = await this._client.request(`/sandbox/${encodeURIComponent(this._sandboxId)}`);\n const json = (await response.json()) as CreateSandboxResponse;\n return {\n id: json.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n createdAt: json.createdAt ? new Date(json.createdAt) : (this._createdAt ?? new Date()),\n metadata: {\n // The platform assigns its own sandbox id on create (the advisory id\n // sent in the POST body is not honored). Expose it so callers that\n // persist a reattach id (e.g. the Factory sandbox fleet, which reads\n // `metadata.sandboxId`) store the id the proxy actually recognizes\n // instead of the locally generated construction id.\n sandboxId: json.id,\n providerResourceId: json.providerResourceId ?? undefined,\n platformStatus: json.status,\n },\n };\n }\n\n getInstructions(opts?: { requestContext?: RequestContext }): string {\n const defaultInstructions = `Platform sandbox${this._sandboxId ? ` ${this._sandboxId}` : ''}. Execute commands with the sandbox command APIs.`;\n if (typeof this._instructionsOverride === 'function') {\n return this._instructionsOverride({ defaultInstructions, requestContext: opts?.requestContext });\n }\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return defaultInstructions;\n }\n}\n","import type { FilesystemProvider, SandboxProvider } from '@mastra/core/editor';\nimport type { PlatformFilesystemOptions } from './filesystem.js';\nimport { PlatformFilesystem } from './filesystem.js';\nimport type { PlatformSandboxOptions } from './sandbox.js';\nimport { PlatformSandbox } from './sandbox.js';\n\nexport const platformSandboxProvider: SandboxProvider<PlatformSandboxOptions> = {\n id: 'platform',\n name: 'Mastra Platform Sandbox',\n description: 'Environment-scoped sandbox execution through Mastra Platform workspace proxy',\n configSchema: {\n type: 'object',\n properties: {\n accessToken: {\n type: 'string',\n description: 'Mastra Platform access token (falls back to MASTRA_PLATFORM_ACCESS_TOKEN)',\n },\n projectId: { type: 'string', description: 'Platform project ID (falls back to MASTRA_PROJECT_ID)' },\n actingUserId: { type: 'string', description: 'Opaque user subject attributed to sandbox requests' },\n environmentId: { type: 'string', description: 'Platform environment ID (falls back to MASTRA_ENVIRONMENT_ID)' },\n sandboxId: { type: 'string', description: 'Reattach to an existing Platform sandbox by ID' },\n idleTimeoutMinutes: { type: 'number', description: 'Minutes before the sandbox can be destroyed while idle' },\n networkIsolation: {\n type: 'string',\n description: 'Network isolation mode',\n enum: ['ISOLATED', 'PRIVATE'],\n default: 'ISOLATED',\n },\n env: { type: 'object', description: 'Environment variables', additionalProperties: { type: 'string' } },\n timeout: { type: 'number', description: 'Default command timeout in ms' },\n },\n },\n createSandbox: config => new PlatformSandbox(config),\n};\n\nexport const platformFilesystemProvider: FilesystemProvider<PlatformFilesystemOptions> = {\n id: 'platform',\n name: 'Mastra Platform Filesystem',\n description: 'Bucket-backed filesystem access through Mastra Platform workspace proxy',\n configSchema: {\n type: 'object',\n properties: {\n accessToken: {\n type: 'string',\n description: 'Mastra Platform access token (falls back to MASTRA_PLATFORM_ACCESS_TOKEN)',\n },\n projectId: { type: 'string', description: 'Platform project ID (falls back to MASTRA_PROJECT_ID)' },\n bucketName: {\n type: 'string',\n description: 'Platform workspace bucket name (falls back to MASTRA_PLATFORM_BUCKET_NAME)',\n },\n readOnly: { type: 'boolean', description: 'Mount as read-only', default: false },\n },\n },\n createFilesystem: config => new PlatformFilesystem(config),\n};\n","/**\n * In-process `sandboxId → instanceUrl` registry populated by\n * {@link PlatformSandbox.start} from the `instanceUrl` field workspace-proxy\n * includes on create + get responses, and consumed by\n * {@link PlatformSandbox.executeCommand} on the private-network fast path.\n *\n * The registry lives in the same Node process as the `PlatformSandbox`\n * consumer — for shipyard, that is the Mastra runtime deployed from\n * `mastracode/web`. There is no receiver route and no cross-service dance;\n * the address is just a field copied from a response the runtime already\n * receives.\n *\n * State intentionally does not persist:\n *\n * - The IPv6 rotates on every sandbox recreate.\n * - The URL has no meaning after the sandbox is destroyed.\n * - The live sandbox binding, session context, and lease all die with the\n * runtime process; the address dying with them is correct.\n * - The proxy's `environment_sandboxes.instance_url` column is the durable\n * source of truth — a runtime restart re-populates the registry on the\n * next `start()` / reattach from the proxy's response.\n */\n\nimport type { SandboxAddressRegistry } from './sandbox.js';\n\n/**\n * Concrete in-process {@link SandboxAddressRegistry}. Backed by a `Map`; no\n * eviction policy, no TTL — entries live until an observed transport failure\n * calls `delete`, until the sandbox is explicitly destroyed, or until the\n * process exits.\n */\nexport class InProcessSandboxAddressRegistry implements SandboxAddressRegistry {\n readonly #map = new Map<string, string>();\n\n get(sandboxId: string): string | undefined {\n return this.#map.get(sandboxId);\n }\n\n /**\n * Populate or overwrite the address for a sandbox. Called by\n * {@link PlatformSandbox.start} on every fresh provision and every reattach;\n * overwriting is intentional so a re-provision with a fresh IPv6 heals the\n * map without a branch.\n */\n set(sandboxId: string, instanceUrl: string): void {\n this.#map.set(sandboxId, instanceUrl);\n }\n\n delete(sandboxId: string): void {\n this.#map.delete(sandboxId);\n }\n\n /**\n * Test-only introspection. Not part of {@link SandboxAddressRegistry} —\n * production callers must not read the registry as a whole.\n */\n get size(): number {\n return this.#map.size;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["Buffer","#operations","#family","#buildEnvs","#append","#appendOptionalInstall","#map"],"sources":["../src/client.ts","../src/filesystem.ts","../src/template.ts","../src/direct-exec.ts","../src/e2b-exec.ts","../src/private-net-exec.ts","../src/sandbox.ts","../src/repo-template.ts","../src/provider.ts","../src/address-registry.ts"],"sourcesContent":["export interface PlatformClientOptions {\n accessToken?: string;\n projectId?: string;\n actingUserId?: string;\n sandboxProvider?: SandboxProvider;\n /**\n * Advisory correlation id for the factory session driving this client.\n * Sent as `x-mastra-session-id` on every proxy request so proxy-side logs\n * can be joined back to the calling session without a multi-store hand-join\n * (`threadId → sessionId → sandboxId → providerResourceId`). Never used for\n * authorization — the Bearer token remains the only credential.\n */\n sessionId?: string;\n /**\n * Advisory correlation id for the factory thread, sent as\n * `x-mastra-thread-id` when present. See {@link PlatformClientOptions.sessionId}.\n */\n threadId?: string;\n fetch?: typeof fetch;\n}\n\nexport interface PlatformRequestOptions extends RequestInit {\n query?: Record<string, string | number | boolean | undefined>;\n}\n\nexport type SandboxProvider = 'railway' | 'e2b';\n\nconst DEFAULT_PROXY_URL = 'https://workspaces.mastra.ai';\n\n/**\n * Default per-request timeout for calls to the workspace proxy. Applied only\n * when the caller doesn't already pass an `AbortSignal`. Long-running routes\n * (e.g. `POST /sandbox/:id/exec`) pass their own longer signal.\n */\nconst DEFAULT_REQUEST_TIMEOUT_MS = 60_000;\n\nexport function requireOption(value: string | undefined, name: string): string {\n if (!value) throw new Error(`${name} is required`);\n return value;\n}\n\nfunction resolveSandboxProvider(value: string | undefined): SandboxProvider {\n const provider = value?.trim() || 'e2b';\n if (provider !== 'railway' && provider !== 'e2b') {\n throw new Error('SANDBOX_PROVIDER must be either \"railway\" or \"e2b\"');\n }\n return provider;\n}\n\nexport function resolvePlatformOptions(options: PlatformClientOptions) {\n const environmentSandboxProvider = process.env.SANDBOX_PROVIDER?.trim();\n const configuredSandboxProvider = options.sandboxProvider ?? environmentSandboxProvider;\n\n return {\n accessToken: requireOption(options.accessToken ?? process.env.MASTRA_PLATFORM_ACCESS_TOKEN, 'accessToken'),\n projectId: requireOption(options.projectId ?? process.env.MASTRA_PROJECT_ID, 'projectId'),\n actingUserId: options.actingUserId?.trim() || undefined,\n proxyUrl: (process.env.MASTRA_WORKSPACE_PROXY_URL ?? DEFAULT_PROXY_URL).replace(/\\/$/, ''),\n sandboxProvider: resolveSandboxProvider(configuredSandboxProvider),\n sessionId: options.sessionId,\n threadId: options.threadId,\n fetch: options.fetch ?? fetch,\n };\n}\n\n/**\n * Structured error shape returned by the workspace proxy. All routes emit\n * `{ error: { message, type } }` on failure — see servers/workspace-proxy in\n * the Platform repo. Kept as a wire-level type so callers can switch on\n * `error.code` without re-parsing `error.body`.\n */\nexport interface PlatformProxyError {\n message: string;\n /** Machine-readable error kind, e.g. `not_found`, `invalid_request`, `authentication_error`. */\n type: string;\n}\n\nfunction parseProxyError(body: string): PlatformProxyError | undefined {\n if (!body) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n return undefined;\n }\n if (typeof parsed !== 'object' || parsed === null) return undefined;\n const err = (parsed as { error?: unknown }).error;\n if (typeof err !== 'object' || err === null) return undefined;\n const { message, type } = err as { message?: unknown; type?: unknown };\n if (typeof message !== 'string' || typeof type !== 'string') return undefined;\n return { message, type };\n}\n\nexport class PlatformApiError extends Error {\n readonly status: number;\n readonly body: string;\n /** Machine-readable proxy error kind (e.g. `not_found`), when the response body matches `{ error: { message, type } }`. */\n readonly code: string | undefined;\n /** Human-readable proxy error message, when the response body matches `{ error: { message, type } }`. */\n readonly proxyMessage: string | undefined;\n\n constructor(status: number, body: string) {\n const parsed = parseProxyError(body);\n const summary = parsed ? `${parsed.type}: ${parsed.message}` : body;\n super(`Platform proxy request failed with ${status}${summary ? `: ${summary}` : ''}`);\n this.name = 'PlatformApiError';\n this.status = status;\n this.body = body;\n this.code = parsed?.type;\n this.proxyMessage = parsed?.message;\n }\n}\n\nexport class PlatformClient {\n readonly accessToken: string;\n readonly projectId: string;\n readonly actingUserId: string | undefined;\n readonly proxyUrl: string;\n readonly sandboxProvider: SandboxProvider;\n /** Advisory session correlation id — see {@link PlatformClientOptions.sessionId}. */\n readonly sessionId: string | undefined;\n /** Advisory thread correlation id — see {@link PlatformClientOptions.threadId}. */\n readonly threadId: string | undefined;\n readonly fetch: typeof fetch;\n\n constructor(options: PlatformClientOptions) {\n const resolved = resolvePlatformOptions(options);\n this.accessToken = resolved.accessToken;\n this.projectId = resolved.projectId;\n this.actingUserId = resolved.actingUserId;\n this.proxyUrl = resolved.proxyUrl;\n this.sandboxProvider = resolved.sandboxProvider;\n this.sessionId = resolved.sessionId;\n this.threadId = resolved.threadId;\n this.fetch = resolved.fetch;\n }\n\n async request(path: string, options: PlatformRequestOptions = {}): Promise<Response> {\n return this.requestAtPath(`/${this.sandboxProvider}`, path, options);\n }\n\n async requestProvider(path: string, options: PlatformRequestOptions = {}): Promise<Response> {\n return this.requestAtPath(`/${this.sandboxProvider}`, path, options);\n }\n\n private async requestAtPath(providerPath: string, path: string, options: PlatformRequestOptions): Promise<Response> {\n const url = new URL(`${this.proxyUrl}/v1${providerPath}/projects/${encodeURIComponent(this.projectId)}${path}`);\n for (const [key, value] of Object.entries(options.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value));\n }\n\n const headers = new Headers(options.headers);\n headers.set('authorization', `Bearer ${this.accessToken}`);\n if (this.actingUserId) headers.set('x-acting-user-id', this.actingUserId);\n // Advisory correlation headers — the proxy folds them into its log lines\n // so proxy-side events can be joined back to the calling factory session\n // without a cross-store hand-join. Unknown headers are passthrough for\n // older proxies; these are never used for authorization.\n if (this.sessionId) headers.set('x-mastra-session-id', this.sessionId);\n if (this.threadId) headers.set('x-mastra-thread-id', this.threadId);\n\n // Strip our helper-only field so the underlying fetch sees a valid RequestInit.\n const { query: _query, ...fetchOptions } = options;\n // Apply a default timeout only when the caller didn't already supply an\n // AbortSignal — long-running routes (exec) provide their own longer signal.\n const signal = fetchOptions.signal ?? AbortSignal.timeout(DEFAULT_REQUEST_TIMEOUT_MS);\n const response = await this.fetch(url, { ...fetchOptions, headers, signal });\n if (!response.ok) {\n throw new PlatformApiError(response.status, await response.text());\n }\n return response;\n }\n}\n","import { Buffer } from 'node:buffer';\nimport nodePath from 'node:path';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type {\n CopyOptions,\n FileContent,\n FileEntry,\n FileStat,\n FilesystemIcon,\n FilesystemInfo,\n InstructionsOption,\n ListOptions,\n MastraFilesystemOptions,\n ProviderStatus,\n ReadOptions,\n RemoveOptions,\n WriteOptions,\n} from '@mastra/core/workspace';\nimport { FileExistsError, FileNotFoundError, MastraFilesystem, WorkspaceReadOnlyError } from '@mastra/core/workspace';\nimport type { PlatformClientOptions } from './client.js';\nimport { PlatformClient } from './client.js';\n\ninterface ProxyListResponse {\n contents?: Array<{ key?: string; size?: number; lastModified?: string }>;\n commonPrefixes?: string[];\n}\n\nexport interface PlatformFilesystemOptions extends PlatformClientOptions, MastraFilesystemOptions {\n id?: string;\n bucketName?: string;\n readOnly?: boolean;\n displayName?: string;\n icon?: FilesystemIcon;\n description?: string;\n instructions?: InstructionsOption;\n}\n\nfunction normalizePath(input: string): string {\n if (!input || input === '.') return '/';\n let normalized = input.startsWith('/') ? input : `/${input}`;\n normalized = nodePath.posix.normalize(normalized);\n return normalized === '.' ? '/' : normalized;\n}\n\nfunction keyFromPath(path: string): string {\n const normalized = normalizePath(path);\n return normalized === '/' ? '' : normalized.slice(1);\n}\n\n/**\n * Encode each `/`-delimited segment of an object key with `encodeURIComponent`\n * so reserved URL characters (`?`, `#`, `%`, `&`, `+`, spaces, etc.) are\n * treated as part of the key instead of URL syntax. Kept segment-aware so\n * `/` continues to act as a path separator on the wire.\n */\nfunction encodeKeyPath(key: string): string {\n return key.split('/').map(encodeURIComponent).join('/');\n}\n\nfunction nameFromPath(path: string): string {\n const normalized = normalizePath(path);\n if (normalized === '/') return '';\n return normalized.slice(normalized.lastIndexOf('/') + 1);\n}\n\nfunction contentToBody(content: FileContent): string | Buffer {\n if (typeof content === 'string') return content;\n return Buffer.from(content);\n}\n\nfunction headerDate(headers: Headers, name: string): Date {\n const value = headers.get(name);\n return value ? new Date(value) : new Date(0);\n}\n\nfunction headerSize(headers: Headers): number {\n const value = headers.get('content-length');\n return value ? Number(value) : 0;\n}\n\nfunction isNotFound(error: unknown): boolean {\n return typeof error === 'object' && error !== null && 'status' in error && error.status === 404;\n}\n\nexport class PlatformFilesystem extends MastraFilesystem {\n readonly id: string;\n readonly name = 'PlatformFilesystem';\n readonly provider = 'platform';\n readonly readOnly?: boolean;\n readonly displayName?: string;\n readonly icon: FilesystemIcon;\n readonly description?: string;\n status: ProviderStatus = 'pending';\n\n private readonly _client: PlatformClient;\n private readonly _bucketName: string;\n private readonly _instructionsOverride?: InstructionsOption;\n\n constructor(options: PlatformFilesystemOptions = {}) {\n super({ ...options, name: 'PlatformFilesystem' });\n this.id = options.id ?? this.generateId();\n this._bucketName = options.bucketName ?? process.env.MASTRA_PLATFORM_BUCKET_NAME ?? '';\n if (!this._bucketName) throw new Error('bucketName is required');\n this.readOnly = options.readOnly;\n this.displayName = options.displayName;\n this.icon = options.icon ?? 'cloud';\n this.description = options.description;\n this._instructionsOverride = options.instructions;\n this._client = new PlatformClient(options);\n }\n\n private generateId(): string {\n return `platform-fs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n async readFile(path: string, options?: ReadOptions): Promise<string | Buffer> {\n await this.ensureReady();\n let response: Response;\n try {\n response = await this._client.request(\n `/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`,\n );\n } catch (error) {\n if (isNotFound(error)) throw new FileNotFoundError(path);\n throw error;\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n return options?.encoding ? buffer.toString(options.encoding) : buffer;\n }\n\n async writeFile(path: string, content: FileContent, options?: WriteOptions): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('writeFile');\n const headers: Record<string, string> = {};\n if (options?.mimeType) headers['content-type'] = options.mimeType;\n if (options?.overwrite === false) headers['if-none-match'] = '*';\n try {\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`, {\n method: 'PUT',\n headers,\n body: contentToBody(content),\n });\n } catch (error) {\n if (typeof error === 'object' && error !== null && 'status' in error && error.status === 412) {\n throw new FileExistsError(path);\n }\n throw error;\n }\n }\n\n /**\n * Append bytes to a file.\n *\n * **Not atomic.** Object storage behind the workspace proxy has no native\n * append or compare-and-swap primitive, so this implementation is a\n * read-modify-write: it reads the current contents, concatenates the new\n * bytes, and PUTs the whole object back. Concurrent `appendFile` calls to\n * the same path can overwrite each other's writes (\"last write wins\").\n * Use `writeFile` with distinct keys for concurrent writers.\n */\n async appendFile(path: string, content: FileContent): Promise<void> {\n const existing = (await this.exists(path)) ? await this.readFile(path) : Buffer.alloc(0);\n await this.writeFile(\n path,\n Buffer.concat([Buffer.isBuffer(existing) ? existing : Buffer.from(existing), Buffer.from(content)]),\n );\n }\n\n async deleteFile(path: string, options?: RemoveOptions): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('deleteFile');\n try {\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`, {\n method: 'DELETE',\n query: { recursive: options?.recursive },\n });\n } catch (error) {\n if (isNotFound(error) && options?.force) return;\n if (isNotFound(error)) throw new FileNotFoundError(path);\n throw error;\n }\n }\n\n async copyFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('copyFile');\n // The workspace proxy's `?op=copy` route always overwrites the destination;\n // there's no conditional wire field to prevent it. Reject the option\n // explicitly instead of silently overwriting when the caller asked us not to.\n if (options?.overwrite === false) {\n throw new Error('PlatformFilesystem.copyFile does not support overwrite: false — the proxy always overwrites.');\n }\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(src))}`, {\n method: 'POST',\n query: { op: 'copy' },\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ destination: keyFromPath(dest) }),\n });\n }\n\n async moveFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('moveFile');\n // Same rationale as copyFile: `?op=rename` always overwrites.\n if (options?.overwrite === false) {\n throw new Error('PlatformFilesystem.moveFile does not support overwrite: false — the proxy always overwrites.');\n }\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(src))}`, {\n method: 'POST',\n query: { op: 'rename' },\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ destination: keyFromPath(dest) }),\n });\n }\n\n async mkdir(path: string, _options?: { recursive?: boolean }): Promise<void> {\n await this.ensureReady();\n if (this.readOnly) throw new WorkspaceReadOnlyError('mkdir');\n await this._client.request(`/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`, {\n method: 'POST',\n query: { op: 'mkdir' },\n });\n }\n\n async rmdir(path: string, options?: RemoveOptions): Promise<void> {\n await this.deleteFile(path.endsWith('/') ? path : `${path}/`, { recursive: true, force: options?.force });\n }\n\n async readdir(path: string, options?: ListOptions): Promise<FileEntry[]> {\n await this.ensureReady();\n const prefix = keyFromPath(path);\n const response = await this._client.request(\n `/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(prefix)}`,\n {\n query: {\n delimiter: options?.recursive ? undefined : '/',\n prefix: prefix ? `${prefix.replace(/\\/$/, '')}/` : undefined,\n },\n },\n );\n const json = (await response.json()) as ProxyListResponse;\n return [\n ...(json.commonPrefixes ?? []).map(prefix => ({\n name: nameFromPath(prefix.replace(/\\/$/, '')),\n type: 'directory' as const,\n })),\n ...(json.contents ?? [])\n .filter(object => object.key && !object.key.endsWith('/'))\n .map(object => ({\n name: nameFromPath(object.key!),\n type: 'file' as const,\n size: object.size,\n })),\n ].filter(\n entry => !options?.extension || entry.type === 'directory' || matchesExtension(entry.name, options.extension),\n );\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n await this.stat(path);\n return true;\n } catch (error) {\n if (isNotFound(error) || error instanceof FileNotFoundError) return false;\n throw error;\n }\n }\n\n async stat(path: string): Promise<FileStat> {\n await this.ensureReady();\n const normalized = normalizePath(path);\n if (normalized === '/') {\n return { name: '', path: '/', type: 'directory', size: 0, createdAt: new Date(0), modifiedAt: new Date(0) };\n }\n let response: Response;\n try {\n response = await this._client.request(\n `/fs/${encodeURIComponent(this._bucketName)}/${encodeKeyPath(keyFromPath(path))}`,\n {\n method: 'HEAD',\n },\n );\n } catch (error) {\n if (isNotFound(error)) throw new FileNotFoundError(path);\n throw error;\n }\n return {\n name: nameFromPath(path),\n path: normalized,\n type: normalized.endsWith('/') ? 'directory' : 'file',\n size: headerSize(response.headers),\n createdAt: headerDate(response.headers, 'last-modified'),\n modifiedAt: headerDate(response.headers, 'last-modified'),\n mimeType: response.headers.get('content-type') ?? undefined,\n };\n }\n\n realpath(path: string): Promise<string> {\n return Promise.resolve(normalizePath(path));\n }\n\n getInstructions(opts?: { requestContext?: RequestContext }): string {\n const defaultInstructions = `Platform filesystem backed by Mastra Platform bucket ${this._bucketName}. Use absolute workspace paths.`;\n if (typeof this._instructionsOverride === 'function') {\n return this._instructionsOverride({ defaultInstructions, requestContext: opts?.requestContext });\n }\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return defaultInstructions;\n }\n\n getInfo(): FilesystemInfo<{ bucketName: string; displayName?: string; description?: string }> {\n return {\n id: this.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n readOnly: this.readOnly,\n icon: this.icon,\n metadata: {\n bucketName: this._bucketName,\n ...(this.displayName && { displayName: this.displayName }),\n ...(this.description && { description: this.description }),\n },\n };\n }\n}\n\nfunction matchesExtension(name: string, extension: string | string[]): boolean {\n const extensions = Array.isArray(extension) ? extension : [extension];\n return extensions.some(ext => name.endsWith(ext));\n}\n","import { PlatformClient, type PlatformClientOptions } from './client.js';\n\nexport type JsonPrimitive = null | boolean | number | string;\nexport type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };\n\nexport type SandboxTemplateMethod =\n | 'cpuCount'\n | 'memoryMB'\n | 'runCmd'\n | 'setWorkdir'\n | 'setEnvs'\n | 'aptInstall'\n | 'pipInstall'\n | 'npmInstall';\n\nexport interface SandboxTemplateOperation {\n method: SandboxTemplateMethod;\n args: JsonValue[];\n}\n\nexport interface SerializedSandboxTemplate {\n schemaVersion: 1;\n operations: SandboxTemplateOperation[];\n /**\n * Optional caller-supplied family key that groups successive builds of\n * the \"same thing\" — e.g. the same repository+workdir across commits,\n * the same recipe across parameter tweaks. For E2B, Platform MAY boot\n * from a prior member with matching effective CPU and memory while the\n * exact template builds in the background. Railway doesn't use family\n * fallback. The server strips this key from exact content identity, so\n * definitions differing only by family share one cache slot; different\n * operations still produce distinct exact builds. Family drives stale\n * lookup separately. Set by builders like `createRepoTemplate`; clients\n * rarely set it directly.\n */\n family?: string;\n}\n\nexport interface AptInstallOptions {\n noInstallRecommends?: boolean;\n fixMissing?: boolean;\n}\n\nexport interface PipInstallOptions {\n g?: boolean;\n}\n\nexport interface NpmInstallOptions {\n g?: boolean;\n dev?: boolean;\n}\n\nexport interface SetEnvsOptions {\n /**\n * Keep these values outside the serialized definition, content identity,\n * and persistent template record. They are supplied only to the live\n * provider build request.\n */\n ephemeral?: boolean;\n}\n\nexport interface SandboxTemplateBuildOptions extends PlatformClientOptions {\n environmentId?: string;\n}\n\nexport interface SandboxTemplateBuildResult {\n status: 'ready' | 'pending' | 'failed';\n templateId: string;\n retryAfterMs?: number;\n error?: string;\n}\n\nexport interface SandboxTemplateBuilder {\n /**\n * Set the E2B template's CPU count. Defaults to 2. Railway ignores this\n * setting because its sandbox template API doesn't expose resource limits.\n */\n cpuCount(count: number): SandboxTemplateBuilder;\n /**\n * Set the E2B template's memory in megabytes. Defaults to 1,024. Railway\n * ignores this setting because its sandbox template API doesn't expose\n * resource limits.\n */\n memoryMB(memoryMB: number): SandboxTemplateBuilder;\n /** Start or reuse this template's provider build without provisioning a sandbox. */\n build(options?: SandboxTemplateBuildOptions): Promise<SandboxTemplateBuildResult>;\n runCmd(command: string | string[]): SandboxTemplateBuilder;\n setWorkdir(path: string): SandboxTemplateBuilder;\n /**\n * Set build environment values. Ephemeral values are sent outside the\n * serialized definition, are unavailable at runtime, and override serialized\n * values with the same key.\n */\n setEnvs(envs: Record<string, string>, options?: SetEnvsOptions): SandboxTemplateBuilder;\n aptInstall(packages: string | string[], options?: AptInstallOptions): SandboxTemplateBuilder;\n pipInstall(packages?: string | string[], options?: PipInstallOptions): SandboxTemplateBuilder;\n npmInstall(packages?: string | string[], options?: NpmInstallOptions): SandboxTemplateBuilder;\n /**\n * Attach a family key that groups successive builds of the same\n * underlying thing (e.g. a repository+workdir across commits). For E2B,\n * Platform can boot from a prior build with matching effective CPU and\n * memory while the exact template builds. Railway doesn't use family\n * fallback. Excluded from exact content identity — definitions differing\n * only by family share one cache slot, while different operations remain\n * distinct exact builds. Family drives stale lookup separately.\n */\n withFamily(family: string): SandboxTemplateBuilder;\n}\n\nconst SERIALIZE_TEMPLATE = Symbol('serializeTemplate');\nconst GET_TEMPLATE_BUILD_ENVS = Symbol('getTemplateBuildEnvs');\nconst MAX_OPERATIONS = 256;\nconst MAX_SERIALIZED_BYTES = 256 * 1024;\nconst MAX_STRING_LENGTH = 32 * 1024;\nconst MAX_COLLECTION_ITEMS = 512;\n\nconst MAX_FAMILY_LENGTH = 200;\n\nclass SerializableSandboxTemplateBuilder implements SandboxTemplateBuilder {\n readonly #operations: readonly SandboxTemplateOperation[];\n readonly #family: string | undefined;\n readonly #buildEnvs: Readonly<Record<string, string>>;\n\n constructor(\n operations: readonly SandboxTemplateOperation[] = [],\n family?: string,\n buildEnvs: Readonly<Record<string, string>> = {},\n ) {\n this.#operations = operations;\n this.#family = family;\n this.#buildEnvs = buildEnvs;\n }\n\n cpuCount(count: number): SandboxTemplateBuilder {\n return this.#append('cpuCount', [validateResourceValue(count, 'count')]);\n }\n\n memoryMB(memoryMB: number): SandboxTemplateBuilder {\n return this.#append('memoryMB', [validateResourceValue(memoryMB, 'memoryMB')]);\n }\n\n async build(options: SandboxTemplateBuildOptions = {}): Promise<SandboxTemplateBuildResult> {\n return buildSandboxTemplate(this, options);\n }\n\n runCmd(command: string | string[]): SandboxTemplateBuilder {\n return this.#append('runCmd', [validateStringOrStrings(command, 'command')]);\n }\n\n setWorkdir(path: string): SandboxTemplateBuilder {\n return this.#append('setWorkdir', [validateString(path, 'path')]);\n }\n\n setEnvs(envs: Record<string, string>, options?: SetEnvsOptions): SandboxTemplateBuilder {\n const copy = validateStringRecord(envs, 'envs', 'environment variable');\n const validatedOptions = options === undefined ? undefined : validateBooleanOptions(options, ['ephemeral']);\n if (validatedOptions?.ephemeral === true) {\n return new SerializableSandboxTemplateBuilder(this.#operations, this.#family, {\n ...this.#buildEnvs,\n ...copy,\n });\n }\n return this.#append('setEnvs', [copy]);\n }\n\n aptInstall(packages: string | string[], options?: AptInstallOptions): SandboxTemplateBuilder {\n const args: JsonValue[] = [validateStringOrStrings(packages, 'packages')];\n if (options !== undefined) args.push(validateBooleanOptions(options, ['noInstallRecommends', 'fixMissing']));\n return this.#append('aptInstall', args);\n }\n\n pipInstall(packages?: string | string[], options?: PipInstallOptions): SandboxTemplateBuilder {\n return this.#appendOptionalInstall('pipInstall', packages, options, ['g']);\n }\n\n npmInstall(packages?: string | string[], options?: NpmInstallOptions): SandboxTemplateBuilder {\n return this.#appendOptionalInstall('npmInstall', packages, options, ['g', 'dev']);\n }\n\n withFamily(family: string): SandboxTemplateBuilder {\n if (typeof family !== 'string' || family.length === 0) {\n throw new TypeError('family must be a non-empty string');\n }\n if (family.length > MAX_FAMILY_LENGTH) {\n throw new RangeError(`family cannot exceed ${MAX_FAMILY_LENGTH} characters`);\n }\n assertSerializedSize(this.#operations, family);\n return new SerializableSandboxTemplateBuilder(this.#operations, family, this.#buildEnvs);\n }\n\n [GET_TEMPLATE_BUILD_ENVS](): Record<string, string> | undefined {\n return Object.keys(this.#buildEnvs).length > 0 ? { ...this.#buildEnvs } : undefined;\n }\n\n [SERIALIZE_TEMPLATE](): SerializedSandboxTemplate {\n return {\n schemaVersion: 1,\n operations: this.#operations.map(operation => ({\n method: operation.method,\n args: cloneJson(operation.args),\n })),\n ...(this.#family !== undefined && { family: this.#family }),\n };\n }\n\n #appendOptionalInstall(\n method: 'pipInstall' | 'npmInstall',\n packages: string | string[] | undefined,\n options: PipInstallOptions | NpmInstallOptions | undefined,\n optionKeys: readonly string[],\n ): SandboxTemplateBuilder {\n const args: JsonValue[] = [];\n if (packages !== undefined) args.push(validateStringOrStrings(packages, 'packages'));\n if (options !== undefined) {\n if (packages === undefined) args.push(null);\n args.push(validateBooleanOptions(options, optionKeys));\n }\n return this.#append(method, args);\n }\n\n #append(method: SandboxTemplateMethod, args: JsonValue[]): SandboxTemplateBuilder {\n if (this.#operations.length >= MAX_OPERATIONS) {\n throw new RangeError(`Sandbox template cannot contain more than ${MAX_OPERATIONS} operations`);\n }\n\n const operation = { method, args: cloneJson(args) } satisfies SandboxTemplateOperation;\n const operations = [...this.#operations, operation];\n assertSerializedSize(operations, this.#family);\n\n return new SerializableSandboxTemplateBuilder(operations, this.#family, this.#buildEnvs);\n }\n}\n\nfunction assertSerializedSize(operations: readonly SandboxTemplateOperation[], family: string | undefined): void {\n const serialized = JSON.stringify({\n schemaVersion: 1,\n operations,\n ...(family !== undefined && { family }),\n });\n if (new TextEncoder().encode(serialized).byteLength > MAX_SERIALIZED_BYTES) {\n throw new RangeError(`Serialized sandbox template cannot exceed ${MAX_SERIALIZED_BYTES} bytes`);\n }\n}\n\nexport function Template(): SandboxTemplateBuilder {\n return new SerializableSandboxTemplateBuilder();\n}\n\nfunction isSandboxTemplateBuilder(value: unknown): value is SerializableSandboxTemplateBuilder {\n return value instanceof SerializableSandboxTemplateBuilder;\n}\n\nexport function serializeSandboxTemplate(template: SandboxTemplateBuilder): SerializedSandboxTemplate {\n if (!isSandboxTemplateBuilder(template)) throw new TypeError('template must be created with Template()');\n return template[SERIALIZE_TEMPLATE]();\n}\n\nexport function getSandboxTemplateBuildEnvs(template: SandboxTemplateBuilder): Record<string, string> | undefined {\n if (!isSandboxTemplateBuilder(template)) throw new TypeError('template must be created with Template()');\n return template[GET_TEMPLATE_BUILD_ENVS]();\n}\n\nasync function buildSandboxTemplate(\n template: SandboxTemplateBuilder,\n options: SandboxTemplateBuildOptions,\n): Promise<SandboxTemplateBuildResult> {\n const environmentId = options.environmentId ?? process.env.MASTRA_ENVIRONMENT_ID;\n if (!environmentId) {\n throw new Error('environmentId is required. Pass it or set MASTRA_ENVIRONMENT_ID.');\n }\n\n const client = new PlatformClient(options);\n const templateBuildEnvs = getSandboxTemplateBuildEnvs(template);\n const response = await client.requestProvider('/sandbox/templates/builds', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n environmentId,\n templateDefinition: serializeSandboxTemplate(template),\n ...(templateBuildEnvs !== undefined && { templateBuildEnvs }),\n }),\n });\n return (await response.json()) as SandboxTemplateBuildResult;\n}\n\nfunction validateResourceValue(value: unknown, name: string): number {\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value <= 0) {\n throw new TypeError(`${name} must be a positive safe integer`);\n }\n return value;\n}\n\nfunction validateString(value: unknown, name: string, allowEmpty = false): string {\n if (typeof value !== 'string') throw new TypeError(`${name} must be a string`);\n if (!allowEmpty && value.length === 0) throw new TypeError(`${name} must not be empty`);\n if (value.length > MAX_STRING_LENGTH) {\n throw new RangeError(`${name} cannot exceed ${MAX_STRING_LENGTH} characters`);\n }\n return value;\n}\n\nfunction validateStringOrStrings(value: unknown, name: string): string | string[] {\n if (typeof value === 'string') return validateString(value, name);\n if (!Array.isArray(value)) throw new TypeError(`${name} must be a string or an array of strings`);\n assertCollectionSize(value.length, name);\n if (value.length === 0) throw new TypeError(`${name} must not be empty`);\n return Array.from(value, (item, index) => validateString(item, `${name}[${index}]`));\n}\n\nfunction validateStringRecord(value: unknown, name: string, entryName: string): Record<string, string> {\n assertPlainObject(value, name);\n const entries = Object.entries(value);\n assertCollectionSize(entries.length, name);\n return Object.fromEntries(\n entries.map(([key, item]) => [\n validateString(key, `${entryName} name`),\n validateString(item, `${entryName} ${key}`, true),\n ]),\n );\n}\n\nfunction validateBooleanOptions(value: unknown, keys: readonly string[]): Record<string, boolean> {\n assertPlainObject(value, 'options');\n const options = value as Record<string, unknown>;\n const unknownKey = Object.keys(options).find(key => !keys.includes(key));\n if (unknownKey) throw new TypeError(`Unsupported option: ${unknownKey}`);\n\n const copy: Record<string, boolean> = {};\n for (const key of keys) {\n const option = options[key];\n if (option === undefined) continue;\n if (typeof option !== 'boolean') throw new TypeError(`${key} must be a boolean`);\n copy[key] = option;\n }\n return copy;\n}\n\nfunction assertPlainObject(value: unknown, name: string): asserts value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new TypeError(`${name} must be a plain object`);\n }\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError(`${name} must be a plain object`);\n }\n}\n\nfunction assertCollectionSize(size: number, name: string): void {\n if (size > MAX_COLLECTION_ITEMS) {\n throw new RangeError(`${name} cannot contain more than ${MAX_COLLECTION_ITEMS} items`);\n }\n}\n\nfunction cloneJson<T extends JsonValue>(value: T): T {\n if (Array.isArray(value)) return value.map(item => cloneJson(item)) as T;\n if (typeof value === 'object' && value !== null) {\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, cloneJson(item)])) as T;\n }\n if (typeof value === 'number' && !Number.isFinite(value)) {\n throw new TypeError('Sandbox template values must contain only finite numbers');\n }\n return value;\n}\n","/**\n * Direct exec client — opens Railway's tcp-proxy exec WebSocket directly using\n * a short-lived JWT minted by the workspace proxy's exec-lease endpoint. This\n * removes the platform data plane from the exec stdout/stderr path entirely\n * (see `docs/factory/direct-sandbox-connection.md` in the Platform repo),\n * cutting payload-scaled Cloud Run egress and RTT for commands like\n * `pnpm install` that stream tens of MB of output.\n *\n * The frame protocol below mirrors `connectExecWs()` in `railway@3.5.5`\n * (`workspaces/railway/node_modules/railway/dist/index.js`). The `railway`\n * SDK's version is pinned on both sides (platform + here); a version bump\n * signals the protocol may have drifted and this module must be revisited.\n */\n\n/** Byte-0 tag on binary WS frames for stdout output. */\nconst STDOUT_FRAME = 1;\n/** Byte-0 tag on binary WS frames for stderr output. */\nconst STDERR_FRAME = 3;\n/**\n * Upper bound on how long we'll wait for the WebSocket to open when the\n * caller didn't supply a `timeoutMs`. Guards against a stalled TLS/WS\n * handshake leaving the promise unresolved forever. Not applied once the\n * socket has opened — a caller with no timeout has opted in to unbounded\n * command runtime, just not to unbounded connection setup.\n */\nconst HANDSHAKE_DEADLINE_MS = 30_000;\n\n/**\n * Minimal WebSocket surface this module depends on. Matches both the browser\n * `WebSocket` global and Node 22+'s built-in `WebSocket`. Extracted so tests\n * can inject a fake without pulling in `ws` or jsdom.\n */\nexport interface DirectExecWebSocket {\n binaryType: 'blob' | 'arraybuffer';\n onopen: ((event: unknown) => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n onclose: ((event: { code: number; reason: string }) => void) | null;\n onerror: ((event: unknown) => void) | null;\n send(data: string): void;\n close(code?: number, reason?: string): void;\n}\n\n/**\n * Factory that opens a WebSocket to `endpoint` with the given subprotocols.\n * Defaults to the global `WebSocket` when omitted, which works on Node 22+\n * (the package's minimum) and in the browser. Tests inject a fake here.\n */\nexport type DirectExecWebSocketFactory = (endpoint: string, subprotocols: string[]) => DirectExecWebSocket;\n\n/** Lease payload returned by `POST /v1/:provider/projects/:projectId/sandbox/:sandboxId/exec-lease`. */\nexport interface ExecLease {\n jwt: string;\n wsEndpoint: string;\n subprotocol: string;\n /** ISO-8601 UTC. Null when the provider issues a JWT without an `exp` claim. */\n expiresAt: string | null;\n}\n\n/** Inputs to a direct exec invocation. Mirrors the shape of the `/exec` route body. */\nexport interface DirectExecOptions {\n command: string;\n cwd?: string;\n env?: Record<string, string>;\n /**\n * Wall-clock cap for the exec. When elapsed, we close the socket and\n * return `{timedOut: true, exitCode: 124}` matching the semantics of the\n * proxy's `/exec` route.\n */\n timeoutMs?: number;\n onStdout?: (chunk: string) => void;\n onStderr?: (chunk: string) => void;\n /** Injected for tests. Defaults to `globalThis.WebSocket`. */\n webSocketFactory?: DirectExecWebSocketFactory;\n}\n\n/**\n * Result of a direct exec. Shape matches the workspace-proxy `/exec` response\n * so the caller (`PlatformSandbox.executeCommand`) can hand it back with no\n * translation.\n *\n * `exitCode` is `null` when the socket closed without an `exit` frame AND the\n * exec did not time out (rare — usually a mid-stream network drop). Callers\n * currently coerce `null` to `1` upstream; kept nullable here to preserve the\n * distinction for future observability.\n */\nexport interface DirectExecResult {\n exitCode: number | null;\n stdout: string;\n stderr: string;\n truncated: boolean;\n timedOut: boolean;\n /**\n * WebSocket close metadata. Populated on any close (normal or transport\n * failure). `opened` distinguishes handshake failures (never opened) from\n * mid-stream drops. Callers use this for diagnostic logging; not part of\n * the CommandResult contract.\n */\n closeCode?: number;\n closeReason?: string;\n opened?: boolean;\n}\n\nconst DEFAULT_WS_FACTORY: DirectExecWebSocketFactory = (endpoint, subprotocols) => {\n const WS = (globalThis as { WebSocket?: unknown }).WebSocket as\n | (new (url: string, protocols: string[]) => DirectExecWebSocket)\n | undefined;\n if (!WS) {\n throw new Error(\n 'Direct exec requires a WebSocket implementation. Node 22+ provides one globally; on older runtimes, pass webSocketFactory explicitly.',\n );\n }\n return new WS(endpoint, subprotocols);\n};\n\n/**\n * Open the provider exec WebSocket using `lease`, run `command`, and resolve\n * with the accumulated stdout/stderr + exit code. See the module docstring\n * for the wire protocol reference.\n *\n * The client sends `stdin_close` immediately after `init_exec`, matching the\n * SDK's own one-shot exec behavior — we never stream stdin from the caller.\n */\nexport function execViaLease(lease: ExecLease, options: DirectExecOptions): Promise<DirectExecResult> {\n const factory = options.webSocketFactory ?? DEFAULT_WS_FACTORY;\n const stdoutDecoder = new TextDecoder();\n const stderrDecoder = new TextDecoder();\n\n return new Promise<DirectExecResult>(resolve => {\n let stdout = '';\n let stderr = '';\n let exitCode: number | null = null;\n let timedOut = false;\n let settled = false;\n let opened = false;\n let closeCode: number | undefined;\n let closeReason: string | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let handshakeTimer: ReturnType<typeof setTimeout> | undefined;\n\n const settle = () => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n if (handshakeTimer) clearTimeout(handshakeTimer);\n // Flush any bytes still buffered in the decoders. A stream:true decode\n // holds trailing partial multi-byte sequences until the next chunk, so\n // without a flush the final char(s) of a UTF-8 stream can be dropped.\n const stdoutTail = stdoutDecoder.decode();\n if (stdoutTail) {\n stdout += stdoutTail;\n options.onStdout?.(stdoutTail);\n }\n const stderrTail = stderrDecoder.decode();\n if (stderrTail) {\n stderr += stderrTail;\n options.onStderr?.(stderrTail);\n }\n try {\n socket.close(1000, '');\n } catch {\n /* already closed */\n }\n resolve({\n exitCode,\n stdout,\n stderr,\n truncated: false,\n timedOut,\n ...(closeCode !== undefined && { closeCode }),\n ...(closeReason !== undefined && { closeReason }),\n opened,\n });\n };\n\n // Arm the timeout BEFORE we open the socket so a stalled handshake can't\n // leave the promise pending. Callers with a positive `timeoutMs` get the\n // wall-clock cap they asked for; callers without one still get a\n // connect-only deadline that clears once the socket opens.\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) {\n timer = setTimeout(() => {\n timedOut = true;\n // 124 matches the proxy's `/exec` semantics (coreutils `timeout`\n // exit code) so callers that switch on exitCode see the same value.\n if (exitCode === null) exitCode = 124;\n settle();\n }, options.timeoutMs);\n } else {\n handshakeTimer = setTimeout(() => {\n // Never opened → treat as a transport failure. Leave exitCode=null\n // so the caller can distinguish this from a normal exit; do not\n // set timedOut (that flag is reserved for the wall-clock case).\n if (!opened) settle();\n }, HANDSHAKE_DEADLINE_MS);\n }\n\n const socket = factory(lease.wsEndpoint, [lease.subprotocol, lease.jwt]);\n socket.binaryType = 'arraybuffer';\n\n socket.onopen = () => {\n opened = true;\n if (handshakeTimer) {\n clearTimeout(handshakeTimer);\n handshakeTimer = undefined;\n }\n const data: Record<string, unknown> = { command: options.command };\n if (options.cwd) data.cwd = options.cwd;\n if (options.env && Object.keys(options.env).length > 0) data.env = options.env;\n socket.send(JSON.stringify({ type: 'init_exec', data }));\n // We never stream stdin for one-shot exec; the SDK does this too, and\n // omitting it can leave the exec hanging waiting on EOF.\n socket.send(JSON.stringify({ type: 'stdin_close' }));\n };\n\n socket.onmessage = event => {\n const { data } = event;\n if (data instanceof ArrayBuffer) {\n handleBinaryFrame(data);\n } else if (typeof data === 'string') {\n handleTextFrame(data);\n }\n };\n\n socket.onclose = event => {\n closeCode = event.code;\n closeReason = event.reason;\n if (!opened) {\n // Never opened — surface as a failure via exitCode=null,\n // truncated=false, timedOut=false so the caller can distinguish\n // it from a normal exit-0 by inspecting `exitCode === null`.\n settle();\n return;\n }\n // Preserve any info captured before close; if the server sent an\n // `exit` frame this is a no-op because settle() already ran.\n settle();\n };\n\n socket.onerror = () => {\n if (settled) return;\n if (!opened) {\n settle();\n }\n // If we're mid-stream and the socket errors, wait for onclose to fire\n // so we settle with whatever output we did receive.\n };\n\n function handleBinaryFrame(buffer: ArrayBuffer) {\n const view = new Uint8Array(buffer);\n if (view.length <= 1) return;\n if (view[0] === STDOUT_FRAME) {\n const chunk = stdoutDecoder.decode(view.subarray(1), { stream: true });\n stdout += chunk;\n options.onStdout?.(chunk);\n } else if (view[0] === STDERR_FRAME) {\n const chunk = stderrDecoder.decode(view.subarray(1), { stream: true });\n stderr += chunk;\n options.onStderr?.(chunk);\n }\n }\n\n function handleTextFrame(text: string) {\n let frame: { type?: string; data?: { exit_code?: number } };\n try {\n frame = JSON.parse(text) as { type?: string; data?: { exit_code?: number } };\n } catch {\n return;\n }\n if (frame.type === 'exit') {\n exitCode = frame.data?.exit_code ?? 0;\n settle();\n }\n // `durable_session` frames are intentionally ignored — we don't reattach\n // or expose session names on the one-shot exec path.\n }\n });\n}\n","import { CommandExitError, Sandbox, TimeoutError } from 'e2b';\n\nimport type { DirectExecOptions, DirectExecResult, ExecLease } from './direct-exec.js';\n\nconst E2B_ENVD_VERSION = '0.4.0';\n\nexport interface E2BExecLease extends ExecLease {\n sandboxId: string;\n}\n\nexport type E2BExecRunner = (lease: E2BExecLease, options: DirectExecOptions) => Promise<DirectExecResult>;\n\nexport const execViaE2BLease: E2BExecRunner = async (lease, options) => {\n const stdoutChunks: string[] = [];\n const stderrChunks: string[] = [];\n const onStdout = (data: string) => {\n stdoutChunks.push(data);\n options.onStdout?.(data);\n };\n const onStderr = (data: string) => {\n stderrChunks.push(data);\n options.onStderr?.(data);\n };\n\n try {\n const sandbox = new Sandbox({\n sandboxId: lease.sandboxId,\n envdVersion: E2B_ENVD_VERSION,\n envdAccessToken: lease.jwt,\n sandboxUrl: lease.wsEndpoint,\n validateApiKey: false,\n });\n const result = await sandbox.commands.run(options.command, {\n cwd: options.cwd,\n envs: options.env,\n timeoutMs: options.timeoutMs,\n onStdout,\n onStderr,\n });\n return {\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n truncated: false,\n timedOut: false,\n opened: true,\n };\n } catch (error) {\n if (error instanceof CommandExitError) {\n return {\n exitCode: error.exitCode,\n stdout: error.stdout,\n stderr: error.stderr,\n truncated: false,\n timedOut: false,\n opened: true,\n };\n }\n return {\n exitCode: null,\n stdout: stdoutChunks.join(''),\n stderr: stderrChunks.join(''),\n truncated: false,\n timedOut: error instanceof TimeoutError,\n closeReason: error instanceof Error ? error.message : String(error),\n opened: true,\n };\n }\n};\n","/**\n * Private-network exec client — dials the in-sandbox sidecar HTTP server\n * directly over Railway's private IPv6 network, bypassing the workspace-proxy\n * exec lease and the public tcp-proxy WebSocket entirely.\n *\n * Wire spec (matches the sidecar's `POST /exec` route, see\n * `.scratch/factory-deploy/issue-sandbox-sidecar-agent-in-base-image.md` in\n * the Platform repo):\n *\n * - Request: `POST ${instanceUrl}/exec` with JSON body\n * `{command, cwd?, env?, timeoutMs?}`.\n * - Response: `text/plain` NDJSON, one JSON object per line, terminated by an\n * `exit` frame:\n * `{\"type\":\"stdout\",\"data\":\"…\"}`\n * `{\"type\":\"stderr\",\"data\":\"…\"}`\n * `{\"type\":\"exit\",\"code\":<number>}`\n *\n * Auth is *network position* — the private ULA IPv6 space is only reachable\n * from workloads inside this Railway environment, and every workload there is\n * our own code. A bearer secret adds no boundary today so we do not send one;\n * `bearerToken` is accepted here as a defense-in-depth hook for when\n * untrusted-tenant sandboxes eventually share a private network.\n *\n * Return shape mirrors {@link ../direct-exec.ts}'s `DirectExecResult` so the\n * caller in `sandbox.ts` can hand results back with no translation regardless\n * of which transport served the exec.\n */\n\n/**\n * Minimal fetch surface this module depends on. Matches the global `fetch`\n * exposed by Node 22+ (undici) and the browser. Extracted so tests can inject\n * a fake without spinning up a real HTTP server.\n */\nexport type PrivateNetFetch = typeof fetch;\n\n/** Inputs to a private-network exec invocation. Mirrors {@link DirectExecOptions}. */\nexport interface PrivateNetExecOptions {\n command: string;\n cwd?: string;\n env?: Record<string, string>;\n /**\n * Wall-clock cap for the exec. When elapsed, we abort the request and\n * return `{timedOut: true, exitCode: 124}` matching the semantics of\n * `direct-exec.ts` (and the proxy's `/exec` route before it).\n */\n timeoutMs?: number;\n onStdout?: (chunk: string) => void;\n onStderr?: (chunk: string) => void;\n /** Injected for tests. Defaults to `globalThis.fetch`. */\n fetch?: PrivateNetFetch;\n /**\n * Optional bearer secret forwarded as `Authorization: Bearer <token>`.\n * Not required today (network position is the boundary). Present so we can\n * flip on per-sandbox secrets in a follow-up without a client-side reshape.\n */\n bearerToken?: string;\n}\n\n/**\n * Result of a private-network exec. Same shape as `DirectExecResult` — the\n * caller does not care which transport produced it.\n *\n * `exitCode` is `null` when the response body ended without an `exit` frame\n * AND the exec did not time out. That is a transport-level failure (the\n * sidecar died mid-stream or the socket was cut) and callers should treat it\n * as such (invalidate the cached `instanceUrl`, fall back to the lease path).\n */\nexport interface PrivateNetExecResult {\n exitCode: number | null;\n stdout: string;\n stderr: string;\n timedOut: boolean;\n /**\n * True when we got a full HTTP response (status + at least the response\n * headers), even if the stream later dropped. False when we could not\n * establish the connection or the sidecar refused the request outright.\n * Used by the caller to distinguish \"sidecar unreachable\" (invalidate\n * cache) from \"sidecar answered but the stream broke\" (still invalidate,\n * but log differently).\n */\n opened: boolean;\n /** HTTP status when we got a response. Undefined on connection failure. */\n status?: number;\n /** Populated when we could not even open the request (DNS/connect/TLS). */\n transportErrorMessage?: string;\n}\n\n/**\n * Thrown by {@link execViaPrivateNetwork} when the sidecar returns a non-2xx\n * HTTP response. This is an *application* error, not a transport error — the\n * sidecar is reachable and answered, it just refused the exec. Callers should\n * fall back to the lease path for this one call but MUST NOT invalidate the\n * cached `instanceUrl` (the address is still good).\n */\nexport class PrivateNetExecHttpError extends Error {\n readonly status: number;\n readonly body: string;\n\n constructor(status: number, body: string) {\n super(`Sidecar /exec returned ${status}${body ? `: ${body.slice(0, 200)}` : ''}`);\n this.name = 'PrivateNetExecHttpError';\n this.status = status;\n this.body = body;\n }\n}\n\nconst DEFAULT_FETCH: PrivateNetFetch = (input, init) => {\n const f = (globalThis as { fetch?: typeof fetch }).fetch;\n if (!f) {\n throw new Error(\n 'Private-network exec requires a fetch implementation. Node 22+ provides one globally; on older runtimes, pass fetch explicitly.',\n );\n }\n return f(input, init);\n};\n\n/**\n * Wire frame shapes accepted from the sidecar. Anything else on the stream\n * is ignored so a future sidecar can add new frame types without breaking\n * older clients.\n */\ntype SidecarFrame =\n | { type: 'stdout'; data: string }\n | { type: 'stderr'; data: string }\n | { type: 'exit'; code: number };\n\n/**\n * Dial `${instanceUrl}/exec` and stream the response, resolving with the\n * accumulated stdout/stderr + exit code.\n *\n * Errors:\n * - Connection failure (DNS, refused, reset) → resolves with\n * `{opened:false, exitCode:null, transportErrorMessage}`. Never throws for\n * transport failures — the shape matches the lease-path result so the\n * caller can treat both transports uniformly.\n * - Non-2xx HTTP response from the sidecar → throws {@link PrivateNetExecHttpError}.\n * Application-level; caller decides whether to fall back.\n * - Stream ends without an `exit` frame → resolves with\n * `{opened:true, exitCode:null}`, matching the lease-path semantics for a\n * mid-stream drop.\n * - `timeoutMs` elapsed → aborts the request, resolves with\n * `{timedOut:true, exitCode:124}`.\n */\nexport async function execViaPrivateNetwork(\n instanceUrl: string,\n options: PrivateNetExecOptions,\n): Promise<PrivateNetExecResult> {\n const fetchImpl = options.fetch ?? DEFAULT_FETCH;\n const url = `${instanceUrl.replace(/\\/$/, '')}/exec`;\n\n const controller = new AbortController();\n let timedOut = false;\n let timeoutTimer: ReturnType<typeof setTimeout> | undefined;\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) {\n timeoutTimer = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, options.timeoutMs);\n }\n\n const body: Record<string, unknown> = { command: options.command };\n if (options.cwd) body.cwd = options.cwd;\n if (options.env && Object.keys(options.env).length > 0) body.env = options.env;\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) body.timeoutMs = options.timeoutMs;\n\n const headers: Record<string, string> = { 'content-type': 'application/json' };\n if (options.bearerToken) headers.authorization = `Bearer ${options.bearerToken}`;\n\n let response: Response;\n try {\n response = await fetchImpl(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (error) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n // AbortError from our own timeout → treat as timeout, not transport error.\n if (timedOut) {\n return {\n exitCode: 124,\n stdout: '',\n stderr: '',\n timedOut: true,\n opened: false,\n };\n }\n return {\n exitCode: null,\n stdout: '',\n stderr: '',\n timedOut: false,\n opened: false,\n transportErrorMessage: error instanceof Error ? error.message : String(error),\n };\n }\n\n if (!response.ok) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n const text = await response.text().catch(() => '');\n throw new PrivateNetExecHttpError(response.status, text);\n }\n\n if (!response.body) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n // A 200 without a body is a broken sidecar. Treat as mid-stream drop\n // (opened=true, no exit frame) so the caller invalidates cache.\n return {\n exitCode: null,\n stdout: '',\n stderr: '',\n timedOut: false,\n opened: true,\n status: response.status,\n };\n }\n\n let stdout = '';\n let stderr = '';\n let exitCode: number | null = null;\n const decoder = new TextDecoder();\n let buffer = '';\n\n const handleLine = (line: string): void => {\n if (!line) return;\n let frame: SidecarFrame | undefined;\n try {\n frame = JSON.parse(line) as SidecarFrame;\n } catch {\n // Unknown / malformed frame — ignore. A well-behaved sidecar only emits\n // JSON objects, but tolerating garbage protects against a partial write.\n return;\n }\n if (!frame || typeof frame !== 'object') return;\n if (frame.type === 'stdout' && typeof frame.data === 'string') {\n stdout += frame.data;\n options.onStdout?.(frame.data);\n } else if (frame.type === 'stderr' && typeof frame.data === 'string') {\n stderr += frame.data;\n options.onStderr?.(frame.data);\n } else if (frame.type === 'exit' && typeof frame.code === 'number') {\n exitCode = frame.code;\n }\n // Any other frame type is intentionally ignored (see SidecarFrame jsdoc).\n };\n\n try {\n const reader = response.body.getReader();\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n // NDJSON: split on newline; last piece stays in buffer for the next chunk.\n let newlineIdx = buffer.indexOf('\\n');\n while (newlineIdx !== -1) {\n const line = buffer.slice(0, newlineIdx).trim();\n buffer = buffer.slice(newlineIdx + 1);\n handleLine(line);\n newlineIdx = buffer.indexOf('\\n');\n }\n }\n // Flush the decoder + any trailing (no-newline) line at EOF.\n buffer += decoder.decode();\n const trailing = buffer.trim();\n if (trailing) handleLine(trailing);\n } catch (error) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n if (timedOut) {\n return {\n exitCode: 124,\n stdout,\n stderr,\n timedOut: true,\n opened: true,\n status: response.status,\n };\n }\n // Mid-stream failure. Return whatever we accumulated with exitCode=null\n // so the caller sees this as a transport failure and can invalidate.\n return {\n exitCode,\n stdout,\n stderr,\n timedOut: false,\n opened: true,\n status: response.status,\n transportErrorMessage: error instanceof Error ? error.message : String(error),\n };\n } finally {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n }\n\n return {\n exitCode,\n stdout,\n stderr,\n timedOut: false,\n opened: true,\n status: response.status,\n };\n}\n","import type { RequestContext } from '@mastra/core/di';\nimport type {\n CommandResult,\n ExecuteCommandOptions,\n InstructionsOption,\n MastraSandboxOptions,\n ProcessInfo,\n ProviderStatus,\n SandboxCloneOptions,\n SandboxInfo,\n SandboxStartResult,\n SpawnProcessOptions,\n} from '@mastra/core/workspace';\nimport {\n MastraSandbox,\n ProcessHandle,\n UnsupportedStdinCloseError,\n SandboxNotReadyError,\n SandboxProcessManager,\n} from '@mastra/core/workspace';\nimport type { PlatformClientOptions, PlatformRequestOptions } from './client.js';\nimport { PlatformApiError, PlatformClient } from './client.js';\nimport type { DirectExecWebSocketFactory, ExecLease } from './direct-exec.js';\nimport { execViaLease } from './direct-exec.js';\nimport type { E2BExecRunner } from './e2b-exec.js';\nimport { execViaE2BLease } from './e2b-exec.js';\nimport type { PrivateNetExecOptions, PrivateNetExecResult, PrivateNetFetch } from './private-net-exec.js';\nimport { execViaPrivateNetwork, PrivateNetExecHttpError } from './private-net-exec.js';\nimport type { SandboxTemplateBuilder, SerializedSandboxTemplate } from './template.js';\nimport { getSandboxTemplateBuildEnvs, serializeSandboxTemplate } from './template.js';\n\nexport type PlatformSandboxNetworkIsolation = 'ISOLATED' | 'PRIVATE';\n\nexport type PlatformSandboxTemplate =\n | SandboxTemplateBuilder\n | (() => SandboxTemplateBuilder | undefined | Promise<SandboxTemplateBuilder | undefined>);\n\n/**\n * In-process `sandboxId → instanceUrl` map that lets\n * {@link PlatformSandbox.executeCommand} dial the in-sandbox sidecar over\n * Railway's private network instead of paying for a lease + WebSocket\n * round-trip through Railway's public control plane.\n *\n * The workspace proxy discovers each sandbox's IPv6 during\n * `POST /v1/:provider/projects/:pid/sandbox` and returns it as `instanceUrl` on the\n * create + get responses (see the platform inline-discovery issue). The\n * `PlatformSandbox` client copies that field into this registry from both\n * {@link PlatformSandbox.start} branches (fresh provision + reattach), evicts\n * on {@link PlatformSandbox.destroy}, and evicts again on any observed\n * transport failure so the next exec falls back to the lease path cleanly.\n *\n * See:\n * - `.scratch/factory-deploy/issue-runtime-sandbox-address-discovery.md`\n * - `.scratch/factory-deploy/issue-platform-sandbox-exec-via-private-network.md`\n */\nexport interface SandboxAddressRegistry {\n set(sandboxId: string, instanceUrl: string): void;\n get(sandboxId: string): string | undefined;\n delete(sandboxId: string): void;\n}\n\nexport interface PlatformSandboxOptions extends Omit<MastraSandboxOptions, 'processes'>, PlatformClientOptions {\n id?: string;\n environmentId?: string;\n sandboxId?: string;\n /** Boot-only fallback checkpoint for a fresh sandbox whose primary recovery key has no state. */\n seedCheckpointName?: string;\n /**\n * Template builder or a lazy resolver for one. The resolver runs only when\n * start() must provision a fresh sandbox. Platform content-addresses the\n * serialized definition and starts or reuses its provider build without\n * blocking sandbox creation. With E2B, cpuCount() and memoryMB() default to 2\n * CPUs and 1,024 MB; the latest setters determine the template identity and\n * stale fallback is restricted to builds with the same effective resources.\n * A provider-base fallback may use provider-default resources while the exact\n * build is pending; inspect templatePending to detect that case. Railway\n * ignores the resource setters. `setEnvs(values, { ephemeral: true })`\n * supplies build-only values outside the serialized definition, content\n * identity, and persistent template record. Resolver failures also fall back\n * to the provider default and are retried on the next fresh provision.\n */\n template?: PlatformSandboxTemplate;\n idleTimeoutMinutes?: number;\n networkIsolation?: PlatformSandboxNetworkIsolation;\n env?: Record<string, string>;\n timeout?: number;\n instructions?: InstructionsOption;\n /**\n * Injected WebSocket factory used by the direct-exec code path. Defaults to\n * the global `WebSocket` (available on Node 22+, this package's minimum) and\n * only exists so tests can drive the exec state machine deterministically\n * without a real network socket.\n */\n webSocketFactory?: DirectExecWebSocketFactory;\n /** Injected E2B direct-exec implementation used by tests. */\n e2bExecRunner?: E2BExecRunner;\n /**\n * Injected fetch implementation used by the private-network exec code path\n * to dial the in-sandbox sidecar. Defaults to `globalThis.fetch` and only\n * exists so tests can drive that transport without a real HTTP server.\n * Note: this is separate from the `fetch` on {@link PlatformClientOptions},\n * which is used for calls to the workspace proxy.\n */\n privateNetFetch?: PrivateNetFetch;\n /**\n * Registry that maps `sandboxId → instanceUrl` for the private-network\n * exec path. When set, {@link PlatformSandbox.start} populates it from the\n * `instanceUrl` field workspace-proxy returns on create + get responses,\n * and {@link PlatformSandbox.executeCommand} looks it up before every exec\n * and tries the private-network transport first, falling back to the lease\n * path on any transport failure (and invalidating the registry entry so\n * the next call goes to the lease path cleanly). When absent, all execs\n * go straight to the lease path — this is the pre-existing behavior and\n * the expected mode outside the shipyard runtime. See\n * {@link SandboxAddressRegistry}.\n */\n addressRegistry?: SandboxAddressRegistry;\n}\n\ninterface ExecLeaseResponse {\n provider: string;\n sandboxId: string;\n providerResourceId: string;\n jwt: string;\n wsEndpoint: string;\n subprotocol: string;\n expiresAt: string | null;\n}\n\ninterface CachedExecLease extends ExecLease {\n provider: string;\n sandboxId: string;\n providerResourceId: string;\n expiresAtMs: number | null;\n}\n\n/**\n * How long before a lease's stated `expiresAt` we should treat it as\n * expired. Avoids a race where the JWT is valid at cache-hit time but the\n * server rejects it by the time the WebSocket handshake completes.\n */\nconst LEASE_REFRESH_MARGIN_MS = 60_000;\n\ninterface CreateSandboxResponse {\n id: string;\n providerResourceId?: string | null;\n status?: string;\n createdAt?: string;\n destroyedAt?: string | null;\n /**\n * Present when the sandbox booted from a prior member of the same\n * template family or the provider base template while the requested\n * exact template continues to build in the background. Absent when the\n * sandbox booted on the exact template. See {@link SandboxTemplatePending}\n * for semantics.\n *\n * Only emitted by the create route today; reattach responses never carry\n * this field.\n */\n templatePending?: SandboxTemplatePending;\n /**\n * Full sidecar URL (`http://[<ipv6>]:<port>`) the runtime can dial over\n * Railway's private network to reach the in-sandbox exec sidecar. The\n * workspace proxy discovers the sandbox's IPv6 during `Sandbox.create()`\n * via one `sandbox.exec(\"awk … /proc/net/if_inet6\")` and stores it in\n * `environment_sandboxes.instance_url`; the same field is echoed on\n * `GET /sandbox/:id`. `null` when discovery failed (returned by the proxy\n * so the runtime knows to skip private-net dial for this sandbox rather\n * than fall back on a missing-field ambiguity).\n */\n instanceUrl?: string | null;\n}\n\n/** Max attempts for `POST /sandbox` when the proxy returns transient 5xx errors. */\nconst CREATE_MAX_ATTEMPTS = 3;\n/** Base delay between create retries; multiplied by the attempt number. */\nconst CREATE_RETRY_BASE_DELAY_MS = 2_000;\n\n/**\n * Observability handle for a template that was requested but is still being\n * built by the platform. Present on {@link CreateSandboxResponse} and echoed\n * as {@link PlatformSandbox.templatePending} when the sandbox booted from\n * a prior member of the same template family or from the provider's base\n * template while the exact template continues to build in the background.\n * Absent when the sandbox booted on the exact template.\n *\n * `PlatformSandbox` does not act on this: freshness is reconciled by the\n * caller's own `onStart` runtime setup (e.g. `git fetch && checkout`), not\n * by replaying template operations inside the running sandbox.\n */\nexport interface SandboxTemplatePending {\n templateId: string;\n retryAfterMs: number;\n}\n\n/**\n * How long to wait for the in-sandbox sidecar's `/health` endpoint to respond\n * before giving up and leaving the address registry unpopulated (execs fall\n * back to the lease path). This bounds the fire-and-forget probe that runs\n * after `start()` resolves; the sandbox is usable immediately — the probe\n * only controls whether early execs go via private-net or lease.\n */\nconst SIDECAR_PROBE_TIMEOUT_MS = 30_000;\n/** Delay between sidecar probe attempts. */\nconst SIDECAR_PROBE_INTERVAL_MS = 250;\n/**\n * How long `executeCommand` waits for the transport to become ready before\n * falling back to the lease path. This is much shorter than\n * `SIDECAR_PROBE_TIMEOUT_MS` because we want execs to proceed quickly if\n * the sidecar is slow to boot — the probe continues in the background and\n * later execs will use private-net once it succeeds.\n */\nconst TRANSPORT_READY_WAIT_MS = 5_000;\n\n/**\n * Diagnostic error thrown when the direct-exec WebSocket transport fails\n * twice in a row (opening handshake refused or socket closed mid-stream\n * without an `exit` frame). Distinguishes \"the sandbox transport is broken\"\n * from \"your command failed\" so callers can decide whether to retry at a\n * higher level (e.g. reprovision the sandbox) or surface the error.\n *\n * `opened` is `true` when the WebSocket completed its handshake at least\n * once before closing; `false` when Railway refused the upgrade outright.\n */\nexport class SandboxExecTransportError extends Error {\n readonly sandboxId: string | undefined;\n readonly command: string;\n readonly attempts: number;\n readonly opened: boolean;\n readonly closeCode: number | undefined;\n readonly closeReason: string | undefined;\n readonly wsEndpoint: string;\n\n constructor(\n message: string,\n diagnostics: {\n sandboxId?: string;\n command: string;\n attempts: number;\n opened: boolean;\n closeCode?: number;\n closeReason?: string;\n wsEndpoint: string;\n },\n ) {\n super(message);\n this.name = 'SandboxExecTransportError';\n this.sandboxId = diagnostics.sandboxId;\n this.command = diagnostics.command;\n this.attempts = diagnostics.attempts;\n this.opened = diagnostics.opened;\n this.closeCode = diagnostics.closeCode;\n this.closeReason = diagnostics.closeReason;\n this.wsEndpoint = diagnostics.wsEndpoint;\n }\n}\n\n/**\n * Outcome of {@link PlatformSandbox.captureCheckpoint}. Mirrors the shape of\n * the OSS `@mastra/railway` `RailwaySandbox.captureCheckpoint()` return so a\n * caller (e.g. the factory fleet) can branch on `status`/`reason` uniformly\n * across providers without knowing which one is underneath.\n *\n * `captured` and `coalesced` both represent a successful capture the caller\n * can persist against — they carry the checkpoint name inline so callers\n * don't have to reach back into the sandbox instance to learn what was\n * written. `skipped` carries a machine-readable `reason` so the discriminant\n * set stays extensible.\n *\n * Note: the platform proxy's own `skipped` (returned when the upstream\n * sandbox is already destroyed) is mapped to `sandbox-not-running` here to\n * keep the discriminant identical to the OSS provider. The diagnostic\n * distinction (pre-flight vs post-hoc discovery) is preserved in log lines,\n * not the return type — see {@link PlatformSandbox.captureCheckpoint}.\n */\nexport type CaptureCheckpointResult =\n | { status: 'captured'; checkpointName: string }\n | { status: 'coalesced'; checkpointName: string }\n | { status: 'skipped'; reason: 'no-checkpoint-name-configured' | 'sandbox-not-running' };\n\n/**\n * Thrown when `/exec-lease` returns 410 Gone — the sandbox has been destroyed\n * (Railway destroy, quota reclamation, etc.). The client cannot recover from\n * this on its own because it does not own the binding store; only the fleet\n * layer can clear the stale sandbox id and provision a fresh one. Callers\n * (typically `SandboxFleet`) must catch this and reprovision-and-replay.\n *\n * When this is thrown the cached `_lease` and `_sandboxId` on the sandbox\n * instance are cleared, so the next `ensureRunning()` on a reused instance\n * will re-provision cleanly.\n */\nexport class SandboxDestroyedError extends Error {\n readonly sandboxId: string | undefined;\n readonly command: string;\n readonly attempts: number;\n\n constructor(message: string, diagnostics: { sandboxId?: string; command: string; attempts: number }) {\n super(message);\n this.name = 'SandboxDestroyedError';\n this.sandboxId = diagnostics.sandboxId;\n this.command = diagnostics.command;\n this.attempts = diagnostics.attempts;\n }\n}\n\n/**\n * Compose a shell command line from a `command` string and optional `args`.\n *\n * IMPORTANT: `command` is treated as a **shell string** and passed to the\n * remote shell verbatim so callers can use pipes, redirects, and chaining\n * (`ls -la | grep foo`). This matches the contract of {@link MastraSandbox}\n * and the local sandbox implementation. `args` are always shell-quoted so\n * they cannot inject syntax.\n *\n * Callers MUST NOT pass untrusted input as `command`. Untrusted values must\n * be passed via `args`, where they are safely quoted. Passing untrusted\n * input as `command` allows arbitrary shell syntax execution on the remote\n * sandbox.\n */\nfunction buildCommand(command: string, args?: string[]): string {\n return args?.length ? `${command} ${args.map(shellQuote).join(' ')}` : command;\n}\n\nfunction shellQuote(arg: string): string {\n if (/^[a-zA-Z0-9._\\-/=:@]+$/.test(arg)) return arg;\n return `'${arg.replace(/'/g, `'\\\\''`)}'`;\n}\n\nclass PlatformProcessHandle extends ProcessHandle {\n readonly pid: string;\n private readonly resultPromise: Promise<CommandResult>;\n private exitCodeValue: number | undefined;\n\n constructor(pid: string, resultPromise: Promise<CommandResult>, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this.resultPromise = resultPromise.then(result => {\n this.exitCodeValue = result.exitCode;\n if (result.stdout) this.emitStdout(result.stdout);\n if (result.stderr) this.emitStderr(result.stderr);\n return result;\n });\n }\n\n get exitCode(): number | undefined {\n return this.exitCodeValue;\n }\n\n async wait(): Promise<CommandResult> {\n return this.resultPromise;\n }\n\n async kill(): Promise<boolean> {\n // The workspace proxy has no cancel-exec endpoint; each `executeCommand`\n // is a synchronous round-trip that has already completed (or timed out)\n // by the time a handle exists to kill. Making this explicit avoids\n // callers silently believing they cancelled a still-running process.\n throw new Error('Platform sandbox command execution does not support killing individual processes');\n }\n\n async sendStdin(): Promise<void> {\n throw new Error('Platform sandbox command execution does not support stdin');\n }\n\n async closeStdin(): Promise<void> {\n throw new UnsupportedStdinCloseError('Platform sandbox command execution does not support closing stdin');\n }\n}\n\nclass PlatformProcessManager extends SandboxProcessManager<PlatformSandbox> {\n private spawnCounter = 0;\n\n /**\n * Spawn a process on the remote sandbox.\n *\n * `command` is interpreted as a shell string by the remote shell, matching\n * the {@link MastraSandbox} contract. See {@link PlatformSandbox.executeCommand}\n * for the untrusted-input caveat: never pass untrusted values as `command`.\n */\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n const pid = `platform-proc-${Date.now().toString(36)}-${(this.spawnCounter++).toString(36)}`;\n const resultPromise = this.sandbox.executeCommand(command, undefined, options);\n const handle = new PlatformProcessHandle(pid, resultPromise, options);\n this._tracked.set(handle.pid, handle);\n return handle;\n }\n\n async list(): Promise<ProcessInfo[]> {\n return Array.from(this._tracked.values()).map(handle => ({\n pid: handle.pid,\n command: handle.command,\n running: handle.exitCode === undefined,\n ...(handle.exitCode !== undefined && { exitCode: handle.exitCode }),\n }));\n }\n}\n\nexport class PlatformSandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'PlatformSandbox';\n readonly provider = 'platform';\n status: ProviderStatus = 'pending';\n declare readonly processes: PlatformProcessManager;\n /**\n * Populated from the platform's create/reattach response when the sandbox\n * booted from a prior member of the same template family or the provider\n * base template while the requested exact template continues to build in\n * the background.\n * `undefined` when the sandbox booted on the exact template (or when no\n * template was requested). Observability-only; consumers reconcile freshness\n * in their own runtime setup and reprovision to pick up the ready template\n * on a later start.\n */\n templatePending?: SandboxTemplatePending;\n\n private readonly _client: PlatformClient;\n private readonly _usesProviderRoutes: boolean;\n private readonly _environmentId: string;\n private _sandboxId?: string;\n private readonly _seedCheckpointName?: string;\n private _templateDefinition?: SerializedSandboxTemplate;\n private _templateBuildEnvs?: Record<string, string>;\n private readonly _template?: PlatformSandboxTemplate;\n private _templateResolutionInFlight?: Promise<void>;\n private readonly _idleTimeoutMinutes?: number;\n private readonly _networkIsolation?: PlatformSandboxNetworkIsolation;\n private readonly _env: Record<string, string>;\n private readonly _timeout?: number;\n private readonly _instructionsOverride?: InstructionsOption;\n private _createdAt: Date | null = null;\n private readonly _webSocketFactory?: DirectExecWebSocketFactory;\n private readonly _e2bExecRunner: E2BExecRunner;\n private readonly _privateNetFetch?: PrivateNetFetch;\n /**\n * Registry that maps `sandboxId → instanceUrl` for the private-network\n * exec path. Injected by the composition site via\n * {@link PlatformSandboxOptions.addressRegistry} and populated by this\n * class itself in `start()` when the workspace-proxy's create/reattach\n * response includes an `instanceUrl` field. The registry IS the cache —\n * there is no per-instance mirror on `PlatformSandbox`, so every exec is\n * a `Map.get()` (in the default in-process impl) against the live view.\n * When absent, executes go straight to the lease path with no extra\n * round-trip.\n */\n private readonly _addressRegistry?: SandboxAddressRegistry;\n /**\n * Cached exec lease for this sandbox. `null` before the first exec and\n * after {@link destroy}. Refreshed when `expiresAt - LEASE_REFRESH_MARGIN_MS < now`\n * (see {@link _ensureLease}); a lease without a disclosed `expiresAt`\n * is refreshed on every call.\n */\n private _lease: CachedExecLease | null = null;\n /**\n * In-flight mint request; concurrent `_ensureLease` callers on a cold or\n * near-expiry cache all await this single promise so we don't burn N\n * `POST /exec-lease` round-trips when the sandbox is doing N parallel execs.\n * Cleared (regardless of success or failure) when the request settles.\n */\n private _leaseInFlight: Promise<CachedExecLease> | null = null;\n /**\n * True when this sandbox was constructed with a caller-supplied `id` (the\n * recovery key the proxy hashes into an on-provider checkpoint name).\n * `captureCheckpoint()` needs this to distinguish \"no checkpoint intent\"\n * (auto-generated random id — capture would land under a name no future\n * boot would look for) from \"capture on demand\". Cloned sandboxes route\n * `checkpointName` through `id`, so both entry points set this the same\n * way.\n */\n private readonly _hasRecoveryKey: boolean;\n /**\n * In-flight `captureCheckpoint()` request. Concurrent callers on the same\n * instance coalesce onto this single promise so we don't burn N `POST\n * /checkpoint` round-trips when the fleet fires several turn-end captures\n * before the first one resolves. Cleared when the request settles.\n */\n private _captureInFlight: Promise<CaptureCheckpointResult> | null = null;\n /**\n * Generation token for the sidecar probe. Incremented on every `start()`\n * and on teardown. The probe captures this value when it begins; if the\n * generation has changed by the time the probe succeeds, the probe skips\n * the `set()` to avoid re-populating a deleted or superseded sandbox entry.\n */\n private _probeGeneration = 0;\n /**\n * In-flight sidecar probe promise. Concurrent `executeCommand` callers that\n * arrive before the registry is populated all await this single promise so\n * we don't fire N independent lease requests during the sidecar boot window.\n * Once the probe resolves (success or timeout), callers check the registry\n * and proceed — either via private-net (probe succeeded) or via lease (probe\n * failed/timed out, but now coalesced via `_leaseInFlight`).\n */\n private _transportReadyPromise: Promise<void> | null = null;\n /**\n * The sidecar address of the most recent `start()`, kept so a timed-out\n * probe can be restarted by a later exec ({@link _awaitTransportReady})\n * instead of pinning the sandbox to the lease path for its lifetime.\n */\n private _probeTarget: { sandboxId: string; instanceUrl: string } | null = null;\n\n constructor(options: PlatformSandboxOptions = {}) {\n super({ ...options, name: 'PlatformSandbox', processes: new PlatformProcessManager() });\n this._hasRecoveryKey = options.id !== undefined;\n this.id = options.id ?? this.generateId();\n this._client = new PlatformClient(options);\n this._environmentId = options.environmentId ?? process.env.MASTRA_ENVIRONMENT_ID ?? '';\n if (!this._environmentId && !options.sandboxId) throw new Error('environmentId is required');\n this._sandboxId = options.sandboxId;\n this._seedCheckpointName = options.seedCheckpointName;\n this._usesProviderRoutes = options.template !== undefined;\n this._template = options.template;\n this._idleTimeoutMinutes = options.idleTimeoutMinutes;\n this._networkIsolation = options.networkIsolation;\n this._env = options.env ?? {};\n this._timeout = options.timeout;\n this._instructionsOverride = options.instructions;\n this._webSocketFactory = options.webSocketFactory;\n this._e2bExecRunner = options.e2bExecRunner ?? execViaE2BLease;\n this._privateNetFetch = options.privateNetFetch;\n this._addressRegistry = options.addressRegistry;\n }\n\n private generateId(): string {\n return `platform-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n private _request(path: string, options: PlatformRequestOptions = {}): Promise<Response> {\n return this._usesProviderRoutes ? this._client.requestProvider(path, options) : this._client.request(path, options);\n }\n\n /**\n * Construct a sibling {@link PlatformSandbox} that inherits this sandbox's\n * credentials and defaults (access token, project, environment, network\n * isolation, timeout, instructions, env, idle timeout) with per-instance\n * overrides from `options`.\n *\n * Performs no I/O and does not require this sandbox to be started — the\n * returned sandbox is not started and provisions (or reattaches, when\n * `sandboxId` is set) on its own `start()`. Use it when one configured\n * sandbox acts as the template for a fleet of independent sandboxes\n * (e.g. one per project).\n */\n clone(options: SandboxCloneOptions = {}): PlatformSandbox {\n // The proxy hashes `body.id` on POST /sandbox to look up a prior\n // checkpoint. A stable `checkpointName` is only useful if it round-trips\n // to `body.id`, so route it through the sandbox id when the caller\n // didn't pick one explicitly. Without this, every clone gets a random\n // id and no boot ever hits its captured checkpoint (see\n // issue-platform-sandbox-clone-drops-checkpoint-name.md).\n const id = options.id ?? options.checkpointName;\n const seedCheckpointName =\n options.seedCheckpointName ??\n (this._client.sandboxProvider === 'e2b' ? options.checkpointName : undefined) ??\n this._seedCheckpointName;\n const clone = new PlatformSandbox({\n ...(id !== undefined && { id }),\n accessToken: this._client.accessToken,\n projectId: this._client.projectId,\n ...(this._usesProviderRoutes || this._client.sandboxProvider !== 'railway'\n ? { sandboxProvider: this._client.sandboxProvider }\n : {}),\n actingUserId: options.actingUserId ?? this._client.actingUserId,\n ...(this._client.sessionId !== undefined && { sessionId: this._client.sessionId }),\n ...(this._client.threadId !== undefined && { threadId: this._client.threadId }),\n fetch: this._client.fetch,\n environmentId: this._environmentId,\n ...(options.sandboxId !== undefined && { sandboxId: options.sandboxId }),\n ...(seedCheckpointName !== undefined && { seedCheckpointName }),\n ...(this._template !== undefined && { template: this._template }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n env: options.env ?? this._env,\n ...(this._timeout !== undefined && { timeout: this._timeout }),\n ...(this._instructionsOverride !== undefined && { instructions: this._instructionsOverride }),\n ...(this._webSocketFactory !== undefined && { webSocketFactory: this._webSocketFactory }),\n e2bExecRunner: this._e2bExecRunner,\n ...(this._privateNetFetch !== undefined && { privateNetFetch: this._privateNetFetch }),\n // Propagate the registry — the clone is a different sandbox with a\n // different id, so it will `get()` its OWN address (or nothing) out\n // of the shared registry, not the parent's. See\n // `.scratch/factory-deploy/issue-platform-sandbox-exec-via-private-network.md`.\n ...(this._addressRegistry !== undefined && { addressRegistry: this._addressRegistry }),\n });\n clone._templateDefinition = this._templateDefinition ? structuredClone(this._templateDefinition) : undefined;\n clone._templateBuildEnvs = this._templateBuildEnvs ? { ...this._templateBuildEnvs } : undefined;\n return clone;\n }\n\n /**\n * Start the sandbox: reattach to a known provider `sandboxId` when one is\n * set and still live, otherwise provision a fresh sandbox via the proxy.\n *\n * Concurrent-caller coalescing lives in the `MastraSandbox` base class\n * (constructor-wrapped `start()`): joined callers share one attempt and\n * observe its result; the in-flight slot is cleared on settle so a failed\n * attempt is not a permanent latch.\n *\n * Reports `outcome: 'connected'` on reattach and `outcome: 'created'` on provision.\n * Note: a `POST /sandbox` seeded from an id-keyed checkpoint is still a\n * fresh VM and reports `outcome: 'created'`.\n */\n async start(): Promise<SandboxStartResult> {\n const startedAt = Date.now();\n if (this._sandboxId) {\n try {\n const requestStartedAt = Date.now();\n const response = await this._request(`/sandbox/${encodeURIComponent(this._sandboxId)}`);\n const requestMs = Date.now() - requestStartedAt;\n const json = (await response.json()) as CreateSandboxResponse;\n // A destroyed record (idle GC, manual delete) is not reattachable —\n // treat it like a missing sandbox so we fall through to a fresh\n // provision instead of pointing exec at a dead resource.\n if (!json.destroyedAt) {\n this._createdAt = json.createdAt ? new Date(json.createdAt) : new Date();\n // Reattach responses never carry templatePending — the field is\n // set only by the create route. Leave the instance's value alone.\n this._populateAddressFromResponse(json);\n this._logStartComplete(json.id, startedAt, requestMs, 'reattach');\n return { outcome: 'connected' };\n }\n this._sandboxId = undefined;\n } catch (error) {\n if (!(error instanceof PlatformApiError) || error.status !== 404) throw error;\n this._sandboxId = undefined;\n }\n }\n\n if (!this._environmentId) throw new Error('environmentId is required');\n\n await this._prepareLazyTemplate();\n\n const createBody = () =>\n JSON.stringify({\n // Sent so the platform can associate the provisioned resource with a\n // caller-stable identifier (used for opt-in checkpoint recovery). The\n // platform treats it as an advisory key: unknown values fall through\n // to a fresh sandbox, matching pre-existing behavior.\n id: this.id,\n seedCheckpointName: this._seedCheckpointName,\n templateDefinition: this._templateDefinition,\n templateBuildEnvs: this._templateBuildEnvs,\n environmentId: this._environmentId,\n idleTimeoutMinutes: this._idleTimeoutMinutes,\n networkIsolation: this._networkIsolation,\n env: this._env,\n });\n // Provisioning is observed to fail intermittently with proxy 500s while\n // the provider is under load. A create either succeeds (201) or fails\n // without allocating a caller-visible resource, so retrying transient\n // 5xx responses with a short backoff is safe and keeps a single flaky\n // window from killing the caller's whole workflow.\n //\n // Template builds never block a create anymore: the proxy always returns\n // a running sandbox on the best available fallback (a prior member of the\n // same template family if one exists, otherwise the provider base\n // template) and surfaces `templatePending` in the 201 body describing the\n // build that continues in the background.\n let response: Response | undefined;\n const requestStartedAt = Date.now();\n for (let attempt = 1; ; attempt++) {\n try {\n response = await this._request('/sandbox', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: createBody(),\n });\n break;\n } catch (error) {\n const transient = error instanceof PlatformApiError && error.status >= 500;\n if (!transient || attempt >= CREATE_MAX_ATTEMPTS) throw error;\n await new Promise(resolve => setTimeout(resolve, CREATE_RETRY_BASE_DELAY_MS * attempt));\n }\n }\n const requestMs = Date.now() - requestStartedAt;\n const json = (await response.json()) as CreateSandboxResponse;\n this._sandboxId = json.id;\n this._createdAt = json.createdAt ? new Date(json.createdAt) : new Date();\n this.templatePending = json.templatePending;\n this._populateAddressFromResponse(json);\n this._logStartComplete(json.id, startedAt, requestMs, 'provision');\n return { outcome: 'created' };\n }\n\n private async _prepareLazyTemplate(): Promise<void> {\n if (this._templateDefinition !== undefined || this._template === undefined) return;\n if (!this._templateResolutionInFlight) {\n const attempt = this._resolveTemplate();\n this._templateResolutionInFlight = attempt.finally(() => {\n this._templateResolutionInFlight = undefined;\n });\n }\n await this._templateResolutionInFlight;\n }\n\n private async _resolveTemplate(): Promise<void> {\n try {\n const resolved = typeof this._template === 'function' ? await this._template() : this._template;\n if (!resolved) return;\n this._templateDefinition = serializeSandboxTemplate(resolved);\n this._templateBuildEnvs = getSandboxTemplateBuildEnvs(resolved);\n } catch (error) {\n this.logger.warn(\n `Platform sandbox template resolution failed; using provider default template: ${String(error)}`,\n );\n }\n }\n\n /**\n * One timing summary per completed `start()` — the whole\n * `PlatformSandbox`-visible boot in a single greppable line.\n *\n * `requestMs` is the proxy round-trip (`GET /sandbox/:id` on reattach,\n * `POST /sandbox` including transient-5xx retries on provision) — a black\n * box from this side that rolls up Railway RPC, sidecar launch, and the\n * proxy's discovery exec. Sidecar probe cost is intentionally NOT here: the\n * probe is fire-and-forget and outlives `start()` by design, so its\n * duration lands on the `platform-workspace probe ok` line instead.\n */\n private _logStartComplete(sandboxId: string, startedAt: number, requestMs: number, mode: string): void {\n this.logger.info('platform-workspace start complete', {\n sandboxId,\n sessionId: this._client.sessionId,\n mode,\n totalMs: Date.now() - startedAt,\n requestMs,\n });\n }\n\n /**\n * Copy `response.instanceUrl` into the injected {@link SandboxAddressRegistry}\n * when both are present. Called from both {@link start} branches (fresh\n * provision + reattach) with the workspace-proxy response for this sandbox.\n *\n * The proxy discovers the IPv6 during `Sandbox.create()` and stores it in\n * `environment_sandboxes.instance_url`; both the create response and\n * `GET /sandbox/:id` echo the same field. The runtime does not do any\n * discovery of its own — it only mirrors the field into an in-process map\n * so {@link executeCommand} can `Map.get()` before every exec without an\n * HTTP round-trip.\n *\n * `null`/absent `instanceUrl` (proxy discovery failed, or an older proxy\n * that predates the field) evicts any stale registry address and leaves\n * executes on the lease path.\n */\n private _populateAddressFromResponse(json: CreateSandboxResponse): void {\n if (!this._addressRegistry) return;\n if (!json.instanceUrl) {\n // A later start() without an address must not keep probing the previous\n // sidecar or reuse a leftover registry URL. Invalidate any in-flight\n // probe, drop the remembered target, and evict the stale entry.\n this._probeGeneration++;\n this._probeTarget = null;\n this._transportReadyPromise = null;\n this._addressRegistry.delete(json.id);\n return;\n }\n // Clear any stale entry before probing. On reattach, the registry may have\n // the old sandbox's address; execs should fall back to lease until the new\n // probe succeeds rather than dialing the stale address.\n this._addressRegistry.delete(json.id);\n // Start the sidecar probe and expose it so executeCommand can await it.\n // Early execs wait for the probe (up to TRANSPORT_READY_WAIT_MS) rather\n // than all racing to the lease path independently.\n const generation = ++this._probeGeneration;\n // Remember the probe target so a later exec can restart the probe if this\n // one times out, instead of falling back to the lease path forever.\n this._probeTarget = { sandboxId: json.id, instanceUrl: json.instanceUrl };\n this._transportReadyPromise = this._probeSidecarThenRegister(json.id, json.instanceUrl, generation);\n }\n\n /**\n * Fire-and-forget probe that polls the sidecar's `/health` endpoint until\n * it responds, then populates the address registry. Runs detached from\n * `start()` so sandbox provision latency is unchanged; early execs simply\n * fall back to the lease path until the probe succeeds.\n *\n * If the sidecar never comes up within {@link SIDECAR_PROBE_TIMEOUT_MS},\n * the registry stays unpopulated, `_transportReadyPromise` is cleared,\n * and a later {@link _awaitTransportReady} call restarts the probe\n * instead of pinning this sandbox to the lease path.\n *\n * @param generation - The probe generation captured at call time. If this\n * no longer matches `_probeGeneration` when the probe succeeds, the probe\n * was superseded by a teardown or a new `start()`, so we skip the `set()`.\n */\n private async _probeSidecarThenRegister(sandboxId: string, instanceUrl: string, generation: number): Promise<void> {\n const probeStartedAt = Date.now();\n const deadline = probeStartedAt + SIDECAR_PROBE_TIMEOUT_MS;\n const fetchFn = this._privateNetFetch ?? fetch;\n let attempts = 0;\n while (Date.now() < deadline) {\n // Teardown or new start() superseded this probe — bail out early.\n if (generation !== this._probeGeneration) return;\n attempts++;\n try {\n const res = await fetchFn(`${instanceUrl}/health`, {\n method: 'GET',\n signal: AbortSignal.timeout(1_000),\n });\n const ok = res.ok;\n // Release the response body so the connection returns to the pool.\n await res.body?.cancel().catch(() => {});\n if (ok) {\n // A ~1-attempt probe means the sidecar was ready when the proxy\n // returned; hundreds of ms means it was still booting — the exact\n // window that used to silently fall back to the lease path.\n this.logger.info('platform-workspace probe ok', {\n sandboxId,\n sessionId: this._client.sessionId,\n probeDurationMs: Date.now() - probeStartedAt,\n attempts,\n });\n // Sidecar is listening. Only populate if this probe is still current.\n if (generation === this._probeGeneration && this._sandboxId === sandboxId) {\n this._addressRegistry?.set(sandboxId, instanceUrl);\n }\n return;\n }\n } catch {\n // Connection refused / timeout — keep polling.\n }\n await new Promise(r => setTimeout(r, SIDECAR_PROBE_INTERVAL_MS));\n }\n // Sidecar never came up within this probe's window. Leave the registry\n // entry unset (execs go via lease) but clear the ready promise so a later\n // exec can restart the probe rather than pinning this sandbox to the\n // lease path for its lifetime.\n if (generation === this._probeGeneration && this._transportReadyPromise) {\n this._transportReadyPromise = null;\n }\n this.logger.warn('platform-workspace probe timed out', {\n sandboxId,\n sessionId: this._client.sessionId,\n timeoutMs: SIDECAR_PROBE_TIMEOUT_MS,\n attempts,\n });\n }\n\n /**\n * Wait for the transport to become ready (sidecar probe succeeds) or time\n * out. Concurrent callers all await the same probe promise, coalescing the\n * cold-start storm into a single warmup attempt.\n *\n * If no probe is in flight (no registry, or registry already populated),\n * this returns immediately. After the wait (success or timeout), callers\n * check the registry and proceed — either via private-net or lease. The\n * lease path is still coalesced via `_leaseInFlight`, so even if the probe\n * times out, we only mint one lease for all concurrent execs.\n */\n private async _awaitTransportReady(): Promise<void> {\n // Fast path: registry already has an entry, transport is warm.\n if (this._sandboxId && this._addressRegistry?.get(this._sandboxId)) {\n return;\n }\n // No probe in flight. If a previous probe timed out for the current\n // sandbox, restart it — the sidecar may just have been slow to boot, and\n // one exec paying a short wait beats every exec going via lease forever.\n if (!this._transportReadyPromise) {\n const target = this._probeTarget;\n if (!target || this._sandboxId !== target.sandboxId) return;\n const generation = ++this._probeGeneration;\n this._transportReadyPromise = this._probeSidecarThenRegister(target.sandboxId, target.instanceUrl, generation);\n }\n // Race the probe against a timeout. We don't want to block execs forever\n // if the sidecar is slow to boot — they can proceed via lease after a\n // short wait, and later execs will use private-net once the probe succeeds.\n await Promise.race([this._transportReadyPromise, new Promise<void>(r => setTimeout(r, TRANSPORT_READY_WAIT_MS))]);\n }\n\n /**\n * Stop the sandbox while **preserving its recovery checkpoint**.\n *\n * Semantic parity with `@mastra/railway` `RailwaySandbox.stop()`: the VM\n * is released but the on-provider checkpoint survives, so a subsequent\n * `start()` on a sandbox constructed with the same `id` can restore from\n * it. Any in-flight capture is awaited first so the preserved checkpoint\n * reflects the latest disk state we asked for.\n *\n * Corresponds to `DELETE /v1/:provider/projects/:pid/sandbox/:sandboxId` on\n * workspace-proxy, which by contract does not touch the checkpoint. Use\n * {@link destroy} when you want the checkpoint released too.\n */\n async stop(): Promise<void> {\n // Await any in-flight capture so the preserved checkpoint reflects the\n // latest capture the caller triggered. Never rethrow — a failing capture\n // must not block teardown; the proxy's safety-net refresh timer is a\n // fallback for the checkpoint state.\n if (this._captureInFlight) {\n await this._captureInFlight.catch(error => {\n this.logger.warn(`stop(): failed to flush in-flight capture before teardown:`, error);\n });\n }\n await this._teardownSandbox();\n }\n\n /**\n * Destroy the sandbox **and release its recovery checkpoint**.\n *\n * Semantic parity with `@mastra/railway` `RailwaySandbox.destroy()`:\n * cancels any in-flight capture (the checkpoint is about to be deleted\n * — no reason to burn a capture on state we're releasing), asks the\n * proxy to delete the checkpoint, then releases the VM. Both remote\n * operations are best-effort logged failures — a stray checkpoint or a\n * transient proxy error must not leave the caller with a half-torn-down\n * sandbox they can't safely retry.\n *\n * Railway requires a caller-supplied recovery `id` before it can have a\n * checkpoint to delete. E2B also permits capture with the automatic id, so\n * destroy releases that named snapshot even when no recovery id was supplied.\n */\n async destroy(): Promise<void> {\n if (!this._sandboxId) return;\n const destroyedSandboxId = this._sandboxId;\n\n // Drop the in-flight capture promise — we're about to delete the\n // checkpoint, so completing an in-flight capture is at best a wasted\n // round-trip and at worst races with the delete. Callers get whatever\n // resolution the pending capture already had; we don't rethrow.\n this._captureInFlight = null;\n\n if (this._hasRecoveryKey || this._client.sandboxProvider === 'e2b') {\n // Body mirrors the POST /checkpoint shape (`{ id }`) so the proxy\n // can hash the same recovery key into the same checkpoint name.\n // Best-effort: a proxy 404/410 means the checkpoint is already\n // absent (idle GC, prior delete) and we can proceed with the VM\n // teardown; other failures are surfaced in logs but do not abort\n // — the VM DELETE below is the operation the caller most needs.\n try {\n await this._request(`/sandbox/${encodeURIComponent(destroyedSandboxId)}/checkpoint`, {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: this.id }),\n });\n } catch (error) {\n if (error instanceof PlatformApiError && (error.status === 404 || error.status === 410)) {\n this.logger.debug(`destroy(): checkpoint already absent upstream (status=${error.status})`);\n } else {\n this.logger.warn(`destroy(): failed to delete checkpoint upstream:`, error);\n }\n }\n }\n\n await this._teardownSandbox();\n }\n\n /**\n * Release the remote sandbox VM and clear the local state pointing at it.\n *\n * Shared body of {@link stop} and {@link destroy} — both funnel through\n * here after they've dealt with the checkpoint (preserve vs release).\n * The VM DELETE is safe to issue in either mode: the proxy's DELETE\n * route does not touch the checkpoint on its own, so `stop()` correctly\n * leaves the checkpoint intact and `destroy()` has already removed it\n * before this call.\n */\n private async _teardownSandbox(): Promise<void> {\n if (!this._sandboxId) return;\n const destroyedSandboxId = this._sandboxId;\n // Invalidate any in-flight probe so it doesn't re-populate the registry\n // after we've deleted the entry below. The probe checks this generation\n // before calling set(). Also drop the re-probe target so later execs\n // don't restart a probe against the deleted sandbox's address.\n this._probeGeneration++;\n this._probeTarget = null;\n this._transportReadyPromise = null;\n await this._request(`/sandbox/${encodeURIComponent(destroyedSandboxId)}`, { method: 'DELETE' });\n // Clear local state so a subsequent start() creates a fresh remote sandbox\n // instead of taking the reattach branch and pointing exec at a deleted resource.\n this._sandboxId = undefined;\n this._createdAt = null;\n // Drop the exec lease with the sandbox — the JWT is tied to the provider\n // instance id and would be rejected against a fresh one.\n this._lease = null;\n // Evict the sidecar address from the registry explicitly. Destroy\n // deallocates the IPv6, so any stale entry would be a dial-to-nowhere;\n // clearing here prevents a transport-failure round-trip on the next\n // exec against a reused instance. A subsequent start() (fresh provision\n // or reattach) will re-populate the entry from the workspace-proxy's\n // response.\n this._addressRegistry?.delete(destroyedSandboxId);\n }\n\n /** Persist the configured recovery checkpoint when available. */\n async snapshot(): Promise<void> {\n await this.captureCheckpoint();\n }\n\n /** Snapshots persist real checkpoints that can seed future sandboxes. */\n readonly supportsCheckpoints: boolean = true;\n\n /**\n * Capture the sandbox's checkpoint on demand, outside any refresh timer the\n * workspace-proxy owns internally.\n *\n * Intended for callers (e.g. a factory-side scheduler) that want to refresh\n * the recovery checkpoint at semantic moments — turn end, session-idle,\n * pre-teardown — rather than only just before the upstream's idle destroy.\n *\n * Mirrors the OSS `@mastra/railway` `RailwaySandbox.captureCheckpoint()`\n * shape so factory can call `sandbox.captureCheckpoint()` uniformly and\n * branch on `status`/`reason` without knowing which provider is underneath.\n * Both `captured` and `coalesced` carry the checkpoint name inline so the\n * caller can persist a session→checkpoint binding atomically with the\n * awaited capture.\n *\n * Skip semantics:\n * - No caller-supplied `id`: returns `{ status: 'skipped', reason:\n * 'no-checkpoint-name-configured' }`. An auto-generated random id is\n * never a meaningful recovery key (no future boot would look for a\n * checkpoint under it), so capturing would silently produce dead data.\n * - Not started (no `_sandboxId`): returns `{ status: 'skipped', reason:\n * 'sandbox-not-running' }` without a round-trip.\n * - Upstream 410 (workspace-proxy or Railway reports the sandbox is\n * already destroyed): returns the same `sandbox-not-running` skip so\n * the discriminant matches the pre-flight case. Local state\n * (`_sandboxId`, `_lease`, sidecar address) is cleared as a side\n * effect so the next `start()` provisions fresh instead of reattaching\n * to a dead id. The diagnostic distinction (pre-flight vs post-hoc)\n * is preserved in log level: debug for the expected pre-flight skip,\n * warn for the surprise upstream destroy.\n *\n * Concurrent callers on the same instance coalesce onto a single in-flight\n * `POST /checkpoint` so N simultaneous turn-end fires (e.g. several tabs)\n * do not each round-trip the proxy. Both the originator and joiners\n * receive `{ status: 'coalesced', ... }` for the joined result — the\n * outer contract does not distinguish who started the request, only that\n * one upstream capture was made.\n *\n * Never throws for expected outcomes. Transport failures (5xx, 4xx other\n * than 410) propagate as {@link PlatformApiError}; a 410 is normalized\n * to a skip as described above.\n */\n async captureCheckpoint(): Promise<CaptureCheckpointResult> {\n if (!this._hasRecoveryKey && this._client.sandboxProvider !== 'e2b') {\n this.logger.debug(\n `captureCheckpoint skipped: no recovery key configured for sandbox ${this._sandboxId ?? '(unstarted)'}`,\n );\n return { status: 'skipped', reason: 'no-checkpoint-name-configured' };\n }\n\n if (!this._sandboxId) {\n this.logger.debug(`captureCheckpoint skipped: sandbox not running (local pre-flight, id=${this.id})`);\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n\n if (this._captureInFlight) {\n return this._captureInFlight;\n }\n\n const sandboxId = this._sandboxId;\n const capture = this._doCaptureCheckpoint(sandboxId).finally(() => {\n if (this._captureInFlight === capture) {\n this._captureInFlight = null;\n }\n });\n this._captureInFlight = capture;\n return capture;\n }\n\n /**\n * The single `POST /checkpoint` attempt behind {@link captureCheckpoint}.\n *\n * Split out so the coalescing wrapper can install a shared in-flight\n * promise without inlining the transport + response-mapping logic.\n * Joined callers observe `{ status: 'coalesced', ... }` — the initiator\n * sees the underlying `captured` / `coalesced` / `skipped` result the\n * proxy returned. Both are legitimate: the OSS mirror uses the same\n * \"initiator sees the truth, joiners see coalesced\" split.\n */\n private async _doCaptureCheckpoint(sandboxId: string): Promise<CaptureCheckpointResult> {\n let response: Response;\n try {\n response = await this._request(`/sandbox/${encodeURIComponent(sandboxId)}/checkpoint`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: this.id }),\n });\n } catch (error) {\n if (error instanceof PlatformApiError && error.status === 410) {\n this.logger.warn(`captureCheckpoint skipped: sandbox destroyed upstream (proxy 410, sandboxId=${sandboxId})`);\n this._clearDestroyedState(sandboxId);\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n throw error;\n }\n const json = (await response.json()) as { checkpointName: string; status: 'captured' | 'coalesced' | 'skipped' };\n if (json.status === 'skipped') {\n // Proxy's own `skipped` means the upstream sandbox is already\n // destroyed — same actionable outcome as a 410, so normalize to\n // the same discriminant + clear local state.\n this.logger.warn(\n `captureCheckpoint skipped: sandbox destroyed upstream (proxy reported skipped, sandboxId=${sandboxId})`,\n );\n this._clearDestroyedState(sandboxId);\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n return { status: json.status, checkpointName: json.checkpointName };\n }\n\n /**\n * Clear local state that would otherwise let the caller keep exec'ing\n * against a sandbox the upstream has already destroyed. Mirrors what\n * `destroy()` does minus the outbound DELETE — the sandbox is already\n * gone, so all that remains is to stop pointing at it.\n *\n * Also resets `status` to `'pending'` so a subsequent `_start()` on this\n * reused instance re-runs provisioning instead of short-circuiting on\n * the cached `'running'` state (see `MastraSandbox._start`).\n */\n private _clearDestroyedState(destroyedSandboxId: string): void {\n this._probeGeneration++;\n this._probeTarget = null;\n this._transportReadyPromise = null;\n this._sandboxId = undefined;\n this._createdAt = null;\n this._lease = null;\n this._addressRegistry?.delete(destroyedSandboxId);\n this.status = 'pending';\n }\n\n /**\n * Execute a command on the remote sandbox.\n *\n * `command` is a **shell string**: it is concatenated verbatim into the\n * command line sent to the remote shell, which lets callers use pipes,\n * redirects, and chaining (`ls -la | grep foo`). This matches the contract\n * of {@link MastraSandbox} and the local sandbox implementation.\n *\n * `args`, when provided, are always shell-quoted so they cannot inject\n * additional shell syntax.\n *\n * Security: callers MUST NOT pass untrusted input as `command`. If any part\n * of the invocation is derived from an untrusted source, pass it through\n * `args` (which is safely quoted) or shell-quote it yourself before\n * inclusion. Untrusted `command` values allow arbitrary shell syntax\n * execution on the remote sandbox.\n */\n async executeCommand(command: string, args?: string[], options?: ExecuteCommandOptions): Promise<CommandResult> {\n await this.ensureRunning();\n if (!this._sandboxId) throw new SandboxNotReadyError(this.id);\n\n const started = Date.now();\n const fullCommand = buildCommand(command, args);\n // Nullish check so an explicit `timeout: 0` still overrides the instance\n // default. `_runDirectExec` omits `timeoutMs` from the exec payload when\n // the value is 0, which disables the client-side timer entirely.\n const effectiveTimeout = options?.timeout ?? this._timeout;\n\n // Merge the sandbox env under per-call env once, up front — every exec\n // transport below (private network, WebSocket lease, E2B lease) receives\n // these options, and none of them route through the process manager.\n const sandboxEnv = this.getEnv();\n const execCallOptions =\n Object.keys(sandboxEnv).length > 0 ? { ...options, env: { ...sandboxEnv, ...options?.env } } : options;\n\n // Wait for the transport to become ready before proceeding. During the\n // sidecar boot window (immediately after start()), concurrent execs all\n // await the same probe promise rather than each independently racing to\n // the lease path — this coalesces the cold-start storm into a single\n // warmup attempt. Once the probe resolves (or times out after\n // TRANSPORT_READY_WAIT_MS), we check the registry and proceed.\n await this._awaitTransportReady();\n\n // Preferred path: dial the in-sandbox sidecar over Railway's private\n // network (~16 ms p50). No GraphQL, no lease mint, no public tcp-proxy.\n // Available only when the in-process address registry has an entry for\n // this sandboxId — populated by start() from the workspace-proxy's\n // create/reattach response when the proxy discloses `instanceUrl`. On\n // any transport failure (connection refused, mid-stream drop, no exit\n // frame) we invalidate the registry entry and fall through to the lease\n // path — application-level failures (sidecar returns 5xx) still fall\n // back for this call but do NOT invalidate the entry. See\n // `.scratch/factory-deploy/issue-platform-sandbox-exec-via-private-network.md`.\n const instanceUrl = this._addressRegistry?.get(this._sandboxId);\n if (instanceUrl) {\n const privateNet = await this._tryExecViaPrivateNetwork(\n instanceUrl,\n fullCommand,\n effectiveTimeout,\n execCallOptions,\n );\n if (privateNet) {\n const privateExit = privateNet.exitCode ?? 124;\n return {\n success: privateExit === 0,\n exitCode: privateExit,\n stdout: privateNet.stdout,\n stderr: privateNet.stderr,\n timedOut: privateNet.timedOut,\n command: fullCommand,\n executionTimeMs: Date.now() - started,\n };\n }\n // Fall through — `_tryExecViaPrivateNetwork` already evicted the\n // registry entry if this was a transport failure.\n }\n\n // Fallback: WebSocket direct-exec via `/exec-lease`. `_runDirectExec`\n // handles single-shot transport retry and throws typed errors on\n // unrecoverable failure: `SandboxDestroyedError` when `/exec-lease`\n // returns 410 (fleet must reprovision), `SandboxExecTransportError`\n // when the WebSocket transport fails twice against a live sandbox,\n // `PlatformApiError` for other `/exec-lease` errors (404/500/501).\n // See ./direct-exec.ts and `docs/factory/direct-sandbox-connection.md`\n // in the Platform repo.\n const result = await this._runDirectExec(fullCommand, effectiveTimeout, execCallOptions);\n // `_runDirectExec` throws on transport failure (see its jsdoc), so a\n // `null` exitCode here can only mean `timedOut: true` — the sandbox\n // never got to send an exit frame because we cut the command short.\n // Use 124 for that (the conventional timeout exit code). We are NOT\n // coercing transport-failure nulls to fake exit codes — those throw.\n const exitCode = result.exitCode ?? 124;\n return {\n success: exitCode === 0,\n exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n timedOut: result.timedOut,\n command: fullCommand,\n executionTimeMs: Date.now() - started,\n };\n }\n\n /**\n * Run a single exec against the direct-exec transport, with one in-flight\n * retry on WebSocket transport failure (socket closed without an `exit`\n * frame and the exec did not time out). The retry mints a fresh lease\n * — the failure could be a stale JWT — and reopens a new WebSocket.\n *\n * Error taxonomy:\n * - **410 on `/exec-lease`** (either attempt) → the sandbox is gone.\n * Nulls the cached `_lease` and `_sandboxId` and throws\n * {@link SandboxDestroyedError}. Callers (typically `SandboxFleet`) must\n * catch this, clear the stale binding, and reprovision + replay.\n * - **Persistent transport failure** (both WS attempts close without an\n * `exit` frame against a live sandbox) → {@link SandboxExecTransportError}\n * with WebSocket close diagnostics.\n * - **Other `PlatformApiError`s** (404/500/501) propagate directly.\n * - **Real command result** (exit code from Railway's exit frame, or\n * `timedOut: true`) returns normally.\n *\n * Returns a result with a real `exitCode` OR `timedOut: true`. Never\n * returns `{ exitCode: null, timedOut: false }` — that case throws.\n */\n /**\n * Drop undefined values so the result matches the Record<string, string>\n * shape the exec transports expect (`ExecuteCommandOptions.env` is\n * NodeJS.ProcessEnv). The sandbox's own env is already merged in by\n * `executeCommand` before a transport sees these options. Returns undefined\n * when there is nothing to send.\n */\n private _execEnv(options: ExecuteCommandOptions | undefined): Record<string, string> | undefined {\n if (!options?.env) return undefined;\n const filtered = Object.fromEntries(\n Object.entries(options.env).filter((entry): entry is [string, string] => entry[1] !== undefined),\n );\n return Object.keys(filtered).length > 0 ? filtered : undefined;\n }\n\n private async _runDirectExec(\n fullCommand: string,\n effectiveTimeout: number | undefined,\n options: ExecuteCommandOptions | undefined,\n ): Promise<{ exitCode: number | null; stdout: string; stderr: string; timedOut: boolean }> {\n const filteredEnv = this._execEnv(options);\n\n let lastResult: Awaited<ReturnType<typeof execViaLease>> | undefined;\n let lastLease: CachedExecLease | undefined;\n let attemptsMade = 0;\n // Two attempts: initial + one retry. On the second attempt we drop the\n // cached lease so we don't reuse a JWT that may itself be the cause of\n // the transport failure — but only if the cache still holds the same\n // lease we just failed against. A concurrent exec sharing this instance\n // may have already cached a fresh, unrelated lease in between, and we\n // must not discard that.\n for (let attempt = 0; attempt < 2; attempt++) {\n if (attempt > 0 && lastLease && this._lease === lastLease) this._lease = null;\n let lease: CachedExecLease;\n try {\n lease = await this._ensureLease();\n } catch (error) {\n // 410 → sandbox has been destroyed. Clear all cached state so a\n // reused instance re-provisions cleanly, then hand off to the fleet\n // layer via a typed error. Other PlatformApiErrors (404/500/501)\n // propagate as-is — those are configuration or platform errors, not\n // a \"reprovision me\" signal.\n if (error instanceof PlatformApiError && error.status === 410) {\n this._lease = null;\n const priorSandboxId = this._sandboxId;\n this._sandboxId = undefined;\n // Reset lifecycle status too: the next `ensureRunning()` must re-run\n // the full start lifecycle (acquisition + `onStart` hook) so a\n // replacement VM is set up, not just leased.\n this.status = 'stopped';\n throw new SandboxDestroyedError(\n `Sandbox ${priorSandboxId ?? '(unknown)'} was destroyed; /exec-lease returned 410`,\n {\n ...(priorSandboxId && { sandboxId: priorSandboxId }),\n command: fullCommand,\n attempts: attempt + 1,\n },\n );\n }\n throw error;\n }\n lastLease = lease;\n attemptsMade = attempt + 1;\n const execOptions = {\n command: fullCommand,\n ...(options?.cwd !== undefined && { cwd: options.cwd }),\n ...(filteredEnv !== undefined && { env: filteredEnv }),\n ...(effectiveTimeout != null && effectiveTimeout > 0 && { timeoutMs: effectiveTimeout }),\n ...(this._webSocketFactory && { webSocketFactory: this._webSocketFactory }),\n };\n const result =\n lease.provider === 'e2b'\n ? await this._e2bExecRunner(lease, execOptions)\n : await execViaLease(lease, execOptions);\n lastResult = result;\n // `null` exitCode with `timedOut: false` means the socket closed\n // without an exit frame — a transport failure (handshake stalled,\n // mid-stream drop, expired token). Any other outcome (real exit code\n // or timed-out) is a valid result and we return it.\n if (result.exitCode !== null || result.timedOut) return result;\n }\n\n // Both attempts failed at the transport layer against a live sandbox.\n // Surface a loud, typed error with close diagnostics so callers can\n // distinguish \"your command failed\" from \"the sandbox transport is\n // broken.\"\n const result = lastResult!;\n const lease = lastLease!;\n // The lease from the failed second attempt is still cached; drop it so\n // the next `executeCommand` doesn't waste its first attempt on the same\n // implicated JWT before minting fresh. Identity-check first so a\n // concurrent exec that has already cached a fresh, unrelated lease\n // isn't collateral-damaged.\n if (this._lease === lease) this._lease = null;\n throw new SandboxExecTransportError(\n `Direct-exec transport failed for sandbox ${this._sandboxId ?? '(unknown)'} after ${attemptsMade} attempt(s)` +\n (result.closeCode !== undefined\n ? ` (close ${result.closeCode}${result.closeReason ? ` ${result.closeReason}` : ''})`\n : ''),\n {\n ...(this._sandboxId && { sandboxId: this._sandboxId }),\n command: fullCommand,\n attempts: attemptsMade,\n opened: result.opened ?? false,\n ...(result.closeCode !== undefined && { closeCode: result.closeCode }),\n ...(result.closeReason !== undefined && { closeReason: result.closeReason }),\n wsEndpoint: lease.wsEndpoint,\n },\n );\n }\n\n /**\n * Try to run the exec against the in-sandbox sidecar over Railway's private\n * network. Returns the result on success (including non-zero exit codes and\n * timeouts — those are real command results, not failures). Returns\n * `undefined` when the caller should fall back to the lease path:\n *\n * - Transport failure (connection refused, mid-stream drop, no `exit`\n * frame). The registry entry is evicted so subsequent execs skip the\n * private-net dial until the sidecar re-registers.\n * - Sidecar answered with a non-2xx HTTP status. Registry is left intact —\n * the address is still valid; something else is wrong (bad request,\n * sidecar bug). Only this specific exec falls back.\n */\n private async _tryExecViaPrivateNetwork(\n instanceUrl: string,\n fullCommand: string,\n effectiveTimeout: number | undefined,\n options: ExecuteCommandOptions | undefined,\n ): Promise<PrivateNetExecResult | undefined> {\n const filteredEnv = this._execEnv(options);\n\n const execOptions: PrivateNetExecOptions = {\n command: fullCommand,\n ...(options?.cwd !== undefined && { cwd: options.cwd }),\n ...(filteredEnv !== undefined && { env: filteredEnv }),\n ...(effectiveTimeout != null && effectiveTimeout > 0 && { timeoutMs: effectiveTimeout }),\n ...(this._privateNetFetch && { fetch: this._privateNetFetch }),\n };\n\n let result: PrivateNetExecResult;\n try {\n result = await execViaPrivateNetwork(instanceUrl, execOptions);\n } catch (error) {\n if (error instanceof PrivateNetExecHttpError) {\n // Application-level failure from a reachable sidecar. Fall back for\n // this call, but do NOT evict the registry entry — future calls\n // should still prefer the private-network path.\n return undefined;\n }\n // Anything else escaping is unexpected (e.g. options validation). Treat\n // it like a transport failure so we don't wedge the caller.\n this._invalidateAddress();\n return undefined;\n }\n\n // A timeout is always the caller's answer, never a lease-fallback trigger:\n // the sidecar may already be running the command, so re-executing on the\n // lease path would double-run non-idempotent work (rm, git push, DB\n // migrations) and return the second result instead of `timedOut: true`.\n // If we never opened the response (pre-headers abort), the address is\n // still evicted so subsequent execs skip a dial we already know is slow —\n // but the timed-out result itself flows back to the caller unchanged.\n if (result.timedOut) {\n if (!result.opened) this._invalidateAddress();\n return result;\n }\n\n // A completed exec (real exit code) is a valid result — hand it back even\n // if exitCode is non-zero. Only evict when the transport itself failed:\n // never opened, or opened without an exit frame. `opened=false` here\n // means connection refused (no timeout to disambiguate).\n const transportFailed = !result.opened || result.exitCode === null;\n if (transportFailed) {\n this._invalidateAddress();\n return undefined;\n }\n\n return result;\n }\n\n /**\n * Evict this sandbox's entry from the address registry after an observed\n * transport failure. The entry stays gone until the next start() re-reads\n * `instanceUrl` from a workspace-proxy response — until then, execs skip\n * the private-net dial and go straight to the lease path.\n */\n private _invalidateAddress(): void {\n if (this._sandboxId) this._addressRegistry?.delete(this._sandboxId);\n }\n\n /**\n * Return a cached exec lease, minting a fresh one when the cache is empty\n * or the JWT is within {@link LEASE_REFRESH_MARGIN_MS} of `expiresAt`.\n *\n * Callers are expected to be on the \"sandbox is running\" path; we don't\n * re-check `_sandboxId` here because `executeCommand` already gated on it.\n */\n private async _ensureLease(): Promise<CachedExecLease> {\n const now = Date.now();\n // Cache hit only when we know the expiry AND we're comfortably before it.\n // A null `expiresAtMs` means the provider didn't disclose a TTL — treat\n // that as \"refresh every call\" rather than \"cache forever\", so a token\n // that turns out to be short-lived can't wedge the sandbox until restart.\n if (this._lease && this._lease.expiresAtMs !== null && this._lease.expiresAtMs - LEASE_REFRESH_MARGIN_MS > now) {\n return this._lease;\n }\n // Coalesce concurrent mints on a cold/expired cache.\n if (this._leaseInFlight) return this._leaseInFlight;\n if (!this._sandboxId) throw new SandboxNotReadyError(this.id);\n const sandboxId = this._sandboxId;\n const inFlight = (async () => {\n const response = await this._request(`/sandbox/${encodeURIComponent(sandboxId)}/exec-lease`, {\n method: 'POST',\n });\n const json = (await response.json()) as ExecLeaseResponse;\n const expiresAtMs = json.expiresAt ? Date.parse(json.expiresAt) : null;\n const lease: CachedExecLease = {\n provider: json.provider,\n sandboxId: json.sandboxId,\n providerResourceId: json.providerResourceId,\n jwt: json.jwt,\n wsEndpoint: json.wsEndpoint,\n subprotocol: json.subprotocol,\n expiresAt: json.expiresAt,\n // Guard against `Date.parse` returning NaN for malformed values by\n // treating them as \"no expiry known\", which forces a mint every call\n // rather than silently caching a broken lease forever.\n expiresAtMs: expiresAtMs !== null && !Number.isNaN(expiresAtMs) ? expiresAtMs : null,\n };\n this._lease = lease;\n return lease;\n })();\n this._leaseInFlight = inFlight;\n try {\n return await inFlight;\n } finally {\n // Clear on both success and failure so a failed mint doesn't wedge\n // future callers into awaiting the same rejected promise forever.\n if (this._leaseInFlight === inFlight) this._leaseInFlight = null;\n }\n }\n\n async getInfo(): Promise<SandboxInfo> {\n if (!this._sandboxId) {\n return {\n id: this.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n createdAt: this._createdAt ?? new Date(),\n };\n }\n // Skip the workspace-proxy round-trip when the address registry has an\n // entry for this sandbox — a live entry is proof that start() saw an\n // `instanceUrl` on the create/reattach response and that no exec since\n // has evicted it via a transport failure. Serving `getInfo()` from\n // local state here removes the per-poll `GET /sandbox/:id` hit that\n // otherwise triggers a Railway GraphQL call + `sandboxExec` awk on\n // `/proc/net/if_inet6` inside the proxy.\n //\n // Note: this does NOT probe the sidecar. If the sandbox has been\n // destroyed out-of-band the next exec will fail transport, evict the\n // registry entry, and a subsequent getInfo() will fall through to the\n // proxy below and observe the true status.\n if (this._addressRegistry?.get(this._sandboxId)) {\n return {\n id: this._sandboxId,\n name: this.name,\n provider: this.provider,\n status: this.status,\n createdAt: this._createdAt ?? new Date(),\n metadata: {\n sandboxId: this._sandboxId,\n },\n };\n }\n const response = await this._request(`/sandbox/${encodeURIComponent(this._sandboxId)}`);\n const json = (await response.json()) as CreateSandboxResponse;\n return {\n id: json.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n createdAt: json.createdAt ? new Date(json.createdAt) : (this._createdAt ?? new Date()),\n metadata: {\n // The platform assigns its own sandbox id on create (the advisory id\n // sent in the POST body is not honored). Expose it so callers that\n // persist a reattach id (e.g. the Factory sandbox fleet, which reads\n // `metadata.sandboxId`) store the id the proxy actually recognizes\n // instead of the locally generated construction id.\n sandboxId: json.id,\n providerResourceId: json.providerResourceId ?? undefined,\n platformStatus: json.status,\n },\n };\n }\n\n getInstructions(opts?: { requestContext?: RequestContext }): string {\n const defaultInstructions = `Platform sandbox${this._sandboxId ? ` ${this._sandboxId}` : ''}. Execute commands with the sandbox command APIs.`;\n if (typeof this._instructionsOverride === 'function') {\n return this._instructionsOverride({ defaultInstructions, requestContext: opts?.requestContext });\n }\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return defaultInstructions;\n }\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nimport { Template, type SandboxTemplateBuilder } from './template.js';\n\nconst execFileAsync = promisify(execFile);\ntype GitExec = (\n file: string,\n args: string[],\n options: { timeout: number; maxBuffer: number; env: NodeJS.ProcessEnv },\n) => Promise<{ stdout: string }>;\nconst SHA_PATTERN = /^[0-9a-f]{7,40}$/i;\nconst BUILD_TOKEN_ENV = 'MASTRA_REPOSITORY_ACCESS_TOKEN';\n\n/**\n * Clone URLs interpolate into the template's build commands, so constrain\n * them to https plus plain host/path characters. Every regex here is a\n * single anchored character class, so matching stays linear on adversarial\n * input; the structural checks go through WHATWG URL parsing instead of one\n * big backtracking pattern.\n */\nconst CLONE_URL_ALLOWED_CHARS = /^[a-z0-9:/._-]+$/i;\nconst CLONE_URL_HOST_PATTERN = /^[a-z0-9.-]+$/i;\nconst CLONE_URL_SEGMENT_PATTERN = /^[\\w.-]+$/;\n\n/**\n * Structurally matches the repository access resolver a Factory sandbox\n * context carries, so a host can pass its context straight through.\n */\nexport interface PlatformRepositoryAccess {\n /** https clone URL, e.g. `https://github.com/acme/widgets.git`. */\n cloneUrl: string;\n /**\n * Short-lived credential for private repositories. The token is used for\n * head resolution and sent as a transient template build environment value;\n * it is excluded from the serialized definition, content identity, and\n * persistent template record.\n */\n authorization?: { scheme: 'bearer'; token: string };\n}\n\nexport interface PlatformRepoTemplateOptions {\n /**\n * Resolves the repository's clone URL and, for private repositories, a\n * short-lived credential. Absent — the session has no repository — makes\n * `createRepoTemplate` return `undefined`, which asks PlatformSandbox for\n * the provider default without a conditional at the call site.\n */\n getRepositoryAccess: (() => Promise<PlatformRepositoryAccess | undefined>) | undefined;\n /** Setup command run inside the checkout during the provider build. */\n setupCommand?: string;\n /**\n * vCPU count for the template build and the sandboxes created from it.\n * Identity-bearing: a different count builds a different template, and the\n * platform namespaces warm family fallbacks by size so a resized request\n * can never boot on a differently-sized filesystem. Omitted uses the\n * provider default.\n */\n cpuCount?: number;\n /** Memory in MB. Same identity and fallback semantics as `cpuCount`. */\n memoryMB?: number;\n /** Test/integration seam for resolving the default-branch head. */\n resolveHead?: (cloneUrl: string, token?: string) => Promise<string | undefined>;\n}\n\nexport type PlatformRepoTemplateResolver = () => Promise<SandboxTemplateBuilder | undefined>;\n\n/**\n * Create a lazy repository template definition for PlatformSandbox, mirroring\n * `@mastra/e2b`'s `createRepoTemplate`: pass the sandbox context through and a\n * repo-less session boots the provider default.\n *\n * The resolver performs no work until a fresh sandbox starts. It clones the\n * URL `getRepositoryAccess` resolves — the only source of the clone URL, so\n * what gets cloned and what the template is identified by can't drift — and\n * pins repositories to their current default-branch commit. Private repository\n * credentials are used for head resolution and sent to the provider as\n * transient build envs; they never enter the serialized definition. If the\n * head cannot be resolved, the resolver returns undefined so PlatformSandbox\n * boots from the provider default and the caller's runtime setup materializes\n * the checkout instead.\n */\nexport function createRepoTemplate(options: PlatformRepoTemplateOptions): PlatformRepoTemplateResolver | undefined {\n const getRepositoryAccess = options.getRepositoryAccess;\n if (!getRepositoryAccess) return undefined;\n const resolveHead = options.resolveHead ?? resolveDefaultBranchHead;\n\n return async () => {\n const access = await getRepositoryAccess().catch(() => undefined);\n if (!access?.cloneUrl) return undefined;\n const cloneUrl = normalizeCloneUrl(access.cloneUrl);\n if (!isValidCloneUrl(cloneUrl)) return undefined;\n\n const token = access.authorization?.token;\n const sha = await (token ? resolveHead(cloneUrl, token) : resolveHead(cloneUrl)).catch(() => undefined);\n if (!sha || !SHA_PATTERN.test(sha)) return undefined;\n\n const workdir = defaultWorkdir(cloneUrl);\n const auth = token ? `${gitAuthFlag()} ` : '';\n const steps = [\n `git ${auth}clone ${cloneUrl} \"${workdir}\"`,\n `git -C \"${workdir}\" ${auth}fetch origin ${sha}`,\n `git -C \"${workdir}\" checkout ${sha}`,\n ...(options.setupCommand ? [`cd \"${workdir}\" && ${options.setupCommand}`] : []),\n ];\n\n // Commit-independent family key that groups every commit of the same\n // repo+workdir together. The platform uses it to find a prior build in\n // the same family so new commits boot on a warm filesystem while the\n // exact template continues to build in the background.\n const family = `repo:${cloneUrl}:${workdir}`;\n let template = Template();\n if (token) template = template.setEnvs({ [BUILD_TOKEN_ENV]: token }, { ephemeral: true });\n if (options.cpuCount !== undefined) template = template.cpuCount(options.cpuCount);\n if (options.memoryMB !== undefined) template = template.memoryMB(options.memoryMB);\n return template.runCmd(steps).withFamily(family);\n };\n}\n\nfunction isValidCloneUrl(cloneUrl: string): boolean {\n // The raw string is what reaches the build's shell commands, so allowlist\n // it directly: URL normalization must not be able to launder characters\n // the raw string carries.\n if (cloneUrl.length > 2048 || !CLONE_URL_ALLOWED_CHARS.test(cloneUrl)) return false;\n let url: URL;\n try {\n url = new URL(cloneUrl);\n } catch {\n return false;\n }\n if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) return false;\n if (!CLONE_URL_HOST_PATTERN.test(url.hostname)) return false;\n // At least one path segment, none empty — rejects bare hosts and\n // trailing slashes.\n const segments = url.pathname.split('/').slice(1);\n return segments.length > 0 && segments.every(segment => CLONE_URL_SEGMENT_PATTERN.test(segment));\n}\n\n/**\n * Canonical form used for identity, the family key, and the build's clone:\n * lowercase host, no trailing `.git` or slash. Two spellings of one\n * repository must not produce two templates.\n */\nfunction normalizeCloneUrl(cloneUrl: string): string {\n // Trailing slashes are trimmed with a scan, not an end-anchored `\\/+$`\n // regex, which backtracks quadratically on slash runs.\n let end = cloneUrl.length;\n while (end > 0 && cloneUrl[end - 1] === '/') end--;\n const withoutSuffix = cloneUrl.slice(0, end).replace(/\\.git$/i, '');\n return withoutSuffix.replace(/^(https:\\/\\/)([^/]+)/i, (_match, scheme: string, host: string) => {\n return `${scheme.toLowerCase()}${host.toLowerCase()}`;\n });\n}\n\nfunction defaultWorkdir(cloneUrl: string): string {\n const repo = normalizeCloneUrl(cloneUrl).split('/').at(-1) ?? '';\n const name = repo.replace(/[^\\w.-]/g, '-').replace(/^\\.+/, '') || 'repo';\n return `$HOME/${name}`;\n}\n\nfunction gitAuthFlag(): string {\n return `-c http.extraheader=\"AUTHORIZATION: basic $(printf 'x-access-token:%s' \"$${BUILD_TOKEN_ENV}\" | base64 -w0)\"`;\n}\n\nexport async function resolveDefaultBranchHead(\n cloneUrl: string,\n token?: string,\n execute: GitExec = execFileAsync as GitExec,\n): Promise<string | undefined> {\n try {\n const env: NodeJS.ProcessEnv = { ...process.env, GIT_TERMINAL_PROMPT: '0' };\n if (token) {\n env.GIT_CONFIG_COUNT = '1';\n env.GIT_CONFIG_KEY_0 = 'http.extraheader';\n env.GIT_CONFIG_VALUE_0 = `AUTHORIZATION: basic ${Buffer.from(`x-access-token:${token}`).toString('base64')}`;\n }\n // `--` makes the URL position unambiguous to git: even a hostile value\n // can never be read as an option such as `--upload-pack`. Git config is\n // supplied through the child environment so the token never appears in\n // the process argument list. GIT_TERMINAL_PROMPT=0 makes an inaccessible\n // repository fail fast instead of hanging on a credential prompt.\n const { stdout } = await execute('git', ['ls-remote', '--', cloneUrl, 'HEAD'], {\n timeout: 10_000,\n maxBuffer: 1024 * 1024,\n env,\n });\n const sha = stdout.trim().split(/\\s+/, 1)[0];\n return sha && SHA_PATTERN.test(sha) ? sha : undefined;\n } catch {\n return undefined;\n }\n}\n","import type { FilesystemProvider, SandboxProvider } from '@mastra/core/editor';\nimport type { PlatformFilesystemOptions } from './filesystem.js';\nimport { PlatformFilesystem } from './filesystem.js';\nimport type { PlatformSandboxOptions } from './sandbox.js';\nimport { PlatformSandbox } from './sandbox.js';\n\nexport const platformSandboxProvider: SandboxProvider<PlatformSandboxOptions> = {\n id: 'platform',\n name: 'Mastra Platform Sandbox',\n description: 'Environment-scoped sandbox execution through Mastra Platform workspace proxy',\n configSchema: {\n type: 'object',\n properties: {\n accessToken: {\n type: 'string',\n description: 'Mastra Platform access token (falls back to MASTRA_PLATFORM_ACCESS_TOKEN)',\n },\n projectId: { type: 'string', description: 'Platform project ID (falls back to MASTRA_PROJECT_ID)' },\n actingUserId: { type: 'string', description: 'Opaque user subject attributed to sandbox requests' },\n sandboxProvider: {\n type: 'string',\n description: 'Sandbox provider (falls back to SANDBOX_PROVIDER, then e2b)',\n enum: ['railway', 'e2b'],\n default: 'e2b',\n },\n environmentId: { type: 'string', description: 'Platform environment ID (falls back to MASTRA_ENVIRONMENT_ID)' },\n sandboxId: { type: 'string', description: 'Reattach to an existing Platform sandbox by ID' },\n idleTimeoutMinutes: { type: 'number', description: 'Minutes before the sandbox can be destroyed while idle' },\n networkIsolation: {\n type: 'string',\n description: 'Network isolation mode',\n enum: ['ISOLATED', 'PRIVATE'],\n default: 'ISOLATED',\n },\n env: { type: 'object', description: 'Environment variables', additionalProperties: { type: 'string' } },\n timeout: { type: 'number', description: 'Default command timeout in ms' },\n },\n },\n createSandbox: config => new PlatformSandbox(config),\n};\n\nexport const platformFilesystemProvider: FilesystemProvider<PlatformFilesystemOptions> = {\n id: 'platform',\n name: 'Mastra Platform Filesystem',\n description: 'Bucket-backed filesystem access through Mastra Platform workspace proxy',\n configSchema: {\n type: 'object',\n properties: {\n accessToken: {\n type: 'string',\n description: 'Mastra Platform access token (falls back to MASTRA_PLATFORM_ACCESS_TOKEN)',\n },\n projectId: { type: 'string', description: 'Platform project ID (falls back to MASTRA_PROJECT_ID)' },\n bucketName: {\n type: 'string',\n description: 'Platform workspace bucket name (falls back to MASTRA_PLATFORM_BUCKET_NAME)',\n },\n readOnly: { type: 'boolean', description: 'Mount as read-only', default: false },\n },\n },\n createFilesystem: config => new PlatformFilesystem(config),\n};\n","/**\n * In-process `sandboxId → instanceUrl` registry populated by\n * {@link PlatformSandbox.start} from the `instanceUrl` field workspace-proxy\n * includes on create + get responses, and consumed by\n * {@link PlatformSandbox.executeCommand} on the private-network fast path.\n *\n * The registry lives in the same Node process as the `PlatformSandbox`\n * consumer — for shipyard, that is the Mastra runtime deployed from\n * `mastracode/web`. There is no receiver route and no cross-service dance;\n * the address is just a field copied from a response the runtime already\n * receives.\n *\n * State intentionally does not persist:\n *\n * - The IPv6 rotates on every sandbox recreate.\n * - The URL has no meaning after the sandbox is destroyed.\n * - The live sandbox binding, session context, and lease all die with the\n * runtime process; the address dying with them is correct.\n * - The proxy's `environment_sandboxes.instance_url` column is the durable\n * source of truth — a runtime restart re-populates the registry on the\n * next `start()` / reattach from the proxy's response.\n */\n\nimport type { SandboxAddressRegistry } from './sandbox.js';\n\n/**\n * Concrete in-process {@link SandboxAddressRegistry}. Backed by a `Map`; no\n * eviction policy, no TTL — entries live until an observed transport failure\n * calls `delete`, until the sandbox is explicitly destroyed, or until the\n * process exits.\n */\nexport class InProcessSandboxAddressRegistry implements SandboxAddressRegistry {\n readonly #map = new Map<string, string>();\n\n get(sandboxId: string): string | undefined {\n return this.#map.get(sandboxId);\n }\n\n /**\n * Populate or overwrite the address for a sandbox. Called by\n * {@link PlatformSandbox.start} on every fresh provision and every reattach;\n * overwriting is intentional so a re-provision with a fresh IPv6 heals the\n * map without a branch.\n */\n set(sandboxId: string, instanceUrl: string): void {\n this.#map.set(sandboxId, instanceUrl);\n }\n\n delete(sandboxId: string): void {\n this.#map.delete(sandboxId);\n }\n\n /**\n * Test-only introspection. Not part of {@link SandboxAddressRegistry} —\n * production callers must not read the registry as a whole.\n */\n get size(): number {\n return this.#map.size;\n }\n}\n"],"mappings":"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"}
|