@mastra/daytona 0.9.0-alpha.1 → 0.9.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/dist/index.js CHANGED
@@ -617,6 +617,8 @@ function validateMountPath(mountPath) {
617
617
  }
618
618
  /** Allowlist for marker filenames from ls output — e.g. "mount-abc123" */
619
619
  const SAFE_MARKER_NAME = /^mount-[a-z0-9]+$/;
620
+ /** Default port of the noVNC web viewer started by Daytona computer use. */
621
+ const DEFAULT_NOVNC_PORT = 6080;
620
622
  /** Patterns indicating the sandbox is dead/gone (@daytonaio/sdk@0.143.0). */
621
623
  const SANDBOX_DEAD_PATTERNS = [
622
624
  /sandbox is not running/i,
@@ -689,6 +691,9 @@ var DaytonaSandbox = class DaytonaSandbox extends MastraSandbox {
689
691
  _createdAt = null;
690
692
  _workingDir = null;
691
693
  _isRetrying = false;
694
+ _computerUseStarted = null;
695
+ computerUseAutoStart;
696
+ noVncPort;
692
697
  timeout;
693
698
  language;
694
699
  resources;
@@ -741,6 +746,10 @@ var DaytonaSandbox = class DaytonaSandbox extends MastraSandbox {
741
746
  ...options.target !== void 0 && { target: options.target }
742
747
  };
743
748
  this._constructorOptions = { ...options };
749
+ const computerUseOption = options.computerUse ?? true;
750
+ this.computerUseAutoStart = typeof computerUseOption === "object" ? computerUseOption.autoStart ?? true : true;
751
+ this.noVncPort = typeof computerUseOption === "object" ? computerUseOption.noVncPort ?? DEFAULT_NOVNC_PORT : DEFAULT_NOVNC_PORT;
752
+ if (computerUseOption !== false) this.computer = this.createComputer();
744
753
  }
745
754
  generateId() {
746
755
  return `daytona-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -875,6 +884,7 @@ var DaytonaSandbox = class DaytonaSandbox extends MastraSandbox {
875
884
  await this._daytona.stop(this._sandbox);
876
885
  } catch {}
877
886
  this._sandbox = null;
887
+ this._computerUseStarted = null;
878
888
  }
879
889
  /**
880
890
  * Destroy the Daytona sandbox and clean up all resources.
@@ -891,6 +901,7 @@ var DaytonaSandbox = class DaytonaSandbox extends MastraSandbox {
891
901
  this._sandbox = null;
892
902
  this._daytonaSandboxId = void 0;
893
903
  this._daytona = null;
904
+ this._computerUseStarted = null;
894
905
  this.mounts?.clear();
895
906
  }
896
907
  /**
@@ -954,6 +965,96 @@ var DaytonaSandbox = class DaytonaSandbox extends MastraSandbox {
954
965
  })));
955
966
  }
956
967
  /**
968
+ * Ensure the Daytona computer use processes (Xvfb, xfce4, x11vnc, noVNC)
969
+ * are running. Memoized per attached sandbox; the memo is reset when the
970
+ * sandbox stops, dies, or is destroyed so a fresh sandbox restarts them.
971
+ */
972
+ async ensureComputerUseStarted() {
973
+ if (!this.computerUseAutoStart) return;
974
+ if (!this._computerUseStarted) this._computerUseStarted = this.daytona.computerUse.start().then(() => void 0).catch((error) => {
975
+ this._computerUseStarted = null;
976
+ throw error;
977
+ });
978
+ return this._computerUseStarted;
979
+ }
980
+ /**
981
+ * Build the {@link SandboxComputer} capability backed by Daytona's
982
+ * computer use API (`sandbox.computerUse`).
983
+ *
984
+ * Every operation ensures the sandbox is running and the desktop processes
985
+ * are started, and retries once if the sandbox died (mirroring command
986
+ * execution behavior).
987
+ */
988
+ createComputer() {
989
+ const run = async (fn) => {
990
+ await this.ensureRunning();
991
+ return this.retryOnDead(async () => {
992
+ await this.ensureComputerUseStarted();
993
+ return fn(this.daytona.computerUse);
994
+ });
995
+ };
996
+ return {
997
+ screenshot: async () => {
998
+ const response = await run((computerUse) => computerUse.screenshot.takeFullScreen());
999
+ if (!response.screenshot) throw new Error(`${LOG_PREFIX} Daytona returned an empty screenshot response`);
1000
+ return {
1001
+ data: new Uint8Array(Buffer.from(response.screenshot, "base64")),
1002
+ mediaType: "image/png"
1003
+ };
1004
+ },
1005
+ leftClick: async (x, y) => {
1006
+ await run((computerUse) => computerUse.mouse.click(x, y, "left"));
1007
+ },
1008
+ rightClick: async (x, y) => {
1009
+ await run((computerUse) => computerUse.mouse.click(x, y, "right"));
1010
+ },
1011
+ doubleClick: async (x, y) => {
1012
+ await run((computerUse) => computerUse.mouse.click(x, y, "left", true));
1013
+ },
1014
+ moveMouse: async (x, y) => {
1015
+ await run((computerUse) => computerUse.mouse.move(x, y));
1016
+ },
1017
+ drag: async (from, to) => {
1018
+ await run((computerUse) => computerUse.mouse.drag(from.x, from.y, to.x, to.y));
1019
+ },
1020
+ scroll: async (direction, amount) => {
1021
+ await run(async (computerUse) => {
1022
+ const position = await computerUse.mouse.getPosition();
1023
+ return computerUse.mouse.scroll(position.x ?? 0, position.y ?? 0, direction, amount);
1024
+ });
1025
+ },
1026
+ type: async (text) => {
1027
+ await run((computerUse) => computerUse.keyboard.type(text));
1028
+ },
1029
+ press: async (key) => {
1030
+ await run((computerUse) => Array.isArray(key) ? computerUse.keyboard.hotkey(key.join("+")) : computerUse.keyboard.press(key));
1031
+ },
1032
+ getScreenSize: async () => {
1033
+ const info = await run((computerUse) => computerUse.display.getInfo());
1034
+ const display = info.displays?.find((d) => d.isActive) ?? info.displays?.[0];
1035
+ if (!display || display.width === void 0 || display.height === void 0) throw new Error(`${LOG_PREFIX} Daytona did not return display information`);
1036
+ return {
1037
+ width: display.width,
1038
+ height: display.height
1039
+ };
1040
+ },
1041
+ getCursorPosition: async () => {
1042
+ const position = await run((computerUse) => computerUse.mouse.getPosition());
1043
+ return {
1044
+ x: position.x ?? 0,
1045
+ y: position.y ?? 0
1046
+ };
1047
+ },
1048
+ streamUrl: async () => {
1049
+ try {
1050
+ return (await run(() => this.daytona.getPreviewLink(this.noVncPort)))?.url ?? null;
1051
+ } catch {
1052
+ return null;
1053
+ }
1054
+ }
1055
+ };
1056
+ }
1057
+ /**
957
1058
  * Mount a filesystem at a path in the sandbox.
958
1059
  * Uses FUSE tools (s3fs, gcsfuse) to mount cloud storage.
959
1060
  */
@@ -1388,6 +1489,7 @@ var DaytonaSandbox = class DaytonaSandbox extends MastraSandbox {
1388
1489
  */
1389
1490
  handleSandboxTimeout() {
1390
1491
  this._sandbox = null;
1492
+ this._computerUseStarted = null;
1391
1493
  if (this.mounts) {
1392
1494
  for (const [path, entry] of this.mounts.entries) if (entry.state === "mounted" || entry.state === "mounting") this.mounts.set(path, { state: "pending" });
1393
1495
  }