@mastra/railway 0.6.0 → 0.7.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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # @mastra/railway
2
2
 
3
+ ## 0.7.0-alpha.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Honor the sandbox runtime environment (`setEnv()`/`getEnv()` from `@mastra/core`) in every workspace sandbox provider. Environment variables set after construction now reach subsequent commands on all providers: ([#22250](https://github.com/mastra-ai/mastra/pull/22250))
8
+
9
+ - Process-manager-routed providers (E2B, Blaxel, Cloudflare, Daytona, Docker, Modal, Vercel microVM spawns) inherit the merge from the core spawn wrapper; their duplicated per-manager env plumbing is removed.
10
+ - Providers with their own exec transports (AgentCore, Apple Container, Railway, Vercel microVM and serverless `executeCommand`, Platform's private-network, WebSocket lease, and E2B lease paths) now merge `getEnv()` under per-call env.
11
+
12
+ Constructor `env` continues to behave as before: it seeds the sandbox runtime environment, and providers that bake env into the VM or container at creation time (Docker, Modal, Railway, Apple Container, Vercel, Platform) still do so. Per-call `env` on `executeCommand` still takes precedence for that command only.
13
+
14
+ Removed exported types (minor bump for these two packages): `BlaxelProcessManagerOptions` from `@mastra/blaxel` and `RailwayProcessManagerOptions` from `@mastra/railway`. Both existed only to pass `env` into a process manager constructed by hand; the core spawn wrapper now owns that merge, so the option and its type are gone.
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [[`aa3a85d`](https://github.com/mastra-ai/mastra/commit/aa3a85daf094c683bb97efdf4b6a696d2e474af5), [`d29d06f`](https://github.com/mastra-ai/mastra/commit/d29d06fe00bbd35b4571150ea04c59d2ed783c71), [`e6516df`](https://github.com/mastra-ai/mastra/commit/e6516dfcdae4f4ac0e7971d84359a81385ee602f), [`0b2a3d1`](https://github.com/mastra-ai/mastra/commit/0b2a3d1783875c5b97b7b36ab3d03d7360e0dde7), [`6bb5d71`](https://github.com/mastra-ai/mastra/commit/6bb5d7193fe9166b219f0fccae17db7a5ae86e65), [`57de7d6`](https://github.com/mastra-ai/mastra/commit/57de7d644ba7146edb4e9e6111ec4fa98c3a59e9), [`e8e299c`](https://github.com/mastra-ai/mastra/commit/e8e299cc6abdfc39947e2fec25803493015d3882), [`edfc548`](https://github.com/mastra-ai/mastra/commit/edfc548886bc7bae17b681f8b6b41a47eb32bcd2), [`a8a4871`](https://github.com/mastra-ai/mastra/commit/a8a4871215f51da95c47129602157ce5372f634a), [`5165cdc`](https://github.com/mastra-ai/mastra/commit/5165cdcdcf50e144bb8113278535196cc9b07065), [`6bb5d71`](https://github.com/mastra-ai/mastra/commit/6bb5d7193fe9166b219f0fccae17db7a5ae86e65), [`9ee8120`](https://github.com/mastra-ai/mastra/commit/9ee8120ce17f76b9f617489e05a283353742690a), [`d975e92`](https://github.com/mastra-ai/mastra/commit/d975e924d4936f46c386bd3dee39c671720289f6), [`1cfa878`](https://github.com/mastra-ai/mastra/commit/1cfa8784d8da0dfaa0317e5048bc48b6084a5ea5), [`c118318`](https://github.com/mastra-ai/mastra/commit/c1183181c9804303db4b511c2e2648f8b714712b), [`fc07c64`](https://github.com/mastra-ai/mastra/commit/fc07c6465043e08e99193a6751a01c56ffc2e7a1), [`542dee2`](https://github.com/mastra-ai/mastra/commit/542dee254167f974ff8cbbbfc0ce10f9a2616a7b), [`a58483c`](https://github.com/mastra-ai/mastra/commit/a58483cff1a9d41fce7c931843f48cb0ac450f64), [`a58483c`](https://github.com/mastra-ai/mastra/commit/a58483cff1a9d41fce7c931843f48cb0ac450f64), [`895e9df`](https://github.com/mastra-ai/mastra/commit/895e9dfc17d6f34299eca64e317ded9e5f5e5ef8)]:
19
+ - @mastra/core@1.62.0-alpha.8
20
+
3
21
  ## 0.6.0
4
22
 
5
23
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -108,15 +108,9 @@ var RailwayProcessHandle = class extends _mastra_core_workspace.ProcessHandle {
108
108
  */
109
109
  var RailwayProcessManager = class extends _mastra_core_workspace.SandboxProcessManager {
110
110
  _spawnCounter = 0;
111
- constructor(opts = {}) {
112
- super({ env: opts.env });
113
- }
114
111
  async spawn(command, options = {}) {
115
112
  const railway = this.sandbox.railway;
116
- const mergedEnv = {
117
- ...this.env,
118
- ...options.env
119
- };
113
+ const mergedEnv = { ...options.env };
120
114
  const env = Object.fromEntries(Object.entries(mergedEnv).filter((entry) => entry[1] !== void 0));
121
115
  const pid = `railway-proc-${Date.now().toString(36)}-${(this._spawnCounter++).toString(36)}`;
122
116
  let handle;
@@ -214,7 +208,7 @@ var RailwaySandbox = class RailwaySandbox extends _mastra_core_workspace.MastraS
214
208
  super({
215
209
  ...options,
216
210
  name: "RailwaySandbox",
217
- processes: new RailwayProcessManager({ env: options.env })
211
+ processes: new RailwayProcessManager()
218
212
  });
219
213
  this.id = options.id ?? this.generateId();
220
214
  this._token = options.token ?? process.env.RAILWAY_API_TOKEN;
@@ -564,7 +558,11 @@ var RailwaySandbox = class RailwaySandbox extends _mastra_core_workspace.MastraS
564
558
  }
565
559
  const fullCommand = args.length > 0 ? `${command} ${args.map(shellQuote).join(" ")}` : command;
566
560
  const timeout = options.timeout ?? this._timeout;
567
- const env = options.env ? Object.fromEntries(Object.entries(options.env).filter((entry) => entry[1] !== void 0)) : void 0;
561
+ const mergedEnv = {
562
+ ...this.getEnv(),
563
+ ...options.env
564
+ };
565
+ const env = Object.keys(mergedEnv).length ? Object.fromEntries(Object.entries(mergedEnv).filter((entry) => entry[1] !== void 0)) : void 0;
568
566
  const startedAt = Date.now();
569
567
  const result = await this.railway.exec(fullCommand, {
570
568
  ...timeout !== void 0 && { timeoutSec: Math.ceil(timeout / 1e3) },
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["ProcessHandle","UnsupportedStdinCloseError","SandboxProcessManager","MastraSandbox","SandboxNotReadyError","SandboxNotFoundError","Sandbox"],"sources":["../src/utils/shell-quote.ts","../src/sandbox/process-manager.ts","../src/sandbox/index.ts","../src/provider.ts"],"sourcesContent":["/**\n * Shell-quote a single argument for safe use in a command string.\n *\n * Arguments containing only safe characters are returned as-is.\n * All others are wrapped in single quotes with embedded single quotes escaped.\n */\nexport function shellQuote(arg: string): string {\n // Safe characters that don't need quoting\n if (/^[a-zA-Z0-9._\\-/@:=]+$/.test(arg)) return arg;\n // Wrap in single quotes, escaping any embedded single quotes\n return \"'\" + arg.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n","/**\n * Railway Process Manager\n *\n * Implements SandboxProcessManager for Railway sandboxes.\n * Wraps the Railway SDK's `Sandbox.exec()` API.\n *\n * Railway's `exec(command, options)` accepts per-call `cwd` and `env` options\n * (since SDK v3.3.1) and returns an `ExecHandle` that runs the command\n * server-side, independently of the client. Each spawn() starts one exec.\n * The handle streams output via `onStdout`/`onStderr` callbacks wired to\n * `emitStdout`/`emitStderr`, exposes a durable `sessionName`, and can be\n * terminated with `kill(signal)`.\n */\n\nimport { ProcessHandle, UnsupportedStdinCloseError, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { ExecHandle, ExecResult } from 'railway';\nimport type { RailwaySandbox } from './index';\n\nexport const LOG_PREFIX = '[RailwaySandbox]';\n\n// =============================================================================\n// Railway Process Handle\n// =============================================================================\n\n/**\n * Wraps a Railway ExecHandle to conform to Mastra's ProcessHandle.\n * Not exported — internal to this module.\n */\nclass RailwayProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _execHandle: ExecHandle;\n private readonly _startTime: number;\n private _exitCode: number | undefined;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _killed = false;\n\n constructor(pid: string, execHandle: ExecHandle, startTime: number, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this._execHandle = execHandle;\n this._startTime = startTime;\n\n // Resolve exit code once the command completes so exitCode is available\n // without an explicit wait().\n void this._execHandle.then(\n (result: ExecResult) => {\n // -1 means terminated by a signal (e.g. after kill()).\n this._exitCode = result.exitCode ?? (this._killed ? 137 : -1);\n },\n () => {\n if (this._exitCode === undefined) {\n this._exitCode = 1;\n }\n },\n );\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n async wait(): Promise<CommandResult> {\n // Idempotent — cache the promise so repeated calls return the same result.\n if (!this._waitPromise) {\n this._waitPromise = this._doWait();\n }\n return this._waitPromise;\n }\n\n private async _doWait(): Promise<CommandResult> {\n try {\n const result = await this._execHandle;\n const exitCode = result.exitCode ?? (this._killed ? 137 : -1);\n this._exitCode = exitCode;\n\n // Railway captures output server-side; surface it through the base buffers\n // if streaming callbacks didn't already populate them.\n if (result.stdout && !this.stdout) this.emitStdout(result.stdout);\n if (result.stderr && !this.stderr) this.emitStderr(result.stderr);\n\n return {\n success: exitCode === 0,\n exitCode,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n killed: this._killed,\n timedOut: result.timedOut,\n };\n } catch (error) {\n const exitCode = this._exitCode ?? 1;\n this._exitCode = exitCode;\n return {\n success: false,\n exitCode,\n stdout: this.stdout,\n stderr: this.stderr || (error instanceof Error ? error.message : String(error)),\n executionTimeMs: Date.now() - this._startTime,\n killed: this._killed,\n };\n }\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n this._killed = true;\n try {\n return await this._execHandle.kill('TERM');\n } catch {\n // Command may already be gone.\n return false;\n }\n }\n\n async sendStdin(_data: string): Promise<void> {\n // Railway's exec API does not expose stdin streaming.\n throw new Error(`${LOG_PREFIX} sending stdin is not supported by the Railway sandbox provider`);\n }\n\n async closeStdin(): Promise<void> {\n throw new UnsupportedStdinCloseError(\n `${LOG_PREFIX} closing stdin is not supported by the Railway sandbox provider`,\n );\n }\n}\n\n// =============================================================================\n// Railway Process Manager\n// =============================================================================\n\nexport interface RailwayProcessManagerOptions {\n env?: Record<string, string | undefined>;\n}\n\n/**\n * Railway implementation of SandboxProcessManager.\n * Uses the Railway SDK's `Sandbox.exec()` with one exec per spawned process.\n */\nexport class RailwayProcessManager extends SandboxProcessManager<RailwaySandbox> {\n private _spawnCounter = 0;\n\n constructor(opts: RailwayProcessManagerOptions = {}) {\n super({ env: opts.env });\n }\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n const railway = this.sandbox.railway;\n\n // Merge default env with per-spawn env.\n const mergedEnv = { ...this.env, ...options.env };\n const env = Object.fromEntries(\n Object.entries(mergedEnv).filter((entry): entry is [string, string] => entry[1] !== undefined),\n );\n\n const pid = `railway-proc-${Date.now().toString(36)}-${(this._spawnCounter++).toString(36)}`;\n\n // Deferred reference — callbacks fire asynchronously after the handle is\n // assigned, so `handle` is always defined by the time they run.\n let handle: RailwayProcessHandle;\n\n const execHandle = railway.exec(command, {\n ...(options.timeout !== undefined && { timeoutSec: Math.ceil(options.timeout / 1000) }),\n ...(options.cwd !== undefined && { cwd: options.cwd }),\n ...(Object.keys(env).length > 0 && { env }),\n onStdout: (chunk: string) => handle.emitStdout(chunk),\n onStderr: (chunk: string) => handle.emitStderr(chunk),\n });\n\n handle = new RailwayProcessHandle(pid, execHandle, Date.now(), options);\n this._tracked.set(handle.pid, handle);\n return handle;\n }\n\n /**\n * List tracked processes.\n *\n * Railway has no API to enumerate running exec sessions by sandbox, so this\n * reports the processes this manager spawned.\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","/**\n * Railway Sandbox Provider\n *\n * A Railway sandbox implementation for Mastra workspaces. Provisions an\n * ephemeral, isolated Linux VM on Railway, runs commands in it via the\n * Railway TypeScript SDK, and destroys it on teardown.\n *\n * @see https://docs.railway.com/sandboxes\n */\n\nimport type {\n CommandResult,\n ExecuteCommandOptions,\n InstructionsOption,\n MastraSandboxOptions,\n ProviderStatus,\n SandboxCloneOptions,\n SandboxInfo,\n} from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxNotReadyError } from '@mastra/core/workspace';\nimport { Sandbox, SandboxFailedError, SandboxNotFoundError, SandboxTimeoutError } from 'railway';\nimport type { SandboxNetworkIsolation, SandboxTemplate } from 'railway';\nimport { shellQuote } from '../utils/shell-quote';\nimport { LOG_PREFIX, RailwayProcessManager } from './process-manager';\n\n/**\n * Safety margin subtracted from the sandbox's idle timeout when scheduling the\n * pre-reap checkpoint refresh. Sized to comfortably exceed Cloud Run cold-start\n * / recycle windows so a scale event during the refresh doesn't cause the timer\n * to lose the race with Railway's idle destroy. If a caller reduces the idle\n * timeout below this margin, the refresh falls back to the 1-second floor and\n * fires almost immediately after start — surfacing the misconfiguration rather\n * than silently skipping the refresh.\n */\nconst CHECKPOINT_REFRESH_MARGIN_MS = 180_000;\n\n// =============================================================================\n// Public capture result\n// =============================================================================\n\n/**\n * Outcome of a {@link RailwaySandbox.captureCheckpoint} call.\n *\n * `captured` and `coalesced` both represent a successful capture the caller can\n * persist against — they carry the checkpoint name inline so callers don't have\n * to reach back into the sandbox instance to learn what they just wrote.\n * `skipped` carries a machine-readable reason so the set stays extensible\n * without another breaking change.\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// Railway Sandbox Options\n// =============================================================================\n\n/**\n * Railway sandbox provider configuration.\n */\nexport interface RailwaySandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Unique identifier for this sandbox instance. */\n id?: string;\n /** Railway API token. Falls back to the RAILWAY_API_TOKEN env var. */\n token?: string;\n /** Railway environment ID. Falls back to the RAILWAY_ENVIRONMENT_ID env var. */\n environmentId?: string;\n /**\n * Reattach to an existing Railway sandbox by its Railway ID instead of\n * creating a new one. When set, `start()` calls `Sandbox.connect()`.\n */\n sandboxId?: string;\n /**\n * Reuse a saved Railway sandbox checkpoint as the baseline filesystem for\n * new sandboxes. When the named checkpoint is missing, the sandbox is created\n * normally and a checkpoint is captured after setup succeeds.\n */\n checkpointName?: string;\n /**\n * Fallback checkpoint used to seed a new sandbox when `checkpointName` has\n * no stored state. Snapshots continue writing to `checkpointName`.\n */\n seedCheckpointName?: string;\n /**\n * How long the sandbox can sit idle (no `exec` interaction) before Railway\n * destroys it automatically. Range depends on plan (1–120 minutes on\n * Hobby/Pro, 1–5 on Trial/Free). Defaults to the plan default when omitted.\n */\n idleTimeoutMinutes?: number;\n /**\n * Network isolation mode.\n * - `ISOLATED` (default): outbound internet only, no private network access.\n * - `PRIVATE`: joins the environment's private network.\n */\n networkIsolation?: SandboxNetworkIsolation;\n /** Environment variables baked into the sandbox, available to every command. */\n env?: Record<string, string>;\n /**\n * Provision the sandbox from a custom base image built with the Railway\n * template builder. Use this to pre-install packages or run setup steps so\n * every sandbox created from it starts ready.\n *\n * - Builder callback — receives the base `Sandbox.template()` and returns the\n * configured template. Railway builds the template when `Sandbox.create()`\n * runs during `start()`.\n * ```ts\n * template: t => t.withPackages('git', 'curl').run('npm i -g pnpm')\n * ```\n * - Pre-built `SandboxTemplate` — pass a template to reuse it across\n * sandboxes. Railway still builds the image during sandbox creation.\n *\n * Ignored when `sandboxId` is set (reattach) or when forking.\n */\n template?: SandboxTemplate | ((base: SandboxTemplate) => SandboxTemplate);\n /**\n * Default execution timeout in milliseconds applied to commands that don't\n * specify their own timeout. When omitted, commands run until they exit.\n */\n timeout?: number;\n /**\n * Custom instructions that override the default instructions returned by\n * `getInstructions()`.\n *\n * - `string` — Fully replaces the default instructions. Pass an empty string\n * to suppress instructions entirely.\n * - `(opts) => string` — Receives the default instructions and optional\n * request context so you can extend or customise per-request.\n */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// Railway Sandbox Implementation\n// =============================================================================\n\n/**\n * Railway sandbox provider for Mastra workspaces.\n *\n * Features:\n * - Ephemeral, isolated Linux VM via the Railway TypeScript SDK\n * - Command execution with streaming output and timeouts\n * - Configurable idle timeout and network isolation\n * - Reattach to an existing sandbox by Railway ID\n *\n * @example Basic usage\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { RailwaySandbox } from '@mastra/railway';\n *\n * const sandbox = new RailwaySandbox({\n * // token + environmentId read from RAILWAY_API_TOKEN / RAILWAY_ENVIRONMENT_ID\n * idleTimeoutMinutes: 30,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCode('console.log(\"Hello!\")');\n * ```\n *\n * @example Private networking\n * ```typescript\n * const sandbox = new RailwaySandbox({\n * networkIsolation: 'PRIVATE',\n * env: { NODE_ENV: 'production' },\n * });\n * ```\n */\nexport class RailwaySandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'RailwaySandbox';\n readonly provider = 'railway';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: RailwayProcessManager;\n\n private _sandbox: Sandbox | null = null;\n private _createdAt: Date | null = null;\n private _checkpointRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n private _checkpointRefreshInFlight: Promise<void> | null = null;\n private _sandboxId?: string;\n private _restoredCheckpointName?: string;\n private _startInFlight: Promise<void> | null = null;\n\n private readonly _token?: string;\n private readonly _environmentId?: string;\n private readonly _checkpointName?: string;\n private readonly _seedCheckpointName?: string;\n private readonly _idleTimeoutMinutes?: number;\n private readonly _networkIsolation?: SandboxNetworkIsolation;\n private readonly _env: Record<string, string>;\n private readonly _timeout?: number;\n private readonly _instructionsOverride?: InstructionsOption;\n private readonly _templateOption?: RailwaySandboxOptions['template'];\n\n constructor(options: RailwaySandboxOptions = {}) {\n super({\n ...options,\n name: 'RailwaySandbox',\n processes: new RailwayProcessManager({ env: options.env }),\n });\n\n this.id = options.id ?? this.generateId();\n this._token = options.token ?? process.env.RAILWAY_API_TOKEN;\n this._environmentId = options.environmentId ?? process.env.RAILWAY_ENVIRONMENT_ID;\n this._sandboxId = options.sandboxId;\n this._checkpointName = options.checkpointName;\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._templateOption = options.template;\n }\n\n private generateId(): string {\n return `railway-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n /**\n * Get the underlying Railway Sandbox instance for direct SDK access.\n *\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get railway(): Sandbox {\n if (!this._sandbox) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._sandbox;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Start the Railway sandbox.\n *\n * Reattaches to an existing sandbox when `sandboxId` is configured,\n * otherwise provisions a new one. Resolves once the sandbox is RUNNING.\n */\n async start(): Promise<void> {\n if (this._sandbox) {\n return;\n }\n\n const clientConfig = this._clientConfig();\n const createOptions = this._createOptions(clientConfig);\n\n if (this._sandboxId) {\n const sandboxId = this._sandboxId;\n this._startInFlight ??= (async () => {\n this._restoredCheckpointName = undefined;\n try {\n this._sandbox = await this._reconnectSandbox(sandboxId, clientConfig);\n } catch (error) {\n if (!(error instanceof SandboxNotFoundError)) {\n throw error;\n }\n this._sandbox = await this._createNewSandbox(createOptions);\n }\n })().finally(() => {\n this._startInFlight = null;\n });\n } else {\n this._startInFlight ??= (async () => {\n this._sandbox = await this._createNewSandbox(createOptions);\n })().finally(() => {\n this._startInFlight = null;\n });\n }\n await this._startInFlight;\n\n if (!this._sandbox) {\n throw new Error('Failed to start Railway sandbox');\n }\n\n const sandbox = this._sandbox as Sandbox;\n this._sandboxId = sandbox.id;\n\n this._createdAt = sandbox.createdAt ? new Date(sandbox.createdAt) : new Date();\n this.logger.debug(`${LOG_PREFIX} Railway sandbox ${sandbox.id} ready for logical ID: ${this.id}`);\n this._scheduleCheckpointRefresh();\n }\n\n /**\n * Create a new Railway sandbox.\n */\n private async _createNewSandbox(createOptions: ReturnType<RailwaySandbox['_createOptions']>): Promise<Sandbox> {\n this.logger.debug(`${LOG_PREFIX} Creating Railway sandbox for: ${this.id}`);\n try {\n let checkpointToRestore: string | undefined;\n if (this._checkpointName || this._seedCheckpointName) {\n const checkpoints = await Sandbox.checkpoints(this._clientConfig());\n const checkpointNames = new Set(checkpoints.map(checkpoint => checkpoint.key));\n checkpointToRestore = checkpointNames.has(this._checkpointName ?? '')\n ? this._checkpointName\n : checkpointNames.has(this._seedCheckpointName ?? '')\n ? this._seedCheckpointName\n : undefined;\n }\n\n const sandbox = checkpointToRestore\n ? await Sandbox.create(checkpointToRestore, createOptions)\n : await Sandbox.create(createOptions);\n this._restoredCheckpointName = checkpointToRestore;\n return sandbox;\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Reconnect to an existing Railway sandbox, creating a fresh one when\n */\n private async _reconnectSandbox(\n reconnectSandboxId: string,\n clientConfig: { token?: string; environmentId?: string },\n ): Promise<Sandbox> {\n this.logger.debug(`${LOG_PREFIX} Reconnecting to Railway sandbox ${reconnectSandboxId}...`);\n\n let connectedSandbox: Sandbox = await Sandbox.connect(reconnectSandboxId, clientConfig);\n\n if (connectedSandbox.status !== 'RUNNING') {\n throw new SandboxNotFoundError({\n id: reconnectSandboxId,\n environmentId: clientConfig.environmentId ?? '',\n });\n }\n\n return connectedSandbox;\n }\n\n private _clientConfig(): { token?: string; environmentId?: string } {\n return {\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n };\n }\n\n private _createOptions(clientConfig: { token?: string; environmentId?: string }) {\n return {\n ...clientConfig,\n ...(this._idleTimeoutMinutes !== undefined && { idleTimeoutMinutes: this._idleTimeoutMinutes }),\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n ...(Object.keys(this._env).length > 0 && { env: this._env }),\n };\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 the idle-timer schedule.\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 Railway's idle destroy.\n *\n * Coalesces with any in-flight timer-driven refresh: concurrent callers join\n * the same underlying `Sandbox.checkpoint` call and receive\n * `{ status: 'coalesced', checkpointName }`. Both `captured` and `coalesced`\n * carry the checkpoint name inline so callers can persist a session→\n * checkpoint binding without a second, non-atomic read against the sandbox.\n * Returns `{ status: 'skipped', reason }` when there's nothing to capture\n * (no `checkpointName` configured, or the sandbox isn't running yet).\n *\n * On successful capture, restarts the idle-timer countdown so the next\n * timer-driven refresh is scheduled from this capture.\n *\n * Never captures without a `checkpointName` and never mutates status — safe\n * to invoke concurrently with `executeCommand`, `restart`, or `stop`.\n */\n async captureCheckpoint(): Promise<CaptureCheckpointResult> {\n const checkpointName = this._checkpointName;\n if (!checkpointName) {\n return { status: 'skipped', reason: 'no-checkpoint-name-configured' };\n }\n\n const sandbox = this._sandbox;\n if (!sandbox) {\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n\n if (this._checkpointRefreshInFlight) {\n await this._checkpointRefreshInFlight;\n return { status: 'coalesced', checkpointName };\n }\n\n const capture = this._checkpointSandbox(sandbox).finally(() => {\n if (this._checkpointRefreshInFlight === capture) {\n this._checkpointRefreshInFlight = null;\n }\n });\n this._checkpointRefreshInFlight = capture;\n\n await capture;\n this._scheduleCheckpointRefresh();\n\n return { status: 'captured', checkpointName };\n }\n\n private async _checkpointSandbox(sandbox: Sandbox): Promise<void> {\n if (!this._checkpointName) {\n return;\n }\n\n this.logger.debug(`${LOG_PREFIX} Capturing Railway sandbox checkpoint ${this._checkpointName} for: ${this.id}`);\n\n const checkpoints = await Sandbox.checkpoints(this._clientConfig());\n const checkpointAlreadyExists = checkpoints.some(checkpoint => checkpoint.key === this._checkpointName);\n\n // Remove first so we can re-create a checkpoint with the same name.\n if (checkpointAlreadyExists) {\n await Sandbox.deleteCheckpoint(this._checkpointName, this._clientConfig());\n }\n\n await sandbox.checkpoint(this._checkpointName);\n }\n\n private _scheduleCheckpointRefresh(): void {\n if (!this._checkpointName || !this._sandbox) {\n return;\n }\n\n const idleTimeoutMinutes = this._idleTimeoutMinutes ?? this._sandbox.idleTimeoutMinutes;\n if (!idleTimeoutMinutes) {\n return;\n }\n\n this._cancelCheckpointRefresh();\n\n const delayMs = Math.max(1_000, idleTimeoutMinutes * 60_000 - CHECKPOINT_REFRESH_MARGIN_MS);\n this._checkpointRefreshTimer = setTimeout(() => {\n this._checkpointRefreshTimer = null;\n const sandbox = this._sandbox;\n if (!sandbox || this._checkpointRefreshInFlight) {\n return;\n }\n\n const refresh = this._checkpointSandbox(sandbox).finally(() => {\n if (this._checkpointRefreshInFlight === refresh) {\n this._checkpointRefreshInFlight = null;\n }\n });\n this._checkpointRefreshInFlight = refresh;\n refresh.catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to refresh Railway sandbox checkpoint ${this._checkpointName}:`, error);\n });\n }, delayMs);\n this._checkpointRefreshTimer.unref?.();\n }\n\n private _cancelCheckpointRefresh(): void {\n if (this._checkpointRefreshTimer) {\n clearTimeout(this._checkpointRefreshTimer);\n this._checkpointRefreshTimer = null;\n }\n }\n\n /**\n * Stop the Railway sandbox.\n *\n * Railway sandboxes have no separate \"stopped\" state — they're either\n * running or destroyed — so stopping destroys the sandbox but we keep a checkpoint of the filesystem.\n */\n async stop(): Promise<void> {\n if (this._checkpointName) {\n await this._flushCheckpointRefresh().catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to checkpoint Railway sandbox ${this._sandbox?.id}:`, error);\n });\n }\n\n await this._teardown();\n }\n\n /**\n * Destroy the Railway sandbox and release its resources including the checkpoint.\n */\n async destroy(): Promise<void> {\n this._cancelCheckpointRefresh();\n if (this._checkpointName) {\n await this._checkpointRefreshInFlight;\n await Sandbox.deleteCheckpoint(this._checkpointName, this._clientConfig()).catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to delete Railway checkpoint ${this._checkpointName}:`, error);\n });\n }\n\n await this._teardown();\n }\n\n private async _flushCheckpointRefresh(): Promise<void> {\n this._cancelCheckpointRefresh();\n\n if (this._checkpointRefreshInFlight) {\n await this._checkpointRefreshInFlight;\n return;\n }\n\n if (this._sandbox) {\n await this._checkpointSandbox(this._sandbox);\n }\n }\n\n private async _teardown(): Promise<void> {\n this._cancelCheckpointRefresh();\n if (!this._sandbox) {\n return;\n }\n await this._checkpointRefreshInFlight;\n\n const sandbox = this._sandbox;\n this._sandbox = null;\n try {\n await sandbox.destroy();\n } catch (error) {\n this.logger.warn(`${LOG_PREFIX} Failed to destroy Railway sandbox ${sandbox.id}:`, error);\n }\n }\n\n /**\n * Fork this running sandbox into a new, independent `RailwaySandbox`.\n *\n * Clones the filesystem (a fresh boot, not live processes) into the same\n * environment. The returned sandbox is already started and reattached to the\n * forked Railway sandbox; it inherits this sandbox's credentials and defaults\n * unless overridden via `options`.\n *\n * @throws {SandboxNotReadyError} If this sandbox has not been started.\n */\n async fork(\n options: Pick<RailwaySandboxOptions, 'id' | 'idleTimeoutMinutes' | 'networkIsolation' | 'env'> = {},\n ): Promise<RailwaySandbox> {\n const source = this.railway;\n const forked = await source.fork({\n ...(options.idleTimeoutMinutes !== undefined && { idleTimeoutMinutes: options.idleTimeoutMinutes }),\n ...(options.networkIsolation !== undefined && { networkIsolation: options.networkIsolation }),\n ...(options.env !== undefined && { env: options.env }),\n });\n\n const child = new RailwaySandbox({\n ...(options.id !== undefined && { id: options.id }),\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n networkIsolation: options.networkIsolation ?? this._networkIsolation,\n env: options.env ?? this._env,\n timeout: this._timeout,\n });\n await child._start();\n return child;\n }\n\n /**\n * Construct a sibling `RailwaySandbox` that inherits this sandbox's\n * credentials and defaults (token, environment, checkpoint, network\n * isolation, timeout, template, instructions) with per-instance overrides.\n *\n * Unlike {@link fork}, `clone` performs no I/O and does not require this\n * sandbox to be started — the returned sandbox is not started and provisions\n * (or reattaches, when `sandboxId` is set) on its own `start()`. Use it when\n * one configured sandbox acts as the template for a fleet of independent\n * sandboxes (e.g. one per project).\n */\n clone(options: SandboxCloneOptions = {}): RailwaySandbox {\n return new RailwaySandbox({\n ...(options.id !== undefined && { id: options.id }),\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n ...((options.checkpointName ?? this._checkpointName) !== undefined && {\n checkpointName: options.checkpointName ?? this._checkpointName,\n }),\n ...(options.seedCheckpointName !== undefined && { seedCheckpointName: options.seedCheckpointName }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n env: options.env ?? this._env,\n ...(this._templateOption !== undefined && { template: this._templateOption }),\n ...(this._timeout !== undefined && { timeout: this._timeout }),\n ...(this._instructionsOverride !== undefined && { instructions: this._instructionsOverride }),\n });\n }\n\n /**\n * Whether a Railway API token was resolved at construction (explicit option\n * or the `RAILWAY_API_TOKEN` env fallback). Lets callers gate features on a\n * usable configuration without provisioning a sandbox.\n */\n get hasCredentials(): boolean {\n return this._token !== undefined && this._token !== '';\n }\n\n /** The configured idle teardown window in minutes, if any. */\n get idleTimeoutMinutes(): number | undefined {\n return this._idleTimeoutMinutes;\n }\n\n // ---------------------------------------------------------------------------\n // Info & Instructions\n // ---------------------------------------------------------------------------\n\n async getInfo(): Promise<SandboxInfo> {\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 metadata: {\n ...(this._sandbox && {\n railwaySandboxId: this._sandbox.id,\n environmentId: this._sandbox.environmentId,\n region: this._sandbox.region,\n networkIsolation: this._sandbox.networkIsolation,\n ...(this._sandbox.idleTimeoutMinutes != null && {\n idleTimeoutMinutes: this._sandbox.idleTimeoutMinutes,\n }),\n ...(this._restoredCheckpointName && { restoredCheckpointName: this._restoredCheckpointName }),\n }),\n },\n };\n }\n\n getInstructions(): string {\n const defaultInstructions = this._buildDefaultInstructions();\n\n if (typeof this._instructionsOverride === 'string') {\n return this._instructionsOverride;\n }\n if (typeof this._instructionsOverride === 'function') {\n return this._instructionsOverride({ defaultInstructions });\n }\n return defaultInstructions;\n }\n\n private _buildDefaultInstructions(): string {\n const parts: string[] = [];\n parts.push('Railway cloud sandbox: an isolated Debian Linux VM with outbound internet access.');\n\n if (this._networkIsolation === 'PRIVATE') {\n parts.push('Joined to the environment private network.');\n }\n\n if (this._timeout !== undefined) {\n parts.push(`Default command timeout: ${Math.ceil(this._timeout / 1000)}s.`);\n } else {\n parts.push('Commands run until they exit unless a timeout is set.');\n }\n\n if (this._idleTimeoutMinutes !== undefined) {\n parts.push(`Idle timeout: ${this._idleTimeoutMinutes} minute(s).`);\n }\n\n return parts.join(' ');\n }\n\n // ---------------------------------------------------------------------------\n // Command Execution\n // ---------------------------------------------------------------------------\n\n /**\n * Execute a command in the sandbox and return the result.\n */\n async executeCommand(\n command: string,\n args: string[] = [],\n options: ExecuteCommandOptions = {},\n ): Promise<CommandResult> {\n const status = this._sandbox?.status;\n\n if (status !== 'RUNNING') {\n if (!this._checkpointName) {\n throw new SandboxNotReadyError(this.id);\n }\n\n this._sandbox = null;\n await this.start();\n }\n\n const fullCommand = args.length > 0 ? `${command} ${args.map(shellQuote).join(' ')}` : command;\n const timeout = options.timeout ?? this._timeout;\n const env = options.env\n ? Object.fromEntries(\n Object.entries(options.env).filter((entry): entry is [string, string] => entry[1] !== undefined),\n )\n : undefined;\n const startedAt = Date.now();\n const result = await this.railway.exec(fullCommand, {\n ...(timeout !== undefined && { timeoutSec: Math.ceil(timeout / 1000) }),\n ...(options.cwd !== undefined && { cwd: options.cwd }),\n ...(env !== undefined && { env }),\n });\n const exitCode = result.exitCode ?? -1;\n return {\n success: exitCode === 0,\n exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n executionTimeMs: Date.now() - startedAt,\n command,\n args,\n timedOut: result.timedOut,\n };\n }\n}\n","/**\n * Railway sandbox provider descriptor for MastraEditor.\n *\n * @example\n * ```typescript\n * import { railwaySandboxProvider } from '@mastra/railway';\n *\n * const editor = new MastraEditor({\n * sandboxes: { [railwaySandboxProvider.id]: railwaySandboxProvider },\n * });\n * ```\n */\nimport type { SandboxProvider } from '@mastra/core/editor';\nimport { RailwaySandbox } from './sandbox';\n\n/**\n * Serializable subset of RailwaySandboxOptions for editor storage.\n */\ninterface RailwayProviderConfig {\n token?: string;\n environmentId?: string;\n sandboxId?: string;\n idleTimeoutMinutes?: number;\n networkIsolation?: 'ISOLATED' | 'PRIVATE';\n env?: Record<string, string>;\n timeout?: number;\n}\n\nexport const railwaySandboxProvider: SandboxProvider<RailwayProviderConfig> = {\n id: 'railway',\n name: 'Railway Sandbox',\n description: 'Ephemeral, isolated Linux VM powered by Railway',\n configSchema: {\n type: 'object',\n properties: {\n token: { type: 'string', description: 'Railway API token (falls back to RAILWAY_API_TOKEN)' },\n environmentId: {\n type: 'string',\n description: 'Railway environment ID (falls back to RAILWAY_ENVIRONMENT_ID)',\n },\n sandboxId: { type: 'string', description: 'Reattach to an existing Railway sandbox by ID' },\n idleTimeoutMinutes: {\n type: 'number',\n description: 'Minutes a sandbox can sit idle before Railway destroys it',\n },\n networkIsolation: {\n type: 'string',\n description: 'Network isolation mode',\n enum: ['ISOLATED', 'PRIVATE'],\n default: 'ISOLATED',\n },\n env: {\n type: 'object',\n description: 'Environment variables',\n additionalProperties: { type: 'string' },\n },\n timeout: { type: 'number', description: 'Default command timeout in ms' },\n },\n },\n createSandbox: config => new RailwaySandbox(config),\n};\n"],"mappings":";;;;;;;;;;AAMA,SAAgB,WAAW,KAAqB;CAE9C,IAAI,yBAAyB,KAAK,GAAG,GAAG,OAAO;CAE/C,OAAO,MAAM,IAAI,QAAQ,MAAM,OAAO,IAAI;AAC5C;;;;;;;;;;;;;;;;ACQA,MAAa,aAAa;;;;;AAU1B,IAAM,uBAAN,cAAmCA,uBAAAA,cAAc;CAC/C;CAEA;CACA;CACA;CACA,eAAsD;CACtD,UAAkB;CAElB,YAAY,KAAa,YAAwB,WAAmB,SAA+B;EACjG,MAAM,OAAO;EACb,KAAK,MAAM;EACX,KAAK,cAAc;EACnB,KAAK,aAAa;EAIlB,KAAU,YAAY,MACnB,WAAuB;GAEtB,KAAK,YAAY,OAAO,aAAa,KAAK,UAAU,MAAM;EAC5D,SACM;GACJ,IAAI,KAAK,cAAc,KAAA,GACrB,KAAK,YAAY;EAErB,CACF;CACF;CAEA,IAAI,WAA+B;EACjC,OAAO,KAAK;CACd;CAEA,MAAM,OAA+B;EAEnC,IAAI,CAAC,KAAK,cACR,KAAK,eAAe,KAAK,QAAQ;EAEnC,OAAO,KAAK;CACd;CAEA,MAAc,UAAkC;EAC9C,IAAI;GACF,MAAM,SAAS,MAAM,KAAK;GAC1B,MAAM,WAAW,OAAO,aAAa,KAAK,UAAU,MAAM;GAC1D,KAAK,YAAY;GAIjB,IAAI,OAAO,UAAU,CAAC,KAAK,QAAQ,KAAK,WAAW,OAAO,MAAM;GAChE,IAAI,OAAO,UAAU,CAAC,KAAK,QAAQ,KAAK,WAAW,OAAO,MAAM;GAEhE,OAAO;IACL,SAAS,aAAa;IACtB;IACA,QAAQ,KAAK;IACb,QAAQ,KAAK;IACb,iBAAiB,KAAK,IAAI,IAAI,KAAK;IACnC,QAAQ,KAAK;IACb,UAAU,OAAO;GACnB;EACF,SAAS,OAAO;GACd,MAAM,WAAW,KAAK,aAAa;GACnC,KAAK,YAAY;GACjB,OAAO;IACL,SAAS;IACT;IACA,QAAQ,KAAK;IACb,QAAQ,KAAK,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC7E,iBAAiB,KAAK,IAAI,IAAI,KAAK;IACnC,QAAQ,KAAK;GACf;EACF;CACF;CAEA,MAAM,OAAyB;EAC7B,IAAI,KAAK,cAAc,KAAA,GAAW,OAAO;EACzC,KAAK,UAAU;EACf,IAAI;GACF,OAAO,MAAM,KAAK,YAAY,KAAK,MAAM;EAC3C,QAAQ;GAEN,OAAO;EACT;CACF;CAEA,MAAM,UAAU,OAA8B;EAE5C,MAAM,IAAI,MAAM,GAAG,WAAW,gEAAgE;CAChG;CAEA,MAAM,aAA4B;EAChC,MAAM,IAAIC,uBAAAA,2BACR,GAAG,WAAW,gEAChB;CACF;AACF;;;;;AAcA,IAAa,wBAAb,cAA2CC,uBAAAA,sBAAsC;CAC/E,gBAAwB;CAExB,YAAY,OAAqC,CAAC,GAAG;EACnD,MAAM,EAAE,KAAK,KAAK,IAAI,CAAC;CACzB;CAEA,MAAM,MAAM,SAAiB,UAA+B,CAAC,GAA2B;EACtF,MAAM,UAAU,KAAK,QAAQ;EAG7B,MAAM,YAAY;GAAE,GAAG,KAAK;GAAK,GAAG,QAAQ;EAAI;EAChD,MAAM,MAAM,OAAO,YACjB,OAAO,QAAQ,SAAS,CAAC,CAAC,QAAQ,UAAqC,MAAM,OAAO,KAAA,CAAS,CAC/F;EAEA,MAAM,MAAM,gBAAgB,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,IAAI,KAAK,gBAAA,CAAiB,SAAS,EAAE;EAIzF,IAAI;EAUJ,SAAS,IAAI,qBAAqB,KARf,QAAQ,KAAK,SAAS;GACvC,GAAI,QAAQ,YAAY,KAAA,KAAa,EAAE,YAAY,KAAK,KAAK,QAAQ,UAAU,GAAI,EAAE;GACrF,GAAI,QAAQ,QAAQ,KAAA,KAAa,EAAE,KAAK,QAAQ,IAAI;GACpD,GAAI,OAAO,KAAK,GAAG,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI;GACzC,WAAW,UAAkB,OAAO,WAAW,KAAK;GACpD,WAAW,UAAkB,OAAO,WAAW,KAAK;EACtD,CAEuC,GAAY,KAAK,IAAI,GAAG,OAAO;EACtE,KAAK,SAAS,IAAI,OAAO,KAAK,MAAM;EACpC,OAAO;CACT;;;;;;;CAQA,MAAM,OAA+B;EACnC,OAAO,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC,CAAC,CAAC,KAAI,YAAW;GACvD,KAAK,OAAO;GACZ,SAAS,OAAO;GAChB,SAAS,OAAO,aAAa,KAAA;GAC7B,GAAI,OAAO,aAAa,KAAA,KAAa,EAAE,UAAU,OAAO,SAAS;EACnE,EAAE;CACJ;AACF;;;;;;;;;;;;AC3JA,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqIrC,IAAa,iBAAb,MAAa,uBAAuBC,uBAAAA,cAAc;CAChD;CACA,OAAgB;CAChB,WAAoB;CACpB,SAAyB;CAIzB,WAAmC;CACnC,aAAkC;CAClC,0BAAwE;CACxE,6BAA2D;CAC3D;CACA;CACA,iBAA+C;CAE/C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,UAAiC,CAAC,GAAG;EAC/C,MAAM;GACJ,GAAG;GACH,MAAM;GACN,WAAW,IAAI,sBAAsB,EAAE,KAAK,QAAQ,IAAI,CAAC;EAC3D,CAAC;EAED,KAAK,KAAK,QAAQ,MAAM,KAAK,WAAW;EACxC,KAAK,SAAS,QAAQ,SAAS,QAAQ,IAAI;EAC3C,KAAK,iBAAiB,QAAQ,iBAAiB,QAAQ,IAAI;EAC3D,KAAK,aAAa,QAAQ;EAC1B,KAAK,kBAAkB,QAAQ;EAC/B,KAAK,sBAAsB,QAAQ;EACnC,KAAK,sBAAsB,QAAQ;EACnC,KAAK,oBAAoB,QAAQ;EACjC,KAAK,OAAO,QAAQ,OAAO,CAAC;EAC5B,KAAK,WAAW,QAAQ;EACxB,KAAK,wBAAwB,QAAQ;EACrC,KAAK,kBAAkB,QAAQ;CACjC;CAEA,aAA6B;EAC3B,OAAO,mBAAmB,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CAC5F;;;;;;CAOA,IAAI,UAAmB;EACrB,IAAI,CAAC,KAAK,UACR,MAAM,IAAIC,uBAAAA,qBAAqB,KAAK,EAAE;EAExC,OAAO,KAAK;CACd;;;;;;;CAYA,MAAM,QAAuB;EAC3B,IAAI,KAAK,UACP;EAGF,MAAM,eAAe,KAAK,cAAc;EACxC,MAAM,gBAAgB,KAAK,eAAe,YAAY;EAEtD,IAAI,KAAK,YAAY;GACnB,MAAM,YAAY,KAAK;GACvB,KAAK,oBAAoB,YAAY;IACnC,KAAK,0BAA0B,KAAA;IAC/B,IAAI;KACF,KAAK,WAAW,MAAM,KAAK,kBAAkB,WAAW,YAAY;IACtE,SAAS,OAAO;KACd,IAAI,EAAE,iBAAiBC,QAAAA,uBACrB,MAAM;KAER,KAAK,WAAW,MAAM,KAAK,kBAAkB,aAAa;IAC5D;GACF,EAAA,CAAG,CAAC,CAAC,cAAc;IACjB,KAAK,iBAAiB;GACxB,CAAC;EACH,OACE,KAAK,oBAAoB,YAAY;GACnC,KAAK,WAAW,MAAM,KAAK,kBAAkB,aAAa;EAC5D,EAAA,CAAG,CAAC,CAAC,cAAc;GACjB,KAAK,iBAAiB;EACxB,CAAC;EAEH,MAAM,KAAK;EAEX,IAAI,CAAC,KAAK,UACR,MAAM,IAAI,MAAM,iCAAiC;EAGnD,MAAM,UAAU,KAAK;EACrB,KAAK,aAAa,QAAQ;EAE1B,KAAK,aAAa,QAAQ,YAAY,IAAI,KAAK,QAAQ,SAAS,oBAAI,IAAI,KAAK;EAC7E,KAAK,OAAO,MAAM,GAAG,WAAW,mBAAmB,QAAQ,GAAG,yBAAyB,KAAK,IAAI;EAChG,KAAK,2BAA2B;CAClC;;;;CAKA,MAAc,kBAAkB,eAA+E;EAC7G,KAAK,OAAO,MAAM,GAAG,WAAW,iCAAiC,KAAK,IAAI;EAC1E,IAAI;GACF,IAAI;GACJ,IAAI,KAAK,mBAAmB,KAAK,qBAAqB;IACpD,MAAM,cAAc,MAAMC,QAAAA,QAAQ,YAAY,KAAK,cAAc,CAAC;IAClE,MAAM,kBAAkB,IAAI,IAAI,YAAY,KAAI,eAAc,WAAW,GAAG,CAAC;IAC7E,sBAAsB,gBAAgB,IAAI,KAAK,mBAAmB,EAAE,IAChE,KAAK,kBACL,gBAAgB,IAAI,KAAK,uBAAuB,EAAE,IAChD,KAAK,sBACL,KAAA;GACR;GAEA,MAAM,UAAU,sBACZ,MAAMA,QAAAA,QAAQ,OAAO,qBAAqB,aAAa,IACvD,MAAMA,QAAAA,QAAQ,OAAO,aAAa;GACtC,KAAK,0BAA0B;GAC/B,OAAO;EACT,SAAS,OAAO;GACd,MAAM;EACR;CACF;;;;CAKA,MAAc,kBACZ,oBACA,cACkB;EAClB,KAAK,OAAO,MAAM,GAAG,WAAW,mCAAmC,mBAAmB,IAAI;EAE1F,IAAI,mBAA4B,MAAMA,QAAAA,QAAQ,QAAQ,oBAAoB,YAAY;EAEtF,IAAI,iBAAiB,WAAW,WAC9B,MAAM,IAAID,QAAAA,qBAAqB;GAC7B,IAAI;GACJ,eAAe,aAAa,iBAAiB;EAC/C,CAAC;EAGH,OAAO;CACT;CAEA,gBAAoE;EAClE,OAAO;GACL,GAAI,KAAK,WAAW,KAAA,KAAa,EAAE,OAAO,KAAK,OAAO;GACtD,GAAI,KAAK,mBAAmB,KAAA,KAAa,EAAE,eAAe,KAAK,eAAe;EAChF;CACF;CAEA,eAAuB,cAA0D;EAC/E,OAAO;GACL,GAAG;GACH,GAAI,KAAK,wBAAwB,KAAA,KAAa,EAAE,oBAAoB,KAAK,oBAAoB;GAC7F,GAAI,KAAK,sBAAsB,KAAA,KAAa,EAAE,kBAAkB,KAAK,kBAAkB;GACvF,GAAI,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,KAAK,KAAK;EAC5D;CACF;;CAGA,MAAM,WAA0B;EAC9B,MAAM,KAAK,kBAAkB;CAC/B;;CAGA,sBAAwC;;;;;;;;;;;;;;;;;;;;;;CAuBxC,MAAM,oBAAsD;EAC1D,MAAM,iBAAiB,KAAK;EAC5B,IAAI,CAAC,gBACH,OAAO;GAAE,QAAQ;GAAW,QAAQ;EAAgC;EAGtE,MAAM,UAAU,KAAK;EACrB,IAAI,CAAC,SACH,OAAO;GAAE,QAAQ;GAAW,QAAQ;EAAsB;EAG5D,IAAI,KAAK,4BAA4B;GACnC,MAAM,KAAK;GACX,OAAO;IAAE,QAAQ;IAAa;GAAe;EAC/C;EAEA,MAAM,UAAU,KAAK,mBAAmB,OAAO,CAAC,CAAC,cAAc;GAC7D,IAAI,KAAK,+BAA+B,SACtC,KAAK,6BAA6B;EAEtC,CAAC;EACD,KAAK,6BAA6B;EAElC,MAAM;EACN,KAAK,2BAA2B;EAEhC,OAAO;GAAE,QAAQ;GAAY;EAAe;CAC9C;CAEA,MAAc,mBAAmB,SAAiC;EAChE,IAAI,CAAC,KAAK,iBACR;EAGF,KAAK,OAAO,MAAM,GAAG,WAAW,wCAAwC,KAAK,gBAAgB,QAAQ,KAAK,IAAI;EAM9G,KAHgC,MADNC,QAAAA,QAAQ,YAAY,KAAK,cAAc,CAAC,EAAA,CACtB,MAAK,eAAc,WAAW,QAAQ,KAAK,eAG7D,GACxB,MAAMA,QAAAA,QAAQ,iBAAiB,KAAK,iBAAiB,KAAK,cAAc,CAAC;EAG3E,MAAM,QAAQ,WAAW,KAAK,eAAe;CAC/C;CAEA,6BAA2C;EACzC,IAAI,CAAC,KAAK,mBAAmB,CAAC,KAAK,UACjC;EAGF,MAAM,qBAAqB,KAAK,uBAAuB,KAAK,SAAS;EACrE,IAAI,CAAC,oBACH;EAGF,KAAK,yBAAyB;EAE9B,MAAM,UAAU,KAAK,IAAI,KAAO,qBAAqB,MAAS,4BAA4B;EAC1F,KAAK,0BAA0B,iBAAiB;GAC9C,KAAK,0BAA0B;GAC/B,MAAM,UAAU,KAAK;GACrB,IAAI,CAAC,WAAW,KAAK,4BACnB;GAGF,MAAM,UAAU,KAAK,mBAAmB,OAAO,CAAC,CAAC,cAAc;IAC7D,IAAI,KAAK,+BAA+B,SACtC,KAAK,6BAA6B;GAEtC,CAAC;GACD,KAAK,6BAA6B;GAClC,QAAQ,OAAM,UAAS;IACrB,KAAK,OAAO,KAAK,GAAG,WAAW,gDAAgD,KAAK,gBAAgB,IAAI,KAAK;GAC/G,CAAC;EACH,GAAG,OAAO;EACV,KAAK,wBAAwB,QAAQ;CACvC;CAEA,2BAAyC;EACvC,IAAI,KAAK,yBAAyB;GAChC,aAAa,KAAK,uBAAuB;GACzC,KAAK,0BAA0B;EACjC;CACF;;;;;;;CAQA,MAAM,OAAsB;EAC1B,IAAI,KAAK,iBACP,MAAM,KAAK,wBAAwB,CAAC,CAAC,OAAM,UAAS;GAClD,KAAK,OAAO,KAAK,GAAG,WAAW,wCAAwC,KAAK,UAAU,GAAG,IAAI,KAAK;EACpG,CAAC;EAGH,MAAM,KAAK,UAAU;CACvB;;;;CAKA,MAAM,UAAyB;EAC7B,KAAK,yBAAyB;EAC9B,IAAI,KAAK,iBAAiB;GACxB,MAAM,KAAK;GACX,MAAMA,QAAAA,QAAQ,iBAAiB,KAAK,iBAAiB,KAAK,cAAc,CAAC,CAAC,CAAC,OAAM,UAAS;IACxF,KAAK,OAAO,KAAK,GAAG,WAAW,uCAAuC,KAAK,gBAAgB,IAAI,KAAK;GACtG,CAAC;EACH;EAEA,MAAM,KAAK,UAAU;CACvB;CAEA,MAAc,0BAAyC;EACrD,KAAK,yBAAyB;EAE9B,IAAI,KAAK,4BAA4B;GACnC,MAAM,KAAK;GACX;EACF;EAEA,IAAI,KAAK,UACP,MAAM,KAAK,mBAAmB,KAAK,QAAQ;CAE/C;CAEA,MAAc,YAA2B;EACvC,KAAK,yBAAyB;EAC9B,IAAI,CAAC,KAAK,UACR;EAEF,MAAM,KAAK;EAEX,MAAM,UAAU,KAAK;EACrB,KAAK,WAAW;EAChB,IAAI;GACF,MAAM,QAAQ,QAAQ;EACxB,SAAS,OAAO;GACd,KAAK,OAAO,KAAK,GAAG,WAAW,qCAAqC,QAAQ,GAAG,IAAI,KAAK;EAC1F;CACF;;;;;;;;;;;CAYA,MAAM,KACJ,UAAiG,CAAC,GACzE;EAEV,MADA,KAAK,QACQ,KAAK;GAC/B,GAAI,QAAQ,uBAAuB,KAAA,KAAa,EAAE,oBAAoB,QAAQ,mBAAmB;GACjG,GAAI,QAAQ,qBAAqB,KAAA,KAAa,EAAE,kBAAkB,QAAQ,iBAAiB;GAC3F,GAAI,QAAQ,QAAQ,KAAA,KAAa,EAAE,KAAK,QAAQ,IAAI;EACtD,CAAC;EAED,MAAM,QAAQ,IAAI,eAAe;GAC/B,GAAI,QAAQ,OAAO,KAAA,KAAa,EAAE,IAAI,QAAQ,GAAG;GACjD,GAAI,KAAK,WAAW,KAAA,KAAa,EAAE,OAAO,KAAK,OAAO;GACtD,GAAI,KAAK,mBAAmB,KAAA,KAAa,EAAE,eAAe,KAAK,eAAe;GAC9E,oBAAoB,QAAQ,sBAAsB,KAAK;GACvD,kBAAkB,QAAQ,oBAAoB,KAAK;GACnD,KAAK,QAAQ,OAAO,KAAK;GACzB,SAAS,KAAK;EAChB,CAAC;EACD,MAAM,MAAM,OAAO;EACnB,OAAO;CACT;;;;;;;;;;;;CAaA,MAAM,UAA+B,CAAC,GAAmB;EACvD,OAAO,IAAI,eAAe;GACxB,GAAI,QAAQ,OAAO,KAAA,KAAa,EAAE,IAAI,QAAQ,GAAG;GACjD,GAAI,KAAK,WAAW,KAAA,KAAa,EAAE,OAAO,KAAK,OAAO;GACtD,GAAI,KAAK,mBAAmB,KAAA,KAAa,EAAE,eAAe,KAAK,eAAe;GAC9E,IAAK,QAAQ,kBAAkB,KAAK,qBAAqB,KAAA,KAAa,EACpE,gBAAgB,QAAQ,kBAAkB,KAAK,gBACjD;GACA,GAAI,QAAQ,uBAAuB,KAAA,KAAa,EAAE,oBAAoB,QAAQ,mBAAmB;GACjG,oBAAoB,QAAQ,sBAAsB,KAAK;GACvD,GAAI,KAAK,sBAAsB,KAAA,KAAa,EAAE,kBAAkB,KAAK,kBAAkB;GACvF,KAAK,QAAQ,OAAO,KAAK;GACzB,GAAI,KAAK,oBAAoB,KAAA,KAAa,EAAE,UAAU,KAAK,gBAAgB;GAC3E,GAAI,KAAK,aAAa,KAAA,KAAa,EAAE,SAAS,KAAK,SAAS;GAC5D,GAAI,KAAK,0BAA0B,KAAA,KAAa,EAAE,cAAc,KAAK,sBAAsB;EAC7F,CAAC;CACH;;;;;;CAOA,IAAI,iBAA0B;EAC5B,OAAO,KAAK,WAAW,KAAA,KAAa,KAAK,WAAW;CACtD;;CAGA,IAAI,qBAAyC;EAC3C,OAAO,KAAK;CACd;CAMA,MAAM,UAAgC;EACpC,OAAO;GACL,IAAI,KAAK;GACT,MAAM,KAAK;GACX,UAAU,KAAK;GACf,QAAQ,KAAK;GACb,WAAW,KAAK,8BAAc,IAAI,KAAK;GACvC,UAAU,EACR,GAAI,KAAK,YAAY;IACnB,kBAAkB,KAAK,SAAS;IAChC,eAAe,KAAK,SAAS;IAC7B,QAAQ,KAAK,SAAS;IACtB,kBAAkB,KAAK,SAAS;IAChC,GAAI,KAAK,SAAS,sBAAsB,QAAQ,EAC9C,oBAAoB,KAAK,SAAS,mBACpC;IACA,GAAI,KAAK,2BAA2B,EAAE,wBAAwB,KAAK,wBAAwB;GAC7F,EACF;EACF;CACF;CAEA,kBAA0B;EACxB,MAAM,sBAAsB,KAAK,0BAA0B;EAE3D,IAAI,OAAO,KAAK,0BAA0B,UACxC,OAAO,KAAK;EAEd,IAAI,OAAO,KAAK,0BAA0B,YACxC,OAAO,KAAK,sBAAsB,EAAE,oBAAoB,CAAC;EAE3D,OAAO;CACT;CAEA,4BAA4C;EAC1C,MAAM,QAAkB,CAAC;EACzB,MAAM,KAAK,mFAAmF;EAE9F,IAAI,KAAK,sBAAsB,WAC7B,MAAM,KAAK,4CAA4C;EAGzD,IAAI,KAAK,aAAa,KAAA,GACpB,MAAM,KAAK,4BAA4B,KAAK,KAAK,KAAK,WAAW,GAAI,EAAE,GAAG;OAE1E,MAAM,KAAK,uDAAuD;EAGpE,IAAI,KAAK,wBAAwB,KAAA,GAC/B,MAAM,KAAK,iBAAiB,KAAK,oBAAoB,YAAY;EAGnE,OAAO,MAAM,KAAK,GAAG;CACvB;;;;CASA,MAAM,eACJ,SACA,OAAiB,CAAC,GAClB,UAAiC,CAAC,GACV;EAGxB,IAFe,KAAK,UAAU,WAEf,WAAW;GACxB,IAAI,CAAC,KAAK,iBACR,MAAM,IAAIF,uBAAAA,qBAAqB,KAAK,EAAE;GAGxC,KAAK,WAAW;GAChB,MAAM,KAAK,MAAM;EACnB;EAEA,MAAM,cAAc,KAAK,SAAS,IAAI,GAAG,QAAQ,GAAG,KAAK,IAAI,UAAU,CAAC,CAAC,KAAK,GAAG,MAAM;EACvF,MAAM,UAAU,QAAQ,WAAW,KAAK;EACxC,MAAM,MAAM,QAAQ,MAChB,OAAO,YACL,OAAO,QAAQ,QAAQ,GAAG,CAAC,CAAC,QAAQ,UAAqC,MAAM,OAAO,KAAA,CAAS,CACjG,IACA,KAAA;EACJ,MAAM,YAAY,KAAK,IAAI;EAC3B,MAAM,SAAS,MAAM,KAAK,QAAQ,KAAK,aAAa;GAClD,GAAI,YAAY,KAAA,KAAa,EAAE,YAAY,KAAK,KAAK,UAAU,GAAI,EAAE;GACrE,GAAI,QAAQ,QAAQ,KAAA,KAAa,EAAE,KAAK,QAAQ,IAAI;GACpD,GAAI,QAAQ,KAAA,KAAa,EAAE,IAAI;EACjC,CAAC;EACD,MAAM,WAAW,OAAO,YAAY;EACpC,OAAO;GACL,SAAS,aAAa;GACtB;GACA,QAAQ,OAAO;GACf,QAAQ,OAAO;GACf,iBAAiB,KAAK,IAAI,IAAI;GAC9B;GACA;GACA,UAAU,OAAO;EACnB;CACF;AACF;;;ACxqBA,MAAa,yBAAiE;CAC5E,IAAI;CACJ,MAAM;CACN,aAAa;CACb,cAAc;EACZ,MAAM;EACN,YAAY;GACV,OAAO;IAAE,MAAM;IAAU,aAAa;GAAsD;GAC5F,eAAe;IACb,MAAM;IACN,aAAa;GACf;GACA,WAAW;IAAE,MAAM;IAAU,aAAa;GAAgD;GAC1F,oBAAoB;IAClB,MAAM;IACN,aAAa;GACf;GACA,kBAAkB;IAChB,MAAM;IACN,aAAa;IACb,MAAM,CAAC,YAAY,SAAS;IAC5B,SAAS;GACX;GACA,KAAK;IACH,MAAM;IACN,aAAa;IACb,sBAAsB,EAAE,MAAM,SAAS;GACzC;GACA,SAAS;IAAE,MAAM;IAAU,aAAa;GAAgC;EAC1E;CACF;CACA,gBAAe,WAAU,IAAI,eAAe,MAAM;AACpD"}
1
+ {"version":3,"file":"index.cjs","names":["ProcessHandle","UnsupportedStdinCloseError","SandboxProcessManager","MastraSandbox","SandboxNotReadyError","SandboxNotFoundError","Sandbox"],"sources":["../src/utils/shell-quote.ts","../src/sandbox/process-manager.ts","../src/sandbox/index.ts","../src/provider.ts"],"sourcesContent":["/**\n * Shell-quote a single argument for safe use in a command string.\n *\n * Arguments containing only safe characters are returned as-is.\n * All others are wrapped in single quotes with embedded single quotes escaped.\n */\nexport function shellQuote(arg: string): string {\n // Safe characters that don't need quoting\n if (/^[a-zA-Z0-9._\\-/@:=]+$/.test(arg)) return arg;\n // Wrap in single quotes, escaping any embedded single quotes\n return \"'\" + arg.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n","/**\n * Railway Process Manager\n *\n * Implements SandboxProcessManager for Railway sandboxes.\n * Wraps the Railway SDK's `Sandbox.exec()` API.\n *\n * Railway's `exec(command, options)` accepts per-call `cwd` and `env` options\n * (since SDK v3.3.1) and returns an `ExecHandle` that runs the command\n * server-side, independently of the client. Each spawn() starts one exec.\n * The handle streams output via `onStdout`/`onStderr` callbacks wired to\n * `emitStdout`/`emitStderr`, exposes a durable `sessionName`, and can be\n * terminated with `kill(signal)`.\n */\n\nimport { ProcessHandle, UnsupportedStdinCloseError, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { ExecHandle, ExecResult } from 'railway';\nimport type { RailwaySandbox } from './index';\n\nexport const LOG_PREFIX = '[RailwaySandbox]';\n\n// =============================================================================\n// Railway Process Handle\n// =============================================================================\n\n/**\n * Wraps a Railway ExecHandle to conform to Mastra's ProcessHandle.\n * Not exported — internal to this module.\n */\nclass RailwayProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _execHandle: ExecHandle;\n private readonly _startTime: number;\n private _exitCode: number | undefined;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _killed = false;\n\n constructor(pid: string, execHandle: ExecHandle, startTime: number, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this._execHandle = execHandle;\n this._startTime = startTime;\n\n // Resolve exit code once the command completes so exitCode is available\n // without an explicit wait().\n void this._execHandle.then(\n (result: ExecResult) => {\n // -1 means terminated by a signal (e.g. after kill()).\n this._exitCode = result.exitCode ?? (this._killed ? 137 : -1);\n },\n () => {\n if (this._exitCode === undefined) {\n this._exitCode = 1;\n }\n },\n );\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n async wait(): Promise<CommandResult> {\n // Idempotent — cache the promise so repeated calls return the same result.\n if (!this._waitPromise) {\n this._waitPromise = this._doWait();\n }\n return this._waitPromise;\n }\n\n private async _doWait(): Promise<CommandResult> {\n try {\n const result = await this._execHandle;\n const exitCode = result.exitCode ?? (this._killed ? 137 : -1);\n this._exitCode = exitCode;\n\n // Railway captures output server-side; surface it through the base buffers\n // if streaming callbacks didn't already populate them.\n if (result.stdout && !this.stdout) this.emitStdout(result.stdout);\n if (result.stderr && !this.stderr) this.emitStderr(result.stderr);\n\n return {\n success: exitCode === 0,\n exitCode,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n killed: this._killed,\n timedOut: result.timedOut,\n };\n } catch (error) {\n const exitCode = this._exitCode ?? 1;\n this._exitCode = exitCode;\n return {\n success: false,\n exitCode,\n stdout: this.stdout,\n stderr: this.stderr || (error instanceof Error ? error.message : String(error)),\n executionTimeMs: Date.now() - this._startTime,\n killed: this._killed,\n };\n }\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n this._killed = true;\n try {\n return await this._execHandle.kill('TERM');\n } catch {\n // Command may already be gone.\n return false;\n }\n }\n\n async sendStdin(_data: string): Promise<void> {\n // Railway's exec API does not expose stdin streaming.\n throw new Error(`${LOG_PREFIX} sending stdin is not supported by the Railway sandbox provider`);\n }\n\n async closeStdin(): Promise<void> {\n throw new UnsupportedStdinCloseError(\n `${LOG_PREFIX} closing stdin is not supported by the Railway sandbox provider`,\n );\n }\n}\n\n// =============================================================================\n// Railway Process Manager\n// =============================================================================\n\n/**\n * Railway implementation of SandboxProcessManager.\n * Uses the Railway SDK's `Sandbox.exec()` with one exec per spawned process.\n */\nexport class RailwayProcessManager extends SandboxProcessManager<RailwaySandbox> {\n private _spawnCounter = 0;\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n const railway = this.sandbox.railway;\n\n // The base spawn wrapper already merged the sandbox env into options.env\n const mergedEnv = { ...options.env };\n const env = Object.fromEntries(\n Object.entries(mergedEnv).filter((entry): entry is [string, string] => entry[1] !== undefined),\n );\n\n const pid = `railway-proc-${Date.now().toString(36)}-${(this._spawnCounter++).toString(36)}`;\n\n // Deferred reference — callbacks fire asynchronously after the handle is\n // assigned, so `handle` is always defined by the time they run.\n let handle: RailwayProcessHandle;\n\n const execHandle = railway.exec(command, {\n ...(options.timeout !== undefined && { timeoutSec: Math.ceil(options.timeout / 1000) }),\n ...(options.cwd !== undefined && { cwd: options.cwd }),\n ...(Object.keys(env).length > 0 && { env }),\n onStdout: (chunk: string) => handle.emitStdout(chunk),\n onStderr: (chunk: string) => handle.emitStderr(chunk),\n });\n\n handle = new RailwayProcessHandle(pid, execHandle, Date.now(), options);\n this._tracked.set(handle.pid, handle);\n return handle;\n }\n\n /**\n * List tracked processes.\n *\n * Railway has no API to enumerate running exec sessions by sandbox, so this\n * reports the processes this manager spawned.\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","/**\n * Railway Sandbox Provider\n *\n * A Railway sandbox implementation for Mastra workspaces. Provisions an\n * ephemeral, isolated Linux VM on Railway, runs commands in it via the\n * Railway TypeScript SDK, and destroys it on teardown.\n *\n * @see https://docs.railway.com/sandboxes\n */\n\nimport type {\n CommandResult,\n ExecuteCommandOptions,\n InstructionsOption,\n MastraSandboxOptions,\n ProviderStatus,\n SandboxCloneOptions,\n SandboxInfo,\n} from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxNotReadyError } from '@mastra/core/workspace';\nimport { Sandbox, SandboxFailedError, SandboxNotFoundError, SandboxTimeoutError } from 'railway';\nimport type { SandboxNetworkIsolation, SandboxTemplate } from 'railway';\nimport { shellQuote } from '../utils/shell-quote';\nimport { LOG_PREFIX, RailwayProcessManager } from './process-manager';\n\n/**\n * Safety margin subtracted from the sandbox's idle timeout when scheduling the\n * pre-reap checkpoint refresh. Sized to comfortably exceed Cloud Run cold-start\n * / recycle windows so a scale event during the refresh doesn't cause the timer\n * to lose the race with Railway's idle destroy. If a caller reduces the idle\n * timeout below this margin, the refresh falls back to the 1-second floor and\n * fires almost immediately after start — surfacing the misconfiguration rather\n * than silently skipping the refresh.\n */\nconst CHECKPOINT_REFRESH_MARGIN_MS = 180_000;\n\n// =============================================================================\n// Public capture result\n// =============================================================================\n\n/**\n * Outcome of a {@link RailwaySandbox.captureCheckpoint} call.\n *\n * `captured` and `coalesced` both represent a successful capture the caller can\n * persist against — they carry the checkpoint name inline so callers don't have\n * to reach back into the sandbox instance to learn what they just wrote.\n * `skipped` carries a machine-readable reason so the set stays extensible\n * without another breaking change.\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// Railway Sandbox Options\n// =============================================================================\n\n/**\n * Railway sandbox provider configuration.\n */\nexport interface RailwaySandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Unique identifier for this sandbox instance. */\n id?: string;\n /** Railway API token. Falls back to the RAILWAY_API_TOKEN env var. */\n token?: string;\n /** Railway environment ID. Falls back to the RAILWAY_ENVIRONMENT_ID env var. */\n environmentId?: string;\n /**\n * Reattach to an existing Railway sandbox by its Railway ID instead of\n * creating a new one. When set, `start()` calls `Sandbox.connect()`.\n */\n sandboxId?: string;\n /**\n * Reuse a saved Railway sandbox checkpoint as the baseline filesystem for\n * new sandboxes. When the named checkpoint is missing, the sandbox is created\n * normally and a checkpoint is captured after setup succeeds.\n */\n checkpointName?: string;\n /**\n * Fallback checkpoint used to seed a new sandbox when `checkpointName` has\n * no stored state. Snapshots continue writing to `checkpointName`.\n */\n seedCheckpointName?: string;\n /**\n * How long the sandbox can sit idle (no `exec` interaction) before Railway\n * destroys it automatically. Range depends on plan (1–120 minutes on\n * Hobby/Pro, 1–5 on Trial/Free). Defaults to the plan default when omitted.\n */\n idleTimeoutMinutes?: number;\n /**\n * Network isolation mode.\n * - `ISOLATED` (default): outbound internet only, no private network access.\n * - `PRIVATE`: joins the environment's private network.\n */\n networkIsolation?: SandboxNetworkIsolation;\n /** Environment variables baked into the sandbox, available to every command. */\n env?: Record<string, string>;\n /**\n * Provision the sandbox from a custom base image built with the Railway\n * template builder. Use this to pre-install packages or run setup steps so\n * every sandbox created from it starts ready.\n *\n * - Builder callback — receives the base `Sandbox.template()` and returns the\n * configured template. Railway builds the template when `Sandbox.create()`\n * runs during `start()`.\n * ```ts\n * template: t => t.withPackages('git', 'curl').run('npm i -g pnpm')\n * ```\n * - Pre-built `SandboxTemplate` — pass a template to reuse it across\n * sandboxes. Railway still builds the image during sandbox creation.\n *\n * Ignored when `sandboxId` is set (reattach) or when forking.\n */\n template?: SandboxTemplate | ((base: SandboxTemplate) => SandboxTemplate);\n /**\n * Default execution timeout in milliseconds applied to commands that don't\n * specify their own timeout. When omitted, commands run until they exit.\n */\n timeout?: number;\n /**\n * Custom instructions that override the default instructions returned by\n * `getInstructions()`.\n *\n * - `string` — Fully replaces the default instructions. Pass an empty string\n * to suppress instructions entirely.\n * - `(opts) => string` — Receives the default instructions and optional\n * request context so you can extend or customise per-request.\n */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// Railway Sandbox Implementation\n// =============================================================================\n\n/**\n * Railway sandbox provider for Mastra workspaces.\n *\n * Features:\n * - Ephemeral, isolated Linux VM via the Railway TypeScript SDK\n * - Command execution with streaming output and timeouts\n * - Configurable idle timeout and network isolation\n * - Reattach to an existing sandbox by Railway ID\n *\n * @example Basic usage\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { RailwaySandbox } from '@mastra/railway';\n *\n * const sandbox = new RailwaySandbox({\n * // token + environmentId read from RAILWAY_API_TOKEN / RAILWAY_ENVIRONMENT_ID\n * idleTimeoutMinutes: 30,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCode('console.log(\"Hello!\")');\n * ```\n *\n * @example Private networking\n * ```typescript\n * const sandbox = new RailwaySandbox({\n * networkIsolation: 'PRIVATE',\n * env: { NODE_ENV: 'production' },\n * });\n * ```\n */\nexport class RailwaySandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'RailwaySandbox';\n readonly provider = 'railway';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: RailwayProcessManager;\n\n private _sandbox: Sandbox | null = null;\n private _createdAt: Date | null = null;\n private _checkpointRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n private _checkpointRefreshInFlight: Promise<void> | null = null;\n private _sandboxId?: string;\n private _restoredCheckpointName?: string;\n private _startInFlight: Promise<void> | null = null;\n\n private readonly _token?: string;\n private readonly _environmentId?: string;\n private readonly _checkpointName?: string;\n private readonly _seedCheckpointName?: string;\n private readonly _idleTimeoutMinutes?: number;\n private readonly _networkIsolation?: SandboxNetworkIsolation;\n private readonly _env: Record<string, string>;\n private readonly _timeout?: number;\n private readonly _instructionsOverride?: InstructionsOption;\n private readonly _templateOption?: RailwaySandboxOptions['template'];\n\n constructor(options: RailwaySandboxOptions = {}) {\n super({\n ...options,\n name: 'RailwaySandbox',\n processes: new RailwayProcessManager(),\n });\n\n this.id = options.id ?? this.generateId();\n this._token = options.token ?? process.env.RAILWAY_API_TOKEN;\n this._environmentId = options.environmentId ?? process.env.RAILWAY_ENVIRONMENT_ID;\n this._sandboxId = options.sandboxId;\n this._checkpointName = options.checkpointName;\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._templateOption = options.template;\n }\n\n private generateId(): string {\n return `railway-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n /**\n * Get the underlying Railway Sandbox instance for direct SDK access.\n *\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get railway(): Sandbox {\n if (!this._sandbox) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._sandbox;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Start the Railway sandbox.\n *\n * Reattaches to an existing sandbox when `sandboxId` is configured,\n * otherwise provisions a new one. Resolves once the sandbox is RUNNING.\n */\n async start(): Promise<void> {\n if (this._sandbox) {\n return;\n }\n\n const clientConfig = this._clientConfig();\n const createOptions = this._createOptions(clientConfig);\n\n if (this._sandboxId) {\n const sandboxId = this._sandboxId;\n this._startInFlight ??= (async () => {\n this._restoredCheckpointName = undefined;\n try {\n this._sandbox = await this._reconnectSandbox(sandboxId, clientConfig);\n } catch (error) {\n if (!(error instanceof SandboxNotFoundError)) {\n throw error;\n }\n this._sandbox = await this._createNewSandbox(createOptions);\n }\n })().finally(() => {\n this._startInFlight = null;\n });\n } else {\n this._startInFlight ??= (async () => {\n this._sandbox = await this._createNewSandbox(createOptions);\n })().finally(() => {\n this._startInFlight = null;\n });\n }\n await this._startInFlight;\n\n if (!this._sandbox) {\n throw new Error('Failed to start Railway sandbox');\n }\n\n const sandbox = this._sandbox as Sandbox;\n this._sandboxId = sandbox.id;\n\n this._createdAt = sandbox.createdAt ? new Date(sandbox.createdAt) : new Date();\n this.logger.debug(`${LOG_PREFIX} Railway sandbox ${sandbox.id} ready for logical ID: ${this.id}`);\n this._scheduleCheckpointRefresh();\n }\n\n /**\n * Create a new Railway sandbox.\n */\n private async _createNewSandbox(createOptions: ReturnType<RailwaySandbox['_createOptions']>): Promise<Sandbox> {\n this.logger.debug(`${LOG_PREFIX} Creating Railway sandbox for: ${this.id}`);\n try {\n let checkpointToRestore: string | undefined;\n if (this._checkpointName || this._seedCheckpointName) {\n const checkpoints = await Sandbox.checkpoints(this._clientConfig());\n const checkpointNames = new Set(checkpoints.map(checkpoint => checkpoint.key));\n checkpointToRestore = checkpointNames.has(this._checkpointName ?? '')\n ? this._checkpointName\n : checkpointNames.has(this._seedCheckpointName ?? '')\n ? this._seedCheckpointName\n : undefined;\n }\n\n const sandbox = checkpointToRestore\n ? await Sandbox.create(checkpointToRestore, createOptions)\n : await Sandbox.create(createOptions);\n this._restoredCheckpointName = checkpointToRestore;\n return sandbox;\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Reconnect to an existing Railway sandbox, creating a fresh one when\n */\n private async _reconnectSandbox(\n reconnectSandboxId: string,\n clientConfig: { token?: string; environmentId?: string },\n ): Promise<Sandbox> {\n this.logger.debug(`${LOG_PREFIX} Reconnecting to Railway sandbox ${reconnectSandboxId}...`);\n\n let connectedSandbox: Sandbox = await Sandbox.connect(reconnectSandboxId, clientConfig);\n\n if (connectedSandbox.status !== 'RUNNING') {\n throw new SandboxNotFoundError({\n id: reconnectSandboxId,\n environmentId: clientConfig.environmentId ?? '',\n });\n }\n\n return connectedSandbox;\n }\n\n private _clientConfig(): { token?: string; environmentId?: string } {\n return {\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n };\n }\n\n private _createOptions(clientConfig: { token?: string; environmentId?: string }) {\n return {\n ...clientConfig,\n ...(this._idleTimeoutMinutes !== undefined && { idleTimeoutMinutes: this._idleTimeoutMinutes }),\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n ...(Object.keys(this._env).length > 0 && { env: this._env }),\n };\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 the idle-timer schedule.\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 Railway's idle destroy.\n *\n * Coalesces with any in-flight timer-driven refresh: concurrent callers join\n * the same underlying `Sandbox.checkpoint` call and receive\n * `{ status: 'coalesced', checkpointName }`. Both `captured` and `coalesced`\n * carry the checkpoint name inline so callers can persist a session→\n * checkpoint binding without a second, non-atomic read against the sandbox.\n * Returns `{ status: 'skipped', reason }` when there's nothing to capture\n * (no `checkpointName` configured, or the sandbox isn't running yet).\n *\n * On successful capture, restarts the idle-timer countdown so the next\n * timer-driven refresh is scheduled from this capture.\n *\n * Never captures without a `checkpointName` and never mutates status — safe\n * to invoke concurrently with `executeCommand`, `restart`, or `stop`.\n */\n async captureCheckpoint(): Promise<CaptureCheckpointResult> {\n const checkpointName = this._checkpointName;\n if (!checkpointName) {\n return { status: 'skipped', reason: 'no-checkpoint-name-configured' };\n }\n\n const sandbox = this._sandbox;\n if (!sandbox) {\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n\n if (this._checkpointRefreshInFlight) {\n await this._checkpointRefreshInFlight;\n return { status: 'coalesced', checkpointName };\n }\n\n const capture = this._checkpointSandbox(sandbox).finally(() => {\n if (this._checkpointRefreshInFlight === capture) {\n this._checkpointRefreshInFlight = null;\n }\n });\n this._checkpointRefreshInFlight = capture;\n\n await capture;\n this._scheduleCheckpointRefresh();\n\n return { status: 'captured', checkpointName };\n }\n\n private async _checkpointSandbox(sandbox: Sandbox): Promise<void> {\n if (!this._checkpointName) {\n return;\n }\n\n this.logger.debug(`${LOG_PREFIX} Capturing Railway sandbox checkpoint ${this._checkpointName} for: ${this.id}`);\n\n const checkpoints = await Sandbox.checkpoints(this._clientConfig());\n const checkpointAlreadyExists = checkpoints.some(checkpoint => checkpoint.key === this._checkpointName);\n\n // Remove first so we can re-create a checkpoint with the same name.\n if (checkpointAlreadyExists) {\n await Sandbox.deleteCheckpoint(this._checkpointName, this._clientConfig());\n }\n\n await sandbox.checkpoint(this._checkpointName);\n }\n\n private _scheduleCheckpointRefresh(): void {\n if (!this._checkpointName || !this._sandbox) {\n return;\n }\n\n const idleTimeoutMinutes = this._idleTimeoutMinutes ?? this._sandbox.idleTimeoutMinutes;\n if (!idleTimeoutMinutes) {\n return;\n }\n\n this._cancelCheckpointRefresh();\n\n const delayMs = Math.max(1_000, idleTimeoutMinutes * 60_000 - CHECKPOINT_REFRESH_MARGIN_MS);\n this._checkpointRefreshTimer = setTimeout(() => {\n this._checkpointRefreshTimer = null;\n const sandbox = this._sandbox;\n if (!sandbox || this._checkpointRefreshInFlight) {\n return;\n }\n\n const refresh = this._checkpointSandbox(sandbox).finally(() => {\n if (this._checkpointRefreshInFlight === refresh) {\n this._checkpointRefreshInFlight = null;\n }\n });\n this._checkpointRefreshInFlight = refresh;\n refresh.catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to refresh Railway sandbox checkpoint ${this._checkpointName}:`, error);\n });\n }, delayMs);\n this._checkpointRefreshTimer.unref?.();\n }\n\n private _cancelCheckpointRefresh(): void {\n if (this._checkpointRefreshTimer) {\n clearTimeout(this._checkpointRefreshTimer);\n this._checkpointRefreshTimer = null;\n }\n }\n\n /**\n * Stop the Railway sandbox.\n *\n * Railway sandboxes have no separate \"stopped\" state — they're either\n * running or destroyed — so stopping destroys the sandbox but we keep a checkpoint of the filesystem.\n */\n async stop(): Promise<void> {\n if (this._checkpointName) {\n await this._flushCheckpointRefresh().catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to checkpoint Railway sandbox ${this._sandbox?.id}:`, error);\n });\n }\n\n await this._teardown();\n }\n\n /**\n * Destroy the Railway sandbox and release its resources including the checkpoint.\n */\n async destroy(): Promise<void> {\n this._cancelCheckpointRefresh();\n if (this._checkpointName) {\n await this._checkpointRefreshInFlight;\n await Sandbox.deleteCheckpoint(this._checkpointName, this._clientConfig()).catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to delete Railway checkpoint ${this._checkpointName}:`, error);\n });\n }\n\n await this._teardown();\n }\n\n private async _flushCheckpointRefresh(): Promise<void> {\n this._cancelCheckpointRefresh();\n\n if (this._checkpointRefreshInFlight) {\n await this._checkpointRefreshInFlight;\n return;\n }\n\n if (this._sandbox) {\n await this._checkpointSandbox(this._sandbox);\n }\n }\n\n private async _teardown(): Promise<void> {\n this._cancelCheckpointRefresh();\n if (!this._sandbox) {\n return;\n }\n await this._checkpointRefreshInFlight;\n\n const sandbox = this._sandbox;\n this._sandbox = null;\n try {\n await sandbox.destroy();\n } catch (error) {\n this.logger.warn(`${LOG_PREFIX} Failed to destroy Railway sandbox ${sandbox.id}:`, error);\n }\n }\n\n /**\n * Fork this running sandbox into a new, independent `RailwaySandbox`.\n *\n * Clones the filesystem (a fresh boot, not live processes) into the same\n * environment. The returned sandbox is already started and reattached to the\n * forked Railway sandbox; it inherits this sandbox's credentials and defaults\n * unless overridden via `options`.\n *\n * @throws {SandboxNotReadyError} If this sandbox has not been started.\n */\n async fork(\n options: Pick<RailwaySandboxOptions, 'id' | 'idleTimeoutMinutes' | 'networkIsolation' | 'env'> = {},\n ): Promise<RailwaySandbox> {\n const source = this.railway;\n const forked = await source.fork({\n ...(options.idleTimeoutMinutes !== undefined && { idleTimeoutMinutes: options.idleTimeoutMinutes }),\n ...(options.networkIsolation !== undefined && { networkIsolation: options.networkIsolation }),\n ...(options.env !== undefined && { env: options.env }),\n });\n\n const child = new RailwaySandbox({\n ...(options.id !== undefined && { id: options.id }),\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n networkIsolation: options.networkIsolation ?? this._networkIsolation,\n env: options.env ?? this._env,\n timeout: this._timeout,\n });\n await child._start();\n return child;\n }\n\n /**\n * Construct a sibling `RailwaySandbox` that inherits this sandbox's\n * credentials and defaults (token, environment, checkpoint, network\n * isolation, timeout, template, instructions) with per-instance overrides.\n *\n * Unlike {@link fork}, `clone` performs no I/O and does not require this\n * sandbox to be started — the returned sandbox is not started and provisions\n * (or reattaches, when `sandboxId` is set) on its own `start()`. Use it when\n * one configured sandbox acts as the template for a fleet of independent\n * sandboxes (e.g. one per project).\n */\n clone(options: SandboxCloneOptions = {}): RailwaySandbox {\n return new RailwaySandbox({\n ...(options.id !== undefined && { id: options.id }),\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n ...((options.checkpointName ?? this._checkpointName) !== undefined && {\n checkpointName: options.checkpointName ?? this._checkpointName,\n }),\n ...(options.seedCheckpointName !== undefined && { seedCheckpointName: options.seedCheckpointName }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n env: options.env ?? this._env,\n ...(this._templateOption !== undefined && { template: this._templateOption }),\n ...(this._timeout !== undefined && { timeout: this._timeout }),\n ...(this._instructionsOverride !== undefined && { instructions: this._instructionsOverride }),\n });\n }\n\n /**\n * Whether a Railway API token was resolved at construction (explicit option\n * or the `RAILWAY_API_TOKEN` env fallback). Lets callers gate features on a\n * usable configuration without provisioning a sandbox.\n */\n get hasCredentials(): boolean {\n return this._token !== undefined && this._token !== '';\n }\n\n /** The configured idle teardown window in minutes, if any. */\n get idleTimeoutMinutes(): number | undefined {\n return this._idleTimeoutMinutes;\n }\n\n // ---------------------------------------------------------------------------\n // Info & Instructions\n // ---------------------------------------------------------------------------\n\n async getInfo(): Promise<SandboxInfo> {\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 metadata: {\n ...(this._sandbox && {\n railwaySandboxId: this._sandbox.id,\n environmentId: this._sandbox.environmentId,\n region: this._sandbox.region,\n networkIsolation: this._sandbox.networkIsolation,\n ...(this._sandbox.idleTimeoutMinutes != null && {\n idleTimeoutMinutes: this._sandbox.idleTimeoutMinutes,\n }),\n ...(this._restoredCheckpointName && { restoredCheckpointName: this._restoredCheckpointName }),\n }),\n },\n };\n }\n\n getInstructions(): string {\n const defaultInstructions = this._buildDefaultInstructions();\n\n if (typeof this._instructionsOverride === 'string') {\n return this._instructionsOverride;\n }\n if (typeof this._instructionsOverride === 'function') {\n return this._instructionsOverride({ defaultInstructions });\n }\n return defaultInstructions;\n }\n\n private _buildDefaultInstructions(): string {\n const parts: string[] = [];\n parts.push('Railway cloud sandbox: an isolated Debian Linux VM with outbound internet access.');\n\n if (this._networkIsolation === 'PRIVATE') {\n parts.push('Joined to the environment private network.');\n }\n\n if (this._timeout !== undefined) {\n parts.push(`Default command timeout: ${Math.ceil(this._timeout / 1000)}s.`);\n } else {\n parts.push('Commands run until they exit unless a timeout is set.');\n }\n\n if (this._idleTimeoutMinutes !== undefined) {\n parts.push(`Idle timeout: ${this._idleTimeoutMinutes} minute(s).`);\n }\n\n return parts.join(' ');\n }\n\n // ---------------------------------------------------------------------------\n // Command Execution\n // ---------------------------------------------------------------------------\n\n /**\n * Execute a command in the sandbox and return the result.\n */\n async executeCommand(\n command: string,\n args: string[] = [],\n options: ExecuteCommandOptions = {},\n ): Promise<CommandResult> {\n const status = this._sandbox?.status;\n\n if (status !== 'RUNNING') {\n if (!this._checkpointName) {\n throw new SandboxNotReadyError(this.id);\n }\n\n this._sandbox = null;\n await this.start();\n }\n\n const fullCommand = args.length > 0 ? `${command} ${args.map(shellQuote).join(' ')}` : command;\n const timeout = options.timeout ?? this._timeout;\n const mergedEnv = { ...this.getEnv(), ...options.env };\n const env = Object.keys(mergedEnv).length\n ? Object.fromEntries(\n Object.entries(mergedEnv).filter((entry): entry is [string, string] => entry[1] !== undefined),\n )\n : undefined;\n const startedAt = Date.now();\n const result = await this.railway.exec(fullCommand, {\n ...(timeout !== undefined && { timeoutSec: Math.ceil(timeout / 1000) }),\n ...(options.cwd !== undefined && { cwd: options.cwd }),\n ...(env !== undefined && { env }),\n });\n const exitCode = result.exitCode ?? -1;\n return {\n success: exitCode === 0,\n exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n executionTimeMs: Date.now() - startedAt,\n command,\n args,\n timedOut: result.timedOut,\n };\n }\n}\n","/**\n * Railway sandbox provider descriptor for MastraEditor.\n *\n * @example\n * ```typescript\n * import { railwaySandboxProvider } from '@mastra/railway';\n *\n * const editor = new MastraEditor({\n * sandboxes: { [railwaySandboxProvider.id]: railwaySandboxProvider },\n * });\n * ```\n */\nimport type { SandboxProvider } from '@mastra/core/editor';\nimport { RailwaySandbox } from './sandbox';\n\n/**\n * Serializable subset of RailwaySandboxOptions for editor storage.\n */\ninterface RailwayProviderConfig {\n token?: string;\n environmentId?: string;\n sandboxId?: string;\n idleTimeoutMinutes?: number;\n networkIsolation?: 'ISOLATED' | 'PRIVATE';\n env?: Record<string, string>;\n timeout?: number;\n}\n\nexport const railwaySandboxProvider: SandboxProvider<RailwayProviderConfig> = {\n id: 'railway',\n name: 'Railway Sandbox',\n description: 'Ephemeral, isolated Linux VM powered by Railway',\n configSchema: {\n type: 'object',\n properties: {\n token: { type: 'string', description: 'Railway API token (falls back to RAILWAY_API_TOKEN)' },\n environmentId: {\n type: 'string',\n description: 'Railway environment ID (falls back to RAILWAY_ENVIRONMENT_ID)',\n },\n sandboxId: { type: 'string', description: 'Reattach to an existing Railway sandbox by ID' },\n idleTimeoutMinutes: {\n type: 'number',\n description: 'Minutes a sandbox can sit idle before Railway destroys it',\n },\n networkIsolation: {\n type: 'string',\n description: 'Network isolation mode',\n enum: ['ISOLATED', 'PRIVATE'],\n default: 'ISOLATED',\n },\n env: {\n type: 'object',\n description: 'Environment variables',\n additionalProperties: { type: 'string' },\n },\n timeout: { type: 'number', description: 'Default command timeout in ms' },\n },\n },\n createSandbox: config => new RailwaySandbox(config),\n};\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { RailwaySandbox, type RailwaySandboxOptions } from './sandbox/index.js';
2
- export { RailwayProcessManager, type RailwayProcessManagerOptions } from './sandbox/process-manager.js';
2
+ export { RailwayProcessManager } from './sandbox/process-manager.js';
3
3
  export { railwaySandboxProvider } from './provider.js';
4
4
  export { SandboxFileNotFoundError } from 'railway';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AACrG,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -107,15 +107,9 @@ var RailwayProcessHandle = class extends ProcessHandle {
107
107
  */
108
108
  var RailwayProcessManager = class extends SandboxProcessManager {
109
109
  _spawnCounter = 0;
110
- constructor(opts = {}) {
111
- super({ env: opts.env });
112
- }
113
110
  async spawn(command, options = {}) {
114
111
  const railway = this.sandbox.railway;
115
- const mergedEnv = {
116
- ...this.env,
117
- ...options.env
118
- };
112
+ const mergedEnv = { ...options.env };
119
113
  const env = Object.fromEntries(Object.entries(mergedEnv).filter((entry) => entry[1] !== void 0));
120
114
  const pid = `railway-proc-${Date.now().toString(36)}-${(this._spawnCounter++).toString(36)}`;
121
115
  let handle;
@@ -213,7 +207,7 @@ var RailwaySandbox = class RailwaySandbox extends MastraSandbox {
213
207
  super({
214
208
  ...options,
215
209
  name: "RailwaySandbox",
216
- processes: new RailwayProcessManager({ env: options.env })
210
+ processes: new RailwayProcessManager()
217
211
  });
218
212
  this.id = options.id ?? this.generateId();
219
213
  this._token = options.token ?? process.env.RAILWAY_API_TOKEN;
@@ -563,7 +557,11 @@ var RailwaySandbox = class RailwaySandbox extends MastraSandbox {
563
557
  }
564
558
  const fullCommand = args.length > 0 ? `${command} ${args.map(shellQuote).join(" ")}` : command;
565
559
  const timeout = options.timeout ?? this._timeout;
566
- const env = options.env ? Object.fromEntries(Object.entries(options.env).filter((entry) => entry[1] !== void 0)) : void 0;
560
+ const mergedEnv = {
561
+ ...this.getEnv(),
562
+ ...options.env
563
+ };
564
+ const env = Object.keys(mergedEnv).length ? Object.fromEntries(Object.entries(mergedEnv).filter((entry) => entry[1] !== void 0)) : void 0;
567
565
  const startedAt = Date.now();
568
566
  const result = await this.railway.exec(fullCommand, {
569
567
  ...timeout !== void 0 && { timeoutSec: Math.ceil(timeout / 1e3) },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/utils/shell-quote.ts","../src/sandbox/process-manager.ts","../src/sandbox/index.ts","../src/provider.ts"],"sourcesContent":["/**\n * Shell-quote a single argument for safe use in a command string.\n *\n * Arguments containing only safe characters are returned as-is.\n * All others are wrapped in single quotes with embedded single quotes escaped.\n */\nexport function shellQuote(arg: string): string {\n // Safe characters that don't need quoting\n if (/^[a-zA-Z0-9._\\-/@:=]+$/.test(arg)) return arg;\n // Wrap in single quotes, escaping any embedded single quotes\n return \"'\" + arg.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n","/**\n * Railway Process Manager\n *\n * Implements SandboxProcessManager for Railway sandboxes.\n * Wraps the Railway SDK's `Sandbox.exec()` API.\n *\n * Railway's `exec(command, options)` accepts per-call `cwd` and `env` options\n * (since SDK v3.3.1) and returns an `ExecHandle` that runs the command\n * server-side, independently of the client. Each spawn() starts one exec.\n * The handle streams output via `onStdout`/`onStderr` callbacks wired to\n * `emitStdout`/`emitStderr`, exposes a durable `sessionName`, and can be\n * terminated with `kill(signal)`.\n */\n\nimport { ProcessHandle, UnsupportedStdinCloseError, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { ExecHandle, ExecResult } from 'railway';\nimport type { RailwaySandbox } from './index';\n\nexport const LOG_PREFIX = '[RailwaySandbox]';\n\n// =============================================================================\n// Railway Process Handle\n// =============================================================================\n\n/**\n * Wraps a Railway ExecHandle to conform to Mastra's ProcessHandle.\n * Not exported — internal to this module.\n */\nclass RailwayProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _execHandle: ExecHandle;\n private readonly _startTime: number;\n private _exitCode: number | undefined;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _killed = false;\n\n constructor(pid: string, execHandle: ExecHandle, startTime: number, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this._execHandle = execHandle;\n this._startTime = startTime;\n\n // Resolve exit code once the command completes so exitCode is available\n // without an explicit wait().\n void this._execHandle.then(\n (result: ExecResult) => {\n // -1 means terminated by a signal (e.g. after kill()).\n this._exitCode = result.exitCode ?? (this._killed ? 137 : -1);\n },\n () => {\n if (this._exitCode === undefined) {\n this._exitCode = 1;\n }\n },\n );\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n async wait(): Promise<CommandResult> {\n // Idempotent — cache the promise so repeated calls return the same result.\n if (!this._waitPromise) {\n this._waitPromise = this._doWait();\n }\n return this._waitPromise;\n }\n\n private async _doWait(): Promise<CommandResult> {\n try {\n const result = await this._execHandle;\n const exitCode = result.exitCode ?? (this._killed ? 137 : -1);\n this._exitCode = exitCode;\n\n // Railway captures output server-side; surface it through the base buffers\n // if streaming callbacks didn't already populate them.\n if (result.stdout && !this.stdout) this.emitStdout(result.stdout);\n if (result.stderr && !this.stderr) this.emitStderr(result.stderr);\n\n return {\n success: exitCode === 0,\n exitCode,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n killed: this._killed,\n timedOut: result.timedOut,\n };\n } catch (error) {\n const exitCode = this._exitCode ?? 1;\n this._exitCode = exitCode;\n return {\n success: false,\n exitCode,\n stdout: this.stdout,\n stderr: this.stderr || (error instanceof Error ? error.message : String(error)),\n executionTimeMs: Date.now() - this._startTime,\n killed: this._killed,\n };\n }\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n this._killed = true;\n try {\n return await this._execHandle.kill('TERM');\n } catch {\n // Command may already be gone.\n return false;\n }\n }\n\n async sendStdin(_data: string): Promise<void> {\n // Railway's exec API does not expose stdin streaming.\n throw new Error(`${LOG_PREFIX} sending stdin is not supported by the Railway sandbox provider`);\n }\n\n async closeStdin(): Promise<void> {\n throw new UnsupportedStdinCloseError(\n `${LOG_PREFIX} closing stdin is not supported by the Railway sandbox provider`,\n );\n }\n}\n\n// =============================================================================\n// Railway Process Manager\n// =============================================================================\n\nexport interface RailwayProcessManagerOptions {\n env?: Record<string, string | undefined>;\n}\n\n/**\n * Railway implementation of SandboxProcessManager.\n * Uses the Railway SDK's `Sandbox.exec()` with one exec per spawned process.\n */\nexport class RailwayProcessManager extends SandboxProcessManager<RailwaySandbox> {\n private _spawnCounter = 0;\n\n constructor(opts: RailwayProcessManagerOptions = {}) {\n super({ env: opts.env });\n }\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n const railway = this.sandbox.railway;\n\n // Merge default env with per-spawn env.\n const mergedEnv = { ...this.env, ...options.env };\n const env = Object.fromEntries(\n Object.entries(mergedEnv).filter((entry): entry is [string, string] => entry[1] !== undefined),\n );\n\n const pid = `railway-proc-${Date.now().toString(36)}-${(this._spawnCounter++).toString(36)}`;\n\n // Deferred reference — callbacks fire asynchronously after the handle is\n // assigned, so `handle` is always defined by the time they run.\n let handle: RailwayProcessHandle;\n\n const execHandle = railway.exec(command, {\n ...(options.timeout !== undefined && { timeoutSec: Math.ceil(options.timeout / 1000) }),\n ...(options.cwd !== undefined && { cwd: options.cwd }),\n ...(Object.keys(env).length > 0 && { env }),\n onStdout: (chunk: string) => handle.emitStdout(chunk),\n onStderr: (chunk: string) => handle.emitStderr(chunk),\n });\n\n handle = new RailwayProcessHandle(pid, execHandle, Date.now(), options);\n this._tracked.set(handle.pid, handle);\n return handle;\n }\n\n /**\n * List tracked processes.\n *\n * Railway has no API to enumerate running exec sessions by sandbox, so this\n * reports the processes this manager spawned.\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","/**\n * Railway Sandbox Provider\n *\n * A Railway sandbox implementation for Mastra workspaces. Provisions an\n * ephemeral, isolated Linux VM on Railway, runs commands in it via the\n * Railway TypeScript SDK, and destroys it on teardown.\n *\n * @see https://docs.railway.com/sandboxes\n */\n\nimport type {\n CommandResult,\n ExecuteCommandOptions,\n InstructionsOption,\n MastraSandboxOptions,\n ProviderStatus,\n SandboxCloneOptions,\n SandboxInfo,\n} from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxNotReadyError } from '@mastra/core/workspace';\nimport { Sandbox, SandboxFailedError, SandboxNotFoundError, SandboxTimeoutError } from 'railway';\nimport type { SandboxNetworkIsolation, SandboxTemplate } from 'railway';\nimport { shellQuote } from '../utils/shell-quote';\nimport { LOG_PREFIX, RailwayProcessManager } from './process-manager';\n\n/**\n * Safety margin subtracted from the sandbox's idle timeout when scheduling the\n * pre-reap checkpoint refresh. Sized to comfortably exceed Cloud Run cold-start\n * / recycle windows so a scale event during the refresh doesn't cause the timer\n * to lose the race with Railway's idle destroy. If a caller reduces the idle\n * timeout below this margin, the refresh falls back to the 1-second floor and\n * fires almost immediately after start — surfacing the misconfiguration rather\n * than silently skipping the refresh.\n */\nconst CHECKPOINT_REFRESH_MARGIN_MS = 180_000;\n\n// =============================================================================\n// Public capture result\n// =============================================================================\n\n/**\n * Outcome of a {@link RailwaySandbox.captureCheckpoint} call.\n *\n * `captured` and `coalesced` both represent a successful capture the caller can\n * persist against — they carry the checkpoint name inline so callers don't have\n * to reach back into the sandbox instance to learn what they just wrote.\n * `skipped` carries a machine-readable reason so the set stays extensible\n * without another breaking change.\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// Railway Sandbox Options\n// =============================================================================\n\n/**\n * Railway sandbox provider configuration.\n */\nexport interface RailwaySandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Unique identifier for this sandbox instance. */\n id?: string;\n /** Railway API token. Falls back to the RAILWAY_API_TOKEN env var. */\n token?: string;\n /** Railway environment ID. Falls back to the RAILWAY_ENVIRONMENT_ID env var. */\n environmentId?: string;\n /**\n * Reattach to an existing Railway sandbox by its Railway ID instead of\n * creating a new one. When set, `start()` calls `Sandbox.connect()`.\n */\n sandboxId?: string;\n /**\n * Reuse a saved Railway sandbox checkpoint as the baseline filesystem for\n * new sandboxes. When the named checkpoint is missing, the sandbox is created\n * normally and a checkpoint is captured after setup succeeds.\n */\n checkpointName?: string;\n /**\n * Fallback checkpoint used to seed a new sandbox when `checkpointName` has\n * no stored state. Snapshots continue writing to `checkpointName`.\n */\n seedCheckpointName?: string;\n /**\n * How long the sandbox can sit idle (no `exec` interaction) before Railway\n * destroys it automatically. Range depends on plan (1–120 minutes on\n * Hobby/Pro, 1–5 on Trial/Free). Defaults to the plan default when omitted.\n */\n idleTimeoutMinutes?: number;\n /**\n * Network isolation mode.\n * - `ISOLATED` (default): outbound internet only, no private network access.\n * - `PRIVATE`: joins the environment's private network.\n */\n networkIsolation?: SandboxNetworkIsolation;\n /** Environment variables baked into the sandbox, available to every command. */\n env?: Record<string, string>;\n /**\n * Provision the sandbox from a custom base image built with the Railway\n * template builder. Use this to pre-install packages or run setup steps so\n * every sandbox created from it starts ready.\n *\n * - Builder callback — receives the base `Sandbox.template()` and returns the\n * configured template. Railway builds the template when `Sandbox.create()`\n * runs during `start()`.\n * ```ts\n * template: t => t.withPackages('git', 'curl').run('npm i -g pnpm')\n * ```\n * - Pre-built `SandboxTemplate` — pass a template to reuse it across\n * sandboxes. Railway still builds the image during sandbox creation.\n *\n * Ignored when `sandboxId` is set (reattach) or when forking.\n */\n template?: SandboxTemplate | ((base: SandboxTemplate) => SandboxTemplate);\n /**\n * Default execution timeout in milliseconds applied to commands that don't\n * specify their own timeout. When omitted, commands run until they exit.\n */\n timeout?: number;\n /**\n * Custom instructions that override the default instructions returned by\n * `getInstructions()`.\n *\n * - `string` — Fully replaces the default instructions. Pass an empty string\n * to suppress instructions entirely.\n * - `(opts) => string` — Receives the default instructions and optional\n * request context so you can extend or customise per-request.\n */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// Railway Sandbox Implementation\n// =============================================================================\n\n/**\n * Railway sandbox provider for Mastra workspaces.\n *\n * Features:\n * - Ephemeral, isolated Linux VM via the Railway TypeScript SDK\n * - Command execution with streaming output and timeouts\n * - Configurable idle timeout and network isolation\n * - Reattach to an existing sandbox by Railway ID\n *\n * @example Basic usage\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { RailwaySandbox } from '@mastra/railway';\n *\n * const sandbox = new RailwaySandbox({\n * // token + environmentId read from RAILWAY_API_TOKEN / RAILWAY_ENVIRONMENT_ID\n * idleTimeoutMinutes: 30,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCode('console.log(\"Hello!\")');\n * ```\n *\n * @example Private networking\n * ```typescript\n * const sandbox = new RailwaySandbox({\n * networkIsolation: 'PRIVATE',\n * env: { NODE_ENV: 'production' },\n * });\n * ```\n */\nexport class RailwaySandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'RailwaySandbox';\n readonly provider = 'railway';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: RailwayProcessManager;\n\n private _sandbox: Sandbox | null = null;\n private _createdAt: Date | null = null;\n private _checkpointRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n private _checkpointRefreshInFlight: Promise<void> | null = null;\n private _sandboxId?: string;\n private _restoredCheckpointName?: string;\n private _startInFlight: Promise<void> | null = null;\n\n private readonly _token?: string;\n private readonly _environmentId?: string;\n private readonly _checkpointName?: string;\n private readonly _seedCheckpointName?: string;\n private readonly _idleTimeoutMinutes?: number;\n private readonly _networkIsolation?: SandboxNetworkIsolation;\n private readonly _env: Record<string, string>;\n private readonly _timeout?: number;\n private readonly _instructionsOverride?: InstructionsOption;\n private readonly _templateOption?: RailwaySandboxOptions['template'];\n\n constructor(options: RailwaySandboxOptions = {}) {\n super({\n ...options,\n name: 'RailwaySandbox',\n processes: new RailwayProcessManager({ env: options.env }),\n });\n\n this.id = options.id ?? this.generateId();\n this._token = options.token ?? process.env.RAILWAY_API_TOKEN;\n this._environmentId = options.environmentId ?? process.env.RAILWAY_ENVIRONMENT_ID;\n this._sandboxId = options.sandboxId;\n this._checkpointName = options.checkpointName;\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._templateOption = options.template;\n }\n\n private generateId(): string {\n return `railway-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n /**\n * Get the underlying Railway Sandbox instance for direct SDK access.\n *\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get railway(): Sandbox {\n if (!this._sandbox) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._sandbox;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Start the Railway sandbox.\n *\n * Reattaches to an existing sandbox when `sandboxId` is configured,\n * otherwise provisions a new one. Resolves once the sandbox is RUNNING.\n */\n async start(): Promise<void> {\n if (this._sandbox) {\n return;\n }\n\n const clientConfig = this._clientConfig();\n const createOptions = this._createOptions(clientConfig);\n\n if (this._sandboxId) {\n const sandboxId = this._sandboxId;\n this._startInFlight ??= (async () => {\n this._restoredCheckpointName = undefined;\n try {\n this._sandbox = await this._reconnectSandbox(sandboxId, clientConfig);\n } catch (error) {\n if (!(error instanceof SandboxNotFoundError)) {\n throw error;\n }\n this._sandbox = await this._createNewSandbox(createOptions);\n }\n })().finally(() => {\n this._startInFlight = null;\n });\n } else {\n this._startInFlight ??= (async () => {\n this._sandbox = await this._createNewSandbox(createOptions);\n })().finally(() => {\n this._startInFlight = null;\n });\n }\n await this._startInFlight;\n\n if (!this._sandbox) {\n throw new Error('Failed to start Railway sandbox');\n }\n\n const sandbox = this._sandbox as Sandbox;\n this._sandboxId = sandbox.id;\n\n this._createdAt = sandbox.createdAt ? new Date(sandbox.createdAt) : new Date();\n this.logger.debug(`${LOG_PREFIX} Railway sandbox ${sandbox.id} ready for logical ID: ${this.id}`);\n this._scheduleCheckpointRefresh();\n }\n\n /**\n * Create a new Railway sandbox.\n */\n private async _createNewSandbox(createOptions: ReturnType<RailwaySandbox['_createOptions']>): Promise<Sandbox> {\n this.logger.debug(`${LOG_PREFIX} Creating Railway sandbox for: ${this.id}`);\n try {\n let checkpointToRestore: string | undefined;\n if (this._checkpointName || this._seedCheckpointName) {\n const checkpoints = await Sandbox.checkpoints(this._clientConfig());\n const checkpointNames = new Set(checkpoints.map(checkpoint => checkpoint.key));\n checkpointToRestore = checkpointNames.has(this._checkpointName ?? '')\n ? this._checkpointName\n : checkpointNames.has(this._seedCheckpointName ?? '')\n ? this._seedCheckpointName\n : undefined;\n }\n\n const sandbox = checkpointToRestore\n ? await Sandbox.create(checkpointToRestore, createOptions)\n : await Sandbox.create(createOptions);\n this._restoredCheckpointName = checkpointToRestore;\n return sandbox;\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Reconnect to an existing Railway sandbox, creating a fresh one when\n */\n private async _reconnectSandbox(\n reconnectSandboxId: string,\n clientConfig: { token?: string; environmentId?: string },\n ): Promise<Sandbox> {\n this.logger.debug(`${LOG_PREFIX} Reconnecting to Railway sandbox ${reconnectSandboxId}...`);\n\n let connectedSandbox: Sandbox = await Sandbox.connect(reconnectSandboxId, clientConfig);\n\n if (connectedSandbox.status !== 'RUNNING') {\n throw new SandboxNotFoundError({\n id: reconnectSandboxId,\n environmentId: clientConfig.environmentId ?? '',\n });\n }\n\n return connectedSandbox;\n }\n\n private _clientConfig(): { token?: string; environmentId?: string } {\n return {\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n };\n }\n\n private _createOptions(clientConfig: { token?: string; environmentId?: string }) {\n return {\n ...clientConfig,\n ...(this._idleTimeoutMinutes !== undefined && { idleTimeoutMinutes: this._idleTimeoutMinutes }),\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n ...(Object.keys(this._env).length > 0 && { env: this._env }),\n };\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 the idle-timer schedule.\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 Railway's idle destroy.\n *\n * Coalesces with any in-flight timer-driven refresh: concurrent callers join\n * the same underlying `Sandbox.checkpoint` call and receive\n * `{ status: 'coalesced', checkpointName }`. Both `captured` and `coalesced`\n * carry the checkpoint name inline so callers can persist a session→\n * checkpoint binding without a second, non-atomic read against the sandbox.\n * Returns `{ status: 'skipped', reason }` when there's nothing to capture\n * (no `checkpointName` configured, or the sandbox isn't running yet).\n *\n * On successful capture, restarts the idle-timer countdown so the next\n * timer-driven refresh is scheduled from this capture.\n *\n * Never captures without a `checkpointName` and never mutates status — safe\n * to invoke concurrently with `executeCommand`, `restart`, or `stop`.\n */\n async captureCheckpoint(): Promise<CaptureCheckpointResult> {\n const checkpointName = this._checkpointName;\n if (!checkpointName) {\n return { status: 'skipped', reason: 'no-checkpoint-name-configured' };\n }\n\n const sandbox = this._sandbox;\n if (!sandbox) {\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n\n if (this._checkpointRefreshInFlight) {\n await this._checkpointRefreshInFlight;\n return { status: 'coalesced', checkpointName };\n }\n\n const capture = this._checkpointSandbox(sandbox).finally(() => {\n if (this._checkpointRefreshInFlight === capture) {\n this._checkpointRefreshInFlight = null;\n }\n });\n this._checkpointRefreshInFlight = capture;\n\n await capture;\n this._scheduleCheckpointRefresh();\n\n return { status: 'captured', checkpointName };\n }\n\n private async _checkpointSandbox(sandbox: Sandbox): Promise<void> {\n if (!this._checkpointName) {\n return;\n }\n\n this.logger.debug(`${LOG_PREFIX} Capturing Railway sandbox checkpoint ${this._checkpointName} for: ${this.id}`);\n\n const checkpoints = await Sandbox.checkpoints(this._clientConfig());\n const checkpointAlreadyExists = checkpoints.some(checkpoint => checkpoint.key === this._checkpointName);\n\n // Remove first so we can re-create a checkpoint with the same name.\n if (checkpointAlreadyExists) {\n await Sandbox.deleteCheckpoint(this._checkpointName, this._clientConfig());\n }\n\n await sandbox.checkpoint(this._checkpointName);\n }\n\n private _scheduleCheckpointRefresh(): void {\n if (!this._checkpointName || !this._sandbox) {\n return;\n }\n\n const idleTimeoutMinutes = this._idleTimeoutMinutes ?? this._sandbox.idleTimeoutMinutes;\n if (!idleTimeoutMinutes) {\n return;\n }\n\n this._cancelCheckpointRefresh();\n\n const delayMs = Math.max(1_000, idleTimeoutMinutes * 60_000 - CHECKPOINT_REFRESH_MARGIN_MS);\n this._checkpointRefreshTimer = setTimeout(() => {\n this._checkpointRefreshTimer = null;\n const sandbox = this._sandbox;\n if (!sandbox || this._checkpointRefreshInFlight) {\n return;\n }\n\n const refresh = this._checkpointSandbox(sandbox).finally(() => {\n if (this._checkpointRefreshInFlight === refresh) {\n this._checkpointRefreshInFlight = null;\n }\n });\n this._checkpointRefreshInFlight = refresh;\n refresh.catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to refresh Railway sandbox checkpoint ${this._checkpointName}:`, error);\n });\n }, delayMs);\n this._checkpointRefreshTimer.unref?.();\n }\n\n private _cancelCheckpointRefresh(): void {\n if (this._checkpointRefreshTimer) {\n clearTimeout(this._checkpointRefreshTimer);\n this._checkpointRefreshTimer = null;\n }\n }\n\n /**\n * Stop the Railway sandbox.\n *\n * Railway sandboxes have no separate \"stopped\" state — they're either\n * running or destroyed — so stopping destroys the sandbox but we keep a checkpoint of the filesystem.\n */\n async stop(): Promise<void> {\n if (this._checkpointName) {\n await this._flushCheckpointRefresh().catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to checkpoint Railway sandbox ${this._sandbox?.id}:`, error);\n });\n }\n\n await this._teardown();\n }\n\n /**\n * Destroy the Railway sandbox and release its resources including the checkpoint.\n */\n async destroy(): Promise<void> {\n this._cancelCheckpointRefresh();\n if (this._checkpointName) {\n await this._checkpointRefreshInFlight;\n await Sandbox.deleteCheckpoint(this._checkpointName, this._clientConfig()).catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to delete Railway checkpoint ${this._checkpointName}:`, error);\n });\n }\n\n await this._teardown();\n }\n\n private async _flushCheckpointRefresh(): Promise<void> {\n this._cancelCheckpointRefresh();\n\n if (this._checkpointRefreshInFlight) {\n await this._checkpointRefreshInFlight;\n return;\n }\n\n if (this._sandbox) {\n await this._checkpointSandbox(this._sandbox);\n }\n }\n\n private async _teardown(): Promise<void> {\n this._cancelCheckpointRefresh();\n if (!this._sandbox) {\n return;\n }\n await this._checkpointRefreshInFlight;\n\n const sandbox = this._sandbox;\n this._sandbox = null;\n try {\n await sandbox.destroy();\n } catch (error) {\n this.logger.warn(`${LOG_PREFIX} Failed to destroy Railway sandbox ${sandbox.id}:`, error);\n }\n }\n\n /**\n * Fork this running sandbox into a new, independent `RailwaySandbox`.\n *\n * Clones the filesystem (a fresh boot, not live processes) into the same\n * environment. The returned sandbox is already started and reattached to the\n * forked Railway sandbox; it inherits this sandbox's credentials and defaults\n * unless overridden via `options`.\n *\n * @throws {SandboxNotReadyError} If this sandbox has not been started.\n */\n async fork(\n options: Pick<RailwaySandboxOptions, 'id' | 'idleTimeoutMinutes' | 'networkIsolation' | 'env'> = {},\n ): Promise<RailwaySandbox> {\n const source = this.railway;\n const forked = await source.fork({\n ...(options.idleTimeoutMinutes !== undefined && { idleTimeoutMinutes: options.idleTimeoutMinutes }),\n ...(options.networkIsolation !== undefined && { networkIsolation: options.networkIsolation }),\n ...(options.env !== undefined && { env: options.env }),\n });\n\n const child = new RailwaySandbox({\n ...(options.id !== undefined && { id: options.id }),\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n networkIsolation: options.networkIsolation ?? this._networkIsolation,\n env: options.env ?? this._env,\n timeout: this._timeout,\n });\n await child._start();\n return child;\n }\n\n /**\n * Construct a sibling `RailwaySandbox` that inherits this sandbox's\n * credentials and defaults (token, environment, checkpoint, network\n * isolation, timeout, template, instructions) with per-instance overrides.\n *\n * Unlike {@link fork}, `clone` performs no I/O and does not require this\n * sandbox to be started — the returned sandbox is not started and provisions\n * (or reattaches, when `sandboxId` is set) on its own `start()`. Use it when\n * one configured sandbox acts as the template for a fleet of independent\n * sandboxes (e.g. one per project).\n */\n clone(options: SandboxCloneOptions = {}): RailwaySandbox {\n return new RailwaySandbox({\n ...(options.id !== undefined && { id: options.id }),\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n ...((options.checkpointName ?? this._checkpointName) !== undefined && {\n checkpointName: options.checkpointName ?? this._checkpointName,\n }),\n ...(options.seedCheckpointName !== undefined && { seedCheckpointName: options.seedCheckpointName }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n env: options.env ?? this._env,\n ...(this._templateOption !== undefined && { template: this._templateOption }),\n ...(this._timeout !== undefined && { timeout: this._timeout }),\n ...(this._instructionsOverride !== undefined && { instructions: this._instructionsOverride }),\n });\n }\n\n /**\n * Whether a Railway API token was resolved at construction (explicit option\n * or the `RAILWAY_API_TOKEN` env fallback). Lets callers gate features on a\n * usable configuration without provisioning a sandbox.\n */\n get hasCredentials(): boolean {\n return this._token !== undefined && this._token !== '';\n }\n\n /** The configured idle teardown window in minutes, if any. */\n get idleTimeoutMinutes(): number | undefined {\n return this._idleTimeoutMinutes;\n }\n\n // ---------------------------------------------------------------------------\n // Info & Instructions\n // ---------------------------------------------------------------------------\n\n async getInfo(): Promise<SandboxInfo> {\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 metadata: {\n ...(this._sandbox && {\n railwaySandboxId: this._sandbox.id,\n environmentId: this._sandbox.environmentId,\n region: this._sandbox.region,\n networkIsolation: this._sandbox.networkIsolation,\n ...(this._sandbox.idleTimeoutMinutes != null && {\n idleTimeoutMinutes: this._sandbox.idleTimeoutMinutes,\n }),\n ...(this._restoredCheckpointName && { restoredCheckpointName: this._restoredCheckpointName }),\n }),\n },\n };\n }\n\n getInstructions(): string {\n const defaultInstructions = this._buildDefaultInstructions();\n\n if (typeof this._instructionsOverride === 'string') {\n return this._instructionsOverride;\n }\n if (typeof this._instructionsOverride === 'function') {\n return this._instructionsOverride({ defaultInstructions });\n }\n return defaultInstructions;\n }\n\n private _buildDefaultInstructions(): string {\n const parts: string[] = [];\n parts.push('Railway cloud sandbox: an isolated Debian Linux VM with outbound internet access.');\n\n if (this._networkIsolation === 'PRIVATE') {\n parts.push('Joined to the environment private network.');\n }\n\n if (this._timeout !== undefined) {\n parts.push(`Default command timeout: ${Math.ceil(this._timeout / 1000)}s.`);\n } else {\n parts.push('Commands run until they exit unless a timeout is set.');\n }\n\n if (this._idleTimeoutMinutes !== undefined) {\n parts.push(`Idle timeout: ${this._idleTimeoutMinutes} minute(s).`);\n }\n\n return parts.join(' ');\n }\n\n // ---------------------------------------------------------------------------\n // Command Execution\n // ---------------------------------------------------------------------------\n\n /**\n * Execute a command in the sandbox and return the result.\n */\n async executeCommand(\n command: string,\n args: string[] = [],\n options: ExecuteCommandOptions = {},\n ): Promise<CommandResult> {\n const status = this._sandbox?.status;\n\n if (status !== 'RUNNING') {\n if (!this._checkpointName) {\n throw new SandboxNotReadyError(this.id);\n }\n\n this._sandbox = null;\n await this.start();\n }\n\n const fullCommand = args.length > 0 ? `${command} ${args.map(shellQuote).join(' ')}` : command;\n const timeout = options.timeout ?? this._timeout;\n const env = options.env\n ? Object.fromEntries(\n Object.entries(options.env).filter((entry): entry is [string, string] => entry[1] !== undefined),\n )\n : undefined;\n const startedAt = Date.now();\n const result = await this.railway.exec(fullCommand, {\n ...(timeout !== undefined && { timeoutSec: Math.ceil(timeout / 1000) }),\n ...(options.cwd !== undefined && { cwd: options.cwd }),\n ...(env !== undefined && { env }),\n });\n const exitCode = result.exitCode ?? -1;\n return {\n success: exitCode === 0,\n exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n executionTimeMs: Date.now() - startedAt,\n command,\n args,\n timedOut: result.timedOut,\n };\n }\n}\n","/**\n * Railway sandbox provider descriptor for MastraEditor.\n *\n * @example\n * ```typescript\n * import { railwaySandboxProvider } from '@mastra/railway';\n *\n * const editor = new MastraEditor({\n * sandboxes: { [railwaySandboxProvider.id]: railwaySandboxProvider },\n * });\n * ```\n */\nimport type { SandboxProvider } from '@mastra/core/editor';\nimport { RailwaySandbox } from './sandbox';\n\n/**\n * Serializable subset of RailwaySandboxOptions for editor storage.\n */\ninterface RailwayProviderConfig {\n token?: string;\n environmentId?: string;\n sandboxId?: string;\n idleTimeoutMinutes?: number;\n networkIsolation?: 'ISOLATED' | 'PRIVATE';\n env?: Record<string, string>;\n timeout?: number;\n}\n\nexport const railwaySandboxProvider: SandboxProvider<RailwayProviderConfig> = {\n id: 'railway',\n name: 'Railway Sandbox',\n description: 'Ephemeral, isolated Linux VM powered by Railway',\n configSchema: {\n type: 'object',\n properties: {\n token: { type: 'string', description: 'Railway API token (falls back to RAILWAY_API_TOKEN)' },\n environmentId: {\n type: 'string',\n description: 'Railway environment ID (falls back to RAILWAY_ENVIRONMENT_ID)',\n },\n sandboxId: { type: 'string', description: 'Reattach to an existing Railway sandbox by ID' },\n idleTimeoutMinutes: {\n type: 'number',\n description: 'Minutes a sandbox can sit idle before Railway destroys it',\n },\n networkIsolation: {\n type: 'string',\n description: 'Network isolation mode',\n enum: ['ISOLATED', 'PRIVATE'],\n default: 'ISOLATED',\n },\n env: {\n type: 'object',\n description: 'Environment variables',\n additionalProperties: { type: 'string' },\n },\n timeout: { type: 'number', description: 'Default command timeout in ms' },\n },\n },\n createSandbox: config => new RailwaySandbox(config),\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/utils/shell-quote.ts","../src/sandbox/process-manager.ts","../src/sandbox/index.ts","../src/provider.ts"],"sourcesContent":["/**\n * Shell-quote a single argument for safe use in a command string.\n *\n * Arguments containing only safe characters are returned as-is.\n * All others are wrapped in single quotes with embedded single quotes escaped.\n */\nexport function shellQuote(arg: string): string {\n // Safe characters that don't need quoting\n if (/^[a-zA-Z0-9._\\-/@:=]+$/.test(arg)) return arg;\n // Wrap in single quotes, escaping any embedded single quotes\n return \"'\" + arg.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n","/**\n * Railway Process Manager\n *\n * Implements SandboxProcessManager for Railway sandboxes.\n * Wraps the Railway SDK's `Sandbox.exec()` API.\n *\n * Railway's `exec(command, options)` accepts per-call `cwd` and `env` options\n * (since SDK v3.3.1) and returns an `ExecHandle` that runs the command\n * server-side, independently of the client. Each spawn() starts one exec.\n * The handle streams output via `onStdout`/`onStderr` callbacks wired to\n * `emitStdout`/`emitStderr`, exposes a durable `sessionName`, and can be\n * terminated with `kill(signal)`.\n */\n\nimport { ProcessHandle, UnsupportedStdinCloseError, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { ExecHandle, ExecResult } from 'railway';\nimport type { RailwaySandbox } from './index';\n\nexport const LOG_PREFIX = '[RailwaySandbox]';\n\n// =============================================================================\n// Railway Process Handle\n// =============================================================================\n\n/**\n * Wraps a Railway ExecHandle to conform to Mastra's ProcessHandle.\n * Not exported — internal to this module.\n */\nclass RailwayProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _execHandle: ExecHandle;\n private readonly _startTime: number;\n private _exitCode: number | undefined;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _killed = false;\n\n constructor(pid: string, execHandle: ExecHandle, startTime: number, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this._execHandle = execHandle;\n this._startTime = startTime;\n\n // Resolve exit code once the command completes so exitCode is available\n // without an explicit wait().\n void this._execHandle.then(\n (result: ExecResult) => {\n // -1 means terminated by a signal (e.g. after kill()).\n this._exitCode = result.exitCode ?? (this._killed ? 137 : -1);\n },\n () => {\n if (this._exitCode === undefined) {\n this._exitCode = 1;\n }\n },\n );\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n async wait(): Promise<CommandResult> {\n // Idempotent — cache the promise so repeated calls return the same result.\n if (!this._waitPromise) {\n this._waitPromise = this._doWait();\n }\n return this._waitPromise;\n }\n\n private async _doWait(): Promise<CommandResult> {\n try {\n const result = await this._execHandle;\n const exitCode = result.exitCode ?? (this._killed ? 137 : -1);\n this._exitCode = exitCode;\n\n // Railway captures output server-side; surface it through the base buffers\n // if streaming callbacks didn't already populate them.\n if (result.stdout && !this.stdout) this.emitStdout(result.stdout);\n if (result.stderr && !this.stderr) this.emitStderr(result.stderr);\n\n return {\n success: exitCode === 0,\n exitCode,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n killed: this._killed,\n timedOut: result.timedOut,\n };\n } catch (error) {\n const exitCode = this._exitCode ?? 1;\n this._exitCode = exitCode;\n return {\n success: false,\n exitCode,\n stdout: this.stdout,\n stderr: this.stderr || (error instanceof Error ? error.message : String(error)),\n executionTimeMs: Date.now() - this._startTime,\n killed: this._killed,\n };\n }\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n this._killed = true;\n try {\n return await this._execHandle.kill('TERM');\n } catch {\n // Command may already be gone.\n return false;\n }\n }\n\n async sendStdin(_data: string): Promise<void> {\n // Railway's exec API does not expose stdin streaming.\n throw new Error(`${LOG_PREFIX} sending stdin is not supported by the Railway sandbox provider`);\n }\n\n async closeStdin(): Promise<void> {\n throw new UnsupportedStdinCloseError(\n `${LOG_PREFIX} closing stdin is not supported by the Railway sandbox provider`,\n );\n }\n}\n\n// =============================================================================\n// Railway Process Manager\n// =============================================================================\n\n/**\n * Railway implementation of SandboxProcessManager.\n * Uses the Railway SDK's `Sandbox.exec()` with one exec per spawned process.\n */\nexport class RailwayProcessManager extends SandboxProcessManager<RailwaySandbox> {\n private _spawnCounter = 0;\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n const railway = this.sandbox.railway;\n\n // The base spawn wrapper already merged the sandbox env into options.env\n const mergedEnv = { ...options.env };\n const env = Object.fromEntries(\n Object.entries(mergedEnv).filter((entry): entry is [string, string] => entry[1] !== undefined),\n );\n\n const pid = `railway-proc-${Date.now().toString(36)}-${(this._spawnCounter++).toString(36)}`;\n\n // Deferred reference — callbacks fire asynchronously after the handle is\n // assigned, so `handle` is always defined by the time they run.\n let handle: RailwayProcessHandle;\n\n const execHandle = railway.exec(command, {\n ...(options.timeout !== undefined && { timeoutSec: Math.ceil(options.timeout / 1000) }),\n ...(options.cwd !== undefined && { cwd: options.cwd }),\n ...(Object.keys(env).length > 0 && { env }),\n onStdout: (chunk: string) => handle.emitStdout(chunk),\n onStderr: (chunk: string) => handle.emitStderr(chunk),\n });\n\n handle = new RailwayProcessHandle(pid, execHandle, Date.now(), options);\n this._tracked.set(handle.pid, handle);\n return handle;\n }\n\n /**\n * List tracked processes.\n *\n * Railway has no API to enumerate running exec sessions by sandbox, so this\n * reports the processes this manager spawned.\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","/**\n * Railway Sandbox Provider\n *\n * A Railway sandbox implementation for Mastra workspaces. Provisions an\n * ephemeral, isolated Linux VM on Railway, runs commands in it via the\n * Railway TypeScript SDK, and destroys it on teardown.\n *\n * @see https://docs.railway.com/sandboxes\n */\n\nimport type {\n CommandResult,\n ExecuteCommandOptions,\n InstructionsOption,\n MastraSandboxOptions,\n ProviderStatus,\n SandboxCloneOptions,\n SandboxInfo,\n} from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxNotReadyError } from '@mastra/core/workspace';\nimport { Sandbox, SandboxFailedError, SandboxNotFoundError, SandboxTimeoutError } from 'railway';\nimport type { SandboxNetworkIsolation, SandboxTemplate } from 'railway';\nimport { shellQuote } from '../utils/shell-quote';\nimport { LOG_PREFIX, RailwayProcessManager } from './process-manager';\n\n/**\n * Safety margin subtracted from the sandbox's idle timeout when scheduling the\n * pre-reap checkpoint refresh. Sized to comfortably exceed Cloud Run cold-start\n * / recycle windows so a scale event during the refresh doesn't cause the timer\n * to lose the race with Railway's idle destroy. If a caller reduces the idle\n * timeout below this margin, the refresh falls back to the 1-second floor and\n * fires almost immediately after start — surfacing the misconfiguration rather\n * than silently skipping the refresh.\n */\nconst CHECKPOINT_REFRESH_MARGIN_MS = 180_000;\n\n// =============================================================================\n// Public capture result\n// =============================================================================\n\n/**\n * Outcome of a {@link RailwaySandbox.captureCheckpoint} call.\n *\n * `captured` and `coalesced` both represent a successful capture the caller can\n * persist against — they carry the checkpoint name inline so callers don't have\n * to reach back into the sandbox instance to learn what they just wrote.\n * `skipped` carries a machine-readable reason so the set stays extensible\n * without another breaking change.\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// Railway Sandbox Options\n// =============================================================================\n\n/**\n * Railway sandbox provider configuration.\n */\nexport interface RailwaySandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Unique identifier for this sandbox instance. */\n id?: string;\n /** Railway API token. Falls back to the RAILWAY_API_TOKEN env var. */\n token?: string;\n /** Railway environment ID. Falls back to the RAILWAY_ENVIRONMENT_ID env var. */\n environmentId?: string;\n /**\n * Reattach to an existing Railway sandbox by its Railway ID instead of\n * creating a new one. When set, `start()` calls `Sandbox.connect()`.\n */\n sandboxId?: string;\n /**\n * Reuse a saved Railway sandbox checkpoint as the baseline filesystem for\n * new sandboxes. When the named checkpoint is missing, the sandbox is created\n * normally and a checkpoint is captured after setup succeeds.\n */\n checkpointName?: string;\n /**\n * Fallback checkpoint used to seed a new sandbox when `checkpointName` has\n * no stored state. Snapshots continue writing to `checkpointName`.\n */\n seedCheckpointName?: string;\n /**\n * How long the sandbox can sit idle (no `exec` interaction) before Railway\n * destroys it automatically. Range depends on plan (1–120 minutes on\n * Hobby/Pro, 1–5 on Trial/Free). Defaults to the plan default when omitted.\n */\n idleTimeoutMinutes?: number;\n /**\n * Network isolation mode.\n * - `ISOLATED` (default): outbound internet only, no private network access.\n * - `PRIVATE`: joins the environment's private network.\n */\n networkIsolation?: SandboxNetworkIsolation;\n /** Environment variables baked into the sandbox, available to every command. */\n env?: Record<string, string>;\n /**\n * Provision the sandbox from a custom base image built with the Railway\n * template builder. Use this to pre-install packages or run setup steps so\n * every sandbox created from it starts ready.\n *\n * - Builder callback — receives the base `Sandbox.template()` and returns the\n * configured template. Railway builds the template when `Sandbox.create()`\n * runs during `start()`.\n * ```ts\n * template: t => t.withPackages('git', 'curl').run('npm i -g pnpm')\n * ```\n * - Pre-built `SandboxTemplate` — pass a template to reuse it across\n * sandboxes. Railway still builds the image during sandbox creation.\n *\n * Ignored when `sandboxId` is set (reattach) or when forking.\n */\n template?: SandboxTemplate | ((base: SandboxTemplate) => SandboxTemplate);\n /**\n * Default execution timeout in milliseconds applied to commands that don't\n * specify their own timeout. When omitted, commands run until they exit.\n */\n timeout?: number;\n /**\n * Custom instructions that override the default instructions returned by\n * `getInstructions()`.\n *\n * - `string` — Fully replaces the default instructions. Pass an empty string\n * to suppress instructions entirely.\n * - `(opts) => string` — Receives the default instructions and optional\n * request context so you can extend or customise per-request.\n */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// Railway Sandbox Implementation\n// =============================================================================\n\n/**\n * Railway sandbox provider for Mastra workspaces.\n *\n * Features:\n * - Ephemeral, isolated Linux VM via the Railway TypeScript SDK\n * - Command execution with streaming output and timeouts\n * - Configurable idle timeout and network isolation\n * - Reattach to an existing sandbox by Railway ID\n *\n * @example Basic usage\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { RailwaySandbox } from '@mastra/railway';\n *\n * const sandbox = new RailwaySandbox({\n * // token + environmentId read from RAILWAY_API_TOKEN / RAILWAY_ENVIRONMENT_ID\n * idleTimeoutMinutes: 30,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCode('console.log(\"Hello!\")');\n * ```\n *\n * @example Private networking\n * ```typescript\n * const sandbox = new RailwaySandbox({\n * networkIsolation: 'PRIVATE',\n * env: { NODE_ENV: 'production' },\n * });\n * ```\n */\nexport class RailwaySandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'RailwaySandbox';\n readonly provider = 'railway';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: RailwayProcessManager;\n\n private _sandbox: Sandbox | null = null;\n private _createdAt: Date | null = null;\n private _checkpointRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n private _checkpointRefreshInFlight: Promise<void> | null = null;\n private _sandboxId?: string;\n private _restoredCheckpointName?: string;\n private _startInFlight: Promise<void> | null = null;\n\n private readonly _token?: string;\n private readonly _environmentId?: string;\n private readonly _checkpointName?: string;\n private readonly _seedCheckpointName?: string;\n private readonly _idleTimeoutMinutes?: number;\n private readonly _networkIsolation?: SandboxNetworkIsolation;\n private readonly _env: Record<string, string>;\n private readonly _timeout?: number;\n private readonly _instructionsOverride?: InstructionsOption;\n private readonly _templateOption?: RailwaySandboxOptions['template'];\n\n constructor(options: RailwaySandboxOptions = {}) {\n super({\n ...options,\n name: 'RailwaySandbox',\n processes: new RailwayProcessManager(),\n });\n\n this.id = options.id ?? this.generateId();\n this._token = options.token ?? process.env.RAILWAY_API_TOKEN;\n this._environmentId = options.environmentId ?? process.env.RAILWAY_ENVIRONMENT_ID;\n this._sandboxId = options.sandboxId;\n this._checkpointName = options.checkpointName;\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._templateOption = options.template;\n }\n\n private generateId(): string {\n return `railway-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n /**\n * Get the underlying Railway Sandbox instance for direct SDK access.\n *\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get railway(): Sandbox {\n if (!this._sandbox) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._sandbox;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Start the Railway sandbox.\n *\n * Reattaches to an existing sandbox when `sandboxId` is configured,\n * otherwise provisions a new one. Resolves once the sandbox is RUNNING.\n */\n async start(): Promise<void> {\n if (this._sandbox) {\n return;\n }\n\n const clientConfig = this._clientConfig();\n const createOptions = this._createOptions(clientConfig);\n\n if (this._sandboxId) {\n const sandboxId = this._sandboxId;\n this._startInFlight ??= (async () => {\n this._restoredCheckpointName = undefined;\n try {\n this._sandbox = await this._reconnectSandbox(sandboxId, clientConfig);\n } catch (error) {\n if (!(error instanceof SandboxNotFoundError)) {\n throw error;\n }\n this._sandbox = await this._createNewSandbox(createOptions);\n }\n })().finally(() => {\n this._startInFlight = null;\n });\n } else {\n this._startInFlight ??= (async () => {\n this._sandbox = await this._createNewSandbox(createOptions);\n })().finally(() => {\n this._startInFlight = null;\n });\n }\n await this._startInFlight;\n\n if (!this._sandbox) {\n throw new Error('Failed to start Railway sandbox');\n }\n\n const sandbox = this._sandbox as Sandbox;\n this._sandboxId = sandbox.id;\n\n this._createdAt = sandbox.createdAt ? new Date(sandbox.createdAt) : new Date();\n this.logger.debug(`${LOG_PREFIX} Railway sandbox ${sandbox.id} ready for logical ID: ${this.id}`);\n this._scheduleCheckpointRefresh();\n }\n\n /**\n * Create a new Railway sandbox.\n */\n private async _createNewSandbox(createOptions: ReturnType<RailwaySandbox['_createOptions']>): Promise<Sandbox> {\n this.logger.debug(`${LOG_PREFIX} Creating Railway sandbox for: ${this.id}`);\n try {\n let checkpointToRestore: string | undefined;\n if (this._checkpointName || this._seedCheckpointName) {\n const checkpoints = await Sandbox.checkpoints(this._clientConfig());\n const checkpointNames = new Set(checkpoints.map(checkpoint => checkpoint.key));\n checkpointToRestore = checkpointNames.has(this._checkpointName ?? '')\n ? this._checkpointName\n : checkpointNames.has(this._seedCheckpointName ?? '')\n ? this._seedCheckpointName\n : undefined;\n }\n\n const sandbox = checkpointToRestore\n ? await Sandbox.create(checkpointToRestore, createOptions)\n : await Sandbox.create(createOptions);\n this._restoredCheckpointName = checkpointToRestore;\n return sandbox;\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Reconnect to an existing Railway sandbox, creating a fresh one when\n */\n private async _reconnectSandbox(\n reconnectSandboxId: string,\n clientConfig: { token?: string; environmentId?: string },\n ): Promise<Sandbox> {\n this.logger.debug(`${LOG_PREFIX} Reconnecting to Railway sandbox ${reconnectSandboxId}...`);\n\n let connectedSandbox: Sandbox = await Sandbox.connect(reconnectSandboxId, clientConfig);\n\n if (connectedSandbox.status !== 'RUNNING') {\n throw new SandboxNotFoundError({\n id: reconnectSandboxId,\n environmentId: clientConfig.environmentId ?? '',\n });\n }\n\n return connectedSandbox;\n }\n\n private _clientConfig(): { token?: string; environmentId?: string } {\n return {\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n };\n }\n\n private _createOptions(clientConfig: { token?: string; environmentId?: string }) {\n return {\n ...clientConfig,\n ...(this._idleTimeoutMinutes !== undefined && { idleTimeoutMinutes: this._idleTimeoutMinutes }),\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n ...(Object.keys(this._env).length > 0 && { env: this._env }),\n };\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 the idle-timer schedule.\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 Railway's idle destroy.\n *\n * Coalesces with any in-flight timer-driven refresh: concurrent callers join\n * the same underlying `Sandbox.checkpoint` call and receive\n * `{ status: 'coalesced', checkpointName }`. Both `captured` and `coalesced`\n * carry the checkpoint name inline so callers can persist a session→\n * checkpoint binding without a second, non-atomic read against the sandbox.\n * Returns `{ status: 'skipped', reason }` when there's nothing to capture\n * (no `checkpointName` configured, or the sandbox isn't running yet).\n *\n * On successful capture, restarts the idle-timer countdown so the next\n * timer-driven refresh is scheduled from this capture.\n *\n * Never captures without a `checkpointName` and never mutates status — safe\n * to invoke concurrently with `executeCommand`, `restart`, or `stop`.\n */\n async captureCheckpoint(): Promise<CaptureCheckpointResult> {\n const checkpointName = this._checkpointName;\n if (!checkpointName) {\n return { status: 'skipped', reason: 'no-checkpoint-name-configured' };\n }\n\n const sandbox = this._sandbox;\n if (!sandbox) {\n return { status: 'skipped', reason: 'sandbox-not-running' };\n }\n\n if (this._checkpointRefreshInFlight) {\n await this._checkpointRefreshInFlight;\n return { status: 'coalesced', checkpointName };\n }\n\n const capture = this._checkpointSandbox(sandbox).finally(() => {\n if (this._checkpointRefreshInFlight === capture) {\n this._checkpointRefreshInFlight = null;\n }\n });\n this._checkpointRefreshInFlight = capture;\n\n await capture;\n this._scheduleCheckpointRefresh();\n\n return { status: 'captured', checkpointName };\n }\n\n private async _checkpointSandbox(sandbox: Sandbox): Promise<void> {\n if (!this._checkpointName) {\n return;\n }\n\n this.logger.debug(`${LOG_PREFIX} Capturing Railway sandbox checkpoint ${this._checkpointName} for: ${this.id}`);\n\n const checkpoints = await Sandbox.checkpoints(this._clientConfig());\n const checkpointAlreadyExists = checkpoints.some(checkpoint => checkpoint.key === this._checkpointName);\n\n // Remove first so we can re-create a checkpoint with the same name.\n if (checkpointAlreadyExists) {\n await Sandbox.deleteCheckpoint(this._checkpointName, this._clientConfig());\n }\n\n await sandbox.checkpoint(this._checkpointName);\n }\n\n private _scheduleCheckpointRefresh(): void {\n if (!this._checkpointName || !this._sandbox) {\n return;\n }\n\n const idleTimeoutMinutes = this._idleTimeoutMinutes ?? this._sandbox.idleTimeoutMinutes;\n if (!idleTimeoutMinutes) {\n return;\n }\n\n this._cancelCheckpointRefresh();\n\n const delayMs = Math.max(1_000, idleTimeoutMinutes * 60_000 - CHECKPOINT_REFRESH_MARGIN_MS);\n this._checkpointRefreshTimer = setTimeout(() => {\n this._checkpointRefreshTimer = null;\n const sandbox = this._sandbox;\n if (!sandbox || this._checkpointRefreshInFlight) {\n return;\n }\n\n const refresh = this._checkpointSandbox(sandbox).finally(() => {\n if (this._checkpointRefreshInFlight === refresh) {\n this._checkpointRefreshInFlight = null;\n }\n });\n this._checkpointRefreshInFlight = refresh;\n refresh.catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to refresh Railway sandbox checkpoint ${this._checkpointName}:`, error);\n });\n }, delayMs);\n this._checkpointRefreshTimer.unref?.();\n }\n\n private _cancelCheckpointRefresh(): void {\n if (this._checkpointRefreshTimer) {\n clearTimeout(this._checkpointRefreshTimer);\n this._checkpointRefreshTimer = null;\n }\n }\n\n /**\n * Stop the Railway sandbox.\n *\n * Railway sandboxes have no separate \"stopped\" state — they're either\n * running or destroyed — so stopping destroys the sandbox but we keep a checkpoint of the filesystem.\n */\n async stop(): Promise<void> {\n if (this._checkpointName) {\n await this._flushCheckpointRefresh().catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to checkpoint Railway sandbox ${this._sandbox?.id}:`, error);\n });\n }\n\n await this._teardown();\n }\n\n /**\n * Destroy the Railway sandbox and release its resources including the checkpoint.\n */\n async destroy(): Promise<void> {\n this._cancelCheckpointRefresh();\n if (this._checkpointName) {\n await this._checkpointRefreshInFlight;\n await Sandbox.deleteCheckpoint(this._checkpointName, this._clientConfig()).catch(error => {\n this.logger.warn(`${LOG_PREFIX} Failed to delete Railway checkpoint ${this._checkpointName}:`, error);\n });\n }\n\n await this._teardown();\n }\n\n private async _flushCheckpointRefresh(): Promise<void> {\n this._cancelCheckpointRefresh();\n\n if (this._checkpointRefreshInFlight) {\n await this._checkpointRefreshInFlight;\n return;\n }\n\n if (this._sandbox) {\n await this._checkpointSandbox(this._sandbox);\n }\n }\n\n private async _teardown(): Promise<void> {\n this._cancelCheckpointRefresh();\n if (!this._sandbox) {\n return;\n }\n await this._checkpointRefreshInFlight;\n\n const sandbox = this._sandbox;\n this._sandbox = null;\n try {\n await sandbox.destroy();\n } catch (error) {\n this.logger.warn(`${LOG_PREFIX} Failed to destroy Railway sandbox ${sandbox.id}:`, error);\n }\n }\n\n /**\n * Fork this running sandbox into a new, independent `RailwaySandbox`.\n *\n * Clones the filesystem (a fresh boot, not live processes) into the same\n * environment. The returned sandbox is already started and reattached to the\n * forked Railway sandbox; it inherits this sandbox's credentials and defaults\n * unless overridden via `options`.\n *\n * @throws {SandboxNotReadyError} If this sandbox has not been started.\n */\n async fork(\n options: Pick<RailwaySandboxOptions, 'id' | 'idleTimeoutMinutes' | 'networkIsolation' | 'env'> = {},\n ): Promise<RailwaySandbox> {\n const source = this.railway;\n const forked = await source.fork({\n ...(options.idleTimeoutMinutes !== undefined && { idleTimeoutMinutes: options.idleTimeoutMinutes }),\n ...(options.networkIsolation !== undefined && { networkIsolation: options.networkIsolation }),\n ...(options.env !== undefined && { env: options.env }),\n });\n\n const child = new RailwaySandbox({\n ...(options.id !== undefined && { id: options.id }),\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n networkIsolation: options.networkIsolation ?? this._networkIsolation,\n env: options.env ?? this._env,\n timeout: this._timeout,\n });\n await child._start();\n return child;\n }\n\n /**\n * Construct a sibling `RailwaySandbox` that inherits this sandbox's\n * credentials and defaults (token, environment, checkpoint, network\n * isolation, timeout, template, instructions) with per-instance overrides.\n *\n * Unlike {@link fork}, `clone` performs no I/O and does not require this\n * sandbox to be started — the returned sandbox is not started and provisions\n * (or reattaches, when `sandboxId` is set) on its own `start()`. Use it when\n * one configured sandbox acts as the template for a fleet of independent\n * sandboxes (e.g. one per project).\n */\n clone(options: SandboxCloneOptions = {}): RailwaySandbox {\n return new RailwaySandbox({\n ...(options.id !== undefined && { id: options.id }),\n ...(this._token !== undefined && { token: this._token }),\n ...(this._environmentId !== undefined && { environmentId: this._environmentId }),\n ...((options.checkpointName ?? this._checkpointName) !== undefined && {\n checkpointName: options.checkpointName ?? this._checkpointName,\n }),\n ...(options.seedCheckpointName !== undefined && { seedCheckpointName: options.seedCheckpointName }),\n idleTimeoutMinutes: options.idleTimeoutMinutes ?? this._idleTimeoutMinutes,\n ...(this._networkIsolation !== undefined && { networkIsolation: this._networkIsolation }),\n env: options.env ?? this._env,\n ...(this._templateOption !== undefined && { template: this._templateOption }),\n ...(this._timeout !== undefined && { timeout: this._timeout }),\n ...(this._instructionsOverride !== undefined && { instructions: this._instructionsOverride }),\n });\n }\n\n /**\n * Whether a Railway API token was resolved at construction (explicit option\n * or the `RAILWAY_API_TOKEN` env fallback). Lets callers gate features on a\n * usable configuration without provisioning a sandbox.\n */\n get hasCredentials(): boolean {\n return this._token !== undefined && this._token !== '';\n }\n\n /** The configured idle teardown window in minutes, if any. */\n get idleTimeoutMinutes(): number | undefined {\n return this._idleTimeoutMinutes;\n }\n\n // ---------------------------------------------------------------------------\n // Info & Instructions\n // ---------------------------------------------------------------------------\n\n async getInfo(): Promise<SandboxInfo> {\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 metadata: {\n ...(this._sandbox && {\n railwaySandboxId: this._sandbox.id,\n environmentId: this._sandbox.environmentId,\n region: this._sandbox.region,\n networkIsolation: this._sandbox.networkIsolation,\n ...(this._sandbox.idleTimeoutMinutes != null && {\n idleTimeoutMinutes: this._sandbox.idleTimeoutMinutes,\n }),\n ...(this._restoredCheckpointName && { restoredCheckpointName: this._restoredCheckpointName }),\n }),\n },\n };\n }\n\n getInstructions(): string {\n const defaultInstructions = this._buildDefaultInstructions();\n\n if (typeof this._instructionsOverride === 'string') {\n return this._instructionsOverride;\n }\n if (typeof this._instructionsOverride === 'function') {\n return this._instructionsOverride({ defaultInstructions });\n }\n return defaultInstructions;\n }\n\n private _buildDefaultInstructions(): string {\n const parts: string[] = [];\n parts.push('Railway cloud sandbox: an isolated Debian Linux VM with outbound internet access.');\n\n if (this._networkIsolation === 'PRIVATE') {\n parts.push('Joined to the environment private network.');\n }\n\n if (this._timeout !== undefined) {\n parts.push(`Default command timeout: ${Math.ceil(this._timeout / 1000)}s.`);\n } else {\n parts.push('Commands run until they exit unless a timeout is set.');\n }\n\n if (this._idleTimeoutMinutes !== undefined) {\n parts.push(`Idle timeout: ${this._idleTimeoutMinutes} minute(s).`);\n }\n\n return parts.join(' ');\n }\n\n // ---------------------------------------------------------------------------\n // Command Execution\n // ---------------------------------------------------------------------------\n\n /**\n * Execute a command in the sandbox and return the result.\n */\n async executeCommand(\n command: string,\n args: string[] = [],\n options: ExecuteCommandOptions = {},\n ): Promise<CommandResult> {\n const status = this._sandbox?.status;\n\n if (status !== 'RUNNING') {\n if (!this._checkpointName) {\n throw new SandboxNotReadyError(this.id);\n }\n\n this._sandbox = null;\n await this.start();\n }\n\n const fullCommand = args.length > 0 ? `${command} ${args.map(shellQuote).join(' ')}` : command;\n const timeout = options.timeout ?? this._timeout;\n const mergedEnv = { ...this.getEnv(), ...options.env };\n const env = Object.keys(mergedEnv).length\n ? Object.fromEntries(\n Object.entries(mergedEnv).filter((entry): entry is [string, string] => entry[1] !== undefined),\n )\n : undefined;\n const startedAt = Date.now();\n const result = await this.railway.exec(fullCommand, {\n ...(timeout !== undefined && { timeoutSec: Math.ceil(timeout / 1000) }),\n ...(options.cwd !== undefined && { cwd: options.cwd }),\n ...(env !== undefined && { env }),\n });\n const exitCode = result.exitCode ?? -1;\n return {\n success: exitCode === 0,\n exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n executionTimeMs: Date.now() - startedAt,\n command,\n args,\n timedOut: result.timedOut,\n };\n }\n}\n","/**\n * Railway sandbox provider descriptor for MastraEditor.\n *\n * @example\n * ```typescript\n * import { railwaySandboxProvider } from '@mastra/railway';\n *\n * const editor = new MastraEditor({\n * sandboxes: { [railwaySandboxProvider.id]: railwaySandboxProvider },\n * });\n * ```\n */\nimport type { SandboxProvider } from '@mastra/core/editor';\nimport { RailwaySandbox } from './sandbox';\n\n/**\n * Serializable subset of RailwaySandboxOptions for editor storage.\n */\ninterface RailwayProviderConfig {\n token?: string;\n environmentId?: string;\n sandboxId?: string;\n idleTimeoutMinutes?: number;\n networkIsolation?: 'ISOLATED' | 'PRIVATE';\n env?: Record<string, string>;\n timeout?: number;\n}\n\nexport const railwaySandboxProvider: SandboxProvider<RailwayProviderConfig> = {\n id: 'railway',\n name: 'Railway Sandbox',\n description: 'Ephemeral, isolated Linux VM powered by Railway',\n configSchema: {\n type: 'object',\n properties: {\n token: { type: 'string', description: 'Railway API token (falls back to RAILWAY_API_TOKEN)' },\n environmentId: {\n type: 'string',\n description: 'Railway environment ID (falls back to RAILWAY_ENVIRONMENT_ID)',\n },\n sandboxId: { type: 'string', description: 'Reattach to an existing Railway sandbox by ID' },\n idleTimeoutMinutes: {\n type: 'number',\n description: 'Minutes a sandbox can sit idle before Railway destroys it',\n },\n networkIsolation: {\n type: 'string',\n description: 'Network isolation mode',\n enum: ['ISOLATED', 'PRIVATE'],\n default: 'ISOLATED',\n },\n env: {\n type: 'object',\n description: 'Environment variables',\n additionalProperties: { type: 'string' },\n },\n timeout: { type: 'number', description: 'Default command timeout in ms' },\n },\n },\n createSandbox: config => new RailwaySandbox(config),\n};\n"],"mappings":";;;;;;;;;AAMA,SAAgB,WAAW,KAAqB;CAE9C,IAAI,yBAAyB,KAAK,GAAG,GAAG,OAAO;CAE/C,OAAO,MAAM,IAAI,QAAQ,MAAM,OAAO,IAAI;AAC5C;;;;;;;;;;;;;;;;ACQA,MAAa,aAAa;;;;;AAU1B,IAAM,uBAAN,cAAmC,cAAc;CAC/C;CAEA;CACA;CACA;CACA,eAAsD;CACtD,UAAkB;CAElB,YAAY,KAAa,YAAwB,WAAmB,SAA+B;EACjG,MAAM,OAAO;EACb,KAAK,MAAM;EACX,KAAK,cAAc;EACnB,KAAK,aAAa;EAIlB,KAAU,YAAY,MACnB,WAAuB;GAEtB,KAAK,YAAY,OAAO,aAAa,KAAK,UAAU,MAAM;EAC5D,SACM;GACJ,IAAI,KAAK,cAAc,KAAA,GACrB,KAAK,YAAY;EAErB,CACF;CACF;CAEA,IAAI,WAA+B;EACjC,OAAO,KAAK;CACd;CAEA,MAAM,OAA+B;EAEnC,IAAI,CAAC,KAAK,cACR,KAAK,eAAe,KAAK,QAAQ;EAEnC,OAAO,KAAK;CACd;CAEA,MAAc,UAAkC;EAC9C,IAAI;GACF,MAAM,SAAS,MAAM,KAAK;GAC1B,MAAM,WAAW,OAAO,aAAa,KAAK,UAAU,MAAM;GAC1D,KAAK,YAAY;GAIjB,IAAI,OAAO,UAAU,CAAC,KAAK,QAAQ,KAAK,WAAW,OAAO,MAAM;GAChE,IAAI,OAAO,UAAU,CAAC,KAAK,QAAQ,KAAK,WAAW,OAAO,MAAM;GAEhE,OAAO;IACL,SAAS,aAAa;IACtB;IACA,QAAQ,KAAK;IACb,QAAQ,KAAK;IACb,iBAAiB,KAAK,IAAI,IAAI,KAAK;IACnC,QAAQ,KAAK;IACb,UAAU,OAAO;GACnB;EACF,SAAS,OAAO;GACd,MAAM,WAAW,KAAK,aAAa;GACnC,KAAK,YAAY;GACjB,OAAO;IACL,SAAS;IACT;IACA,QAAQ,KAAK;IACb,QAAQ,KAAK,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC7E,iBAAiB,KAAK,IAAI,IAAI,KAAK;IACnC,QAAQ,KAAK;GACf;EACF;CACF;CAEA,MAAM,OAAyB;EAC7B,IAAI,KAAK,cAAc,KAAA,GAAW,OAAO;EACzC,KAAK,UAAU;EACf,IAAI;GACF,OAAO,MAAM,KAAK,YAAY,KAAK,MAAM;EAC3C,QAAQ;GAEN,OAAO;EACT;CACF;CAEA,MAAM,UAAU,OAA8B;EAE5C,MAAM,IAAI,MAAM,GAAG,WAAW,gEAAgE;CAChG;CAEA,MAAM,aAA4B;EAChC,MAAM,IAAI,2BACR,GAAG,WAAW,gEAChB;CACF;AACF;;;;;AAUA,IAAa,wBAAb,cAA2C,sBAAsC;CAC/E,gBAAwB;CAExB,MAAM,MAAM,SAAiB,UAA+B,CAAC,GAA2B;EACtF,MAAM,UAAU,KAAK,QAAQ;EAG7B,MAAM,YAAY,EAAE,GAAG,QAAQ,IAAI;EACnC,MAAM,MAAM,OAAO,YACjB,OAAO,QAAQ,SAAS,CAAC,CAAC,QAAQ,UAAqC,MAAM,OAAO,KAAA,CAAS,CAC/F;EAEA,MAAM,MAAM,gBAAgB,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,IAAI,KAAK,gBAAA,CAAiB,SAAS,EAAE;EAIzF,IAAI;EAUJ,SAAS,IAAI,qBAAqB,KARf,QAAQ,KAAK,SAAS;GACvC,GAAI,QAAQ,YAAY,KAAA,KAAa,EAAE,YAAY,KAAK,KAAK,QAAQ,UAAU,GAAI,EAAE;GACrF,GAAI,QAAQ,QAAQ,KAAA,KAAa,EAAE,KAAK,QAAQ,IAAI;GACpD,GAAI,OAAO,KAAK,GAAG,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI;GACzC,WAAW,UAAkB,OAAO,WAAW,KAAK;GACpD,WAAW,UAAkB,OAAO,WAAW,KAAK;EACtD,CAEuC,GAAY,KAAK,IAAI,GAAG,OAAO;EACtE,KAAK,SAAS,IAAI,OAAO,KAAK,MAAM;EACpC,OAAO;CACT;;;;;;;CAQA,MAAM,OAA+B;EACnC,OAAO,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC,CAAC,CAAC,KAAI,YAAW;GACvD,KAAK,OAAO;GACZ,SAAS,OAAO;GAChB,SAAS,OAAO,aAAa,KAAA;GAC7B,GAAI,OAAO,aAAa,KAAA,KAAa,EAAE,UAAU,OAAO,SAAS;EACnE,EAAE;CACJ;AACF;;;;;;;;;;;;ACnJA,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqIrC,IAAa,iBAAb,MAAa,uBAAuB,cAAc;CAChD;CACA,OAAgB;CAChB,WAAoB;CACpB,SAAyB;CAIzB,WAAmC;CACnC,aAAkC;CAClC,0BAAwE;CACxE,6BAA2D;CAC3D;CACA;CACA,iBAA+C;CAE/C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,UAAiC,CAAC,GAAG;EAC/C,MAAM;GACJ,GAAG;GACH,MAAM;GACN,WAAW,IAAI,sBAAsB;EACvC,CAAC;EAED,KAAK,KAAK,QAAQ,MAAM,KAAK,WAAW;EACxC,KAAK,SAAS,QAAQ,SAAS,QAAQ,IAAI;EAC3C,KAAK,iBAAiB,QAAQ,iBAAiB,QAAQ,IAAI;EAC3D,KAAK,aAAa,QAAQ;EAC1B,KAAK,kBAAkB,QAAQ;EAC/B,KAAK,sBAAsB,QAAQ;EACnC,KAAK,sBAAsB,QAAQ;EACnC,KAAK,oBAAoB,QAAQ;EACjC,KAAK,OAAO,QAAQ,OAAO,CAAC;EAC5B,KAAK,WAAW,QAAQ;EACxB,KAAK,wBAAwB,QAAQ;EACrC,KAAK,kBAAkB,QAAQ;CACjC;CAEA,aAA6B;EAC3B,OAAO,mBAAmB,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CAC5F;;;;;;CAOA,IAAI,UAAmB;EACrB,IAAI,CAAC,KAAK,UACR,MAAM,IAAI,qBAAqB,KAAK,EAAE;EAExC,OAAO,KAAK;CACd;;;;;;;CAYA,MAAM,QAAuB;EAC3B,IAAI,KAAK,UACP;EAGF,MAAM,eAAe,KAAK,cAAc;EACxC,MAAM,gBAAgB,KAAK,eAAe,YAAY;EAEtD,IAAI,KAAK,YAAY;GACnB,MAAM,YAAY,KAAK;GACvB,KAAK,oBAAoB,YAAY;IACnC,KAAK,0BAA0B,KAAA;IAC/B,IAAI;KACF,KAAK,WAAW,MAAM,KAAK,kBAAkB,WAAW,YAAY;IACtE,SAAS,OAAO;KACd,IAAI,EAAE,iBAAiB,uBACrB,MAAM;KAER,KAAK,WAAW,MAAM,KAAK,kBAAkB,aAAa;IAC5D;GACF,EAAA,CAAG,CAAC,CAAC,cAAc;IACjB,KAAK,iBAAiB;GACxB,CAAC;EACH,OACE,KAAK,oBAAoB,YAAY;GACnC,KAAK,WAAW,MAAM,KAAK,kBAAkB,aAAa;EAC5D,EAAA,CAAG,CAAC,CAAC,cAAc;GACjB,KAAK,iBAAiB;EACxB,CAAC;EAEH,MAAM,KAAK;EAEX,IAAI,CAAC,KAAK,UACR,MAAM,IAAI,MAAM,iCAAiC;EAGnD,MAAM,UAAU,KAAK;EACrB,KAAK,aAAa,QAAQ;EAE1B,KAAK,aAAa,QAAQ,YAAY,IAAI,KAAK,QAAQ,SAAS,oBAAI,IAAI,KAAK;EAC7E,KAAK,OAAO,MAAM,GAAG,WAAW,mBAAmB,QAAQ,GAAG,yBAAyB,KAAK,IAAI;EAChG,KAAK,2BAA2B;CAClC;;;;CAKA,MAAc,kBAAkB,eAA+E;EAC7G,KAAK,OAAO,MAAM,GAAG,WAAW,iCAAiC,KAAK,IAAI;EAC1E,IAAI;GACF,IAAI;GACJ,IAAI,KAAK,mBAAmB,KAAK,qBAAqB;IACpD,MAAM,cAAc,MAAM,QAAQ,YAAY,KAAK,cAAc,CAAC;IAClE,MAAM,kBAAkB,IAAI,IAAI,YAAY,KAAI,eAAc,WAAW,GAAG,CAAC;IAC7E,sBAAsB,gBAAgB,IAAI,KAAK,mBAAmB,EAAE,IAChE,KAAK,kBACL,gBAAgB,IAAI,KAAK,uBAAuB,EAAE,IAChD,KAAK,sBACL,KAAA;GACR;GAEA,MAAM,UAAU,sBACZ,MAAM,QAAQ,OAAO,qBAAqB,aAAa,IACvD,MAAM,QAAQ,OAAO,aAAa;GACtC,KAAK,0BAA0B;GAC/B,OAAO;EACT,SAAS,OAAO;GACd,MAAM;EACR;CACF;;;;CAKA,MAAc,kBACZ,oBACA,cACkB;EAClB,KAAK,OAAO,MAAM,GAAG,WAAW,mCAAmC,mBAAmB,IAAI;EAE1F,IAAI,mBAA4B,MAAM,QAAQ,QAAQ,oBAAoB,YAAY;EAEtF,IAAI,iBAAiB,WAAW,WAC9B,MAAM,IAAI,qBAAqB;GAC7B,IAAI;GACJ,eAAe,aAAa,iBAAiB;EAC/C,CAAC;EAGH,OAAO;CACT;CAEA,gBAAoE;EAClE,OAAO;GACL,GAAI,KAAK,WAAW,KAAA,KAAa,EAAE,OAAO,KAAK,OAAO;GACtD,GAAI,KAAK,mBAAmB,KAAA,KAAa,EAAE,eAAe,KAAK,eAAe;EAChF;CACF;CAEA,eAAuB,cAA0D;EAC/E,OAAO;GACL,GAAG;GACH,GAAI,KAAK,wBAAwB,KAAA,KAAa,EAAE,oBAAoB,KAAK,oBAAoB;GAC7F,GAAI,KAAK,sBAAsB,KAAA,KAAa,EAAE,kBAAkB,KAAK,kBAAkB;GACvF,GAAI,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,KAAK,KAAK;EAC5D;CACF;;CAGA,MAAM,WAA0B;EAC9B,MAAM,KAAK,kBAAkB;CAC/B;;CAGA,sBAAwC;;;;;;;;;;;;;;;;;;;;;;CAuBxC,MAAM,oBAAsD;EAC1D,MAAM,iBAAiB,KAAK;EAC5B,IAAI,CAAC,gBACH,OAAO;GAAE,QAAQ;GAAW,QAAQ;EAAgC;EAGtE,MAAM,UAAU,KAAK;EACrB,IAAI,CAAC,SACH,OAAO;GAAE,QAAQ;GAAW,QAAQ;EAAsB;EAG5D,IAAI,KAAK,4BAA4B;GACnC,MAAM,KAAK;GACX,OAAO;IAAE,QAAQ;IAAa;GAAe;EAC/C;EAEA,MAAM,UAAU,KAAK,mBAAmB,OAAO,CAAC,CAAC,cAAc;GAC7D,IAAI,KAAK,+BAA+B,SACtC,KAAK,6BAA6B;EAEtC,CAAC;EACD,KAAK,6BAA6B;EAElC,MAAM;EACN,KAAK,2BAA2B;EAEhC,OAAO;GAAE,QAAQ;GAAY;EAAe;CAC9C;CAEA,MAAc,mBAAmB,SAAiC;EAChE,IAAI,CAAC,KAAK,iBACR;EAGF,KAAK,OAAO,MAAM,GAAG,WAAW,wCAAwC,KAAK,gBAAgB,QAAQ,KAAK,IAAI;EAM9G,KAHgC,MADN,QAAQ,YAAY,KAAK,cAAc,CAAC,EAAA,CACtB,MAAK,eAAc,WAAW,QAAQ,KAAK,eAG7D,GACxB,MAAM,QAAQ,iBAAiB,KAAK,iBAAiB,KAAK,cAAc,CAAC;EAG3E,MAAM,QAAQ,WAAW,KAAK,eAAe;CAC/C;CAEA,6BAA2C;EACzC,IAAI,CAAC,KAAK,mBAAmB,CAAC,KAAK,UACjC;EAGF,MAAM,qBAAqB,KAAK,uBAAuB,KAAK,SAAS;EACrE,IAAI,CAAC,oBACH;EAGF,KAAK,yBAAyB;EAE9B,MAAM,UAAU,KAAK,IAAI,KAAO,qBAAqB,MAAS,4BAA4B;EAC1F,KAAK,0BAA0B,iBAAiB;GAC9C,KAAK,0BAA0B;GAC/B,MAAM,UAAU,KAAK;GACrB,IAAI,CAAC,WAAW,KAAK,4BACnB;GAGF,MAAM,UAAU,KAAK,mBAAmB,OAAO,CAAC,CAAC,cAAc;IAC7D,IAAI,KAAK,+BAA+B,SACtC,KAAK,6BAA6B;GAEtC,CAAC;GACD,KAAK,6BAA6B;GAClC,QAAQ,OAAM,UAAS;IACrB,KAAK,OAAO,KAAK,GAAG,WAAW,gDAAgD,KAAK,gBAAgB,IAAI,KAAK;GAC/G,CAAC;EACH,GAAG,OAAO;EACV,KAAK,wBAAwB,QAAQ;CACvC;CAEA,2BAAyC;EACvC,IAAI,KAAK,yBAAyB;GAChC,aAAa,KAAK,uBAAuB;GACzC,KAAK,0BAA0B;EACjC;CACF;;;;;;;CAQA,MAAM,OAAsB;EAC1B,IAAI,KAAK,iBACP,MAAM,KAAK,wBAAwB,CAAC,CAAC,OAAM,UAAS;GAClD,KAAK,OAAO,KAAK,GAAG,WAAW,wCAAwC,KAAK,UAAU,GAAG,IAAI,KAAK;EACpG,CAAC;EAGH,MAAM,KAAK,UAAU;CACvB;;;;CAKA,MAAM,UAAyB;EAC7B,KAAK,yBAAyB;EAC9B,IAAI,KAAK,iBAAiB;GACxB,MAAM,KAAK;GACX,MAAM,QAAQ,iBAAiB,KAAK,iBAAiB,KAAK,cAAc,CAAC,CAAC,CAAC,OAAM,UAAS;IACxF,KAAK,OAAO,KAAK,GAAG,WAAW,uCAAuC,KAAK,gBAAgB,IAAI,KAAK;GACtG,CAAC;EACH;EAEA,MAAM,KAAK,UAAU;CACvB;CAEA,MAAc,0BAAyC;EACrD,KAAK,yBAAyB;EAE9B,IAAI,KAAK,4BAA4B;GACnC,MAAM,KAAK;GACX;EACF;EAEA,IAAI,KAAK,UACP,MAAM,KAAK,mBAAmB,KAAK,QAAQ;CAE/C;CAEA,MAAc,YAA2B;EACvC,KAAK,yBAAyB;EAC9B,IAAI,CAAC,KAAK,UACR;EAEF,MAAM,KAAK;EAEX,MAAM,UAAU,KAAK;EACrB,KAAK,WAAW;EAChB,IAAI;GACF,MAAM,QAAQ,QAAQ;EACxB,SAAS,OAAO;GACd,KAAK,OAAO,KAAK,GAAG,WAAW,qCAAqC,QAAQ,GAAG,IAAI,KAAK;EAC1F;CACF;;;;;;;;;;;CAYA,MAAM,KACJ,UAAiG,CAAC,GACzE;EAEV,MADA,KAAK,QACQ,KAAK;GAC/B,GAAI,QAAQ,uBAAuB,KAAA,KAAa,EAAE,oBAAoB,QAAQ,mBAAmB;GACjG,GAAI,QAAQ,qBAAqB,KAAA,KAAa,EAAE,kBAAkB,QAAQ,iBAAiB;GAC3F,GAAI,QAAQ,QAAQ,KAAA,KAAa,EAAE,KAAK,QAAQ,IAAI;EACtD,CAAC;EAED,MAAM,QAAQ,IAAI,eAAe;GAC/B,GAAI,QAAQ,OAAO,KAAA,KAAa,EAAE,IAAI,QAAQ,GAAG;GACjD,GAAI,KAAK,WAAW,KAAA,KAAa,EAAE,OAAO,KAAK,OAAO;GACtD,GAAI,KAAK,mBAAmB,KAAA,KAAa,EAAE,eAAe,KAAK,eAAe;GAC9E,oBAAoB,QAAQ,sBAAsB,KAAK;GACvD,kBAAkB,QAAQ,oBAAoB,KAAK;GACnD,KAAK,QAAQ,OAAO,KAAK;GACzB,SAAS,KAAK;EAChB,CAAC;EACD,MAAM,MAAM,OAAO;EACnB,OAAO;CACT;;;;;;;;;;;;CAaA,MAAM,UAA+B,CAAC,GAAmB;EACvD,OAAO,IAAI,eAAe;GACxB,GAAI,QAAQ,OAAO,KAAA,KAAa,EAAE,IAAI,QAAQ,GAAG;GACjD,GAAI,KAAK,WAAW,KAAA,KAAa,EAAE,OAAO,KAAK,OAAO;GACtD,GAAI,KAAK,mBAAmB,KAAA,KAAa,EAAE,eAAe,KAAK,eAAe;GAC9E,IAAK,QAAQ,kBAAkB,KAAK,qBAAqB,KAAA,KAAa,EACpE,gBAAgB,QAAQ,kBAAkB,KAAK,gBACjD;GACA,GAAI,QAAQ,uBAAuB,KAAA,KAAa,EAAE,oBAAoB,QAAQ,mBAAmB;GACjG,oBAAoB,QAAQ,sBAAsB,KAAK;GACvD,GAAI,KAAK,sBAAsB,KAAA,KAAa,EAAE,kBAAkB,KAAK,kBAAkB;GACvF,KAAK,QAAQ,OAAO,KAAK;GACzB,GAAI,KAAK,oBAAoB,KAAA,KAAa,EAAE,UAAU,KAAK,gBAAgB;GAC3E,GAAI,KAAK,aAAa,KAAA,KAAa,EAAE,SAAS,KAAK,SAAS;GAC5D,GAAI,KAAK,0BAA0B,KAAA,KAAa,EAAE,cAAc,KAAK,sBAAsB;EAC7F,CAAC;CACH;;;;;;CAOA,IAAI,iBAA0B;EAC5B,OAAO,KAAK,WAAW,KAAA,KAAa,KAAK,WAAW;CACtD;;CAGA,IAAI,qBAAyC;EAC3C,OAAO,KAAK;CACd;CAMA,MAAM,UAAgC;EACpC,OAAO;GACL,IAAI,KAAK;GACT,MAAM,KAAK;GACX,UAAU,KAAK;GACf,QAAQ,KAAK;GACb,WAAW,KAAK,8BAAc,IAAI,KAAK;GACvC,UAAU,EACR,GAAI,KAAK,YAAY;IACnB,kBAAkB,KAAK,SAAS;IAChC,eAAe,KAAK,SAAS;IAC7B,QAAQ,KAAK,SAAS;IACtB,kBAAkB,KAAK,SAAS;IAChC,GAAI,KAAK,SAAS,sBAAsB,QAAQ,EAC9C,oBAAoB,KAAK,SAAS,mBACpC;IACA,GAAI,KAAK,2BAA2B,EAAE,wBAAwB,KAAK,wBAAwB;GAC7F,EACF;EACF;CACF;CAEA,kBAA0B;EACxB,MAAM,sBAAsB,KAAK,0BAA0B;EAE3D,IAAI,OAAO,KAAK,0BAA0B,UACxC,OAAO,KAAK;EAEd,IAAI,OAAO,KAAK,0BAA0B,YACxC,OAAO,KAAK,sBAAsB,EAAE,oBAAoB,CAAC;EAE3D,OAAO;CACT;CAEA,4BAA4C;EAC1C,MAAM,QAAkB,CAAC;EACzB,MAAM,KAAK,mFAAmF;EAE9F,IAAI,KAAK,sBAAsB,WAC7B,MAAM,KAAK,4CAA4C;EAGzD,IAAI,KAAK,aAAa,KAAA,GACpB,MAAM,KAAK,4BAA4B,KAAK,KAAK,KAAK,WAAW,GAAI,EAAE,GAAG;OAE1E,MAAM,KAAK,uDAAuD;EAGpE,IAAI,KAAK,wBAAwB,KAAA,GAC/B,MAAM,KAAK,iBAAiB,KAAK,oBAAoB,YAAY;EAGnE,OAAO,MAAM,KAAK,GAAG;CACvB;;;;CASA,MAAM,eACJ,SACA,OAAiB,CAAC,GAClB,UAAiC,CAAC,GACV;EAGxB,IAFe,KAAK,UAAU,WAEf,WAAW;GACxB,IAAI,CAAC,KAAK,iBACR,MAAM,IAAI,qBAAqB,KAAK,EAAE;GAGxC,KAAK,WAAW;GAChB,MAAM,KAAK,MAAM;EACnB;EAEA,MAAM,cAAc,KAAK,SAAS,IAAI,GAAG,QAAQ,GAAG,KAAK,IAAI,UAAU,CAAC,CAAC,KAAK,GAAG,MAAM;EACvF,MAAM,UAAU,QAAQ,WAAW,KAAK;EACxC,MAAM,YAAY;GAAE,GAAG,KAAK,OAAO;GAAG,GAAG,QAAQ;EAAI;EACrD,MAAM,MAAM,OAAO,KAAK,SAAS,CAAC,CAAC,SAC/B,OAAO,YACL,OAAO,QAAQ,SAAS,CAAC,CAAC,QAAQ,UAAqC,MAAM,OAAO,KAAA,CAAS,CAC/F,IACA,KAAA;EACJ,MAAM,YAAY,KAAK,IAAI;EAC3B,MAAM,SAAS,MAAM,KAAK,QAAQ,KAAK,aAAa;GAClD,GAAI,YAAY,KAAA,KAAa,EAAE,YAAY,KAAK,KAAK,UAAU,GAAI,EAAE;GACrE,GAAI,QAAQ,QAAQ,KAAA,KAAa,EAAE,KAAK,QAAQ,IAAI;GACpD,GAAI,QAAQ,KAAA,KAAa,EAAE,IAAI;EACjC,CAAC;EACD,MAAM,WAAW,OAAO,YAAY;EACpC,OAAO;GACL,SAAS,aAAa;GACtB;GACA,QAAQ,OAAO;GACf,QAAQ,OAAO;GACf,iBAAiB,KAAK,IAAI,IAAI;GAC9B;GACA;GACA,UAAU,OAAO;EACnB;CACF;AACF;;;ACzqBA,MAAa,yBAAiE;CAC5E,IAAI;CACJ,MAAM;CACN,aAAa;CACb,cAAc;EACZ,MAAM;EACN,YAAY;GACV,OAAO;IAAE,MAAM;IAAU,aAAa;GAAsD;GAC5F,eAAe;IACb,MAAM;IACN,aAAa;GACf;GACA,WAAW;IAAE,MAAM;IAAU,aAAa;GAAgD;GAC1F,oBAAoB;IAClB,MAAM;IACN,aAAa;GACf;GACA,kBAAkB;IAChB,MAAM;IACN,aAAa;IACb,MAAM,CAAC,YAAY,SAAS;IAC5B,SAAS;GACX;GACA,KAAK;IACH,MAAM;IACN,aAAa;IACb,sBAAsB,EAAE,MAAM,SAAS;GACzC;GACA,SAAS;IAAE,MAAM;IAAU,aAAa;GAAgC;EAC1E;CACF;CACA,gBAAe,WAAU,IAAI,eAAe,MAAM;AACpD"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"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"}
@@ -15,16 +15,12 @@ import { ProcessHandle, SandboxProcessManager } from '@mastra/core/workspace';
15
15
  import type { ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';
16
16
  import type { RailwaySandbox } from './index.js';
17
17
  export declare const LOG_PREFIX = "[RailwaySandbox]";
18
- export interface RailwayProcessManagerOptions {
19
- env?: Record<string, string | undefined>;
20
- }
21
18
  /**
22
19
  * Railway implementation of SandboxProcessManager.
23
20
  * Uses the Railway SDK's `Sandbox.exec()` with one exec per spawned process.
24
21
  */
25
22
  export declare class RailwayProcessManager extends SandboxProcessManager<RailwaySandbox> {
26
23
  private _spawnCounter;
27
- constructor(opts?: RailwayProcessManagerOptions);
28
24
  spawn(command: string, options?: SpawnProcessOptions): Promise<ProcessHandle>;
29
25
  /**
30
26
  * List tracked processes.
@@ -1 +1 @@
1
- {"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../../src/sandbox/process-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAA8B,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC1G,OAAO,KAAK,EAAiB,WAAW,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,eAAO,MAAM,UAAU,qBAAqB,CAAC;AAiH7C,MAAM,WAAW,4BAA4B;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1C;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,qBAAqB,CAAC,cAAc,CAAC;IAC9E,OAAO,CAAC,aAAa,CAAK;gBAEd,IAAI,GAAE,4BAAiC;IAI7C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC;IA4BvF;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;CAQrC"}
1
+ {"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../../src/sandbox/process-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAA8B,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC1G,OAAO,KAAK,EAAiB,WAAW,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,eAAO,MAAM,UAAU,qBAAqB,CAAC;AAiH7C;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,qBAAqB,CAAC,cAAc,CAAC;IAC9E,OAAO,CAAC,aAAa,CAAK;IAEpB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC;IA4BvF;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;CAQrC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/railway",
3
- "version": "0.6.0",
3
+ "version": "0.7.0-alpha.0",
4
4
  "description": "Railway cloud sandbox provider for Mastra workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,10 +31,10 @@
31
31
  "tsdown": "0.22.9",
32
32
  "typescript": "^6.0.3",
33
33
  "vitest": "4.1.10",
34
- "@internal/lint": "0.0.124",
35
- "@internal/types-builder": "0.0.99",
36
- "@internal/workspace-test-utils": "0.0.68",
37
- "@mastra/core": "1.60.0"
34
+ "@internal/types-builder": "0.0.100",
35
+ "@internal/lint": "0.0.125",
36
+ "@internal/workspace-test-utils": "0.0.69",
37
+ "@mastra/core": "1.62.0-alpha.8"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@mastra/core": ">=1.12.0-0 <2.0.0-0"