import type { FactorySandbox, FactorySandboxContext as CoreFactorySandboxContext, MastraSandbox, SandboxStartHook, WorkspaceSandbox } from '@mastra/core/workspace'; /** * Everything factory knows about a session's sandbox needs: the whole contract * between factory and the host's FactorySandbox. Factory owns intent; the * provider owns resolving `sessionId` to a runnable VM. Defined in * `@mastra/core/workspace` so provider packages can implement it without * depending on factory. */ export type FactorySandboxContext = CoreFactorySandboxContext; /** * The deploy's sandbox configuration: construct a session's sandbox from * intent. The sandbox identity is the session id; the provider must honor * id-keyed getOrCreate on `start()` (reconnect/resume an existing VM for the * id, create otherwise). Construction must be cheap and side-effect-free — * VMs are provisioned on `start()` only. Local sandboxes should root their * `workingDirectory` at a per-session directory (e.g. * `join(root, ctx.sessionId)`); the repo checks out as a subdirectory of it. * * Forward `ctx.sandboxId` to providers that reattach by physical id so resume * reattaches the original VM instead of provisioning a replacement. * * Returns a `MastraSandbox`, not the bare `WorkspaceSandbox` interface: * factory relies on the base class for the start lifecycle and the runtime * env, so providers extend it rather than reimplementing the contract. * * Factory attaches its own session setup to the returned sandbox, so the * callback never has to wire it up. A callback may still pass its own * `onStart`; it runs after factory's setup, against a prepared workspace. * * @example * ```typescript * sandbox: ({ sessionId, sandboxId }) => new E2BSandbox({ id: sessionId, sandboxId }) * ``` * * A FactorySandbox instance (for example `new E2BFactorySandbox({ apiKey })`) * additionally exposes settings and template builds to the environment. */ export type MastraFactorySandboxConfig = (ctx: FactorySandboxContext) => MastraSandbox; /** * The `sandbox` option of `MastraFactoryConfig`: a FactorySandbox instance * (it owns the session sandbox constructor, the repo template and the * environment settings schema) or a bare callback, which the factory wraps as a `provider: 'custom'` sandbox with no settings. */ export type MastraFactorySandboxOption = FactorySandbox | MastraFactorySandboxConfig; /** * What the start hook learned about the setup command before running the * session setup, and how to record its completion afterwards. */ export interface SessionSetupGate { /** True when the sandbox already carries a marker for the current setup command. */ setupDone: boolean; /** Write the marker once the setup command succeeded. Best-effort. */ markSetupDone: () => Promise; } /** * The session's setup work, run against a started sandbox on EVERY start. * Materialize and checkout are idempotent and must always run (a warm boot * still needs its pull); only the setup command consults `gate`. */ export type SessionSetupRun = (sandbox: WorkspaceSandbox, workdir: string, gate: SessionSetupGate) => Promise; /** One environment repository as the boot hook needs it: its slug and setup command. */ export interface SessionEnvironmentRepository { slug: string; setupCommand?: string; } /** What the environment hook learned about one repository before the boot runs. */ export interface SessionEnvironmentRepositoryGate extends SessionEnvironmentRepository { /** `/`, the directory the template cloned this repository into. */ dir: string; gate: SessionSetupGate; } /** The environment hook's view of the workspace: the root, every repository in position order, the workspace gate. */ export interface SessionEnvironmentGate { /** The workspace root, parent of every repository directory. */ root: string; repos: SessionEnvironmentRepositoryGate[]; /** Gate for `workspaceSetupCommand`; `setupDone` when there is no command or its marker matches. */ workspace: SessionSetupGate; } /** The list-form session boot: run on every start, like `SessionSetupRun`. */ export type SessionEnvironmentSetupRun = (sandbox: WorkspaceSandbox, environment: SessionEnvironmentGate) => Promise; /** * Per-process session-id → sandbox instance memo. * * The provider contract is id-keyed getOrCreate, but provider find-then-create * has a real double-create race across independent instances. Memoizing the * instance per session makes the base class's per-instance start coalescing * apply process-wide per session — the same single-flight scope the fleet's * per-binding coalescing provided. Cross-replica races are accepted (the * fleet was also per-replica). */ interface SessionSandboxEntry { sandbox: WorkspaceSandbox; /** * The session's repo checkout root, recorded for passive readers (fs * routes, capture, authz). Local sandboxes derive it at construction; * remote sandboxes clone into the VM's own home, so it is undefined until * `resolveSessionWorkdir` probes the first started VM — passive readers * treat an unresolved workdir as "nothing materialized". */ workdir?: string; /** The session's own repository, the only one `workdir` is ever recorded for. */ ownRepo: string; /** Environment repositories in position order; the session's own repository is among them. */ repos?: string[]; } /** One environment repository as the file readers see it. */ export interface SessionLayoutRepository { slug: string; /** Absolute checkout directory. */ dir: string; /** Path prefix of this checkout under the layout root: empty for a single-repository session, `/` otherwise. */ prefix: string; } /** * Where a session's files are read from. A session with one repository is * rooted at that checkout, as before environments existed; a session with * several is rooted at the workspace root with each checkout as a directory * beneath it. */ export interface SessionLayout { root: string; repos: SessionLayoutRepository[]; } /** The layout of a memoized session, `undefined` until its workdir resolved. */ export declare function sessionLayout(entry: SessionSandboxEntry | undefined): SessionLayout | undefined; /** * Get the session's memoized sandbox entry, constructing (and memoizing) it on * first access. Construction is cheap and side-effect-free by contract; VMs * are provisioned on `start()` only. Local sandboxes get their workdir here; * remote workdirs are a runtime fact of the VM, resolved on first start. */ export declare function getSessionSandbox(sessionId: string, repoFullName: string, construct: () => WorkspaceSandbox, repos?: string[]): SessionSandboxEntry; /** * Resolve (and memoize on the session entry) the session's repo checkout * root. Local sandboxes answer synchronously from their configured * `workingDirectory`; remote sandboxes clone into the VM's own default cwd, * so the first resolution probes it with one `pwd` — the VM tells us where * home is, we never invent a path. Calling this against a stopped sandbox * lazily starts it (the probe is a command), so passive readers must peek * `entry.workdir` instead. The memo is the session's own checkout; another * environment repository lives beside it under the same root, so it is * answered from the memo's parent without a second probe. */ export declare function resolveSessionWorkdir(sessionId: string, sandbox: WorkspaceSandbox, repoFullName: string): Promise; /** * The session's memoized sandbox (and its workdir) when one was already * constructed in this process, else undefined. Never constructs — passive * read paths use this so browsing files cannot provision a VM. */ export declare function peekSessionSandbox(sessionId: string): SessionSandboxEntry | undefined; /** Drop the memoized instance (on stop/destroy/retirement or construction failure). */ export declare function evictSessionSandbox(sessionId: string): void; /** Test-only: reset the process-wide memo between tests. */ export declare function __clearSessionSandboxesForTests(): void; export declare function recordFailedSetupCommand(sessionId: string, command: string): void; export declare function hasFailedSetupCommand(sessionId: string, command: string): boolean; /** * Build the session setup hook, which factory attaches to the constructed * sandbox with `setOnStart`. Runs inside the sandbox start lifecycle on * every start, fresh VM or reconnect: materialize and checkout always run, * and the setup command runs unless the sandbox already carries the marker * for it (a warm template image, or an earlier successful start). Throwing * fails `start()` loudly; core treats onStart errors as fatal. */ export declare function createSessionSetupHook(run: SessionSetupRun, sessionId: string, repoFullName: string, setupCommand: string | undefined): SandboxStartHook; /** * The list-form start hook for a session whose factory has an environment: * the same lifecycle as `createSessionSetupHook`, with one gate per * repository plus one for the workspace setup command. The markers are the * ones the multi-repo templates write (`.mastra-sandbox/repos/`, * `.mastra-sandbox/workspace-setup`, `.mastra-sandbox/setup-failed`), all * under the workspace root, which is the parent of the primary repository's * directory: `resolveSessionWorkdir` keeps answering that directory so the * PR tools and passive readers see the primary checkout, and the root is * derived from it rather than probed twice. * * `repos` is in position order and must include the primary (`repoFullName`). */ export declare function createEnvironmentSetupHook(run: SessionEnvironmentSetupRun, sessionId: string, repoFullName: string, environment: { repos: SessionEnvironmentRepository[]; workspaceSetupCommand?: string; }): SandboxStartHook; export {}; //# sourceMappingURL=session-sandbox.d.ts.map