@mastra/modal 0.3.0 → 0.4.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,53 @@
1
1
  # @mastra/modal
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added `clone()` support to the sandbox providers. `clone()` constructs an unstarted sibling sandbox that inherits the template's configuration (credentials, image, resources) with per-instance overrides for `id` and `env`, so one configured sandbox can act as a template for a fleet of sandbox clones (for example, one per project). ([#19616](https://github.com/mastra-ai/mastra/pull/19616))
8
+
9
+ ```ts
10
+ const template = new E2BSandbox({ apiKey, template: 'base' });
11
+
12
+ const projectSandbox = template.clone({
13
+ id: 'mc-project-42',
14
+ env: { GITHUB_TOKEN: token },
15
+ idleTimeoutMinutes: 30,
16
+ });
17
+ await projectSandbox.start();
18
+ ```
19
+
20
+ `idleTimeoutMinutes` is a best-effort hint that maps to each provider's native lifetime knob (Railway `idleTimeoutMinutes`, E2B/Modal/Vercel timeout in milliseconds, Daytona `autoStopInterval`, Blaxel TTL duration). Docker and Apple Container ignore it since they have no provider-side idle teardown.
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies [[`ec857fc`](https://github.com/mastra-ai/mastra/commit/ec857fc79c264b53b38e16478c789b7177f2ad59), [`d7385ad`](https://github.com/mastra-ai/mastra/commit/d7385ad9e88f9e4f33d15c0ec0bfebedde0cbc2e), [`41a5392`](https://github.com/mastra-ai/mastra/commit/41a5392d9f6c5e18d6b227f0fc0ddf49c50774e9), [`3d6e539`](https://github.com/mastra-ai/mastra/commit/3d6e539272eb2ea0407034605ee1906b3be06b39), [`1426af2`](https://github.com/mastra-ai/mastra/commit/1426af24975879c000d13ac75673f630fcc970c1), [`a40adeb`](https://github.com/mastra-ai/mastra/commit/a40adeb222b961a56a58af56a106106525721b74), [`8a0d145`](https://github.com/mastra-ai/mastra/commit/8a0d145aadbdf7278665aceaaec364b35dd9bd94), [`bd2f1d2`](https://github.com/mastra-ai/mastra/commit/bd2f1d274d05e60e2366f005ea0d94d5cea0d5ff), [`e1f2fae`](https://github.com/mastra-ai/mastra/commit/e1f2faebaf048c3d4c2e2c01d293767c195d5794), [`63aa799`](https://github.com/mastra-ai/mastra/commit/63aa799c6b44eacc7806cda6846b7c5bbee06b37), [`b7e79c3`](https://github.com/mastra-ai/mastra/commit/b7e79c3c02ac5cd415db34ba0975ceafc1464333), [`675fbff`](https://github.com/mastra-ai/mastra/commit/675fbff84d3274391b33e852f76083c38a5514e5), [`da009e1`](https://github.com/mastra-ai/mastra/commit/da009e1aacd89ed94b8d1b2af09c9d4fe7c4db49), [`3b77e77`](https://github.com/mastra-ai/mastra/commit/3b77e7704936522e4769d29de1b5ea6901f302bd), [`c7d30cd`](https://github.com/mastra-ai/mastra/commit/c7d30cd86009c407df91105591f03cd6e3d2854d), [`21a0eb8`](https://github.com/mastra-ai/mastra/commit/21a0eb86746ba0b703acea360d4f84c6a5a493f2), [`8b20926`](https://github.com/mastra-ai/mastra/commit/8b20926cd59e2ba3d66458e062fa0e6e2ada3e68), [`975295d`](https://github.com/mastra-ai/mastra/commit/975295d418552f0d46a59edfef4c3ee555f9930a), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`6b1bf3b`](https://github.com/mastra-ai/mastra/commit/6b1bf3b9494bd51aa8f654c68c9355d6046fa2a1), [`35c2181`](https://github.com/mastra-ai/mastra/commit/35c2181e6a50e47c90ba36260db7c9723d54696f), [`0a2c22c`](https://github.com/mastra-ai/mastra/commit/0a2c22c902604439ec490319e14c17f331e0c84c), [`4cfdd64`](https://github.com/mastra-ai/mastra/commit/4cfdd645794feaea0c4ea711e70ecdfbef0c5b8e), [`b75d749`](https://github.com/mastra-ai/mastra/commit/b75d749621ff5d17e86bcb4ee809d301fb4f7cf3), [`821648b`](https://github.com/mastra-ai/mastra/commit/821648bf2871ef840100c7bacbecf676010bd12a), [`de86fd7`](https://github.com/mastra-ai/mastra/commit/de86fd7119f0438381d1a642e3d258143c0b9c29), [`2745031`](https://github.com/mastra-ai/mastra/commit/2745031d1d4a4978f037092da371428c32e2842a), [`b4b7ea8`](https://github.com/mastra-ai/mastra/commit/b4b7ea8733f033fc441ea47ed03f6afb17ec2248), [`3a8024c`](https://github.com/mastra-ai/mastra/commit/3a8024ce615f8aa89479c0d71fe61d10bb0040be), [`35865a5`](https://github.com/mastra-ai/mastra/commit/35865a53e194aa9634d6a70a97010e7a6b9d58b1), [`74faf8b`](https://github.com/mastra-ai/mastra/commit/74faf8bd9c1018f2492653c06b1e25fc8300e9e6), [`ef03fbc`](https://github.com/mastra-ai/mastra/commit/ef03fbcc556bcbc04c9b3d06fab88771ecaa043c), [`675fbff`](https://github.com/mastra-ai/mastra/commit/675fbff84d3274391b33e852f76083c38a5514e5), [`70687f7`](https://github.com/mastra-ai/mastra/commit/70687f7e495a322a02070b4a67cb0c77a5ca91ec), [`1fadac4`](https://github.com/mastra-ai/mastra/commit/1fadac44537caeefe81f9f775ae2f2f3d94e9069), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`76b7181`](https://github.com/mastra-ai/mastra/commit/76b71810366e6d90b9d3973149d1c7ba3659ffb9), [`792ec9a`](https://github.com/mastra-ai/mastra/commit/792ec9a0869bab8274cf5e0ed2840738737a1607), [`712b864`](https://github.com/mastra-ai/mastra/commit/712b864aa1ed12b14c54390ec17b69de163c37f7), [`85e4fb5`](https://github.com/mastra-ai/mastra/commit/85e4fb50087a81c74df3a762f53b56373db0b912), [`0c0e8d7`](https://github.com/mastra-ai/mastra/commit/0c0e8d7becd4d1445c656b78d5d845f606c1ff9d), [`a7bbe77`](https://github.com/mastra-ai/mastra/commit/a7bbe773577f60bc4761b534ef7ec6b476332dad), [`72e437c`](https://github.com/mastra-ai/mastra/commit/72e437c515942c80b9def5b026e0bdee61b469d9), [`8f7a5de`](https://github.com/mastra-ai/mastra/commit/8f7a5dedc246cdc938bb65516703cf9b27b03756), [`a7bbe77`](https://github.com/mastra-ai/mastra/commit/a7bbe773577f60bc4761b534ef7ec6b476332dad), [`11f6cd9`](https://github.com/mastra-ai/mastra/commit/11f6cd96fe42582403416608beb212cc1a2cc79e), [`ef03c0c`](https://github.com/mastra-ai/mastra/commit/ef03c0cfc62367a458e4cc56462e2148b35681c5), [`4fb4d88`](https://github.com/mastra-ai/mastra/commit/4fb4d881bc107acee13890ad4d78661016c510ed), [`4e68363`](https://github.com/mastra-ai/mastra/commit/4e683634f94ebd062d26a3bb6093a8dfc7263d37), [`c328769`](https://github.com/mastra-ai/mastra/commit/c3287698ff8ef98dba86d415faa566fa3e5f4d56), [`9f7c67a`](https://github.com/mastra-ai/mastra/commit/9f7c67abeeb52c41c51a9b5edee60b62afe7cd8d), [`3b65e68`](https://github.com/mastra-ai/mastra/commit/3b65e68d7f1c771c7a70eea42d83fefdd28cad88), [`4eba27a`](https://github.com/mastra-ai/mastra/commit/4eba27adcf60f991df0e62f94b3e75b4e67f3b4b), [`c701be3`](https://github.com/mastra-ai/mastra/commit/c701be32d7d9aa94a66da8c6cc38dcac6856f464), [`db650ce`](https://github.com/mastra-ai/mastra/commit/db650ce490348914e85b93651d83acdf8f2a4c31), [`232fcbc`](https://github.com/mastra-ai/mastra/commit/232fcbc14fce625dd672ba043329c0b732c62be2), [`6354eeb`](https://github.com/mastra-ai/mastra/commit/6354eeb32efa9f5f68f51dda394e90e2ee76f1fb), [`a8799bb`](https://github.com/mastra-ai/mastra/commit/a8799bb8e44f4a60d01e4e2acd3448ff80bf14f8), [`3d6e539`](https://github.com/mastra-ai/mastra/commit/3d6e539272eb2ea0407034605ee1906b3be06b39), [`e3868e2`](https://github.com/mastra-ai/mastra/commit/e3868e22babfffd0133771669ca724501c2dd58e), [`9251370`](https://github.com/mastra-ai/mastra/commit/9251370ad413af464aa22d7566338bec5613e8de), [`3491666`](https://github.com/mastra-ai/mastra/commit/34916663c4fdd43b48c21f4ab2d5fb6dcccc94f9), [`c0bec73`](https://github.com/mastra-ai/mastra/commit/c0bec732c93d1a22ae5e51ed66cf8cacca8bd6a6)]:
25
+ - @mastra/core@1.52.0
26
+
27
+ ## 0.4.0-alpha.0
28
+
29
+ ### Minor Changes
30
+
31
+ - Added `clone()` support to the sandbox providers. `clone()` constructs an unstarted sibling sandbox that inherits the template's configuration (credentials, image, resources) with per-instance overrides for `id` and `env`, so one configured sandbox can act as a template for a fleet of sandbox clones (for example, one per project). ([#19616](https://github.com/mastra-ai/mastra/pull/19616))
32
+
33
+ ```ts
34
+ const template = new E2BSandbox({ apiKey, template: 'base' });
35
+
36
+ const projectSandbox = template.clone({
37
+ id: 'mc-project-42',
38
+ env: { GITHUB_TOKEN: token },
39
+ idleTimeoutMinutes: 30,
40
+ });
41
+ await projectSandbox.start();
42
+ ```
43
+
44
+ `idleTimeoutMinutes` is a best-effort hint that maps to each provider's native lifetime knob (Railway `idleTimeoutMinutes`, E2B/Modal/Vercel timeout in milliseconds, Daytona `autoStopInterval`, Blaxel TTL duration). Docker and Apple Container ignore it since they have no provider-side idle teardown.
45
+
46
+ ### Patch Changes
47
+
48
+ - Updated dependencies [[`ec857fc`](https://github.com/mastra-ai/mastra/commit/ec857fc79c264b53b38e16478c789b7177f2ad59), [`e1f2fae`](https://github.com/mastra-ai/mastra/commit/e1f2faebaf048c3d4c2e2c01d293767c195d5794), [`63aa799`](https://github.com/mastra-ai/mastra/commit/63aa799c6b44eacc7806cda6846b7c5bbee06b37), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`76b7181`](https://github.com/mastra-ai/mastra/commit/76b71810366e6d90b9d3973149d1c7ba3659ffb9), [`0c0e8d7`](https://github.com/mastra-ai/mastra/commit/0c0e8d7becd4d1445c656b78d5d845f606c1ff9d), [`9f7c67a`](https://github.com/mastra-ai/mastra/commit/9f7c67abeeb52c41c51a9b5edee60b62afe7cd8d), [`3b65e68`](https://github.com/mastra-ai/mastra/commit/3b65e68d7f1c771c7a70eea42d83fefdd28cad88), [`e3868e2`](https://github.com/mastra-ai/mastra/commit/e3868e22babfffd0133771669ca724501c2dd58e)]:
49
+ - @mastra/core@1.52.0-alpha.5
50
+
3
51
  ## 0.3.0
4
52
 
5
53
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -180,7 +180,7 @@ async function drainReader(reader, emit) {
180
180
 
181
181
  // src/sandbox/index.ts
182
182
  var LOG_PREFIX = "[ModalSandbox]";
183
- var ModalSandbox = class extends workspace.MastraSandbox {
183
+ var ModalSandbox = class _ModalSandbox extends workspace.MastraSandbox {
184
184
  id;
185
185
  name = "ModalSandbox";
186
186
  provider = "modal";
@@ -199,6 +199,7 @@ var ModalSandbox = class extends workspace.MastraSandbox {
199
199
  tokenId;
200
200
  tokenSecret;
201
201
  _instructionsOverride;
202
+ _constructorOptions;
202
203
  constructor(options = {}) {
203
204
  super({
204
205
  ...options,
@@ -214,6 +215,30 @@ var ModalSandbox = class extends workspace.MastraSandbox {
214
215
  this.tokenId = options.tokenId;
215
216
  this.tokenSecret = options.tokenSecret;
216
217
  this._instructionsOverride = options.instructions;
218
+ this._constructorOptions = { ...options };
219
+ }
220
+ /**
221
+ * Construct a sibling `ModalSandbox` that inherits this sandbox's
222
+ * configuration (credentials, app, base image, workdir, instructions) with
223
+ * per-instance overrides.
224
+ *
225
+ * Performs no I/O — the sandbox clone provisions (or reconnects to a
226
+ * running Modal sandbox with the same logical `id`) on its own `start()`.
227
+ * Use it when one configured sandbox acts as the template for a fleet of
228
+ * independent sandboxes (e.g. one per project).
229
+ *
230
+ * `options.idleTimeoutMinutes` maps to Modal's `timeoutMs` (wall-clock
231
+ * lifetime); `options.sandboxId` is ignored because Modal reconnects by
232
+ * logical `id`.
233
+ */
234
+ clone(options = {}) {
235
+ const { id: _id, ...base } = this._constructorOptions;
236
+ return new _ModalSandbox({
237
+ ...base,
238
+ ...options.id !== void 0 && { id: options.id },
239
+ ...options.env !== void 0 && { env: options.env },
240
+ ...options.idleTimeoutMinutes !== void 0 && { timeoutMs: options.idleTimeoutMinutes * 6e4 }
241
+ });
217
242
  }
218
243
  /**
219
244
  * Get the underlying Modal Sandbox instance for direct SDK access.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sandbox/process-manager.ts","../src/sandbox/index.ts"],"names":["ProcessHandle","SandboxProcessManager","MastraSandbox","SandboxNotReadyError","NotFoundError","ClientClosedError","ModalClient"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Modal process manager. Each spawn() creates a ContainerProcess via exec().\n * kill() has no SDK equivalent — it cancels stream readers locally; the remote\n * process runs until the sandbox timeout.\n */\n\nimport { ProcessHandle, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { ContainerProcess } from 'modal';\nimport type { ModalSandbox } from './index';\n\n// =============================================================================\n// Modal Process Handle\n// =============================================================================\n\n/**\n * Wraps a Modal ContainerProcess to conform to Mastra's ProcessHandle.\n */\nclass ModalProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _proc: ContainerProcess<string>;\n private readonly _startTime: number;\n private readonly _timeout?: number;\n\n private _exitCode: number | undefined;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _streamingPromise: Promise<void> | null = null;\n private _killed = false;\n private _stdoutReader: ReadableStreamDefaultReader<string> | null = null;\n private _stderrReader: ReadableStreamDefaultReader<string> | null = null;\n\n constructor(pid: string, proc: ContainerProcess<string>, startTime: number, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this._proc = proc;\n this._startTime = startTime;\n this._timeout = options?.timeout;\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n /** @internal Set by the process manager after streaming starts. */\n set streamingPromise(p: Promise<void>) {\n this._streamingPromise = p;\n\n // Resolve exit code when streaming ends so exitCode is available without calling wait()\n p.then(() => this._resolveExitCode()).catch(() => this._resolveExitCode());\n }\n\n /** @internal Set by the process manager so kill() can cancel the readers. */\n setReaders(\n stdoutReader: ReadableStreamDefaultReader<string>,\n stderrReader: ReadableStreamDefaultReader<string>,\n ): void {\n this._stdoutReader = stdoutReader;\n this._stderrReader = stderrReader;\n }\n\n /** Fetch the exit code from the Modal process. No-op if already set. */\n private async _resolveExitCode(): Promise<void> {\n if (this._exitCode !== undefined) return;\n try {\n this._exitCode = await this._proc.wait();\n } catch {\n if (this._exitCode === undefined) {\n this._exitCode = 1;\n }\n }\n }\n\n async wait(): Promise<CommandResult> {\n if (!this._waitPromise) {\n this._waitPromise = this._doWait();\n }\n return this._waitPromise;\n }\n\n private async _doWait(): Promise<CommandResult> {\n const streamDone = this._streamingPromise ?? Promise.resolve();\n\n if (this._timeout) {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Command timed out after ${this._timeout}ms`)), this._timeout);\n });\n\n try {\n await Promise.race([streamDone, timeoutPromise]);\n } catch (error) {\n if (error instanceof Error && error.message.includes('timed out')) {\n await this.kill();\n this._exitCode = 124; // conventional timeout exit code\n return {\n success: false,\n exitCode: 124,\n stdout: this.stdout,\n stderr: this.stderr || error.message,\n executionTimeMs: Date.now() - this._startTime,\n killed: true,\n timedOut: true,\n };\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n } else {\n await streamDone.catch(() => {});\n }\n\n if (this._killed) {\n return {\n success: false,\n exitCode: this._exitCode ?? 137,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n killed: true,\n timedOut: false,\n };\n }\n\n await this._resolveExitCode();\n\n return {\n success: this._exitCode === 0,\n exitCode: this._exitCode ?? 1,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n };\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n this._killed = true;\n this._exitCode = 137; // SIGKILL\n // The remote process may continue running; Modal JS SDK has no per-exec kill.\n try {\n await this._stdoutReader?.cancel();\n } catch {\n // Ignore cancellation errors\n }\n try {\n await this._stderrReader?.cancel();\n } catch {\n // Ignore cancellation errors\n }\n return true;\n }\n\n async sendStdin(_data: string): Promise<void> {\n throw new Error('Modal JS SDK does not expose stdin on exec() — sendStdin() is not supported');\n }\n}\n\n// =============================================================================\n// Modal Process Manager\n// =============================================================================\n\nexport interface ModalProcessManagerOptions {\n env?: Record<string, string | undefined>;\n}\n\n/**\n * Modal implementation of SandboxProcessManager.\n * Uses the Modal SDK's exec() API with one ContainerProcess per spawn.\n */\nexport class ModalProcessManager extends SandboxProcessManager<ModalSandbox> {\n private _spawnCounter = 0;\n\n constructor(opts: ModalProcessManagerOptions = {}) {\n super({ env: opts.env });\n }\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n return this.sandbox.retryOnDead(async () => {\n const sb = this.sandbox.modal;\n\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 // exec() takes string[] — wrap in sh -c to support pipes, redirects, etc.\n const argv = ['sh', '-c', command];\n\n const proc = await sb.exec(argv, {\n env: Object.keys(env).length > 0 ? env : undefined,\n workdir: options.cwd,\n timeoutMs: options.timeout,\n });\n\n const pid = `modal-proc-${Date.now().toString(36)}-${++this._spawnCounter}`;\n const handle = new ModalProcessHandle(pid, proc, Date.now(), options);\n\n const stdoutReader = proc.stdout.getReader();\n const stderrReader = proc.stderr.getReader();\n handle.setReaders(stdoutReader, stderrReader);\n\n const streamingPromise = Promise.all([\n drainReader(stdoutReader, chunk => handle.emitStdout(chunk)),\n drainReader(stderrReader, chunk => handle.emitStderr(chunk)),\n ]).then(() => {});\n\n handle.streamingPromise = streamingPromise;\n\n this._tracked.set(pid, handle);\n return handle;\n });\n }\n\n async list(): Promise<ProcessInfo[]> {\n const result: ProcessInfo[] = [];\n for (const [pid, handle] of this._tracked) {\n result.push({\n pid,\n command: handle.command,\n running: handle.exitCode === undefined,\n exitCode: handle.exitCode,\n });\n }\n return result;\n }\n}\n\n// =============================================================================\n// Stream Helpers\n// =============================================================================\n\n/** Reads chunks from a stream until done or cancelled. */\nasync function drainReader(reader: ReadableStreamDefaultReader<string>, emit: (chunk: string) => void): Promise<void> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n emit(value);\n }\n } catch {\n // cancelled or network error\n }\n}\n","/**\n * @see https://modal.com/docs/reference/modal.Sandbox\n */\n\nimport type { MastraSandboxOptions, ProviderStatus, SandboxInfo } from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxNotReadyError } from '@mastra/core/workspace';\nimport { ClientClosedError, ModalClient, NotFoundError } from 'modal';\nimport type { App, Image, Sandbox } from 'modal';\nimport { ModalProcessManager } from './process-manager';\n\nconst LOG_PREFIX = '[ModalSandbox]';\n\n// =============================================================================\n// Options\n// =============================================================================\n\ntype InstructionsOption = string | ((opts: { defaultInstructions: string }) => string);\n\n/**\n * Modal sandbox provider configuration.\n */\nexport interface ModalSandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Stable name for this sandbox. Reusing the same id reconnects to a running sandbox. */\n id?: string;\n /**\n * Modal App name to associate sandboxes with.\n *\n * @default 'mastra'\n */\n appName?: string;\n /**\n * Docker image to use for the sandbox.\n *\n * @default 'ubuntu:22.04'\n */\n baseImage?: string;\n /**\n * Wall-clock max lifetime in milliseconds. The sandbox is terminated when this expires,\n * regardless of activity. Modal's maximum is 24 hours (86_400_000).\n *\n * @default 300_000 // 5 minutes\n */\n timeoutMs?: number;\n /** Environment variables baked into the sandbox at create time. */\n env?: Record<string, string>;\n /** Default working directory inside the sandbox. */\n workdir?: string;\n /** Modal token ID. Falls back to MODAL_TOKEN_ID env var. */\n tokenId?: string;\n /** Modal token secret. Falls back to MODAL_TOKEN_SECRET env var. */\n tokenSecret?: string;\n /** Custom instructions for getInstructions(). String replaces the default; function receives it. */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// ModalSandbox\n// =============================================================================\n\n/**\n * Modal cloud sandbox provider for Mastra workspaces.\n *\n * @example\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { ModalSandbox } from '@mastra/modal';\n *\n * const sandbox = new ModalSandbox({\n * baseImage: 'ubuntu:22.04',\n * timeoutMs: 60_000,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCommand('echo hello');\n * ```\n */\nexport class ModalSandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'ModalSandbox';\n readonly provider = 'modal';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: ModalProcessManager;\n\n private _sb: Sandbox | null = null;\n private _imageSnapshot: Image | null = null; // for stop-and-resume\n private _client: ModalClient | null = null;\n private _createdAt: Date | null = null;\n private _isRetrying = false;\n\n private readonly appName: string;\n private readonly baseImage: string;\n private readonly timeoutMs: number;\n private readonly env: Record<string, string>;\n private readonly workdir?: string;\n private readonly tokenId?: string;\n private readonly tokenSecret?: string;\n private readonly _instructionsOverride?: InstructionsOption;\n\n constructor(options: ModalSandboxOptions = {}) {\n super({\n ...options,\n name: 'ModalSandbox',\n processes: new ModalProcessManager({ env: options.env ?? {} }),\n });\n\n this.id = options.id ?? this._generateId();\n this.appName = options.appName ?? 'mastra';\n this.baseImage = options.baseImage ?? 'ubuntu:22.04';\n this.timeoutMs = options.timeoutMs ?? 300_000;\n this.env = options.env ?? {};\n this.workdir = options.workdir;\n this.tokenId = options.tokenId;\n this.tokenSecret = options.tokenSecret;\n this._instructionsOverride = options.instructions;\n }\n\n /**\n * Get the underlying Modal Sandbox instance for direct SDK access.\n *\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get modal(): Sandbox {\n if (!this._sb) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._sb;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /** Reconnects to a running sandbox with this id if one exists, otherwise creates a new one. */\n async start(): Promise<void> {\n if (this._sb) {\n return;\n }\n\n const client = this._getClient();\n\n try {\n this._sb = await client.sandboxes.fromName(this.appName, this.id);\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Reconnected to running sandbox: ${this.id}`);\n return;\n } catch (error) {\n if (!(error instanceof NotFoundError)) {\n throw error;\n }\n }\n\n const app: App = await client.apps.fromName(this.appName, { createIfMissing: true });\n\n if (this._imageSnapshot) {\n this.logger.debug(`${LOG_PREFIX} Rebooting from snapshot: ${this.id}`);\n this._sb = await client.sandboxes.create(app, this._imageSnapshot, {\n name: this.id,\n timeoutMs: this.timeoutMs,\n env: Object.keys(this.env).length > 0 ? this.env : undefined,\n workdir: this.workdir,\n });\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Created new sandbox from snapshot: ${this._sb?.sandboxId}`);\n return;\n }\n\n const image: Image = client.images.fromRegistry(this.baseImage);\n this.logger.debug(`${LOG_PREFIX} Creating sandbox: ${this.id} (baseImage: ${this.baseImage})`);\n this._sb = await client.sandboxes.create(app, image, {\n name: this.id,\n timeoutMs: this.timeoutMs,\n env: Object.keys(this.env).length > 0 ? this.env : undefined,\n workdir: this.workdir,\n });\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Created sandbox: ${this._sb.sandboxId}`);\n }\n\n /**\n * Snapshot the sandbox filesystem before terminating it.\n * Future starts will create net-new sandboxes from the snapshot.\n */\n async stop(): Promise<void> {\n if (!this._sb) return;\n\n try {\n const procs = await this.processes.list();\n await Promise.all(procs.filter(p => p.running).map(p => this.processes.kill(p.pid)));\n } catch {\n // Best-effort: sandbox may already be dead\n }\n\n try {\n this._imageSnapshot = await this._sb.snapshotFilesystem();\n this.logger.debug(`${LOG_PREFIX} Snapshot created: ${this._imageSnapshot.imageId}`);\n } catch (error) {\n this.logger.debug(`${LOG_PREFIX} Snapshot failed, terminating without snapshot:`, error);\n }\n\n try {\n await this._sb.terminate({ wait: true });\n this.logger.debug(`${LOG_PREFIX} Sandbox terminated: ${this._sb.sandboxId}`);\n this._sb = null;\n } catch (error) {\n // Best-effort: sandbox may already be dead\n if (this.isSandboxDeadError(error)) {\n this._sb = null;\n } else {\n throw error;\n }\n }\n }\n\n /** Terminates the sandbox, ending its lifetime. Unlike stop(), no snapshot is preserved. */\n async destroy(): Promise<void> {\n if (this._sb) {\n try {\n const procs = await this.processes.list();\n await Promise.all(procs.filter(p => p.running).map(p => this.processes.kill(p.pid)));\n } catch {\n // Best-effort: sandbox may already be dead\n }\n\n try {\n await this._sb.terminate();\n this.logger.debug(`${LOG_PREFIX} Sandbox terminated: ${this._sb.sandboxId}`);\n } catch {\n // Ignore errors during destroy\n }\n\n this._sb = null;\n }\n\n this._imageSnapshot = null;\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 appName: this.appName,\n image: this._imageSnapshot?.imageId ?? this.baseImage,\n timeoutMs: this.timeoutMs,\n },\n };\n }\n\n getInstructions(): string {\n const defaultInstructions = this._getDefaultInstructions();\n if (this._instructionsOverride === undefined) return defaultInstructions;\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return this._instructionsOverride({ defaultInstructions });\n }\n\n private _getDefaultInstructions(): string {\n return `Modal cloud sandbox running ${this.baseImage}. Use executeCommand() to run shell commands.`;\n }\n\n // ---------------------------------------------------------------------------\n // Dead-sandbox Retry\n // ---------------------------------------------------------------------------\n\n private isSandboxDeadError(error: unknown): boolean {\n if (!error) return false;\n if (error instanceof ClientClosedError) return true;\n if (error instanceof NotFoundError) return true;\n const errorStr = String(error);\n return (\n errorStr.includes('sandbox not found') ||\n errorStr.includes('has been terminated') ||\n errorStr.includes('already completed') ||\n errorStr.includes('was cancelled') ||\n // gRPC NOT_FOUND (code 5)\n /status[:\\s]+5\\b/.test(errorStr) ||\n errorStr.includes('NOT_FOUND')\n );\n }\n\n private handleSandboxDead(): void {\n this._sb = null;\n this.status = 'stopped';\n }\n\n /** @internal Retries fn() once after restarting if the sandbox is dead. */\n async retryOnDead<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n if (this.isSandboxDeadError(error) && !this._isRetrying) {\n this.handleSandboxDead();\n this._isRetrying = true;\n try {\n await this.ensureRunning();\n return await fn();\n } finally {\n this._isRetrying = false;\n }\n }\n throw error;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal Helpers\n // ---------------------------------------------------------------------------\n\n private _generateId(): string {\n return `modal-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n private _getClient(): ModalClient {\n if (!this._client) {\n this._client = new ModalClient({\n ...(this.tokenId && { tokenId: this.tokenId }),\n ...(this.tokenSecret && { tokenSecret: this.tokenSecret }),\n });\n }\n return this._client;\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/sandbox/process-manager.ts","../src/sandbox/index.ts"],"names":["ProcessHandle","SandboxProcessManager","MastraSandbox","SandboxNotReadyError","NotFoundError","ClientClosedError","ModalClient"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Modal process manager. Each spawn() creates a ContainerProcess via exec().\n * kill() has no SDK equivalent — it cancels stream readers locally; the remote\n * process runs until the sandbox timeout.\n */\n\nimport { ProcessHandle, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { ContainerProcess } from 'modal';\nimport type { ModalSandbox } from './index';\n\n// =============================================================================\n// Modal Process Handle\n// =============================================================================\n\n/**\n * Wraps a Modal ContainerProcess to conform to Mastra's ProcessHandle.\n */\nclass ModalProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _proc: ContainerProcess<string>;\n private readonly _startTime: number;\n private readonly _timeout?: number;\n\n private _exitCode: number | undefined;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _streamingPromise: Promise<void> | null = null;\n private _killed = false;\n private _stdoutReader: ReadableStreamDefaultReader<string> | null = null;\n private _stderrReader: ReadableStreamDefaultReader<string> | null = null;\n\n constructor(pid: string, proc: ContainerProcess<string>, startTime: number, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this._proc = proc;\n this._startTime = startTime;\n this._timeout = options?.timeout;\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n /** @internal Set by the process manager after streaming starts. */\n set streamingPromise(p: Promise<void>) {\n this._streamingPromise = p;\n\n // Resolve exit code when streaming ends so exitCode is available without calling wait()\n p.then(() => this._resolveExitCode()).catch(() => this._resolveExitCode());\n }\n\n /** @internal Set by the process manager so kill() can cancel the readers. */\n setReaders(\n stdoutReader: ReadableStreamDefaultReader<string>,\n stderrReader: ReadableStreamDefaultReader<string>,\n ): void {\n this._stdoutReader = stdoutReader;\n this._stderrReader = stderrReader;\n }\n\n /** Fetch the exit code from the Modal process. No-op if already set. */\n private async _resolveExitCode(): Promise<void> {\n if (this._exitCode !== undefined) return;\n try {\n this._exitCode = await this._proc.wait();\n } catch {\n if (this._exitCode === undefined) {\n this._exitCode = 1;\n }\n }\n }\n\n async wait(): Promise<CommandResult> {\n if (!this._waitPromise) {\n this._waitPromise = this._doWait();\n }\n return this._waitPromise;\n }\n\n private async _doWait(): Promise<CommandResult> {\n const streamDone = this._streamingPromise ?? Promise.resolve();\n\n if (this._timeout) {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Command timed out after ${this._timeout}ms`)), this._timeout);\n });\n\n try {\n await Promise.race([streamDone, timeoutPromise]);\n } catch (error) {\n if (error instanceof Error && error.message.includes('timed out')) {\n await this.kill();\n this._exitCode = 124; // conventional timeout exit code\n return {\n success: false,\n exitCode: 124,\n stdout: this.stdout,\n stderr: this.stderr || error.message,\n executionTimeMs: Date.now() - this._startTime,\n killed: true,\n timedOut: true,\n };\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n } else {\n await streamDone.catch(() => {});\n }\n\n if (this._killed) {\n return {\n success: false,\n exitCode: this._exitCode ?? 137,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n killed: true,\n timedOut: false,\n };\n }\n\n await this._resolveExitCode();\n\n return {\n success: this._exitCode === 0,\n exitCode: this._exitCode ?? 1,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n };\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n this._killed = true;\n this._exitCode = 137; // SIGKILL\n // The remote process may continue running; Modal JS SDK has no per-exec kill.\n try {\n await this._stdoutReader?.cancel();\n } catch {\n // Ignore cancellation errors\n }\n try {\n await this._stderrReader?.cancel();\n } catch {\n // Ignore cancellation errors\n }\n return true;\n }\n\n async sendStdin(_data: string): Promise<void> {\n throw new Error('Modal JS SDK does not expose stdin on exec() — sendStdin() is not supported');\n }\n}\n\n// =============================================================================\n// Modal Process Manager\n// =============================================================================\n\nexport interface ModalProcessManagerOptions {\n env?: Record<string, string | undefined>;\n}\n\n/**\n * Modal implementation of SandboxProcessManager.\n * Uses the Modal SDK's exec() API with one ContainerProcess per spawn.\n */\nexport class ModalProcessManager extends SandboxProcessManager<ModalSandbox> {\n private _spawnCounter = 0;\n\n constructor(opts: ModalProcessManagerOptions = {}) {\n super({ env: opts.env });\n }\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n return this.sandbox.retryOnDead(async () => {\n const sb = this.sandbox.modal;\n\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 // exec() takes string[] — wrap in sh -c to support pipes, redirects, etc.\n const argv = ['sh', '-c', command];\n\n const proc = await sb.exec(argv, {\n env: Object.keys(env).length > 0 ? env : undefined,\n workdir: options.cwd,\n timeoutMs: options.timeout,\n });\n\n const pid = `modal-proc-${Date.now().toString(36)}-${++this._spawnCounter}`;\n const handle = new ModalProcessHandle(pid, proc, Date.now(), options);\n\n const stdoutReader = proc.stdout.getReader();\n const stderrReader = proc.stderr.getReader();\n handle.setReaders(stdoutReader, stderrReader);\n\n const streamingPromise = Promise.all([\n drainReader(stdoutReader, chunk => handle.emitStdout(chunk)),\n drainReader(stderrReader, chunk => handle.emitStderr(chunk)),\n ]).then(() => {});\n\n handle.streamingPromise = streamingPromise;\n\n this._tracked.set(pid, handle);\n return handle;\n });\n }\n\n async list(): Promise<ProcessInfo[]> {\n const result: ProcessInfo[] = [];\n for (const [pid, handle] of this._tracked) {\n result.push({\n pid,\n command: handle.command,\n running: handle.exitCode === undefined,\n exitCode: handle.exitCode,\n });\n }\n return result;\n }\n}\n\n// =============================================================================\n// Stream Helpers\n// =============================================================================\n\n/** Reads chunks from a stream until done or cancelled. */\nasync function drainReader(reader: ReadableStreamDefaultReader<string>, emit: (chunk: string) => void): Promise<void> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n emit(value);\n }\n } catch {\n // cancelled or network error\n }\n}\n","/**\n * @see https://modal.com/docs/reference/modal.Sandbox\n */\n\nimport type { MastraSandboxOptions, ProviderStatus, SandboxCloneOptions, SandboxInfo } from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxNotReadyError } from '@mastra/core/workspace';\nimport { ClientClosedError, ModalClient, NotFoundError } from 'modal';\nimport type { App, Image, Sandbox } from 'modal';\nimport { ModalProcessManager } from './process-manager';\n\nconst LOG_PREFIX = '[ModalSandbox]';\n\n// =============================================================================\n// Options\n// =============================================================================\n\ntype InstructionsOption = string | ((opts: { defaultInstructions: string }) => string);\n\n/**\n * Modal sandbox provider configuration.\n */\nexport interface ModalSandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Stable name for this sandbox. Reusing the same id reconnects to a running sandbox. */\n id?: string;\n /**\n * Modal App name to associate sandboxes with.\n *\n * @default 'mastra'\n */\n appName?: string;\n /**\n * Docker image to use for the sandbox.\n *\n * @default 'ubuntu:22.04'\n */\n baseImage?: string;\n /**\n * Wall-clock max lifetime in milliseconds. The sandbox is terminated when this expires,\n * regardless of activity. Modal's maximum is 24 hours (86_400_000).\n *\n * @default 300_000 // 5 minutes\n */\n timeoutMs?: number;\n /** Environment variables baked into the sandbox at create time. */\n env?: Record<string, string>;\n /** Default working directory inside the sandbox. */\n workdir?: string;\n /** Modal token ID. Falls back to MODAL_TOKEN_ID env var. */\n tokenId?: string;\n /** Modal token secret. Falls back to MODAL_TOKEN_SECRET env var. */\n tokenSecret?: string;\n /** Custom instructions for getInstructions(). String replaces the default; function receives it. */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// ModalSandbox\n// =============================================================================\n\n/**\n * Modal cloud sandbox provider for Mastra workspaces.\n *\n * @example\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { ModalSandbox } from '@mastra/modal';\n *\n * const sandbox = new ModalSandbox({\n * baseImage: 'ubuntu:22.04',\n * timeoutMs: 60_000,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCommand('echo hello');\n * ```\n */\nexport class ModalSandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'ModalSandbox';\n readonly provider = 'modal';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: ModalProcessManager;\n\n private _sb: Sandbox | null = null;\n private _imageSnapshot: Image | null = null; // for stop-and-resume\n private _client: ModalClient | null = null;\n private _createdAt: Date | null = null;\n private _isRetrying = false;\n\n private readonly appName: string;\n private readonly baseImage: string;\n private readonly timeoutMs: number;\n private readonly env: Record<string, string>;\n private readonly workdir?: string;\n private readonly tokenId?: string;\n private readonly tokenSecret?: string;\n private readonly _instructionsOverride?: InstructionsOption;\n private readonly _constructorOptions: ModalSandboxOptions;\n\n constructor(options: ModalSandboxOptions = {}) {\n super({\n ...options,\n name: 'ModalSandbox',\n processes: new ModalProcessManager({ env: options.env ?? {} }),\n });\n\n this.id = options.id ?? this._generateId();\n this.appName = options.appName ?? 'mastra';\n this.baseImage = options.baseImage ?? 'ubuntu:22.04';\n this.timeoutMs = options.timeoutMs ?? 300_000;\n this.env = options.env ?? {};\n this.workdir = options.workdir;\n this.tokenId = options.tokenId;\n this.tokenSecret = options.tokenSecret;\n this._instructionsOverride = options.instructions;\n this._constructorOptions = { ...options };\n }\n\n /**\n * Construct a sibling `ModalSandbox` that inherits this sandbox's\n * configuration (credentials, app, base image, workdir, instructions) with\n * per-instance overrides.\n *\n * Performs no I/O — the sandbox clone provisions (or reconnects to a\n * running Modal sandbox with the same logical `id`) on its own `start()`.\n * Use it when one configured sandbox acts as the template for a fleet of\n * independent sandboxes (e.g. one per project).\n *\n * `options.idleTimeoutMinutes` maps to Modal's `timeoutMs` (wall-clock\n * lifetime); `options.sandboxId` is ignored because Modal reconnects by\n * logical `id`.\n */\n clone(options: SandboxCloneOptions = {}): ModalSandbox {\n const { id: _id, ...base } = this._constructorOptions;\n return new ModalSandbox({\n ...base,\n ...(options.id !== undefined && { id: options.id }),\n ...(options.env !== undefined && { env: options.env }),\n ...(options.idleTimeoutMinutes !== undefined && { timeoutMs: options.idleTimeoutMinutes * 60_000 }),\n });\n }\n\n /**\n * Get the underlying Modal Sandbox instance for direct SDK access.\n *\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get modal(): Sandbox {\n if (!this._sb) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._sb;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /** Reconnects to a running sandbox with this id if one exists, otherwise creates a new one. */\n async start(): Promise<void> {\n if (this._sb) {\n return;\n }\n\n const client = this._getClient();\n\n try {\n this._sb = await client.sandboxes.fromName(this.appName, this.id);\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Reconnected to running sandbox: ${this.id}`);\n return;\n } catch (error) {\n if (!(error instanceof NotFoundError)) {\n throw error;\n }\n }\n\n const app: App = await client.apps.fromName(this.appName, { createIfMissing: true });\n\n if (this._imageSnapshot) {\n this.logger.debug(`${LOG_PREFIX} Rebooting from snapshot: ${this.id}`);\n this._sb = await client.sandboxes.create(app, this._imageSnapshot, {\n name: this.id,\n timeoutMs: this.timeoutMs,\n env: Object.keys(this.env).length > 0 ? this.env : undefined,\n workdir: this.workdir,\n });\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Created new sandbox from snapshot: ${this._sb?.sandboxId}`);\n return;\n }\n\n const image: Image = client.images.fromRegistry(this.baseImage);\n this.logger.debug(`${LOG_PREFIX} Creating sandbox: ${this.id} (baseImage: ${this.baseImage})`);\n this._sb = await client.sandboxes.create(app, image, {\n name: this.id,\n timeoutMs: this.timeoutMs,\n env: Object.keys(this.env).length > 0 ? this.env : undefined,\n workdir: this.workdir,\n });\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Created sandbox: ${this._sb.sandboxId}`);\n }\n\n /**\n * Snapshot the sandbox filesystem before terminating it.\n * Future starts will create net-new sandboxes from the snapshot.\n */\n async stop(): Promise<void> {\n if (!this._sb) return;\n\n try {\n const procs = await this.processes.list();\n await Promise.all(procs.filter(p => p.running).map(p => this.processes.kill(p.pid)));\n } catch {\n // Best-effort: sandbox may already be dead\n }\n\n try {\n this._imageSnapshot = await this._sb.snapshotFilesystem();\n this.logger.debug(`${LOG_PREFIX} Snapshot created: ${this._imageSnapshot.imageId}`);\n } catch (error) {\n this.logger.debug(`${LOG_PREFIX} Snapshot failed, terminating without snapshot:`, error);\n }\n\n try {\n await this._sb.terminate({ wait: true });\n this.logger.debug(`${LOG_PREFIX} Sandbox terminated: ${this._sb.sandboxId}`);\n this._sb = null;\n } catch (error) {\n // Best-effort: sandbox may already be dead\n if (this.isSandboxDeadError(error)) {\n this._sb = null;\n } else {\n throw error;\n }\n }\n }\n\n /** Terminates the sandbox, ending its lifetime. Unlike stop(), no snapshot is preserved. */\n async destroy(): Promise<void> {\n if (this._sb) {\n try {\n const procs = await this.processes.list();\n await Promise.all(procs.filter(p => p.running).map(p => this.processes.kill(p.pid)));\n } catch {\n // Best-effort: sandbox may already be dead\n }\n\n try {\n await this._sb.terminate();\n this.logger.debug(`${LOG_PREFIX} Sandbox terminated: ${this._sb.sandboxId}`);\n } catch {\n // Ignore errors during destroy\n }\n\n this._sb = null;\n }\n\n this._imageSnapshot = null;\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 appName: this.appName,\n image: this._imageSnapshot?.imageId ?? this.baseImage,\n timeoutMs: this.timeoutMs,\n },\n };\n }\n\n getInstructions(): string {\n const defaultInstructions = this._getDefaultInstructions();\n if (this._instructionsOverride === undefined) return defaultInstructions;\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return this._instructionsOverride({ defaultInstructions });\n }\n\n private _getDefaultInstructions(): string {\n return `Modal cloud sandbox running ${this.baseImage}. Use executeCommand() to run shell commands.`;\n }\n\n // ---------------------------------------------------------------------------\n // Dead-sandbox Retry\n // ---------------------------------------------------------------------------\n\n private isSandboxDeadError(error: unknown): boolean {\n if (!error) return false;\n if (error instanceof ClientClosedError) return true;\n if (error instanceof NotFoundError) return true;\n const errorStr = String(error);\n return (\n errorStr.includes('sandbox not found') ||\n errorStr.includes('has been terminated') ||\n errorStr.includes('already completed') ||\n errorStr.includes('was cancelled') ||\n // gRPC NOT_FOUND (code 5)\n /status[:\\s]+5\\b/.test(errorStr) ||\n errorStr.includes('NOT_FOUND')\n );\n }\n\n private handleSandboxDead(): void {\n this._sb = null;\n this.status = 'stopped';\n }\n\n /** @internal Retries fn() once after restarting if the sandbox is dead. */\n async retryOnDead<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n if (this.isSandboxDeadError(error) && !this._isRetrying) {\n this.handleSandboxDead();\n this._isRetrying = true;\n try {\n await this.ensureRunning();\n return await fn();\n } finally {\n this._isRetrying = false;\n }\n }\n throw error;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal Helpers\n // ---------------------------------------------------------------------------\n\n private _generateId(): string {\n return `modal-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n private _getClient(): ModalClient {\n if (!this._client) {\n this._client = new ModalClient({\n ...(this.tokenId && { tokenId: this.tokenId }),\n ...(this.tokenSecret && { tokenSecret: this.tokenSecret }),\n });\n }\n return this._client;\n }\n}\n"]}
package/dist/index.js CHANGED
@@ -178,7 +178,7 @@ async function drainReader(reader, emit) {
178
178
 
179
179
  // src/sandbox/index.ts
180
180
  var LOG_PREFIX = "[ModalSandbox]";
181
- var ModalSandbox = class extends MastraSandbox {
181
+ var ModalSandbox = class _ModalSandbox extends MastraSandbox {
182
182
  id;
183
183
  name = "ModalSandbox";
184
184
  provider = "modal";
@@ -197,6 +197,7 @@ var ModalSandbox = class extends MastraSandbox {
197
197
  tokenId;
198
198
  tokenSecret;
199
199
  _instructionsOverride;
200
+ _constructorOptions;
200
201
  constructor(options = {}) {
201
202
  super({
202
203
  ...options,
@@ -212,6 +213,30 @@ var ModalSandbox = class extends MastraSandbox {
212
213
  this.tokenId = options.tokenId;
213
214
  this.tokenSecret = options.tokenSecret;
214
215
  this._instructionsOverride = options.instructions;
216
+ this._constructorOptions = { ...options };
217
+ }
218
+ /**
219
+ * Construct a sibling `ModalSandbox` that inherits this sandbox's
220
+ * configuration (credentials, app, base image, workdir, instructions) with
221
+ * per-instance overrides.
222
+ *
223
+ * Performs no I/O — the sandbox clone provisions (or reconnects to a
224
+ * running Modal sandbox with the same logical `id`) on its own `start()`.
225
+ * Use it when one configured sandbox acts as the template for a fleet of
226
+ * independent sandboxes (e.g. one per project).
227
+ *
228
+ * `options.idleTimeoutMinutes` maps to Modal's `timeoutMs` (wall-clock
229
+ * lifetime); `options.sandboxId` is ignored because Modal reconnects by
230
+ * logical `id`.
231
+ */
232
+ clone(options = {}) {
233
+ const { id: _id, ...base } = this._constructorOptions;
234
+ return new _ModalSandbox({
235
+ ...base,
236
+ ...options.id !== void 0 && { id: options.id },
237
+ ...options.env !== void 0 && { env: options.env },
238
+ ...options.idleTimeoutMinutes !== void 0 && { timeoutMs: options.idleTimeoutMinutes * 6e4 }
239
+ });
215
240
  }
216
241
  /**
217
242
  * Get the underlying Modal Sandbox instance for direct SDK access.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sandbox/process-manager.ts","../src/sandbox/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Modal process manager. Each spawn() creates a ContainerProcess via exec().\n * kill() has no SDK equivalent — it cancels stream readers locally; the remote\n * process runs until the sandbox timeout.\n */\n\nimport { ProcessHandle, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { ContainerProcess } from 'modal';\nimport type { ModalSandbox } from './index';\n\n// =============================================================================\n// Modal Process Handle\n// =============================================================================\n\n/**\n * Wraps a Modal ContainerProcess to conform to Mastra's ProcessHandle.\n */\nclass ModalProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _proc: ContainerProcess<string>;\n private readonly _startTime: number;\n private readonly _timeout?: number;\n\n private _exitCode: number | undefined;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _streamingPromise: Promise<void> | null = null;\n private _killed = false;\n private _stdoutReader: ReadableStreamDefaultReader<string> | null = null;\n private _stderrReader: ReadableStreamDefaultReader<string> | null = null;\n\n constructor(pid: string, proc: ContainerProcess<string>, startTime: number, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this._proc = proc;\n this._startTime = startTime;\n this._timeout = options?.timeout;\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n /** @internal Set by the process manager after streaming starts. */\n set streamingPromise(p: Promise<void>) {\n this._streamingPromise = p;\n\n // Resolve exit code when streaming ends so exitCode is available without calling wait()\n p.then(() => this._resolveExitCode()).catch(() => this._resolveExitCode());\n }\n\n /** @internal Set by the process manager so kill() can cancel the readers. */\n setReaders(\n stdoutReader: ReadableStreamDefaultReader<string>,\n stderrReader: ReadableStreamDefaultReader<string>,\n ): void {\n this._stdoutReader = stdoutReader;\n this._stderrReader = stderrReader;\n }\n\n /** Fetch the exit code from the Modal process. No-op if already set. */\n private async _resolveExitCode(): Promise<void> {\n if (this._exitCode !== undefined) return;\n try {\n this._exitCode = await this._proc.wait();\n } catch {\n if (this._exitCode === undefined) {\n this._exitCode = 1;\n }\n }\n }\n\n async wait(): Promise<CommandResult> {\n if (!this._waitPromise) {\n this._waitPromise = this._doWait();\n }\n return this._waitPromise;\n }\n\n private async _doWait(): Promise<CommandResult> {\n const streamDone = this._streamingPromise ?? Promise.resolve();\n\n if (this._timeout) {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Command timed out after ${this._timeout}ms`)), this._timeout);\n });\n\n try {\n await Promise.race([streamDone, timeoutPromise]);\n } catch (error) {\n if (error instanceof Error && error.message.includes('timed out')) {\n await this.kill();\n this._exitCode = 124; // conventional timeout exit code\n return {\n success: false,\n exitCode: 124,\n stdout: this.stdout,\n stderr: this.stderr || error.message,\n executionTimeMs: Date.now() - this._startTime,\n killed: true,\n timedOut: true,\n };\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n } else {\n await streamDone.catch(() => {});\n }\n\n if (this._killed) {\n return {\n success: false,\n exitCode: this._exitCode ?? 137,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n killed: true,\n timedOut: false,\n };\n }\n\n await this._resolveExitCode();\n\n return {\n success: this._exitCode === 0,\n exitCode: this._exitCode ?? 1,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n };\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n this._killed = true;\n this._exitCode = 137; // SIGKILL\n // The remote process may continue running; Modal JS SDK has no per-exec kill.\n try {\n await this._stdoutReader?.cancel();\n } catch {\n // Ignore cancellation errors\n }\n try {\n await this._stderrReader?.cancel();\n } catch {\n // Ignore cancellation errors\n }\n return true;\n }\n\n async sendStdin(_data: string): Promise<void> {\n throw new Error('Modal JS SDK does not expose stdin on exec() — sendStdin() is not supported');\n }\n}\n\n// =============================================================================\n// Modal Process Manager\n// =============================================================================\n\nexport interface ModalProcessManagerOptions {\n env?: Record<string, string | undefined>;\n}\n\n/**\n * Modal implementation of SandboxProcessManager.\n * Uses the Modal SDK's exec() API with one ContainerProcess per spawn.\n */\nexport class ModalProcessManager extends SandboxProcessManager<ModalSandbox> {\n private _spawnCounter = 0;\n\n constructor(opts: ModalProcessManagerOptions = {}) {\n super({ env: opts.env });\n }\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n return this.sandbox.retryOnDead(async () => {\n const sb = this.sandbox.modal;\n\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 // exec() takes string[] — wrap in sh -c to support pipes, redirects, etc.\n const argv = ['sh', '-c', command];\n\n const proc = await sb.exec(argv, {\n env: Object.keys(env).length > 0 ? env : undefined,\n workdir: options.cwd,\n timeoutMs: options.timeout,\n });\n\n const pid = `modal-proc-${Date.now().toString(36)}-${++this._spawnCounter}`;\n const handle = new ModalProcessHandle(pid, proc, Date.now(), options);\n\n const stdoutReader = proc.stdout.getReader();\n const stderrReader = proc.stderr.getReader();\n handle.setReaders(stdoutReader, stderrReader);\n\n const streamingPromise = Promise.all([\n drainReader(stdoutReader, chunk => handle.emitStdout(chunk)),\n drainReader(stderrReader, chunk => handle.emitStderr(chunk)),\n ]).then(() => {});\n\n handle.streamingPromise = streamingPromise;\n\n this._tracked.set(pid, handle);\n return handle;\n });\n }\n\n async list(): Promise<ProcessInfo[]> {\n const result: ProcessInfo[] = [];\n for (const [pid, handle] of this._tracked) {\n result.push({\n pid,\n command: handle.command,\n running: handle.exitCode === undefined,\n exitCode: handle.exitCode,\n });\n }\n return result;\n }\n}\n\n// =============================================================================\n// Stream Helpers\n// =============================================================================\n\n/** Reads chunks from a stream until done or cancelled. */\nasync function drainReader(reader: ReadableStreamDefaultReader<string>, emit: (chunk: string) => void): Promise<void> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n emit(value);\n }\n } catch {\n // cancelled or network error\n }\n}\n","/**\n * @see https://modal.com/docs/reference/modal.Sandbox\n */\n\nimport type { MastraSandboxOptions, ProviderStatus, SandboxInfo } from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxNotReadyError } from '@mastra/core/workspace';\nimport { ClientClosedError, ModalClient, NotFoundError } from 'modal';\nimport type { App, Image, Sandbox } from 'modal';\nimport { ModalProcessManager } from './process-manager';\n\nconst LOG_PREFIX = '[ModalSandbox]';\n\n// =============================================================================\n// Options\n// =============================================================================\n\ntype InstructionsOption = string | ((opts: { defaultInstructions: string }) => string);\n\n/**\n * Modal sandbox provider configuration.\n */\nexport interface ModalSandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Stable name for this sandbox. Reusing the same id reconnects to a running sandbox. */\n id?: string;\n /**\n * Modal App name to associate sandboxes with.\n *\n * @default 'mastra'\n */\n appName?: string;\n /**\n * Docker image to use for the sandbox.\n *\n * @default 'ubuntu:22.04'\n */\n baseImage?: string;\n /**\n * Wall-clock max lifetime in milliseconds. The sandbox is terminated when this expires,\n * regardless of activity. Modal's maximum is 24 hours (86_400_000).\n *\n * @default 300_000 // 5 minutes\n */\n timeoutMs?: number;\n /** Environment variables baked into the sandbox at create time. */\n env?: Record<string, string>;\n /** Default working directory inside the sandbox. */\n workdir?: string;\n /** Modal token ID. Falls back to MODAL_TOKEN_ID env var. */\n tokenId?: string;\n /** Modal token secret. Falls back to MODAL_TOKEN_SECRET env var. */\n tokenSecret?: string;\n /** Custom instructions for getInstructions(). String replaces the default; function receives it. */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// ModalSandbox\n// =============================================================================\n\n/**\n * Modal cloud sandbox provider for Mastra workspaces.\n *\n * @example\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { ModalSandbox } from '@mastra/modal';\n *\n * const sandbox = new ModalSandbox({\n * baseImage: 'ubuntu:22.04',\n * timeoutMs: 60_000,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCommand('echo hello');\n * ```\n */\nexport class ModalSandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'ModalSandbox';\n readonly provider = 'modal';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: ModalProcessManager;\n\n private _sb: Sandbox | null = null;\n private _imageSnapshot: Image | null = null; // for stop-and-resume\n private _client: ModalClient | null = null;\n private _createdAt: Date | null = null;\n private _isRetrying = false;\n\n private readonly appName: string;\n private readonly baseImage: string;\n private readonly timeoutMs: number;\n private readonly env: Record<string, string>;\n private readonly workdir?: string;\n private readonly tokenId?: string;\n private readonly tokenSecret?: string;\n private readonly _instructionsOverride?: InstructionsOption;\n\n constructor(options: ModalSandboxOptions = {}) {\n super({\n ...options,\n name: 'ModalSandbox',\n processes: new ModalProcessManager({ env: options.env ?? {} }),\n });\n\n this.id = options.id ?? this._generateId();\n this.appName = options.appName ?? 'mastra';\n this.baseImage = options.baseImage ?? 'ubuntu:22.04';\n this.timeoutMs = options.timeoutMs ?? 300_000;\n this.env = options.env ?? {};\n this.workdir = options.workdir;\n this.tokenId = options.tokenId;\n this.tokenSecret = options.tokenSecret;\n this._instructionsOverride = options.instructions;\n }\n\n /**\n * Get the underlying Modal Sandbox instance for direct SDK access.\n *\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get modal(): Sandbox {\n if (!this._sb) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._sb;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /** Reconnects to a running sandbox with this id if one exists, otherwise creates a new one. */\n async start(): Promise<void> {\n if (this._sb) {\n return;\n }\n\n const client = this._getClient();\n\n try {\n this._sb = await client.sandboxes.fromName(this.appName, this.id);\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Reconnected to running sandbox: ${this.id}`);\n return;\n } catch (error) {\n if (!(error instanceof NotFoundError)) {\n throw error;\n }\n }\n\n const app: App = await client.apps.fromName(this.appName, { createIfMissing: true });\n\n if (this._imageSnapshot) {\n this.logger.debug(`${LOG_PREFIX} Rebooting from snapshot: ${this.id}`);\n this._sb = await client.sandboxes.create(app, this._imageSnapshot, {\n name: this.id,\n timeoutMs: this.timeoutMs,\n env: Object.keys(this.env).length > 0 ? this.env : undefined,\n workdir: this.workdir,\n });\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Created new sandbox from snapshot: ${this._sb?.sandboxId}`);\n return;\n }\n\n const image: Image = client.images.fromRegistry(this.baseImage);\n this.logger.debug(`${LOG_PREFIX} Creating sandbox: ${this.id} (baseImage: ${this.baseImage})`);\n this._sb = await client.sandboxes.create(app, image, {\n name: this.id,\n timeoutMs: this.timeoutMs,\n env: Object.keys(this.env).length > 0 ? this.env : undefined,\n workdir: this.workdir,\n });\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Created sandbox: ${this._sb.sandboxId}`);\n }\n\n /**\n * Snapshot the sandbox filesystem before terminating it.\n * Future starts will create net-new sandboxes from the snapshot.\n */\n async stop(): Promise<void> {\n if (!this._sb) return;\n\n try {\n const procs = await this.processes.list();\n await Promise.all(procs.filter(p => p.running).map(p => this.processes.kill(p.pid)));\n } catch {\n // Best-effort: sandbox may already be dead\n }\n\n try {\n this._imageSnapshot = await this._sb.snapshotFilesystem();\n this.logger.debug(`${LOG_PREFIX} Snapshot created: ${this._imageSnapshot.imageId}`);\n } catch (error) {\n this.logger.debug(`${LOG_PREFIX} Snapshot failed, terminating without snapshot:`, error);\n }\n\n try {\n await this._sb.terminate({ wait: true });\n this.logger.debug(`${LOG_PREFIX} Sandbox terminated: ${this._sb.sandboxId}`);\n this._sb = null;\n } catch (error) {\n // Best-effort: sandbox may already be dead\n if (this.isSandboxDeadError(error)) {\n this._sb = null;\n } else {\n throw error;\n }\n }\n }\n\n /** Terminates the sandbox, ending its lifetime. Unlike stop(), no snapshot is preserved. */\n async destroy(): Promise<void> {\n if (this._sb) {\n try {\n const procs = await this.processes.list();\n await Promise.all(procs.filter(p => p.running).map(p => this.processes.kill(p.pid)));\n } catch {\n // Best-effort: sandbox may already be dead\n }\n\n try {\n await this._sb.terminate();\n this.logger.debug(`${LOG_PREFIX} Sandbox terminated: ${this._sb.sandboxId}`);\n } catch {\n // Ignore errors during destroy\n }\n\n this._sb = null;\n }\n\n this._imageSnapshot = null;\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 appName: this.appName,\n image: this._imageSnapshot?.imageId ?? this.baseImage,\n timeoutMs: this.timeoutMs,\n },\n };\n }\n\n getInstructions(): string {\n const defaultInstructions = this._getDefaultInstructions();\n if (this._instructionsOverride === undefined) return defaultInstructions;\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return this._instructionsOverride({ defaultInstructions });\n }\n\n private _getDefaultInstructions(): string {\n return `Modal cloud sandbox running ${this.baseImage}. Use executeCommand() to run shell commands.`;\n }\n\n // ---------------------------------------------------------------------------\n // Dead-sandbox Retry\n // ---------------------------------------------------------------------------\n\n private isSandboxDeadError(error: unknown): boolean {\n if (!error) return false;\n if (error instanceof ClientClosedError) return true;\n if (error instanceof NotFoundError) return true;\n const errorStr = String(error);\n return (\n errorStr.includes('sandbox not found') ||\n errorStr.includes('has been terminated') ||\n errorStr.includes('already completed') ||\n errorStr.includes('was cancelled') ||\n // gRPC NOT_FOUND (code 5)\n /status[:\\s]+5\\b/.test(errorStr) ||\n errorStr.includes('NOT_FOUND')\n );\n }\n\n private handleSandboxDead(): void {\n this._sb = null;\n this.status = 'stopped';\n }\n\n /** @internal Retries fn() once after restarting if the sandbox is dead. */\n async retryOnDead<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n if (this.isSandboxDeadError(error) && !this._isRetrying) {\n this.handleSandboxDead();\n this._isRetrying = true;\n try {\n await this.ensureRunning();\n return await fn();\n } finally {\n this._isRetrying = false;\n }\n }\n throw error;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal Helpers\n // ---------------------------------------------------------------------------\n\n private _generateId(): string {\n return `modal-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n private _getClient(): ModalClient {\n if (!this._client) {\n this._client = new ModalClient({\n ...(this.tokenId && { tokenId: this.tokenId }),\n ...(this.tokenSecret && { tokenSecret: this.tokenSecret }),\n });\n }\n return this._client;\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/sandbox/process-manager.ts","../src/sandbox/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Modal process manager. Each spawn() creates a ContainerProcess via exec().\n * kill() has no SDK equivalent — it cancels stream readers locally; the remote\n * process runs until the sandbox timeout.\n */\n\nimport { ProcessHandle, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { ContainerProcess } from 'modal';\nimport type { ModalSandbox } from './index';\n\n// =============================================================================\n// Modal Process Handle\n// =============================================================================\n\n/**\n * Wraps a Modal ContainerProcess to conform to Mastra's ProcessHandle.\n */\nclass ModalProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _proc: ContainerProcess<string>;\n private readonly _startTime: number;\n private readonly _timeout?: number;\n\n private _exitCode: number | undefined;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _streamingPromise: Promise<void> | null = null;\n private _killed = false;\n private _stdoutReader: ReadableStreamDefaultReader<string> | null = null;\n private _stderrReader: ReadableStreamDefaultReader<string> | null = null;\n\n constructor(pid: string, proc: ContainerProcess<string>, startTime: number, options?: SpawnProcessOptions) {\n super(options);\n this.pid = pid;\n this._proc = proc;\n this._startTime = startTime;\n this._timeout = options?.timeout;\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n /** @internal Set by the process manager after streaming starts. */\n set streamingPromise(p: Promise<void>) {\n this._streamingPromise = p;\n\n // Resolve exit code when streaming ends so exitCode is available without calling wait()\n p.then(() => this._resolveExitCode()).catch(() => this._resolveExitCode());\n }\n\n /** @internal Set by the process manager so kill() can cancel the readers. */\n setReaders(\n stdoutReader: ReadableStreamDefaultReader<string>,\n stderrReader: ReadableStreamDefaultReader<string>,\n ): void {\n this._stdoutReader = stdoutReader;\n this._stderrReader = stderrReader;\n }\n\n /** Fetch the exit code from the Modal process. No-op if already set. */\n private async _resolveExitCode(): Promise<void> {\n if (this._exitCode !== undefined) return;\n try {\n this._exitCode = await this._proc.wait();\n } catch {\n if (this._exitCode === undefined) {\n this._exitCode = 1;\n }\n }\n }\n\n async wait(): Promise<CommandResult> {\n if (!this._waitPromise) {\n this._waitPromise = this._doWait();\n }\n return this._waitPromise;\n }\n\n private async _doWait(): Promise<CommandResult> {\n const streamDone = this._streamingPromise ?? Promise.resolve();\n\n if (this._timeout) {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Command timed out after ${this._timeout}ms`)), this._timeout);\n });\n\n try {\n await Promise.race([streamDone, timeoutPromise]);\n } catch (error) {\n if (error instanceof Error && error.message.includes('timed out')) {\n await this.kill();\n this._exitCode = 124; // conventional timeout exit code\n return {\n success: false,\n exitCode: 124,\n stdout: this.stdout,\n stderr: this.stderr || error.message,\n executionTimeMs: Date.now() - this._startTime,\n killed: true,\n timedOut: true,\n };\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n } else {\n await streamDone.catch(() => {});\n }\n\n if (this._killed) {\n return {\n success: false,\n exitCode: this._exitCode ?? 137,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n killed: true,\n timedOut: false,\n };\n }\n\n await this._resolveExitCode();\n\n return {\n success: this._exitCode === 0,\n exitCode: this._exitCode ?? 1,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n };\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n this._killed = true;\n this._exitCode = 137; // SIGKILL\n // The remote process may continue running; Modal JS SDK has no per-exec kill.\n try {\n await this._stdoutReader?.cancel();\n } catch {\n // Ignore cancellation errors\n }\n try {\n await this._stderrReader?.cancel();\n } catch {\n // Ignore cancellation errors\n }\n return true;\n }\n\n async sendStdin(_data: string): Promise<void> {\n throw new Error('Modal JS SDK does not expose stdin on exec() — sendStdin() is not supported');\n }\n}\n\n// =============================================================================\n// Modal Process Manager\n// =============================================================================\n\nexport interface ModalProcessManagerOptions {\n env?: Record<string, string | undefined>;\n}\n\n/**\n * Modal implementation of SandboxProcessManager.\n * Uses the Modal SDK's exec() API with one ContainerProcess per spawn.\n */\nexport class ModalProcessManager extends SandboxProcessManager<ModalSandbox> {\n private _spawnCounter = 0;\n\n constructor(opts: ModalProcessManagerOptions = {}) {\n super({ env: opts.env });\n }\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n return this.sandbox.retryOnDead(async () => {\n const sb = this.sandbox.modal;\n\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 // exec() takes string[] — wrap in sh -c to support pipes, redirects, etc.\n const argv = ['sh', '-c', command];\n\n const proc = await sb.exec(argv, {\n env: Object.keys(env).length > 0 ? env : undefined,\n workdir: options.cwd,\n timeoutMs: options.timeout,\n });\n\n const pid = `modal-proc-${Date.now().toString(36)}-${++this._spawnCounter}`;\n const handle = new ModalProcessHandle(pid, proc, Date.now(), options);\n\n const stdoutReader = proc.stdout.getReader();\n const stderrReader = proc.stderr.getReader();\n handle.setReaders(stdoutReader, stderrReader);\n\n const streamingPromise = Promise.all([\n drainReader(stdoutReader, chunk => handle.emitStdout(chunk)),\n drainReader(stderrReader, chunk => handle.emitStderr(chunk)),\n ]).then(() => {});\n\n handle.streamingPromise = streamingPromise;\n\n this._tracked.set(pid, handle);\n return handle;\n });\n }\n\n async list(): Promise<ProcessInfo[]> {\n const result: ProcessInfo[] = [];\n for (const [pid, handle] of this._tracked) {\n result.push({\n pid,\n command: handle.command,\n running: handle.exitCode === undefined,\n exitCode: handle.exitCode,\n });\n }\n return result;\n }\n}\n\n// =============================================================================\n// Stream Helpers\n// =============================================================================\n\n/** Reads chunks from a stream until done or cancelled. */\nasync function drainReader(reader: ReadableStreamDefaultReader<string>, emit: (chunk: string) => void): Promise<void> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n emit(value);\n }\n } catch {\n // cancelled or network error\n }\n}\n","/**\n * @see https://modal.com/docs/reference/modal.Sandbox\n */\n\nimport type { MastraSandboxOptions, ProviderStatus, SandboxCloneOptions, SandboxInfo } from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxNotReadyError } from '@mastra/core/workspace';\nimport { ClientClosedError, ModalClient, NotFoundError } from 'modal';\nimport type { App, Image, Sandbox } from 'modal';\nimport { ModalProcessManager } from './process-manager';\n\nconst LOG_PREFIX = '[ModalSandbox]';\n\n// =============================================================================\n// Options\n// =============================================================================\n\ntype InstructionsOption = string | ((opts: { defaultInstructions: string }) => string);\n\n/**\n * Modal sandbox provider configuration.\n */\nexport interface ModalSandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Stable name for this sandbox. Reusing the same id reconnects to a running sandbox. */\n id?: string;\n /**\n * Modal App name to associate sandboxes with.\n *\n * @default 'mastra'\n */\n appName?: string;\n /**\n * Docker image to use for the sandbox.\n *\n * @default 'ubuntu:22.04'\n */\n baseImage?: string;\n /**\n * Wall-clock max lifetime in milliseconds. The sandbox is terminated when this expires,\n * regardless of activity. Modal's maximum is 24 hours (86_400_000).\n *\n * @default 300_000 // 5 minutes\n */\n timeoutMs?: number;\n /** Environment variables baked into the sandbox at create time. */\n env?: Record<string, string>;\n /** Default working directory inside the sandbox. */\n workdir?: string;\n /** Modal token ID. Falls back to MODAL_TOKEN_ID env var. */\n tokenId?: string;\n /** Modal token secret. Falls back to MODAL_TOKEN_SECRET env var. */\n tokenSecret?: string;\n /** Custom instructions for getInstructions(). String replaces the default; function receives it. */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// ModalSandbox\n// =============================================================================\n\n/**\n * Modal cloud sandbox provider for Mastra workspaces.\n *\n * @example\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { ModalSandbox } from '@mastra/modal';\n *\n * const sandbox = new ModalSandbox({\n * baseImage: 'ubuntu:22.04',\n * timeoutMs: 60_000,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCommand('echo hello');\n * ```\n */\nexport class ModalSandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'ModalSandbox';\n readonly provider = 'modal';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: ModalProcessManager;\n\n private _sb: Sandbox | null = null;\n private _imageSnapshot: Image | null = null; // for stop-and-resume\n private _client: ModalClient | null = null;\n private _createdAt: Date | null = null;\n private _isRetrying = false;\n\n private readonly appName: string;\n private readonly baseImage: string;\n private readonly timeoutMs: number;\n private readonly env: Record<string, string>;\n private readonly workdir?: string;\n private readonly tokenId?: string;\n private readonly tokenSecret?: string;\n private readonly _instructionsOverride?: InstructionsOption;\n private readonly _constructorOptions: ModalSandboxOptions;\n\n constructor(options: ModalSandboxOptions = {}) {\n super({\n ...options,\n name: 'ModalSandbox',\n processes: new ModalProcessManager({ env: options.env ?? {} }),\n });\n\n this.id = options.id ?? this._generateId();\n this.appName = options.appName ?? 'mastra';\n this.baseImage = options.baseImage ?? 'ubuntu:22.04';\n this.timeoutMs = options.timeoutMs ?? 300_000;\n this.env = options.env ?? {};\n this.workdir = options.workdir;\n this.tokenId = options.tokenId;\n this.tokenSecret = options.tokenSecret;\n this._instructionsOverride = options.instructions;\n this._constructorOptions = { ...options };\n }\n\n /**\n * Construct a sibling `ModalSandbox` that inherits this sandbox's\n * configuration (credentials, app, base image, workdir, instructions) with\n * per-instance overrides.\n *\n * Performs no I/O — the sandbox clone provisions (or reconnects to a\n * running Modal sandbox with the same logical `id`) on its own `start()`.\n * Use it when one configured sandbox acts as the template for a fleet of\n * independent sandboxes (e.g. one per project).\n *\n * `options.idleTimeoutMinutes` maps to Modal's `timeoutMs` (wall-clock\n * lifetime); `options.sandboxId` is ignored because Modal reconnects by\n * logical `id`.\n */\n clone(options: SandboxCloneOptions = {}): ModalSandbox {\n const { id: _id, ...base } = this._constructorOptions;\n return new ModalSandbox({\n ...base,\n ...(options.id !== undefined && { id: options.id }),\n ...(options.env !== undefined && { env: options.env }),\n ...(options.idleTimeoutMinutes !== undefined && { timeoutMs: options.idleTimeoutMinutes * 60_000 }),\n });\n }\n\n /**\n * Get the underlying Modal Sandbox instance for direct SDK access.\n *\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get modal(): Sandbox {\n if (!this._sb) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._sb;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /** Reconnects to a running sandbox with this id if one exists, otherwise creates a new one. */\n async start(): Promise<void> {\n if (this._sb) {\n return;\n }\n\n const client = this._getClient();\n\n try {\n this._sb = await client.sandboxes.fromName(this.appName, this.id);\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Reconnected to running sandbox: ${this.id}`);\n return;\n } catch (error) {\n if (!(error instanceof NotFoundError)) {\n throw error;\n }\n }\n\n const app: App = await client.apps.fromName(this.appName, { createIfMissing: true });\n\n if (this._imageSnapshot) {\n this.logger.debug(`${LOG_PREFIX} Rebooting from snapshot: ${this.id}`);\n this._sb = await client.sandboxes.create(app, this._imageSnapshot, {\n name: this.id,\n timeoutMs: this.timeoutMs,\n env: Object.keys(this.env).length > 0 ? this.env : undefined,\n workdir: this.workdir,\n });\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Created new sandbox from snapshot: ${this._sb?.sandboxId}`);\n return;\n }\n\n const image: Image = client.images.fromRegistry(this.baseImage);\n this.logger.debug(`${LOG_PREFIX} Creating sandbox: ${this.id} (baseImage: ${this.baseImage})`);\n this._sb = await client.sandboxes.create(app, image, {\n name: this.id,\n timeoutMs: this.timeoutMs,\n env: Object.keys(this.env).length > 0 ? this.env : undefined,\n workdir: this.workdir,\n });\n this._createdAt = new Date();\n this.logger.debug(`${LOG_PREFIX} Created sandbox: ${this._sb.sandboxId}`);\n }\n\n /**\n * Snapshot the sandbox filesystem before terminating it.\n * Future starts will create net-new sandboxes from the snapshot.\n */\n async stop(): Promise<void> {\n if (!this._sb) return;\n\n try {\n const procs = await this.processes.list();\n await Promise.all(procs.filter(p => p.running).map(p => this.processes.kill(p.pid)));\n } catch {\n // Best-effort: sandbox may already be dead\n }\n\n try {\n this._imageSnapshot = await this._sb.snapshotFilesystem();\n this.logger.debug(`${LOG_PREFIX} Snapshot created: ${this._imageSnapshot.imageId}`);\n } catch (error) {\n this.logger.debug(`${LOG_PREFIX} Snapshot failed, terminating without snapshot:`, error);\n }\n\n try {\n await this._sb.terminate({ wait: true });\n this.logger.debug(`${LOG_PREFIX} Sandbox terminated: ${this._sb.sandboxId}`);\n this._sb = null;\n } catch (error) {\n // Best-effort: sandbox may already be dead\n if (this.isSandboxDeadError(error)) {\n this._sb = null;\n } else {\n throw error;\n }\n }\n }\n\n /** Terminates the sandbox, ending its lifetime. Unlike stop(), no snapshot is preserved. */\n async destroy(): Promise<void> {\n if (this._sb) {\n try {\n const procs = await this.processes.list();\n await Promise.all(procs.filter(p => p.running).map(p => this.processes.kill(p.pid)));\n } catch {\n // Best-effort: sandbox may already be dead\n }\n\n try {\n await this._sb.terminate();\n this.logger.debug(`${LOG_PREFIX} Sandbox terminated: ${this._sb.sandboxId}`);\n } catch {\n // Ignore errors during destroy\n }\n\n this._sb = null;\n }\n\n this._imageSnapshot = null;\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 appName: this.appName,\n image: this._imageSnapshot?.imageId ?? this.baseImage,\n timeoutMs: this.timeoutMs,\n },\n };\n }\n\n getInstructions(): string {\n const defaultInstructions = this._getDefaultInstructions();\n if (this._instructionsOverride === undefined) return defaultInstructions;\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return this._instructionsOverride({ defaultInstructions });\n }\n\n private _getDefaultInstructions(): string {\n return `Modal cloud sandbox running ${this.baseImage}. Use executeCommand() to run shell commands.`;\n }\n\n // ---------------------------------------------------------------------------\n // Dead-sandbox Retry\n // ---------------------------------------------------------------------------\n\n private isSandboxDeadError(error: unknown): boolean {\n if (!error) return false;\n if (error instanceof ClientClosedError) return true;\n if (error instanceof NotFoundError) return true;\n const errorStr = String(error);\n return (\n errorStr.includes('sandbox not found') ||\n errorStr.includes('has been terminated') ||\n errorStr.includes('already completed') ||\n errorStr.includes('was cancelled') ||\n // gRPC NOT_FOUND (code 5)\n /status[:\\s]+5\\b/.test(errorStr) ||\n errorStr.includes('NOT_FOUND')\n );\n }\n\n private handleSandboxDead(): void {\n this._sb = null;\n this.status = 'stopped';\n }\n\n /** @internal Retries fn() once after restarting if the sandbox is dead. */\n async retryOnDead<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n if (this.isSandboxDeadError(error) && !this._isRetrying) {\n this.handleSandboxDead();\n this._isRetrying = true;\n try {\n await this.ensureRunning();\n return await fn();\n } finally {\n this._isRetrying = false;\n }\n }\n throw error;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal Helpers\n // ---------------------------------------------------------------------------\n\n private _generateId(): string {\n return `modal-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n private _getClient(): ModalClient {\n if (!this._client) {\n this._client = new ModalClient({\n ...(this.tokenId && { tokenId: this.tokenId }),\n ...(this.tokenSecret && { tokenSecret: this.tokenSecret }),\n });\n }\n return this._client;\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @see https://modal.com/docs/reference/modal.Sandbox
3
3
  */
4
- import type { MastraSandboxOptions, ProviderStatus, SandboxInfo } from '@mastra/core/workspace';
4
+ import type { MastraSandboxOptions, ProviderStatus, SandboxCloneOptions, SandboxInfo } from '@mastra/core/workspace';
5
5
  import { MastraSandbox } from '@mastra/core/workspace';
6
6
  import type { Sandbox } from 'modal';
7
7
  import { ModalProcessManager } from './process-manager.js';
@@ -80,7 +80,23 @@ export declare class ModalSandbox extends MastraSandbox {
80
80
  private readonly tokenId?;
81
81
  private readonly tokenSecret?;
82
82
  private readonly _instructionsOverride?;
83
+ private readonly _constructorOptions;
83
84
  constructor(options?: ModalSandboxOptions);
85
+ /**
86
+ * Construct a sibling `ModalSandbox` that inherits this sandbox's
87
+ * configuration (credentials, app, base image, workdir, instructions) with
88
+ * per-instance overrides.
89
+ *
90
+ * Performs no I/O — the sandbox clone provisions (or reconnects to a
91
+ * running Modal sandbox with the same logical `id`) on its own `start()`.
92
+ * Use it when one configured sandbox acts as the template for a fleet of
93
+ * independent sandboxes (e.g. one per project).
94
+ *
95
+ * `options.idleTimeoutMinutes` maps to Modal's `timeoutMs` (wall-clock
96
+ * lifetime); `options.sandboxId` is ignored because Modal reconnects by
97
+ * logical `id`.
98
+ */
99
+ clone(options?: SandboxCloneOptions): ModalSandbox;
84
100
  /**
85
101
  * Get the underlying Modal Sandbox instance for direct SDK access.
86
102
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAChG,OAAO,EAAE,aAAa,EAAwB,MAAM,wBAAwB,CAAC;AAE7E,OAAO,KAAK,EAAc,OAAO,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAQxD,KAAK,kBAAkB,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE;IAAE,mBAAmB,EAAE,MAAM,CAAA;CAAE,KAAK,MAAM,CAAC,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC;IAClF,yFAAyF;IACzF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,YAAa,SAAQ,aAAa;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,QAAQ,WAAW;IAC5B,MAAM,EAAE,cAAc,CAAa;IAEnC,SAAiB,SAAS,EAAE,mBAAmB,CAAC;IAEhD,OAAO,CAAC,GAAG,CAAwB;IACnC,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAyB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAqB;gBAEhD,OAAO,GAAE,mBAAwB;IAkB7C;;;;OAIG;IACH,IAAI,KAAK,IAAI,OAAO,CAKnB;IAMD,+FAA+F;IACzF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6C5B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B3B,4FAA4F;IACtF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBxB,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC;IAerC,eAAe,IAAI,MAAM;IAOzB,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,iBAAiB;IAKzB,2EAA2E;IACrE,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAsBtD,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,UAAU;CASnB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/modal",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Modal cloud sandbox provider for Mastra workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -23,18 +23,18 @@
23
23
  "modal": "^0.7.3"
24
24
  },
25
25
  "devDependencies": {
26
- "@types/node": "22.19.21",
27
- "@vitest/coverage-v8": "4.1.8",
28
- "@vitest/ui": "4.1.8",
26
+ "@types/node": "22.20.1",
27
+ "@vitest/coverage-v8": "4.1.10",
28
+ "@vitest/ui": "4.1.10",
29
29
  "dotenv": "^17.4.2",
30
- "eslint": "^10.4.1",
30
+ "eslint": "^10.7.0",
31
31
  "tsup": "^8.5.1",
32
32
  "typescript": "^6.0.3",
33
- "vitest": "4.1.8",
34
- "@internal/types-builder": "0.0.82",
35
- "@internal/lint": "0.0.107",
36
- "@mastra/core": "1.45.0",
37
- "@internal/workspace-test-utils": "0.0.51"
33
+ "vitest": "4.1.10",
34
+ "@internal/lint": "0.0.115",
35
+ "@internal/types-builder": "0.0.90",
36
+ "@internal/workspace-test-utils": "0.0.59",
37
+ "@mastra/core": "1.52.0"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@mastra/core": ">=1.12.0-0 <2.0.0-0"