You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Summary
Carves PARA-3 (Option B + D) from the `yj/magnificent-marquess` feature
branch — a small, plumbing-only slice of editor namespace fixes that
don't depend on STACK-1 (server permission foundation) or the
agent-builder runtime.
This is foundation work for the agent-builder feature branch but ships
independently with no user-visible behavior changes.
## What's in this PR
### `@mastra/core` (publish.ts)
- `SkillPublishResult` now includes a `files` field with the full skill
file tree and base64-encoded blob content (`StorageSkillFileNode[]`).
- Adds `parseSkillSnapshotFromFiles()` helper and `SkillSnapshotFile`
type for parsing skill snapshot frontmatter from flat file lists.
### `@mastra/editor`
- **base.ts**: `CrudEditorNamespace.clearCache(id)` always calls
`onCacheEvict(id)`, even when the entry wasn't cached. Lets subclasses
clean up runtime registries (e.g. `mastra.#agents`) for version-specific
lookups that bypass the editor cache.
- **skill.ts**: Stores the new `files` field on publish, and strips
`undefined` keys from the snapshot before `update()` so libsql/pg
adapters don't reject `undefined` as a bind argument.
- **workspace.ts**: Adds `snapshotFromWorkspace()` and
`serializeFilesystem()` — the reverse of `hydrateSnapshotToWorkspace()`
— to round-trip a live `Workspace` instance (`CompositeFilesystem`
mounts, sandbox provider, tools config) into a
`StorageWorkspaceSnapshotType` for persistence.
## What's NOT in this PR
Deferred to later PRs (Option A, agent-builder-bound):
- `agent.ts` namespace builder defaults / model policy / browser refs /
visibility (~241 lines)
- `favorites.ts` namespace + tests (STACK-3)
- `MastraEditor` class extensions (`__browsers`, `__builderConfig`,
`ensureBuilderWorkspaces()`, etc.)
- `IMastraEditor` browser/builder method implementations
- `BrowserProvider` type, `StorageBrowserRef`, `MastraBrowser`
## Dependencies
- Branches off `main`, no STACK-1 dependency.
- No runtime impact on existing users:
- `SkillPublishResult.files` is purely additive — existing `{ snapshot,
tree }` destructures keep working.
- `clearCache()` change is a no-op for subclasses that don't override
`onCacheEvict()`.
- `snapshotFromWorkspace()` is a new method, no existing callers.
## Test plan
- `pnpm --filter @mastra/core typecheck` — clean
- `pnpm --filter @mastra/editor typecheck` — clean
- `pnpm --filter @mastra/editor test` — 372 passed / 13 skipped (385
total)
## Changesets
- `silly-wolves-dance.md` — `@mastra/core` minor (publish.ts `files`
field + helpers)
- `brave-tigers-cheer.md` — `@mastra/editor` minor (namespace polish)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
This PR improves how the editor handles skill files and workspace
snapshots: it records the full file tree for published skills, makes
cache eviction reliably trigger cleanup hooks, and adds a way to
serialize a live workspace for storage. These are internal plumbing
changes to prepare for agent-builder work and don't change user-facing
behavior.
---
## Changes Summary
### `@mastra/core` – `packages/core/src/workspace/skills/publish.ts`
- Added `files: StorageSkillFileNode[]` to `SkillPublishResult` — a
UI-facing nested file tree with base64-encoded content for each file.
- Exported `parseSkillSnapshotFromFiles(files: SkillSnapshotFile[])` to
parse SKILL.md frontmatter and derive denormalized snapshot fields from
a flat file list; introduced the `SkillSnapshotFile` type.
- `collectSkillForPublish()` / `publishSkillFromSource()` now build the
nested file nodes (including base64 blobs for binary files) and return
`files`; missing SKILL.md is rethrown with a clearer error.
### `@mastra/editor` – `packages/editor/src/namespaces/base.ts`
- `CrudEditorNamespace.clearCache(id)` now always calls
`onCacheEvict(id)` even when the id wasn't present in the cache,
allowing subclasses to perform runtime cleanup for entries that may
bypass the cache.
### `@mastra/editor` – `packages/editor/src/namespaces/skill.ts`
- `EditorSkillNamespace.publish` captures the new `files` from
`publishSkillFromSource()` and persists it on the skill record.
- Before calling `skillStore.update()`, builds a `snapshotUpdate` object
that strips keys with `undefined` values to avoid adapter bind errors
(libsql/pg).
### `@mastra/editor` – `packages/editor/src/namespaces/workspace.ts`
- Added `snapshotFromWorkspace(workspace: Workspace):
Promise<StorageWorkspaceSnapshotType>` to serialize a live Workspace
into a storage snapshot.
- Added `serializeFilesystem()` helper to serialize primary or mounted
filesystems, calling `fs.getInfo()` when available to preserve provider
metadata.
- Serializes sandbox info via `sandbox.getInfo()` (when present) and
copies static workspace tools settings (`enabled`, `requireApproval`)
into the stored tools config.
---
## Compatibility & Safety
- Additive, backward-compatible API change: `SkillPublishResult.files`
is optional/additive for callers that ignore it.
- `clearCache()` behavior is a no-op for subclasses that don't override
`onCacheEvict()`.
- `snapshotFromWorkspace()` is new and has no existing callers.
- No STACK-1 dependency; branches off main.
- Typechecks pass for `@mastra/core` and `@mastra/editor`. Tests: 372
passed / 13 skipped.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16673?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
`snapshotFromWorkspace()` is `async` and awaits `sandbox.getInfo()` and `filesystem.getInfo()` so async providers like `CompositeFilesystem` keep their mount metadata in the stored config.
13
+
14
+
Also includes two smaller behavioral fixes:
15
+
16
+
-`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).
17
+
-`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.
`publishSkillFromSource()` (and `collectSkillForPublish()`) now return a `files` field containing the full skill source as a tree of `StorageSkillFileNode` entries with base64-encoded blob content — handy for storing a UI-facing copy of a skill alongside its content-addressable tree:
0 commit comments