@mastra/daytona 0.1.0-alpha.0 → 0.2.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,119 @@
1
1
  # @mastra/daytona
2
2
 
3
+ ## 0.2.0-alpha.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added provider-specific `daytona` getter to access the underlying Daytona `Sandbox` instance directly. Deprecated the generic `instance` getter in favor of the new `daytona` getter for better IDE discoverability and consistency with other sandbox providers. ([#14166](https://github.com/mastra-ai/mastra/pull/14166))
8
+
9
+ ```typescript
10
+ // Before
11
+ const daytonaSandbox = sandbox.instance;
12
+
13
+ // After
14
+ const daytonaSandbox = sandbox.daytona;
15
+ ```
16
+
17
+ ### Patch Changes
18
+
19
+ - Improved Daytona process handling to use provider session IDs directly as `ProcessHandle.pid`. ([#13591](https://github.com/mastra-ai/mastra/pull/13591))
20
+
21
+ ```typescript
22
+ const handle = await sandbox.processes.spawn('node server.js');
23
+ await sandbox.processes.get(handle.pid);
24
+ ```
25
+
26
+ - Fixed sandbox reconnection when Daytona sandbox is externally stopped or times out due to inactivity. Previously, the error thrown by the Daytona SDK (e.g. "failed to resolve container IP") did not match the known dead-sandbox patterns, so the automatic retry logic would not trigger and the error would propagate to the user. Added two new error patterns to correctly detect stopped sandboxes and trigger automatic recovery. ([#14175](https://github.com/mastra-ai/mastra/pull/14175))
27
+
28
+ - dependencies updates: ([#13591](https://github.com/mastra-ai/mastra/pull/13591))
29
+ - Updated peerDependency `@mastra/core` to `>=1.12.0-0 <2.0.0-0`
30
+ - Updated dependencies [[`9cede11`](https://github.com/mastra-ai/mastra/commit/9cede110abac9d93072e0521bb3c8bcafb9fdadf), [`a59f126`](https://github.com/mastra-ai/mastra/commit/a59f1269104f54726699c5cdb98c72c93606d2df), [`c510833`](https://github.com/mastra-ai/mastra/commit/c5108333e8cbc19dafee5f8bfefbcb5ee935335c), [`7296fcc`](https://github.com/mastra-ai/mastra/commit/7296fcc599c876a68699a71c7054a16d5aaf2337), [`00c27f9`](https://github.com/mastra-ai/mastra/commit/00c27f9080731433230a61be69c44e39a7a7b4c7), [`ee19c9b`](https://github.com/mastra-ai/mastra/commit/ee19c9ba3ec3ed91feb214ad539bdc766c53bb01)]:
31
+ - @mastra/core@1.12.0-alpha.1
32
+
33
+ ## 0.1.0
34
+
35
+ ### Minor Changes
36
+
37
+ - Add DaytonaSandbox workspace provider — Daytona cloud sandbox integration for Mastra workspaces, implementing the WorkspaceSandbox interface with support for command execution, environment variables, resource configuration, snapshots, and Daytona volumes. ([#13112](https://github.com/mastra-ai/mastra/pull/13112))
38
+
39
+ **Basic usage**
40
+
41
+ ```ts
42
+ import { Workspace } from '@mastra/core/workspace';
43
+ import { DaytonaSandbox } from '@mastra/daytona';
44
+
45
+ const sandbox = new DaytonaSandbox({
46
+ id: 'my-sandbox',
47
+ env: { NODE_ENV: 'production' },
48
+ });
49
+
50
+ const workspace = new Workspace({ sandbox });
51
+ await workspace.init();
52
+
53
+ const result = await workspace.sandbox.executeCommand('echo', ['Hello!']);
54
+ console.log(result.stdout); // "Hello!"
55
+
56
+ await workspace.destroy();
57
+ ```
58
+
59
+ - Added S3 and GCS cloud filesystem mounting support via FUSE (s3fs-fuse, gcsfuse). Daytona sandboxes can now mount cloud storage as local directories, matching the mount capabilities of E2B and Blaxel providers. ([#13544](https://github.com/mastra-ai/mastra/pull/13544))
60
+
61
+ **New methods:**
62
+ - `mount(filesystem, mountPath)` — Mount an S3 or GCS filesystem at a path in the sandbox
63
+ - `unmount(mountPath)` — Unmount a previously mounted filesystem
64
+
65
+ **What changed:**
66
+ - Added S3 and GCS bucket mounts as local directories in Daytona sandboxes.
67
+ - Improved reconnect behavior so mounts are restored reliably.
68
+ - Added safety checks to prevent mounting into non-empty directories.
69
+ - Improved concurrent mount support by isolating credentials per mount.
70
+
71
+ **Usage:**
72
+
73
+ ```typescript
74
+ import { Workspace } from '@mastra/core/workspace';
75
+ import { S3Filesystem } from '@mastra/s3';
76
+ import { DaytonaSandbox } from '@mastra/daytona';
77
+
78
+ const workspace = new Workspace({
79
+ mounts: {
80
+ '/data': new S3Filesystem({
81
+ bucket: 'my-bucket',
82
+ region: 'us-east-1',
83
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
84
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
85
+ }),
86
+ },
87
+ sandbox: new DaytonaSandbox(),
88
+ });
89
+ ```
90
+
91
+ ### Patch Changes
92
+
93
+ - Remove internal `processes` field from sandbox provider options ([#13597](https://github.com/mastra-ai/mastra/pull/13597))
94
+
95
+ The `processes` field is no longer exposed in constructor options for E2B, Daytona, and Blaxel sandbox providers. This field is managed internally and was not intended to be user-configurable.
96
+
97
+ - Improved S3/GCS FUSE mounting reliability and sandbox reconnection. ([#13543](https://github.com/mastra-ai/mastra/pull/13543))
98
+
99
+ **Mounting improvements**
100
+ - Replaced direct SDK coupling in mount helpers with callback-based context, making mount operations more testable and resilient
101
+ - Added tmpfs overlay to handle FUSE-on-FUSE remount scenarios that previously failed with ENOENT
102
+ - Added `mount --move` fallback when standard FUSE unmount fails on stuck mounts
103
+ - `stop()` now unmounts all filesystems before stopping the sandbox
104
+ - Added early connectivity check for GCS mounting that detects Daytona's restricted internet tiers and fails fast with an actionable error message instead of hanging
105
+ - Improved gcsfuse installation with distro-aware codename detection (bookworm for Debian, jammy for Ubuntu)
106
+ - Added input validation for bucket names, endpoints, and credentials before interpolating into shell commands
107
+
108
+ **Reconnection improvements**
109
+ - `findExistingSandbox` now looks up sandboxes by name first (works for stopped sandboxes), then falls back to label search
110
+ - Added transitional state handling that polls and waits when a sandbox is starting/stopping/restoring before attempting to start it, avoiding "State change in progress" errors
111
+
112
+ - Sandbox instructions no longer include a working directory path, keeping instructions stable across sessions. ([#13520](https://github.com/mastra-ai/mastra/pull/13520))
113
+
114
+ - Updated dependencies [[`504fc8b`](https://github.com/mastra-ai/mastra/commit/504fc8b9d0ddab717577ad3bf9c95ea4bd5377bd), [`f9c150b`](https://github.com/mastra-ai/mastra/commit/f9c150b7595ad05ad9cc9a11098e2944361e8c22), [`88de7e8`](https://github.com/mastra-ai/mastra/commit/88de7e8dfe4b7e1951a9e441bb33136e705ce24e), [`edee4b3`](https://github.com/mastra-ai/mastra/commit/edee4b37dff0af515fc7cc0e8d71ee39e6a762f0), [`3790c75`](https://github.com/mastra-ai/mastra/commit/3790c7578cc6a47d854eb12d89e6b1912867fe29), [`e7a235b`](https://github.com/mastra-ai/mastra/commit/e7a235be6472e0c870ed6c791ddb17c492dc188b), [`d51d298`](https://github.com/mastra-ai/mastra/commit/d51d298953967aab1f58ec965b644d109214f085), [`6dbeeb9`](https://github.com/mastra-ai/mastra/commit/6dbeeb94a8b1eebb727300d1a98961f882180794), [`d5f0d8d`](https://github.com/mastra-ai/mastra/commit/d5f0d8d6a03e515ddaa9b5da19b7e44b8357b07b), [`09c3b18`](https://github.com/mastra-ai/mastra/commit/09c3b1802ff14e243a8a8baea327440bc8cc2e32), [`b896379`](https://github.com/mastra-ai/mastra/commit/b8963791c6afa79484645fcec596a201f936b9a2), [`85c84eb`](https://github.com/mastra-ai/mastra/commit/85c84ebb78aebfcba9d209c8e152b16d7a00cb71), [`a89272a`](https://github.com/mastra-ai/mastra/commit/a89272a5d71939b9fcd284e6a6dc1dd091a6bdcf), [`ee9c8df`](https://github.com/mastra-ai/mastra/commit/ee9c8df644f19d055af5f496bf4942705f5a47b7), [`77b4a25`](https://github.com/mastra-ai/mastra/commit/77b4a254e51907f8ff3a3ba95596a18e93ae4b35), [`276246e`](https://github.com/mastra-ai/mastra/commit/276246e0b9066a1ea48bbc70df84dbe528daaf99), [`08ecfdb`](https://github.com/mastra-ai/mastra/commit/08ecfdbdad6fb8285deef86a034bdf4a6047cfca), [`d5f628c`](https://github.com/mastra-ai/mastra/commit/d5f628ca86c6f6f3ff1035d52f635df32dd81cab), [`524c0f3`](https://github.com/mastra-ai/mastra/commit/524c0f3c434c3d9d18f66338dcef383d6161b59c), [`c18a0e9`](https://github.com/mastra-ai/mastra/commit/c18a0e9cef1e4ca004b2963d35e4cfc031971eac), [`4bd21ea`](https://github.com/mastra-ai/mastra/commit/4bd21ea43d44d0a0427414fc047577f9f0aa3bec), [`115a7a4`](https://github.com/mastra-ai/mastra/commit/115a7a47db5e9896fec12ae6507501adb9ec89bf), [`22a48ae`](https://github.com/mastra-ai/mastra/commit/22a48ae2513eb54d8d79dad361fddbca97a155e8), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9311c17`](https://github.com/mastra-ai/mastra/commit/9311c17d7a0640d9c4da2e71b814dc67c57c6369), [`7edf78f`](https://github.com/mastra-ai/mastra/commit/7edf78f80422c43e84585f08ba11df0d4d0b73c5), [`1c4221c`](https://github.com/mastra-ai/mastra/commit/1c4221cf6032ec98d0e094d4ee11da3e48490d96), [`d25b9ea`](https://github.com/mastra-ai/mastra/commit/d25b9eabd400167255a97b690ffbc4ee4097ded5), [`fe1ce5c`](https://github.com/mastra-ai/mastra/commit/fe1ce5c9211c03d561606fda95cbfe7df1d9a9b5), [`b03c0e0`](https://github.com/mastra-ai/mastra/commit/b03c0e0389a799523929a458b0509c9e4244d562), [`0a8366b`](https://github.com/mastra-ai/mastra/commit/0a8366b0a692fcdde56c4d526e4cf03c502ae4ac), [`85664e9`](https://github.com/mastra-ai/mastra/commit/85664e9fd857320fbc245e301f764f45f66f32a3), [`bc79650`](https://github.com/mastra-ai/mastra/commit/bc796500c6e0334faa158a96077e3fb332274869), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4), [`3a3a59e`](https://github.com/mastra-ai/mastra/commit/3a3a59e8ffaa6a985fe3d9a126a3f5ade11a6724), [`3108d4e`](https://github.com/mastra-ai/mastra/commit/3108d4e649c9fddbf03253a6feeb388a5fa9fa5a), [`0c33b2c`](https://github.com/mastra-ai/mastra/commit/0c33b2c9db537f815e1c59e2c898ffce2e395a79), [`191e5bd`](https://github.com/mastra-ai/mastra/commit/191e5bd29b82f5bda35243945790da7bc7b695c2), [`f77cd94`](https://github.com/mastra-ai/mastra/commit/f77cd94c44eabed490384e7d19232a865e13214c), [`e8135c7`](https://github.com/mastra-ai/mastra/commit/e8135c7e300dac5040670eec7eab896ac6092e30), [`daca48f`](https://github.com/mastra-ai/mastra/commit/daca48f0fb17b7ae0b62a2ac40cf0e491b2fd0b7), [`257d14f`](https://github.com/mastra-ai/mastra/commit/257d14faca5931f2e4186fc165b6f0b1f915deee), [`352f25d`](https://github.com/mastra-ai/mastra/commit/352f25da316b24cdd5b410fd8dddf6a8b763da2a), [`93477d0`](https://github.com/mastra-ai/mastra/commit/93477d0769b8a13ea5ed73d508d967fb23eaeed9), [`31c78b3`](https://github.com/mastra-ai/mastra/commit/31c78b3eb28f58a8017f1dcc795c33214d87feac), [`0bc0720`](https://github.com/mastra-ai/mastra/commit/0bc07201095791858087cc56f353fcd65e87ab54), [`36516ac`](https://github.com/mastra-ai/mastra/commit/36516aca1021cbeb42e74751b46a2614101f37c8), [`e947652`](https://github.com/mastra-ai/mastra/commit/e9476527fdecb4449e54570e80dfaf8466901254), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4), [`ec248f6`](https://github.com/mastra-ai/mastra/commit/ec248f6b56e8a037c066c49b2178e2507471d988)]:
115
+ - @mastra/core@1.9.0
116
+
3
117
  ## 0.1.0-alpha.0
4
118
 
5
119
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -250,7 +250,6 @@ Sandbox network response: ${checkOutput}` : "")
250
250
  }
251
251
  var DaytonaProcessHandle = class extends workspace.ProcessHandle {
252
252
  pid;
253
- _sessionId;
254
253
  _cmdId;
255
254
  _sandbox;
256
255
  _startTime;
@@ -259,10 +258,9 @@ var DaytonaProcessHandle = class extends workspace.ProcessHandle {
259
258
  _waitPromise = null;
260
259
  _streamingPromise = null;
261
260
  _killed = false;
262
- constructor(pid, sessionId, cmdId, sandbox, startTime, options) {
261
+ constructor(sessionId, cmdId, sandbox, startTime, options) {
263
262
  super(options);
264
- this.pid = pid;
265
- this._sessionId = sessionId;
263
+ this.pid = sessionId;
266
264
  this._cmdId = cmdId;
267
265
  this._sandbox = sandbox;
268
266
  this._startTime = startTime;
@@ -280,7 +278,7 @@ var DaytonaProcessHandle = class extends workspace.ProcessHandle {
280
278
  async _resolveExitCode() {
281
279
  if (this._exitCode !== void 0) return;
282
280
  try {
283
- const cmd = await this._sandbox.process.getSessionCommand(this._sessionId, this._cmdId);
281
+ const cmd = await this._sandbox.process.getSessionCommand(this.pid, this._cmdId);
284
282
  this._exitCode = cmd.exitCode ?? 0;
285
283
  } catch {
286
284
  if (this._exitCode === void 0) {
@@ -346,7 +344,7 @@ var DaytonaProcessHandle = class extends workspace.ProcessHandle {
346
344
  this._killed = true;
347
345
  this._exitCode = 137;
348
346
  try {
349
- await this._sandbox.process.deleteSession(this._sessionId);
347
+ await this._sandbox.process.deleteSession(this.pid);
350
348
  } catch {
351
349
  }
352
350
  return true;
@@ -355,11 +353,11 @@ var DaytonaProcessHandle = class extends workspace.ProcessHandle {
355
353
  if (this._exitCode !== void 0) {
356
354
  throw new Error(`Process ${this.pid} has already exited with code ${this._exitCode}`);
357
355
  }
358
- await this._sandbox.process.sendSessionCommandInput(this._sessionId, this._cmdId, data);
356
+ await this._sandbox.process.sendSessionCommandInput(this.pid, this._cmdId, data);
359
357
  }
360
358
  };
361
359
  var DaytonaProcessManager = class extends workspace.SandboxProcessManager {
362
- _nextPid = 1;
360
+ _spawnCounter = 0;
363
361
  _defaultTimeout;
364
362
  constructor(opts = {}) {
365
363
  super({ env: opts.env });
@@ -371,20 +369,19 @@ var DaytonaProcessManager = class extends workspace.SandboxProcessManager {
371
369
  timeout: options.timeout ?? this._defaultTimeout
372
370
  };
373
371
  return this.sandbox.retryOnDead(async () => {
374
- const sandbox = this.sandbox.instance;
375
- const pid = this._nextPid++;
372
+ const sandbox = this.sandbox.daytona;
376
373
  const mergedEnv = { ...this.env, ...effectiveOptions.env };
377
374
  const envs = Object.fromEntries(
378
375
  Object.entries(mergedEnv).filter((entry) => entry[1] !== void 0)
379
376
  );
380
377
  const sessionCommand = buildSpawnCommand(command, effectiveOptions.cwd, envs);
381
- const sessionId = `mastra-proc-${Date.now().toString(36)}-${pid}`;
378
+ const sessionId = `mastra-proc-${Date.now().toString(36)}-${++this._spawnCounter}`;
382
379
  await sandbox.process.createSession(sessionId);
383
380
  const { cmdId } = await sandbox.process.executeSessionCommand(sessionId, {
384
381
  command: sessionCommand,
385
382
  runAsync: true
386
383
  });
387
- const handle = new DaytonaProcessHandle(pid, sessionId, cmdId, sandbox, Date.now(), effectiveOptions);
384
+ const handle = new DaytonaProcessHandle(sessionId, cmdId, sandbox, Date.now(), effectiveOptions);
388
385
  const streamingPromise = sandbox.process.getSessionCommandLogs(
389
386
  sessionId,
390
387
  cmdId,
@@ -393,7 +390,7 @@ var DaytonaProcessManager = class extends workspace.SandboxProcessManager {
393
390
  ).catch(() => {
394
391
  });
395
392
  handle.streamingPromise = streamingPromise;
396
- this._tracked.set(pid, handle);
393
+ this._tracked.set(handle.pid, handle);
397
394
  return handle;
398
395
  });
399
396
  }
@@ -409,9 +406,6 @@ var DaytonaProcessManager = class extends workspace.SandboxProcessManager {
409
406
  }
410
407
  return result;
411
408
  }
412
- async get(pid) {
413
- return this._tracked.get(pid);
414
- }
415
409
  };
416
410
  function buildSpawnCommand(command, cwd, envs) {
417
411
  const parts = [];
@@ -458,7 +452,9 @@ var SAFE_MARKER_NAME = /^mount-[a-z0-9]+$/;
458
452
  var SANDBOX_DEAD_PATTERNS = [
459
453
  /sandbox is not running/i,
460
454
  /sandbox already destroyed/i,
461
- /sandbox.*not found/i
455
+ /sandbox.*not found/i,
456
+ /failed to resolve container IP/i,
457
+ /is the sandbox started/i
462
458
  ];
463
459
  var DaytonaSandbox = class _DaytonaSandbox extends workspace.MastraSandbox {
464
460
  id;
@@ -535,16 +531,21 @@ var DaytonaSandbox = class _DaytonaSandbox extends workspace.MastraSandbox {
535
531
  *
536
532
  * @example Direct file operations
537
533
  * ```typescript
538
- * const daytonaSandbox = sandbox.instance;
534
+ * await sandbox.start();
535
+ * const daytonaSandbox = sandbox.daytona;
539
536
  * await daytonaSandbox.fs.uploadFile(Buffer.from('Hello'), '/tmp/test.txt');
540
537
  * ```
541
538
  */
542
- get instance() {
539
+ get daytona() {
543
540
  if (!this._sandbox) {
544
541
  throw new workspace.SandboxNotReadyError(this.id);
545
542
  }
546
543
  return this._sandbox;
547
544
  }
545
+ /** @deprecated Use `daytona` instead. */
546
+ get instance() {
547
+ return this.daytona;
548
+ }
548
549
  // ---------------------------------------------------------------------------
549
550
  // Lifecycle
550
551
  // ---------------------------------------------------------------------------