@mastra/editor 0.8.2-alpha.0 → 0.9.0-alpha.1

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,27 @@
1
1
  # @mastra/editor
2
2
 
3
+ ## 0.9.0-alpha.1
4
+
5
+ ### Minor Changes
6
+
7
+ - `EditorWorkspaceNamespace` can now snapshot a live `Workspace` for persistence — the reverse of `hydrateSnapshotToWorkspace()`: ([#16673](https://github.com/mastra-ai/mastra/pull/16673))
8
+
9
+ ```ts
10
+ const snapshot = await editor.workspace.snapshotFromWorkspace(runtimeWorkspace);
11
+ await editor.workspace.create({ id: 'my-workspace', ...snapshot });
12
+ ```
13
+
14
+ `snapshotFromWorkspace()` is `async` and awaits `sandbox.getInfo()` and `filesystem.getInfo()` so async providers like `CompositeFilesystem` keep their mount metadata in the stored config.
15
+
16
+ Also includes two smaller behavioral fixes:
17
+ - `EditorSkillNamespace.publishSkillFromSource()` stores the new `files` field on the published skill version and strips `undefined` keys before calling `update()` (libsql/pg adapters reject `undefined` bind arguments).
18
+ - `CrudEditorNamespace.clearCache(id)` always calls `onCacheEvict(id)`, even when the entity wasn't cached, so subclasses can clean up runtime registries for version-specific lookups that bypass the editor cache.
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies [[`5ba7253`](https://github.com/mastra-ai/mastra/commit/5ba7253745c85e8df8012a76d954c640ffa336f7), [`f73980d`](https://github.com/mastra-ai/mastra/commit/f73980d651eb5f7f1ab20582de4615a1b6f10fce), [`9c88701`](https://github.com/mastra-ai/mastra/commit/9c8870195b41a38dc40b6ba2aa55eda04df8fa69), [`4e88dc6`](https://github.com/mastra-ai/mastra/commit/4e88dc6b89f154c0eae37221c8126be0c23c569f), [`19018f0`](https://github.com/mastra-ai/mastra/commit/19018f05722af74a5978781a7731a654b26f7f2a)]:
23
+ - @mastra/core@1.36.0-alpha.2
24
+
3
25
  ## 0.8.2-alpha.0
4
26
 
5
27
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -154,11 +154,8 @@ var CrudEditorNamespace = class extends EditorNamespace {
154
154
  */
155
155
  clearCache(id) {
156
156
  if (id) {
157
- const wasCached = this._cache.has(id);
158
157
  this._cache.delete(id);
159
- if (wasCached) {
160
- this.onCacheEvict(id);
161
- }
158
+ this.onCacheEvict(id);
162
159
  this.logger?.debug(`[clearCache] Cleared cache for "${id}"`);
163
160
  } else {
164
161
  for (const cachedId of Array.from(this._cache.keys())) {
@@ -1804,6 +1801,59 @@ var EditorWorkspaceNamespace = class extends CrudEditorNamespace {
1804
1801
  }
1805
1802
  return new import_workspace2.Workspace(config);
1806
1803
  }
1804
+ /**
1805
+ * Serialize a runtime Workspace instance into a StorageWorkspaceSnapshotType.
1806
+ * The reverse of hydrateSnapshotToWorkspace — extracts provider IDs and config
1807
+ * from live filesystem/sandbox instances so the workspace can be persisted to the DB.
1808
+ */
1809
+ async snapshotFromWorkspace(workspace) {
1810
+ const snapshot = {
1811
+ name: workspace.name
1812
+ };
1813
+ const fs = workspace.filesystem;
1814
+ if (fs) {
1815
+ if (fs instanceof import_workspace2.CompositeFilesystem) {
1816
+ const mounts = {};
1817
+ for (const [mountPath, mountedFs] of fs.mounts) {
1818
+ mounts[mountPath] = await this.serializeFilesystem(mountedFs);
1819
+ }
1820
+ snapshot.mounts = mounts;
1821
+ } else {
1822
+ snapshot.filesystem = await this.serializeFilesystem(fs);
1823
+ }
1824
+ }
1825
+ const sandbox = workspace.sandbox;
1826
+ if (sandbox) {
1827
+ const info = typeof sandbox.getInfo === "function" ? await sandbox.getInfo() : void 0;
1828
+ snapshot.sandbox = {
1829
+ provider: sandbox.provider,
1830
+ config: info?.metadata ?? {}
1831
+ };
1832
+ }
1833
+ const tools = workspace.getToolsConfig();
1834
+ if (tools) {
1835
+ const storageTools = {};
1836
+ if (typeof tools.enabled === "boolean") storageTools.enabled = tools.enabled;
1837
+ if (typeof tools.requireApproval === "boolean") storageTools.requireApproval = tools.requireApproval;
1838
+ if (Object.keys(storageTools).length > 0) {
1839
+ snapshot.tools = storageTools;
1840
+ }
1841
+ }
1842
+ return snapshot;
1843
+ }
1844
+ /**
1845
+ * Serialize a runtime WorkspaceFilesystem into a StorageFilesystemConfig.
1846
+ * Awaits getInfo() so async providers like CompositeFilesystem keep their mount metadata.
1847
+ */
1848
+ async serializeFilesystem(fs) {
1849
+ const info = typeof fs.getInfo === "function" ? await fs.getInfo() : void 0;
1850
+ const metadata = info && typeof info === "object" && "metadata" in info ? info.metadata : void 0;
1851
+ return {
1852
+ provider: fs.provider,
1853
+ config: metadata ?? {},
1854
+ readOnly: fs.readOnly
1855
+ };
1856
+ }
1807
1857
  /**
1808
1858
  * Resolve a stored filesystem config to a runtime WorkspaceFilesystem instance.
1809
1859
  * Looks up the provider by ID in the editor's registry (which includes built-in providers).
@@ -1880,11 +1930,16 @@ var EditorSkillNamespace = class extends CrudEditorNamespace {
1880
1930
  const blobStore = await this.editor.resolveBlobStore();
1881
1931
  if (!blobStore)
1882
1932
  throw new Error("No blob store is configured. Register one via new MastraEditor({ blobStores: [...] })");
1883
- const { snapshot, tree } = await (0, import_workspace3.publishSkillFromSource)(source, skillPath, blobStore);
1933
+ const { snapshot, tree, files } = await (0, import_workspace3.publishSkillFromSource)(source, skillPath, blobStore);
1934
+ const snapshotUpdate = {};
1935
+ for (const [key, value] of Object.entries(snapshot)) {
1936
+ if (value !== void 0) snapshotUpdate[key] = value;
1937
+ }
1884
1938
  await skillStore.update({
1885
1939
  id: skillId,
1886
- ...snapshot,
1940
+ ...snapshotUpdate,
1887
1941
  tree,
1942
+ files,
1888
1943
  status: "published"
1889
1944
  });
1890
1945
  const latestVersion = await skillStore.getLatestVersion(skillId);
package/dist/index.d.cts CHANGED
@@ -275,6 +275,17 @@ declare class EditorWorkspaceNamespace extends CrudEditorNamespace<StorageCreate
275
275
  hydrateSnapshotToWorkspace(id: string, snapshot: StorageWorkspaceSnapshotType, options?: {
276
276
  skillSource?: SkillSource;
277
277
  }): Promise<Workspace<WorkspaceFilesystem | undefined, WorkspaceSandbox | undefined, Record<string, WorkspaceFilesystem> | undefined>>;
278
+ /**
279
+ * Serialize a runtime Workspace instance into a StorageWorkspaceSnapshotType.
280
+ * The reverse of hydrateSnapshotToWorkspace — extracts provider IDs and config
281
+ * from live filesystem/sandbox instances so the workspace can be persisted to the DB.
282
+ */
283
+ snapshotFromWorkspace(workspace: Workspace): Promise<StorageWorkspaceSnapshotType>;
284
+ /**
285
+ * Serialize a runtime WorkspaceFilesystem into a StorageFilesystemConfig.
286
+ * Awaits getInfo() so async providers like CompositeFilesystem keep their mount metadata.
287
+ */
288
+ private serializeFilesystem;
278
289
  /**
279
290
  * Resolve a stored filesystem config to a runtime WorkspaceFilesystem instance.
280
291
  * Looks up the provider by ID in the editor's registry (which includes built-in providers).
package/dist/index.d.ts CHANGED
@@ -275,6 +275,17 @@ declare class EditorWorkspaceNamespace extends CrudEditorNamespace<StorageCreate
275
275
  hydrateSnapshotToWorkspace(id: string, snapshot: StorageWorkspaceSnapshotType, options?: {
276
276
  skillSource?: SkillSource;
277
277
  }): Promise<Workspace<WorkspaceFilesystem | undefined, WorkspaceSandbox | undefined, Record<string, WorkspaceFilesystem> | undefined>>;
278
+ /**
279
+ * Serialize a runtime Workspace instance into a StorageWorkspaceSnapshotType.
280
+ * The reverse of hydrateSnapshotToWorkspace — extracts provider IDs and config
281
+ * from live filesystem/sandbox instances so the workspace can be persisted to the DB.
282
+ */
283
+ snapshotFromWorkspace(workspace: Workspace): Promise<StorageWorkspaceSnapshotType>;
284
+ /**
285
+ * Serialize a runtime WorkspaceFilesystem into a StorageFilesystemConfig.
286
+ * Awaits getInfo() so async providers like CompositeFilesystem keep their mount metadata.
287
+ */
288
+ private serializeFilesystem;
278
289
  /**
279
290
  * Resolve a stored filesystem config to a runtime WorkspaceFilesystem instance.
280
291
  * Looks up the provider by ID in the editor's registry (which includes built-in providers).
package/dist/index.js CHANGED
@@ -106,11 +106,8 @@ var CrudEditorNamespace = class extends EditorNamespace {
106
106
  */
107
107
  clearCache(id) {
108
108
  if (id) {
109
- const wasCached = this._cache.has(id);
110
109
  this._cache.delete(id);
111
- if (wasCached) {
112
- this.onCacheEvict(id);
113
- }
110
+ this.onCacheEvict(id);
114
111
  this.logger?.debug(`[clearCache] Cleared cache for "${id}"`);
115
112
  } else {
116
113
  for (const cachedId of Array.from(this._cache.keys())) {
@@ -1683,7 +1680,7 @@ Explain your reasoning for this score in a clear, concise paragraph.`;
1683
1680
  };
1684
1681
 
1685
1682
  // src/namespaces/workspace.ts
1686
- import { Workspace as Workspace2 } from "@mastra/core/workspace";
1683
+ import { Workspace as Workspace2, CompositeFilesystem } from "@mastra/core/workspace";
1687
1684
  var EditorWorkspaceNamespace = class extends CrudEditorNamespace {
1688
1685
  onCacheEvict(_id) {
1689
1686
  }
@@ -1756,6 +1753,59 @@ var EditorWorkspaceNamespace = class extends CrudEditorNamespace {
1756
1753
  }
1757
1754
  return new Workspace2(config);
1758
1755
  }
1756
+ /**
1757
+ * Serialize a runtime Workspace instance into a StorageWorkspaceSnapshotType.
1758
+ * The reverse of hydrateSnapshotToWorkspace — extracts provider IDs and config
1759
+ * from live filesystem/sandbox instances so the workspace can be persisted to the DB.
1760
+ */
1761
+ async snapshotFromWorkspace(workspace) {
1762
+ const snapshot = {
1763
+ name: workspace.name
1764
+ };
1765
+ const fs = workspace.filesystem;
1766
+ if (fs) {
1767
+ if (fs instanceof CompositeFilesystem) {
1768
+ const mounts = {};
1769
+ for (const [mountPath, mountedFs] of fs.mounts) {
1770
+ mounts[mountPath] = await this.serializeFilesystem(mountedFs);
1771
+ }
1772
+ snapshot.mounts = mounts;
1773
+ } else {
1774
+ snapshot.filesystem = await this.serializeFilesystem(fs);
1775
+ }
1776
+ }
1777
+ const sandbox = workspace.sandbox;
1778
+ if (sandbox) {
1779
+ const info = typeof sandbox.getInfo === "function" ? await sandbox.getInfo() : void 0;
1780
+ snapshot.sandbox = {
1781
+ provider: sandbox.provider,
1782
+ config: info?.metadata ?? {}
1783
+ };
1784
+ }
1785
+ const tools = workspace.getToolsConfig();
1786
+ if (tools) {
1787
+ const storageTools = {};
1788
+ if (typeof tools.enabled === "boolean") storageTools.enabled = tools.enabled;
1789
+ if (typeof tools.requireApproval === "boolean") storageTools.requireApproval = tools.requireApproval;
1790
+ if (Object.keys(storageTools).length > 0) {
1791
+ snapshot.tools = storageTools;
1792
+ }
1793
+ }
1794
+ return snapshot;
1795
+ }
1796
+ /**
1797
+ * Serialize a runtime WorkspaceFilesystem into a StorageFilesystemConfig.
1798
+ * Awaits getInfo() so async providers like CompositeFilesystem keep their mount metadata.
1799
+ */
1800
+ async serializeFilesystem(fs) {
1801
+ const info = typeof fs.getInfo === "function" ? await fs.getInfo() : void 0;
1802
+ const metadata = info && typeof info === "object" && "metadata" in info ? info.metadata : void 0;
1803
+ return {
1804
+ provider: fs.provider,
1805
+ config: metadata ?? {},
1806
+ readOnly: fs.readOnly
1807
+ };
1808
+ }
1759
1809
  /**
1760
1810
  * Resolve a stored filesystem config to a runtime WorkspaceFilesystem instance.
1761
1811
  * Looks up the provider by ID in the editor's registry (which includes built-in providers).
@@ -1832,11 +1882,16 @@ var EditorSkillNamespace = class extends CrudEditorNamespace {
1832
1882
  const blobStore = await this.editor.resolveBlobStore();
1833
1883
  if (!blobStore)
1834
1884
  throw new Error("No blob store is configured. Register one via new MastraEditor({ blobStores: [...] })");
1835
- const { snapshot, tree } = await publishSkillFromSource(source, skillPath, blobStore);
1885
+ const { snapshot, tree, files } = await publishSkillFromSource(source, skillPath, blobStore);
1886
+ const snapshotUpdate = {};
1887
+ for (const [key, value] of Object.entries(snapshot)) {
1888
+ if (value !== void 0) snapshotUpdate[key] = value;
1889
+ }
1836
1890
  await skillStore.update({
1837
1891
  id: skillId,
1838
- ...snapshot,
1892
+ ...snapshotUpdate,
1839
1893
  tree,
1894
+ files,
1840
1895
  status: "published"
1841
1896
  });
1842
1897
  const latestVersion = await skillStore.getLatestVersion(skillId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/editor",
3
- "version": "0.8.2-alpha.0",
3
+ "version": "0.9.0-alpha.1",
4
4
  "description": "Mastra Editor for agent management and instantiation",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -65,8 +65,8 @@
65
65
  "@arcadeai/arcadejs": "^2.3.0",
66
66
  "@composio/core": "^0.6.5",
67
67
  "@composio/mastra": "^0.6.5",
68
- "@mastra/schema-compat": "1.2.10",
69
- "@mastra/memory": "1.18.3-alpha.0"
68
+ "@mastra/memory": "1.18.3-alpha.0",
69
+ "@mastra/schema-compat": "1.2.10"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@hono/node-server": "^1.19.11",
@@ -76,11 +76,11 @@
76
76
  "vitest": "4.1.5",
77
77
  "zod": "^3.25.76",
78
78
  "@internal/ai-sdk-v4": "0.0.43",
79
- "@internal/ai-v6": "0.0.43",
80
79
  "@internal/ai-sdk-v5": "0.0.43",
81
- "@mastra/hono": "1.4.18-alpha.0",
80
+ "@mastra/hono": "1.4.18-alpha.2",
81
+ "@mastra/core": "1.36.0-alpha.2",
82
+ "@internal/ai-v6": "0.0.43",
82
83
  "@mastra/libsql": "1.11.0",
83
- "@mastra/core": "1.36.0-alpha.0",
84
84
  "@mastra/mcp": "1.7.1-alpha.0"
85
85
  },
86
86
  "peerDependencies": {