@mastra/code-sdk 1.1.1-alpha.0 → 1.1.1-alpha.3
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 +34 -0
- package/dist/agents/prompts/agent-instructions.d.ts +41 -2
- package/dist/agents/prompts/agent-instructions.d.ts.map +1 -1
- package/dist/agents/prompts/agent-instructions.js +122 -12
- package/dist/agents/prompts/agent-instructions.js.map +1 -1
- package/dist/agents/prompts/index.d.ts.map +1 -1
- package/dist/agents/prompts/index.js +8 -2
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/sandbox-filesystem.d.ts +10 -0
- package/dist/agents/sandbox-filesystem.d.ts.map +1 -1
- package/dist/agents/sandbox-filesystem.js +95 -21
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +60 -16
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +15 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -0
- package/dist/schema.js.map +1 -1
- package/package.json +12 -11
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { posix } from "path";
|
|
2
|
+
import { FileExistsError, FileNotFoundError, IsDirectoryError } from "@mastra/core/workspace";
|
|
2
3
|
//#region src/agents/sandbox-filesystem.ts
|
|
3
4
|
/**
|
|
4
5
|
* SandboxFilesystem
|
|
@@ -14,6 +15,13 @@ import { posix } from "path";
|
|
|
14
15
|
*
|
|
15
16
|
* Reads/writes use base64 over the wire so binary content survives the shell.
|
|
16
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* Sentinel exit codes used by guard clauses that run before the real command,
|
|
20
|
+
* so shell failures can be mapped to typed filesystem errors.
|
|
21
|
+
*/
|
|
22
|
+
const EXIT_NOT_FOUND = 20;
|
|
23
|
+
const EXIT_IS_DIRECTORY = 21;
|
|
24
|
+
const EXIT_EXISTS = 22;
|
|
17
25
|
/** Default per-command deadline so a hung sandbox can't block file tools forever. */
|
|
18
26
|
const COMMAND_TIMEOUT_MS = 3e4;
|
|
19
27
|
/** Single-quote a string for safe POSIX shell interpolation. */
|
|
@@ -37,14 +45,21 @@ var SandboxFilesystem = class {
|
|
|
37
45
|
constructor(options) {
|
|
38
46
|
this.sandbox = options.sandbox;
|
|
39
47
|
this.basePath = options.workdir;
|
|
40
|
-
this.id = options.id ?? `sandbox-fs:${options.sandbox.id}`;
|
|
48
|
+
this.id = options.id ?? `sandbox-fs:${options.sandbox.id}:${options.workdir}`;
|
|
41
49
|
}
|
|
42
50
|
/**
|
|
43
51
|
* Resolve a workspace path to an absolute path inside the sandbox, enforcing
|
|
44
52
|
* that it stays within the workdir.
|
|
53
|
+
*
|
|
54
|
+
* Accepts both workspace-relative paths (`src/foo.ts`, `/src/foo.ts`) and
|
|
55
|
+
* absolute sandbox paths that already live under the workdir — the agent's
|
|
56
|
+
* prompt advertises the workdir as its working directory, so tools are
|
|
57
|
+
* routinely called with fully-qualified paths like `<workdir>/src/foo.ts`.
|
|
45
58
|
*/
|
|
46
59
|
resolve(inputPath) {
|
|
47
|
-
const
|
|
60
|
+
const base = posix.normalize(this.basePath);
|
|
61
|
+
const normalizedInput = posix.normalize(inputPath);
|
|
62
|
+
const rel = normalizedInput === base ? "" : normalizedInput.startsWith(`${base}/`) ? normalizedInput.slice(base.length + 1) : inputPath.startsWith("/") ? inputPath.slice(1) : inputPath;
|
|
48
63
|
const resolved = posix.normalize(posix.join(this.basePath, rel));
|
|
49
64
|
const root = posix.normalize(this.basePath);
|
|
50
65
|
if (resolved !== root && !resolved.startsWith(`${root}/`)) throw new Error(`Path escapes workspace root: ${inputPath}`);
|
|
@@ -60,12 +75,25 @@ var SandboxFilesystem = class {
|
|
|
60
75
|
* Lexical guard catches `..` traversal, but a symlink inside the workdir can
|
|
61
76
|
* still point outside it. After resolving a path that refers to an existing
|
|
62
77
|
* entry, verify its realpath is still contained in the workdir.
|
|
78
|
+
*
|
|
79
|
+
* Canonicalization tries `realpath`, then `readlink -f` (GNU/busybox), then
|
|
80
|
+
* `cd && pwd -P` for directories — covering GNU hosts, macOS/BSD, and
|
|
81
|
+
* busybox. If the path exists but cannot be canonicalized we fail CLOSED:
|
|
82
|
+
* returning without a check would let a symlink bypass containment.
|
|
63
83
|
*/
|
|
64
84
|
async assertContainedRealpath(abs, inputPath) {
|
|
65
|
-
const result = await this.exec(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
85
|
+
const result = await this.exec([
|
|
86
|
+
`p=${shellQuote(abs)}`,
|
|
87
|
+
`if [ ! -e "$p" ] && [ ! -L "$p" ]; then exit ${EXIT_NOT_FOUND}; fi`,
|
|
88
|
+
`root=$(cd ${shellQuote(this.basePath)} 2>/dev/null && pwd -P)`,
|
|
89
|
+
`[ -n "$root" ] || exit 1`,
|
|
90
|
+
`rp=$(realpath "$p" 2>/dev/null) || rp=$(readlink -f "$p" 2>/dev/null) || { [ -d "$p" ] && rp=$(cd "$p" 2>/dev/null && pwd -P); }`,
|
|
91
|
+
`[ -n "$rp" ] || exit 1`,
|
|
92
|
+
`printf '%s\\n%s' "$root" "$rp"`
|
|
93
|
+
].join("\n"));
|
|
94
|
+
if (result.exitCode === EXIT_NOT_FOUND) return;
|
|
95
|
+
const [root, real] = result.stdout.split("\n").map((s) => s.trim());
|
|
96
|
+
if (result.exitCode !== 0 || !root || !real) throw new Error(`Unable to verify path stays within workspace root: ${inputPath}`);
|
|
69
97
|
if (real !== root && !real.startsWith(`${root}/`)) throw new Error(`Path escapes workspace root (symlink): ${inputPath}`);
|
|
70
98
|
}
|
|
71
99
|
/**
|
|
@@ -88,8 +116,10 @@ var SandboxFilesystem = class {
|
|
|
88
116
|
async readFile(path, options) {
|
|
89
117
|
const abs = this.resolve(path);
|
|
90
118
|
await this.assertContainedRealpath(abs, path);
|
|
91
|
-
const result = await this.exec(`base64 < ${shellQuote(abs)}`);
|
|
92
|
-
if (result.exitCode
|
|
119
|
+
const result = await this.exec(`if [ -d ${shellQuote(abs)} ]; then exit ${EXIT_IS_DIRECTORY}; elif [ ! -e ${shellQuote(abs)} ]; then exit ${EXIT_NOT_FOUND}; fi; base64 < ${shellQuote(abs)}`);
|
|
120
|
+
if (result.exitCode === EXIT_IS_DIRECTORY) throw new IsDirectoryError(path);
|
|
121
|
+
if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(path);
|
|
122
|
+
if (result.exitCode !== 0) throw new Error(`readFile ${path} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);
|
|
93
123
|
const buffer = Buffer.from(result.stdout.replace(/\s/g, ""), "base64");
|
|
94
124
|
if (options?.encoding) return buffer.toString(options.encoding);
|
|
95
125
|
return buffer;
|
|
@@ -101,7 +131,10 @@ var SandboxFilesystem = class {
|
|
|
101
131
|
const dir = posix.dirname(abs);
|
|
102
132
|
const mkdir = options?.recursive === false ? "" : `mkdir -p ${shellQuote(dir)} && `;
|
|
103
133
|
if (options?.overwrite === false) {
|
|
104
|
-
|
|
134
|
+
const result = await this.exec(`${mkdir}{ (set -C; printf %s ${shellQuote(b64)} | base64 -d > ${shellQuote(abs)}) 2>/dev/null || { [ -e ${shellQuote(abs)} ] && exit ${EXIT_EXISTS} || exit 1; }; }`);
|
|
135
|
+
if (result.exitCode === EXIT_EXISTS) throw new FileExistsError(path);
|
|
136
|
+
if (result.exitCode !== 0) throw new Error(`writeFile ${path} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);
|
|
137
|
+
return;
|
|
105
138
|
}
|
|
106
139
|
await this.execOk(`${mkdir}printf %s ${shellQuote(b64)} | base64 -d > ${shellQuote(abs)}`, `writeFile ${path}`);
|
|
107
140
|
}
|
|
@@ -113,8 +146,14 @@ var SandboxFilesystem = class {
|
|
|
113
146
|
}
|
|
114
147
|
async deleteFile(path, options) {
|
|
115
148
|
const abs = this.resolve(path);
|
|
116
|
-
|
|
117
|
-
if (
|
|
149
|
+
await this.assertContainedRealpath(posix.dirname(abs), path);
|
|
150
|
+
if (options?.force) {
|
|
151
|
+
await this.execOk(`rm -f ${shellQuote(abs)}`, `deleteFile ${path}`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const result = await this.exec(`if [ ! -e ${shellQuote(abs)} ]; then exit ${EXIT_NOT_FOUND}; fi; rm ${shellQuote(abs)}`);
|
|
155
|
+
if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(path);
|
|
156
|
+
if (result.exitCode !== 0) throw new Error(`deleteFile ${path} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);
|
|
118
157
|
}
|
|
119
158
|
async copyFile(src, dest, options) {
|
|
120
159
|
const srcAbs = this.resolve(src);
|
|
@@ -123,9 +162,29 @@ var SandboxFilesystem = class {
|
|
|
123
162
|
await this.assertContainedDest(destAbs, dest);
|
|
124
163
|
const recursive = options?.recursive ? "-r " : "";
|
|
125
164
|
if (options?.overwrite === false) {
|
|
126
|
-
|
|
165
|
+
const result = await this.exec([
|
|
166
|
+
`src=${shellQuote(srcAbs)}`,
|
|
167
|
+
`dest=${shellQuote(destAbs)}`,
|
|
168
|
+
`if [ ! -e "$src" ] && [ ! -L "$src" ]; then exit ${EXIT_NOT_FOUND}; fi`,
|
|
169
|
+
`mkdir -p ${shellQuote(posix.dirname(destAbs))} || exit 1`,
|
|
170
|
+
`if [ -d "$src" ]; then`,
|
|
171
|
+
` mkdir "$dest" 2>/dev/null || exit ${EXIT_EXISTS}`,
|
|
172
|
+
` cp -R "$src"/. "$dest"/`,
|
|
173
|
+
`else`,
|
|
174
|
+
` tmp="$dest.__cptmp$$"`,
|
|
175
|
+
` cp "$src" "$tmp" || exit 1`,
|
|
176
|
+
` ln "$tmp" "$dest" 2>/dev/null || { rm -f "$tmp"; [ -e "$dest" ] && exit ${EXIT_EXISTS} || exit 1; }`,
|
|
177
|
+
` rm -f "$tmp"`,
|
|
178
|
+
`fi`
|
|
179
|
+
].join("\n"));
|
|
180
|
+
if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(src);
|
|
181
|
+
if (result.exitCode === EXIT_EXISTS) throw new FileExistsError(dest);
|
|
182
|
+
if (result.exitCode !== 0) throw new Error(`copyFile ${src} -> ${dest} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);
|
|
183
|
+
return;
|
|
127
184
|
}
|
|
128
|
-
await this.
|
|
185
|
+
const result = await this.exec(`if [ ! -e ${shellQuote(srcAbs)} ]; then exit ${EXIT_NOT_FOUND}; fi; mkdir -p ${shellQuote(posix.dirname(destAbs))} && cp ${recursive}${shellQuote(srcAbs)} ${shellQuote(destAbs)}`);
|
|
186
|
+
if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(src);
|
|
187
|
+
if (result.exitCode !== 0) throw new Error(`copyFile ${src} -> ${dest} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);
|
|
129
188
|
}
|
|
130
189
|
async moveFile(src, dest, options) {
|
|
131
190
|
const srcAbs = this.resolve(src);
|
|
@@ -133,9 +192,22 @@ var SandboxFilesystem = class {
|
|
|
133
192
|
await this.assertContainedRealpath(srcAbs, src);
|
|
134
193
|
await this.assertContainedDest(destAbs, dest);
|
|
135
194
|
if (options?.overwrite === false) {
|
|
136
|
-
|
|
195
|
+
const result = await this.exec([
|
|
196
|
+
`src=${shellQuote(srcAbs)}`,
|
|
197
|
+
`dest=${shellQuote(destAbs)}`,
|
|
198
|
+
`if [ ! -e "$src" ] && [ ! -L "$src" ]; then exit ${EXIT_NOT_FOUND}; fi`,
|
|
199
|
+
`mkdir -p ${shellQuote(posix.dirname(destAbs))} || exit 1`,
|
|
200
|
+
`mv -n "$src" "$dest" 2>/dev/null || exit 1`,
|
|
201
|
+
`if [ -e "$src" ] || [ -L "$src" ]; then exit ${EXIT_EXISTS}; fi`
|
|
202
|
+
].join("\n"));
|
|
203
|
+
if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(src);
|
|
204
|
+
if (result.exitCode === EXIT_EXISTS) throw new FileExistsError(dest);
|
|
205
|
+
if (result.exitCode !== 0) throw new Error(`moveFile ${src} -> ${dest} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);
|
|
206
|
+
return;
|
|
137
207
|
}
|
|
138
|
-
await this.
|
|
208
|
+
const result = await this.exec(`if [ ! -e ${shellQuote(srcAbs)} ]; then exit ${EXIT_NOT_FOUND}; fi; mkdir -p ${shellQuote(posix.dirname(destAbs))} && mv ${shellQuote(srcAbs)} ${shellQuote(destAbs)}`);
|
|
209
|
+
if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(src);
|
|
210
|
+
if (result.exitCode !== 0) throw new Error(`moveFile ${src} -> ${dest} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);
|
|
139
211
|
}
|
|
140
212
|
async mkdir(path, options) {
|
|
141
213
|
const abs = this.resolve(path);
|
|
@@ -145,6 +217,7 @@ var SandboxFilesystem = class {
|
|
|
145
217
|
}
|
|
146
218
|
async rmdir(path, options) {
|
|
147
219
|
const abs = this.resolve(path);
|
|
220
|
+
await this.assertContainedRealpath(posix.dirname(abs), path);
|
|
148
221
|
if (options?.recursive) {
|
|
149
222
|
const force = options?.force ? "-f " : "";
|
|
150
223
|
await this.execOk(`rm -r ${force}${shellQuote(abs)}`, `rmdir ${path}`);
|
|
@@ -156,11 +229,11 @@ var SandboxFilesystem = class {
|
|
|
156
229
|
const abs = this.resolve(path);
|
|
157
230
|
await this.assertContainedRealpath(abs, path);
|
|
158
231
|
if (options?.recursive) {
|
|
159
|
-
const result = await this.exec(`find ${shellQuote(abs)} -mindepth 1 ${options.maxDepth ? `-maxdepth ${Number(options.maxDepth)} ` : ""}-printf '%
|
|
232
|
+
const result = await this.exec(`test -d ${shellQuote(abs)} && find ${shellQuote(abs)} -mindepth 1 ${options.maxDepth ? `-maxdepth ${Number(options.maxDepth)} ` : ""}2>/dev/null | while IFS= read -r f; do if [ -d "$f" ]; then printf 'd\\t%s\\n' "$f"; else printf 'f\\t%s\\n' "$f"; fi; done`);
|
|
160
233
|
if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);
|
|
161
234
|
return this.parseFindOutput(result.stdout, abs, options);
|
|
162
235
|
}
|
|
163
|
-
const result = await this.exec(`cd ${shellQuote(abs)} 2>/dev/null && for f in * .[!.]*; do [ -e "$f" ] || continue; if [ -d "$f" ]; then
|
|
236
|
+
const result = await this.exec(`cd ${shellQuote(abs)} 2>/dev/null && for f in * .[!.]*; do [ -e "$f" ] || continue; if [ -d "$f" ]; then printf 'd\\t%s\\n' "$f"; else printf 'f\\t%s\\n' "$f"; fi; done`);
|
|
164
237
|
if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);
|
|
165
238
|
return this.parseListOutput(result.stdout, options);
|
|
166
239
|
}
|
|
@@ -210,10 +283,10 @@ var SandboxFilesystem = class {
|
|
|
210
283
|
async stat(path) {
|
|
211
284
|
const abs = this.resolve(path);
|
|
212
285
|
await this.assertContainedRealpath(abs, path);
|
|
213
|
-
const result = await this.exec(`stat -c '%F
|
|
214
|
-
if (result.exitCode !== 0) throw new
|
|
215
|
-
const [kind, sizeStr, mtimeStr, ctimeStr] = result.stdout.trim().split("
|
|
216
|
-
const type = kind && kind.includes("directory") ? "directory" : "file";
|
|
286
|
+
const result = await this.exec(`stat -c '%F|%s|%Y|%W' ${shellQuote(abs)} 2>/dev/null || stat -f '%HT|%z|%m|%B' ${shellQuote(abs)}`);
|
|
287
|
+
if (result.exitCode !== 0) throw new FileNotFoundError(path);
|
|
288
|
+
const [kind, sizeStr, mtimeStr, ctimeStr] = result.stdout.trim().split("|");
|
|
289
|
+
const type = kind && kind.toLowerCase().includes("directory") ? "directory" : "file";
|
|
217
290
|
const size = Number(sizeStr) || 0;
|
|
218
291
|
const mtime = Number(mtimeStr) || 0;
|
|
219
292
|
const ctime = Number(ctimeStr);
|
|
@@ -238,6 +311,7 @@ var SandboxFilesystem = class {
|
|
|
238
311
|
id: this.id,
|
|
239
312
|
name: this.name,
|
|
240
313
|
provider: this.provider,
|
|
314
|
+
status: this.status,
|
|
241
315
|
metadata: {
|
|
242
316
|
basePath: this.basePath,
|
|
243
317
|
sandboxId: this.sandbox.id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox-filesystem.js","names":["posixPath"],"sources":["../../src/agents/sandbox-filesystem.ts"],"sourcesContent":["/**\n * SandboxFilesystem\n *\n * A `WorkspaceFilesystem` that stores files inside a remote `MastraSandbox`\n * (e.g. a Railway VM) rather than on the server host. File operations are\n * implemented by shelling out through the sandbox's `executeCommand`, so the\n * agent's file tools and command tools share one VM and one view of the repo.\n *\n * Paths are workspace-relative (`/src/foo.ts`) and resolve under the sandbox\n * working directory (`basePath`). A traversal guard rejects any path that\n * escapes the workdir, mirroring `LocalFilesystem`'s contained mode.\n *\n * Reads/writes use base64 over the wire so binary content survives the shell.\n */\n\nimport { posix as posixPath } from 'node:path';\nimport type {\n CopyOptions,\n FileContent,\n FileEntry,\n FileStat,\n FilesystemInfo,\n ListOptions,\n ProviderStatus,\n ReadOptions,\n RemoveOptions,\n WorkspaceFilesystem,\n WriteOptions,\n} from '@mastra/core/workspace';\n\n/** Minimal command result shape we depend on. */\nexport interface SandboxCommandResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\n/** Minimal sandbox surface the filesystem needs. */\nexport interface SandboxExec {\n readonly id: string;\n executeCommand(command: string, args?: string[], options?: { timeout?: number }): Promise<SandboxCommandResult>;\n}\n\nexport interface SandboxFilesystemOptions {\n /** Live sandbox to run commands in. */\n sandbox: SandboxExec;\n /** Absolute path inside the sandbox that is the workspace root. */\n workdir: string;\n /** Optional stable id; defaults to a sandbox-derived id. */\n id?: string;\n}\n\n/** Default per-command deadline so a hung sandbox can't block file tools forever. */\nconst COMMAND_TIMEOUT_MS = 30_000;\n\n/** Single-quote a string for safe POSIX shell interpolation. */\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\nfunction isFileContentString(content: FileContent): content is string {\n return typeof content === 'string';\n}\n\nfunction toBuffer(content: FileContent): Buffer {\n if (isFileContentString(content)) return Buffer.from(content, 'utf8');\n return Buffer.from(content);\n}\n\nexport class SandboxFilesystem implements WorkspaceFilesystem {\n readonly id: string;\n readonly name = 'SandboxFilesystem';\n readonly provider = 'sandbox';\n readonly basePath: string;\n status: ProviderStatus = 'ready';\n\n private readonly sandbox: SandboxExec;\n\n constructor(options: SandboxFilesystemOptions) {\n this.sandbox = options.sandbox;\n this.basePath = options.workdir;\n this.id = options.id ?? `sandbox-fs:${options.sandbox.id}`;\n }\n\n // ── Path handling ──────────────────────────────────────────────────────\n\n /**\n * Resolve a workspace path to an absolute path inside the sandbox, enforcing\n * that it stays within the workdir.\n */\n private resolve(inputPath: string): string {\n const rel = inputPath.startsWith('/') ? inputPath.slice(1) : inputPath;\n const resolved = posixPath.normalize(posixPath.join(this.basePath, rel));\n const root = posixPath.normalize(this.basePath);\n if (resolved !== root && !resolved.startsWith(`${root}/`)) {\n throw new Error(`Path escapes workspace root: ${inputPath}`);\n }\n return resolved;\n }\n\n resolveAbsolutePath(inputPath: string): string | undefined {\n return this.resolve(inputPath);\n }\n\n // ── Command helper ─────────────────────────────────────────────────────\n\n private async exec(script: string): Promise<SandboxCommandResult> {\n return this.sandbox.executeCommand('sh', ['-c', script], { timeout: COMMAND_TIMEOUT_MS });\n }\n\n /**\n * Lexical guard catches `..` traversal, but a symlink inside the workdir can\n * still point outside it. After resolving a path that refers to an existing\n * entry, verify its realpath is still contained in the workdir.\n */\n private async assertContainedRealpath(abs: string, inputPath: string): Promise<void> {\n const result = await this.exec(`readlink -f -- ${shellQuote(abs)} 2>/dev/null`);\n const real = result.stdout.trim();\n // If readlink couldn't resolve (path doesn't exist yet), nothing to check.\n if (result.exitCode !== 0 || !real) return;\n const root = posixPath.normalize(this.basePath);\n if (real !== root && !real.startsWith(`${root}/`)) {\n throw new Error(`Path escapes workspace root (symlink): ${inputPath}`);\n }\n }\n\n /**\n * Guard for write destinations. The lexical guard catches `..`, but a symlink\n * inside the workdir can redirect a write outside it. For an existing target\n * we check its realpath; for a not-yet-existing target we check the realpath\n * of its nearest existing ancestor directory, since a symlinked parent is the\n * escape vector (e.g. `link -> /etc` then writing `link/passwd`).\n */\n private async assertContainedDest(abs: string, inputPath: string): Promise<void> {\n // First check the target itself (covers overwriting an existing symlink).\n await this.assertContainedRealpath(abs, inputPath);\n // Then check the parent directory's realpath; readlink -f resolves the\n // nearest existing ancestor when the leaf doesn't exist yet.\n const parent = posixPath.dirname(abs);\n if (parent && parent !== abs) {\n await this.assertContainedRealpath(parent, inputPath);\n }\n }\n\n private async execOk(script: string, context: string): Promise<SandboxCommandResult> {\n const result = await this.exec(script);\n if (result.exitCode !== 0) {\n throw new Error(`${context} failed (exit ${result.exitCode}): ${result.stderr.trim() || result.stdout.trim()}`);\n }\n return result;\n }\n\n // ── File operations ────────────────────────────────────────────────────\n\n async readFile(path: string, options?: ReadOptions): Promise<string | Buffer> {\n const abs = this.resolve(path);\n await this.assertContainedRealpath(abs, path);\n const result = await this.exec(`base64 < ${shellQuote(abs)}`);\n if (result.exitCode !== 0) {\n throw new Error(`File not found: ${path}`);\n }\n const buffer = Buffer.from(result.stdout.replace(/\\s/g, ''), 'base64');\n if (options?.encoding) {\n return buffer.toString(options.encoding);\n }\n return buffer;\n }\n\n async writeFile(path: string, content: FileContent, options?: WriteOptions): Promise<void> {\n const abs = this.resolve(path);\n await this.assertContainedDest(abs, path);\n const b64 = toBuffer(content).toString('base64');\n const dir = posixPath.dirname(abs);\n const mkdir = options?.recursive === false ? '' : `mkdir -p ${shellQuote(dir)} && `;\n if (options?.overwrite === false) {\n const exists = await this.exists(path);\n if (exists) throw new Error(`File already exists: ${path}`);\n }\n await this.execOk(`${mkdir}printf %s ${shellQuote(b64)} | base64 -d > ${shellQuote(abs)}`, `writeFile ${path}`);\n }\n\n async appendFile(path: string, content: FileContent): Promise<void> {\n const abs = this.resolve(path);\n await this.assertContainedDest(abs, path);\n const b64 = toBuffer(content).toString('base64');\n await this.execOk(\n `mkdir -p ${shellQuote(posixPath.dirname(abs))} && printf %s ${shellQuote(b64)} | base64 -d >> ${shellQuote(abs)}`,\n `appendFile ${path}`,\n );\n }\n\n async deleteFile(path: string, options?: RemoveOptions): Promise<void> {\n const abs = this.resolve(path);\n const force = options?.force ? '-f ' : '';\n const result = await this.exec(`rm ${force}${shellQuote(abs)}`);\n if (result.exitCode !== 0 && !options?.force) {\n throw new Error(`File not found: ${path}`);\n }\n }\n\n async copyFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n const srcAbs = this.resolve(src);\n const destAbs = this.resolve(dest);\n await this.assertContainedRealpath(srcAbs, src);\n await this.assertContainedDest(destAbs, dest);\n const recursive = options?.recursive ? '-r ' : '';\n if (options?.overwrite === false) {\n const exists = await this.exists(dest);\n if (exists) throw new Error(`Destination exists: ${dest}`);\n }\n await this.execOk(`cp ${recursive}${shellQuote(srcAbs)} ${shellQuote(destAbs)}`, `copyFile ${src} -> ${dest}`);\n }\n\n async moveFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n const srcAbs = this.resolve(src);\n const destAbs = this.resolve(dest);\n await this.assertContainedRealpath(srcAbs, src);\n await this.assertContainedDest(destAbs, dest);\n if (options?.overwrite === false) {\n const exists = await this.exists(dest);\n if (exists) throw new Error(`Destination exists: ${dest}`);\n }\n await this.execOk(`mv ${shellQuote(srcAbs)} ${shellQuote(destAbs)}`, `moveFile ${src} -> ${dest}`);\n }\n\n // ── Directory operations ───────────────────────────────────────────────\n\n async mkdir(path: string, options?: { recursive?: boolean }): Promise<void> {\n const abs = this.resolve(path);\n await this.assertContainedDest(abs, path);\n const flag = options?.recursive === false ? '' : '-p ';\n await this.execOk(`mkdir ${flag}${shellQuote(abs)}`, `mkdir ${path}`);\n }\n\n async rmdir(path: string, options?: RemoveOptions): Promise<void> {\n const abs = this.resolve(path);\n if (options?.recursive) {\n const force = options?.force ? '-f ' : '';\n await this.execOk(`rm -r ${force}${shellQuote(abs)}`, `rmdir ${path}`);\n return;\n }\n const result = await this.exec(`rmdir ${shellQuote(abs)}`);\n if (result.exitCode !== 0 && !options?.force) {\n throw new Error(`Directory not empty or not found: ${path}`);\n }\n }\n\n async readdir(path: string, options?: ListOptions): Promise<FileEntry[]> {\n const abs = this.resolve(path);\n await this.assertContainedRealpath(abs, path);\n if (options?.recursive) {\n // Use find for recursive listings; emit \"type\\tpath\".\n const result = await this.exec(\n `find ${shellQuote(abs)} -mindepth 1 ${options.maxDepth ? `-maxdepth ${Number(options.maxDepth)} ` : ''}-printf '%y\\\\t%p\\\\n' 2>/dev/null`,\n );\n if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);\n return this.parseFindOutput(result.stdout, abs, options);\n }\n // Non-recursive: list with name + type via a portable loop.\n const result = await this.exec(\n `cd ${shellQuote(abs)} 2>/dev/null && for f in * .[!.]*; do [ -e \"$f\" ] || continue; if [ -d \"$f\" ]; then echo \"d\\t$f\"; else echo \"f\\t$f\"; fi; done`,\n );\n if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);\n return this.parseListOutput(result.stdout, options);\n }\n\n private parseListOutput(stdout: string, options?: ListOptions): FileEntry[] {\n const entries: FileEntry[] = [];\n for (const line of stdout.split('\\n')) {\n if (!line) continue;\n const tab = line.indexOf('\\t');\n if (tab < 0) continue;\n const type = line.slice(0, tab) === 'd' ? 'directory' : 'file';\n const name = line.slice(tab + 1);\n if (!name || name === '.' || name === '..') continue;\n if (type === 'file' && !this.matchesExtension(name, options?.extension)) continue;\n entries.push({ name, type });\n }\n return entries;\n }\n\n private parseFindOutput(stdout: string, base: string, options?: ListOptions): FileEntry[] {\n const entries: FileEntry[] = [];\n for (const line of stdout.split('\\n')) {\n if (!line) continue;\n const tab = line.indexOf('\\t');\n if (tab < 0) continue;\n const type = line.slice(0, tab) === 'd' ? 'directory' : 'file';\n const fullPath = line.slice(tab + 1);\n const name = posixPath.relative(base, fullPath);\n if (!name) continue;\n if (type === 'file' && !this.matchesExtension(name, options?.extension)) continue;\n entries.push({ name, type });\n }\n return entries;\n }\n\n private matchesExtension(name: string, extension?: string | string[]): boolean {\n if (!extension) return true;\n const exts = Array.isArray(extension) ? extension : [extension];\n return exts.some(ext => name.endsWith(ext));\n }\n\n // ── Path / metadata ────────────────────────────────────────────────────\n\n async exists(path: string): Promise<boolean> {\n const abs = this.resolve(path);\n const result = await this.exec(`test -e ${shellQuote(abs)}`);\n return result.exitCode === 0;\n }\n\n async stat(path: string): Promise<FileStat> {\n const abs = this.resolve(path);\n await this.assertContainedRealpath(abs, path);\n // %F=type, %s=size, %X=atime, %Y=mtime (epoch seconds), %W=birth (or -1).\n const result = await this.exec(`stat -c '%F\\\\t%s\\\\t%Y\\\\t%W' ${shellQuote(abs)}`);\n if (result.exitCode !== 0) {\n throw new Error(`Path not found: ${path}`);\n }\n const [kind, sizeStr, mtimeStr, ctimeStr] = result.stdout.trim().split('\\t');\n const type = kind && kind.includes('directory') ? 'directory' : 'file';\n const size = Number(sizeStr) || 0;\n const mtime = Number(mtimeStr) || 0;\n const ctime = Number(ctimeStr);\n return {\n name: posixPath.basename(abs),\n path: `/${posixPath.relative(this.basePath, abs)}`,\n type,\n size: type === 'directory' ? 0 : size,\n modifiedAt: new Date(mtime * 1000),\n createdAt: new Date((ctime > 0 ? ctime : mtime) * 1000),\n };\n }\n\n // ── Lifecycle ──────────────────────────────────────────────────────────\n\n async init(): Promise<void> {\n await this.execOk(`mkdir -p ${shellQuote(this.basePath)}`, 'init workdir');\n }\n\n async destroy(): Promise<void> {\n // The sandbox lifecycle is owned by the caller; nothing to tear down here.\n }\n\n async isReady(): Promise<boolean> {\n const result = await this.exec(`test -d ${shellQuote(this.basePath)}`);\n return result.exitCode === 0;\n }\n\n getInfo(): FilesystemInfo {\n return {\n id: this.id,\n name: this.name,\n provider: this.provider,\n metadata: { basePath: this.basePath, sandboxId: this.sandbox.id },\n };\n }\n\n getInstructions(): string {\n return `Files are stored in a remote sandbox at ${this.basePath}. Use absolute workspace paths like /src/index.ts. All reads, writes and commands run inside the same sandbox.`;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sandbox-filesystem.js","names":["posixPath"],"sources":["../../src/agents/sandbox-filesystem.ts"],"sourcesContent":["/**\n * SandboxFilesystem\n *\n * A `WorkspaceFilesystem` that stores files inside a remote `MastraSandbox`\n * (e.g. a Railway VM) rather than on the server host. File operations are\n * implemented by shelling out through the sandbox's `executeCommand`, so the\n * agent's file tools and command tools share one VM and one view of the repo.\n *\n * Paths are workspace-relative (`/src/foo.ts`) and resolve under the sandbox\n * working directory (`basePath`). A traversal guard rejects any path that\n * escapes the workdir, mirroring `LocalFilesystem`'s contained mode.\n *\n * Reads/writes use base64 over the wire so binary content survives the shell.\n */\n\nimport { posix as posixPath } from 'node:path';\nimport type {\n CopyOptions,\n FileContent,\n FileEntry,\n FileStat,\n FilesystemInfo,\n ListOptions,\n ProviderStatus,\n ReadOptions,\n RemoveOptions,\n WorkspaceFilesystem,\n WriteOptions,\n} from '@mastra/core/workspace';\nimport { FileExistsError, FileNotFoundError, IsDirectoryError } from '@mastra/core/workspace';\n\n/**\n * Sentinel exit codes used by guard clauses that run before the real command,\n * so shell failures can be mapped to typed filesystem errors.\n */\nconst EXIT_NOT_FOUND = 20;\nconst EXIT_IS_DIRECTORY = 21;\nconst EXIT_EXISTS = 22;\n\n/** Minimal command result shape we depend on. */\nexport interface SandboxCommandResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\n/** Minimal sandbox surface the filesystem needs. */\nexport interface SandboxExec {\n readonly id: string;\n executeCommand(command: string, args?: string[], options?: { timeout?: number }): Promise<SandboxCommandResult>;\n}\n\nexport interface SandboxFilesystemOptions {\n /** Live sandbox to run commands in. */\n sandbox: SandboxExec;\n /** Absolute path inside the sandbox that is the workspace root. */\n workdir: string;\n /** Optional stable id; defaults to a sandbox-derived id. */\n id?: string;\n}\n\n/** Default per-command deadline so a hung sandbox can't block file tools forever. */\nconst COMMAND_TIMEOUT_MS = 30_000;\n\n/** Single-quote a string for safe POSIX shell interpolation. */\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\nfunction isFileContentString(content: FileContent): content is string {\n return typeof content === 'string';\n}\n\nfunction toBuffer(content: FileContent): Buffer {\n if (isFileContentString(content)) return Buffer.from(content, 'utf8');\n return Buffer.from(content);\n}\n\nexport class SandboxFilesystem implements WorkspaceFilesystem {\n readonly id: string;\n readonly name = 'SandboxFilesystem';\n readonly provider = 'sandbox';\n readonly basePath: string;\n status: ProviderStatus = 'ready';\n\n private readonly sandbox: SandboxExec;\n\n constructor(options: SandboxFilesystemOptions) {\n this.sandbox = options.sandbox;\n this.basePath = options.workdir;\n // Include the workdir: one sandbox can back several filesystems rooted at\n // different worktrees, and each needs a distinct id.\n this.id = options.id ?? `sandbox-fs:${options.sandbox.id}:${options.workdir}`;\n }\n\n // ── Path handling ──────────────────────────────────────────────────────\n\n /**\n * Resolve a workspace path to an absolute path inside the sandbox, enforcing\n * that it stays within the workdir.\n *\n * Accepts both workspace-relative paths (`src/foo.ts`, `/src/foo.ts`) and\n * absolute sandbox paths that already live under the workdir — the agent's\n * prompt advertises the workdir as its working directory, so tools are\n * routinely called with fully-qualified paths like `<workdir>/src/foo.ts`.\n */\n private resolve(inputPath: string): string {\n const base = posixPath.normalize(this.basePath);\n const normalizedInput = posixPath.normalize(inputPath);\n const rel =\n normalizedInput === base\n ? ''\n : normalizedInput.startsWith(`${base}/`)\n ? normalizedInput.slice(base.length + 1)\n : inputPath.startsWith('/')\n ? inputPath.slice(1)\n : inputPath;\n const resolved = posixPath.normalize(posixPath.join(this.basePath, rel));\n const root = posixPath.normalize(this.basePath);\n if (resolved !== root && !resolved.startsWith(`${root}/`)) {\n throw new Error(`Path escapes workspace root: ${inputPath}`);\n }\n return resolved;\n }\n\n resolveAbsolutePath(inputPath: string): string | undefined {\n return this.resolve(inputPath);\n }\n\n // ── Command helper ─────────────────────────────────────────────────────\n\n private async exec(script: string): Promise<SandboxCommandResult> {\n return this.sandbox.executeCommand('sh', ['-c', script], { timeout: COMMAND_TIMEOUT_MS });\n }\n\n /**\n * Lexical guard catches `..` traversal, but a symlink inside the workdir can\n * still point outside it. After resolving a path that refers to an existing\n * entry, verify its realpath is still contained in the workdir.\n *\n * Canonicalization tries `realpath`, then `readlink -f` (GNU/busybox), then\n * `cd && pwd -P` for directories — covering GNU hosts, macOS/BSD, and\n * busybox. If the path exists but cannot be canonicalized we fail CLOSED:\n * returning without a check would let a symlink bypass containment.\n */\n private async assertContainedRealpath(abs: string, inputPath: string): Promise<void> {\n const result = await this.exec(\n [\n `p=${shellQuote(abs)}`,\n `if [ ! -e \"$p\" ] && [ ! -L \"$p\" ]; then exit ${EXIT_NOT_FOUND}; fi`,\n // The workdir itself may contain symlinked components (/tmp on macOS),\n // so canonicalize it as the comparison root.\n `root=$(cd ${shellQuote(this.basePath)} 2>/dev/null && pwd -P)`,\n `[ -n \"$root\" ] || exit 1`,\n `rp=$(realpath \"$p\" 2>/dev/null) || rp=$(readlink -f \"$p\" 2>/dev/null) || { [ -d \"$p\" ] && rp=$(cd \"$p\" 2>/dev/null && pwd -P); }`,\n `[ -n \"$rp\" ] || exit 1`,\n `printf '%s\\\\n%s' \"$root\" \"$rp\"`,\n ].join('\\n'),\n );\n // Path doesn't exist yet: nothing to canonicalize (writes to a fresh leaf\n // are covered by assertContainedDest checking the parent directory).\n if (result.exitCode === EXIT_NOT_FOUND) return;\n const [root, real] = result.stdout.split('\\n').map(s => s.trim());\n if (result.exitCode !== 0 || !root || !real) {\n throw new Error(`Unable to verify path stays within workspace root: ${inputPath}`);\n }\n if (real !== root && !real.startsWith(`${root}/`)) {\n throw new Error(`Path escapes workspace root (symlink): ${inputPath}`);\n }\n }\n\n /**\n * Guard for write destinations. The lexical guard catches `..`, but a symlink\n * inside the workdir can redirect a write outside it. For an existing target\n * we check its realpath; for a not-yet-existing target we check the realpath\n * of its nearest existing ancestor directory, since a symlinked parent is the\n * escape vector (e.g. `link -> /etc` then writing `link/passwd`).\n */\n private async assertContainedDest(abs: string, inputPath: string): Promise<void> {\n // First check the target itself (covers overwriting an existing symlink).\n await this.assertContainedRealpath(abs, inputPath);\n // Then check the parent directory's realpath; readlink -f resolves the\n // nearest existing ancestor when the leaf doesn't exist yet.\n const parent = posixPath.dirname(abs);\n if (parent && parent !== abs) {\n await this.assertContainedRealpath(parent, inputPath);\n }\n }\n\n private async execOk(script: string, context: string): Promise<SandboxCommandResult> {\n const result = await this.exec(script);\n if (result.exitCode !== 0) {\n throw new Error(`${context} failed (exit ${result.exitCode}): ${result.stderr.trim() || result.stdout.trim()}`);\n }\n return result;\n }\n\n // ── File operations ────────────────────────────────────────────────────\n\n async readFile(path: string, options?: ReadOptions): Promise<string | Buffer> {\n const abs = this.resolve(path);\n await this.assertContainedRealpath(abs, path);\n // Guard clauses first: redirecting from a directory \"succeeds\" with empty\n // output on some shells, so classify before reading.\n const result = await this.exec(\n `if [ -d ${shellQuote(abs)} ]; then exit ${EXIT_IS_DIRECTORY}; elif [ ! -e ${shellQuote(abs)} ]; then exit ${EXIT_NOT_FOUND}; fi; base64 < ${shellQuote(abs)}`,\n );\n if (result.exitCode === EXIT_IS_DIRECTORY) throw new IsDirectoryError(path);\n if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(path);\n if (result.exitCode !== 0) {\n throw new Error(`readFile ${path} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);\n }\n const buffer = Buffer.from(result.stdout.replace(/\\s/g, ''), 'base64');\n if (options?.encoding) {\n return buffer.toString(options.encoding);\n }\n return buffer;\n }\n\n async writeFile(path: string, content: FileContent, options?: WriteOptions): Promise<void> {\n const abs = this.resolve(path);\n await this.assertContainedDest(abs, path);\n const b64 = toBuffer(content).toString('base64');\n const dir = posixPath.dirname(abs);\n const mkdir = options?.recursive === false ? '' : `mkdir -p ${shellQuote(dir)} && `;\n if (options?.overwrite === false) {\n // `set -C` (noclobber) makes the redirect itself the exclusivity check —\n // no exists() pre-check that could race with a concurrent writer.\n const result = await this.exec(\n `${mkdir}{ (set -C; printf %s ${shellQuote(b64)} | base64 -d > ${shellQuote(abs)}) 2>/dev/null || { [ -e ${shellQuote(abs)} ] && exit ${EXIT_EXISTS} || exit 1; }; }`,\n );\n if (result.exitCode === EXIT_EXISTS) throw new FileExistsError(path);\n if (result.exitCode !== 0) {\n throw new Error(`writeFile ${path} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);\n }\n return;\n }\n await this.execOk(`${mkdir}printf %s ${shellQuote(b64)} | base64 -d > ${shellQuote(abs)}`, `writeFile ${path}`);\n }\n\n async appendFile(path: string, content: FileContent): Promise<void> {\n const abs = this.resolve(path);\n await this.assertContainedDest(abs, path);\n const b64 = toBuffer(content).toString('base64');\n await this.execOk(\n `mkdir -p ${shellQuote(posixPath.dirname(abs))} && printf %s ${shellQuote(b64)} | base64 -d >> ${shellQuote(abs)}`,\n `appendFile ${path}`,\n );\n }\n\n async deleteFile(path: string, options?: RemoveOptions): Promise<void> {\n const abs = this.resolve(path);\n // Contain the parent's realpath: deleting `link/file` where `link` points\n // outside the workdir must fail, while deleting a symlink entry itself\n // (which lives inside the workdir) stays allowed.\n await this.assertContainedRealpath(posixPath.dirname(abs), path);\n if (options?.force) {\n // `rm -f` already succeeds for a missing file, but still fails for\n // directories and permission errors — surface those.\n await this.execOk(`rm -f ${shellQuote(abs)}`, `deleteFile ${path}`);\n return;\n }\n const result = await this.exec(\n `if [ ! -e ${shellQuote(abs)} ]; then exit ${EXIT_NOT_FOUND}; fi; rm ${shellQuote(abs)}`,\n );\n if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(path);\n if (result.exitCode !== 0) {\n throw new Error(`deleteFile ${path} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);\n }\n }\n\n async copyFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n const srcAbs = this.resolve(src);\n const destAbs = this.resolve(dest);\n await this.assertContainedRealpath(srcAbs, src);\n await this.assertContainedDest(destAbs, dest);\n const recursive = options?.recursive ? '-r ' : '';\n if (options?.overwrite === false) {\n // Atomic no-clobber: directories claim the destination with an exclusive\n // mkdir; files copy to a temp name then hardlink into place (link(2)\n // fails if the destination exists). No racy exists() pre-check.\n const result = await this.exec(\n [\n `src=${shellQuote(srcAbs)}`,\n `dest=${shellQuote(destAbs)}`,\n `if [ ! -e \"$src\" ] && [ ! -L \"$src\" ]; then exit ${EXIT_NOT_FOUND}; fi`,\n `mkdir -p ${shellQuote(posixPath.dirname(destAbs))} || exit 1`,\n `if [ -d \"$src\" ]; then`,\n ` mkdir \"$dest\" 2>/dev/null || exit ${EXIT_EXISTS}`,\n ` cp -R \"$src\"/. \"$dest\"/`,\n `else`,\n ` tmp=\"$dest.__cptmp$$\"`,\n ` cp \"$src\" \"$tmp\" || exit 1`,\n ` ln \"$tmp\" \"$dest\" 2>/dev/null || { rm -f \"$tmp\"; [ -e \"$dest\" ] && exit ${EXIT_EXISTS} || exit 1; }`,\n ` rm -f \"$tmp\"`,\n `fi`,\n ].join('\\n'),\n );\n if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(src);\n if (result.exitCode === EXIT_EXISTS) throw new FileExistsError(dest);\n if (result.exitCode !== 0) {\n throw new Error(`copyFile ${src} -> ${dest} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);\n }\n return;\n }\n const result = await this.exec(\n `if [ ! -e ${shellQuote(srcAbs)} ]; then exit ${EXIT_NOT_FOUND}; fi; mkdir -p ${shellQuote(posixPath.dirname(destAbs))} && cp ${recursive}${shellQuote(srcAbs)} ${shellQuote(destAbs)}`,\n );\n if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(src);\n if (result.exitCode !== 0) {\n throw new Error(`copyFile ${src} -> ${dest} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);\n }\n }\n\n async moveFile(src: string, dest: string, options?: CopyOptions): Promise<void> {\n const srcAbs = this.resolve(src);\n const destAbs = this.resolve(dest);\n await this.assertContainedRealpath(srcAbs, src);\n await this.assertContainedDest(destAbs, dest);\n if (options?.overwrite === false) {\n // `mv -n` exits 0 even when it skips, so detect a skipped move by the\n // source surviving. The no-clobber rename itself is atomic; no racy\n // exists() pre-check.\n const result = await this.exec(\n [\n `src=${shellQuote(srcAbs)}`,\n `dest=${shellQuote(destAbs)}`,\n `if [ ! -e \"$src\" ] && [ ! -L \"$src\" ]; then exit ${EXIT_NOT_FOUND}; fi`,\n `mkdir -p ${shellQuote(posixPath.dirname(destAbs))} || exit 1`,\n `mv -n \"$src\" \"$dest\" 2>/dev/null || exit 1`,\n `if [ -e \"$src\" ] || [ -L \"$src\" ]; then exit ${EXIT_EXISTS}; fi`,\n ].join('\\n'),\n );\n if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(src);\n if (result.exitCode === EXIT_EXISTS) throw new FileExistsError(dest);\n if (result.exitCode !== 0) {\n throw new Error(`moveFile ${src} -> ${dest} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);\n }\n return;\n }\n const result = await this.exec(\n `if [ ! -e ${shellQuote(srcAbs)} ]; then exit ${EXIT_NOT_FOUND}; fi; mkdir -p ${shellQuote(posixPath.dirname(destAbs))} && mv ${shellQuote(srcAbs)} ${shellQuote(destAbs)}`,\n );\n if (result.exitCode === EXIT_NOT_FOUND) throw new FileNotFoundError(src);\n if (result.exitCode !== 0) {\n throw new Error(`moveFile ${src} -> ${dest} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);\n }\n }\n\n // ── Directory operations ───────────────────────────────────────────────\n\n async mkdir(path: string, options?: { recursive?: boolean }): Promise<void> {\n const abs = this.resolve(path);\n await this.assertContainedDest(abs, path);\n const flag = options?.recursive === false ? '' : '-p ';\n await this.execOk(`mkdir ${flag}${shellQuote(abs)}`, `mkdir ${path}`);\n }\n\n async rmdir(path: string, options?: RemoveOptions): Promise<void> {\n const abs = this.resolve(path);\n // Same parent containment as deleteFile — `rm -r` through a symlinked\n // parent would otherwise delete outside the workspace.\n await this.assertContainedRealpath(posixPath.dirname(abs), path);\n if (options?.recursive) {\n const force = options?.force ? '-f ' : '';\n await this.execOk(`rm -r ${force}${shellQuote(abs)}`, `rmdir ${path}`);\n return;\n }\n const result = await this.exec(`rmdir ${shellQuote(abs)}`);\n if (result.exitCode !== 0 && !options?.force) {\n throw new Error(`Directory not empty or not found: ${path}`);\n }\n }\n\n async readdir(path: string, options?: ListOptions): Promise<FileEntry[]> {\n const abs = this.resolve(path);\n await this.assertContainedRealpath(abs, path);\n if (options?.recursive) {\n // Recursive listing emitting \"type\\tpath\". `find -printf` is GNU-only\n // (fails on macOS/BSD hosts backing a local sandbox), so classify each\n // entry with a portable shell loop instead.\n const result = await this.exec(\n `test -d ${shellQuote(abs)} && find ${shellQuote(abs)} -mindepth 1 ${options.maxDepth ? `-maxdepth ${Number(options.maxDepth)} ` : ''}2>/dev/null | while IFS= read -r f; do if [ -d \"$f\" ]; then printf 'd\\\\t%s\\\\n' \"$f\"; else printf 'f\\\\t%s\\\\n' \"$f\"; fi; done`,\n );\n if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);\n return this.parseFindOutput(result.stdout, abs, options);\n }\n // Non-recursive: list with name + type via a portable loop. Use printf,\n // not echo — bash-as-/bin/sh (macOS local sandboxes) does not expand \\t\n // in echo arguments.\n const result = await this.exec(\n `cd ${shellQuote(abs)} 2>/dev/null && for f in * .[!.]*; do [ -e \"$f\" ] || continue; if [ -d \"$f\" ]; then printf 'd\\\\t%s\\\\n' \"$f\"; else printf 'f\\\\t%s\\\\n' \"$f\"; fi; done`,\n );\n if (result.exitCode !== 0) throw new Error(`Directory not found: ${path}`);\n return this.parseListOutput(result.stdout, options);\n }\n\n private parseListOutput(stdout: string, options?: ListOptions): FileEntry[] {\n const entries: FileEntry[] = [];\n for (const line of stdout.split('\\n')) {\n if (!line) continue;\n const tab = line.indexOf('\\t');\n if (tab < 0) continue;\n const type = line.slice(0, tab) === 'd' ? 'directory' : 'file';\n const name = line.slice(tab + 1);\n if (!name || name === '.' || name === '..') continue;\n if (type === 'file' && !this.matchesExtension(name, options?.extension)) continue;\n entries.push({ name, type });\n }\n return entries;\n }\n\n private parseFindOutput(stdout: string, base: string, options?: ListOptions): FileEntry[] {\n const entries: FileEntry[] = [];\n for (const line of stdout.split('\\n')) {\n if (!line) continue;\n const tab = line.indexOf('\\t');\n if (tab < 0) continue;\n const type = line.slice(0, tab) === 'd' ? 'directory' : 'file';\n const fullPath = line.slice(tab + 1);\n const name = posixPath.relative(base, fullPath);\n if (!name) continue;\n if (type === 'file' && !this.matchesExtension(name, options?.extension)) continue;\n entries.push({ name, type });\n }\n return entries;\n }\n\n private matchesExtension(name: string, extension?: string | string[]): boolean {\n if (!extension) return true;\n const exts = Array.isArray(extension) ? extension : [extension];\n return exts.some(ext => name.endsWith(ext));\n }\n\n // ── Path / metadata ────────────────────────────────────────────────────\n\n async exists(path: string): Promise<boolean> {\n const abs = this.resolve(path);\n const result = await this.exec(`test -e ${shellQuote(abs)}`);\n return result.exitCode === 0;\n }\n\n async stat(path: string): Promise<FileStat> {\n const abs = this.resolve(path);\n await this.assertContainedRealpath(abs, path);\n // GNU stat: %F=type, %s=size, %Y=mtime (epoch seconds), %W=birth (or -1).\n // BSD/macOS stat (local sandbox hosts) rejects `-c`; fall back to its\n // `-f` format with the same field order (%HT=type, %z=size, %m=mtime,\n // %B=birth). Delimit with `|` — neither stat interprets `\\t` escapes in\n // its format string.\n const result = await this.exec(\n `stat -c '%F|%s|%Y|%W' ${shellQuote(abs)} 2>/dev/null || stat -f '%HT|%z|%m|%B' ${shellQuote(abs)}`,\n );\n if (result.exitCode !== 0) {\n throw new FileNotFoundError(path);\n }\n const [kind, sizeStr, mtimeStr, ctimeStr] = result.stdout.trim().split('|');\n const type = kind && kind.toLowerCase().includes('directory') ? 'directory' : 'file';\n const size = Number(sizeStr) || 0;\n const mtime = Number(mtimeStr) || 0;\n const ctime = Number(ctimeStr);\n return {\n name: posixPath.basename(abs),\n path: `/${posixPath.relative(this.basePath, abs)}`,\n type,\n size: type === 'directory' ? 0 : size,\n modifiedAt: new Date(mtime * 1000),\n createdAt: new Date((ctime > 0 ? ctime : mtime) * 1000),\n };\n }\n\n // ── Lifecycle ──────────────────────────────────────────────────────────\n\n async init(): Promise<void> {\n await this.execOk(`mkdir -p ${shellQuote(this.basePath)}`, 'init workdir');\n }\n\n async destroy(): Promise<void> {\n // The sandbox lifecycle is owned by the caller; nothing to tear down here.\n }\n\n async isReady(): Promise<boolean> {\n const result = await this.exec(`test -d ${shellQuote(this.basePath)}`);\n return result.exitCode === 0;\n }\n\n getInfo(): FilesystemInfo {\n return {\n id: this.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n metadata: { basePath: this.basePath, sandboxId: this.sandbox.id },\n };\n }\n\n getInstructions(): string {\n return `Files are stored in a remote sandbox at ${this.basePath}. Use absolute workspace paths like /src/index.ts. All reads, writes and commands run inside the same sandbox.`;\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EAErB,mBAAmB,EACnB,uBAAuB,EAEvB,OAAO,EACR,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAQ7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAmB,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EACL,aAAa,EAId,MAAM,uBAAuB,CAAC;AAM/B,OAAO,EAA+D,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { setAuthStorage } from "./providers/openai-codex.js";
|
|
|
5
5
|
import { MASTRA_GATEWAY_PROVIDER, OBSERVABILITY_AUTH_PREFIX, loadSettings, resolveModelDefaults, resolveOmRoleModel, saveSettings } from "./onboarding/settings.js";
|
|
6
6
|
import { hasCredentialStoreProvider } from "./agents/credential-resolver.js";
|
|
7
7
|
import { getDynamicWorkspace, getGoalJudgeTools } from "./agents/workspace.js";
|
|
8
|
-
import { getStaticallyLoadedInstructionPaths } from "./agents/prompts/agent-instructions.js";
|
|
8
|
+
import { createGitRefInstructionReader, createGitRefReminderReader, getStaticallyLoadedInstructionPaths } from "./agents/prompts/agent-instructions.js";
|
|
9
9
|
import { getDynamicInstructions } from "./agents/instructions.js";
|
|
10
10
|
import { createAmazonBedrockGateway } from "./providers/amazon-bedrock-gateway.js";
|
|
11
11
|
import { setAuthStorage as setAuthStorage$1 } from "./providers/claude-max.js";
|
|
@@ -66,11 +66,24 @@ const MASTRACODE_TRANSIENT_CONNECTION_RETRY_INITIAL_DELAY_MS = 500;
|
|
|
66
66
|
const MASTRACODE_TRANSIENT_CONNECTION_RETRY_MAX_DELAY_MS = 3e4;
|
|
67
67
|
const TRANSIENT_CONNECTION_ERROR_CODES = /* @__PURE__ */ new Set(["ECONNRESET", "EPIPE"]);
|
|
68
68
|
const TRANSIENT_CONNECTION_MESSAGE_PATTERN = /econnreset|socket hang up|write epipe|other side closed/i;
|
|
69
|
+
const TRANSIENT_SERVER_ERROR_STATUSES = /* @__PURE__ */ new Set([
|
|
70
|
+
500,
|
|
71
|
+
502,
|
|
72
|
+
503
|
|
73
|
+
]);
|
|
74
|
+
const TRANSIENT_SERVER_ERROR_MESSAGE_PATTERN = /internal server|server error|api may be experiencing issues/i;
|
|
69
75
|
/**
|
|
70
76
|
* Matcher for transient connection failures. Cause-chain traversal is handled
|
|
71
77
|
* by `StreamErrorRetryProcessor.isRetryableStreamError`, which calls each
|
|
72
78
|
* matcher at every level of the cause chain.
|
|
73
79
|
*/
|
|
80
|
+
/**
|
|
81
|
+
* Read the session state fields the AgentsMDInjector callbacks need from the
|
|
82
|
+
* controller request context (set by hosts like the factory review flow).
|
|
83
|
+
*/
|
|
84
|
+
function getInjectorSessionState(requestContext) {
|
|
85
|
+
return (requestContext?.get("controller"))?.getState();
|
|
86
|
+
}
|
|
74
87
|
function isTransientConnectionError(error) {
|
|
75
88
|
if (!error) return false;
|
|
76
89
|
const code = typeof error === "object" && "code" in error ? error.code : void 0;
|
|
@@ -79,7 +92,17 @@ function isTransientConnectionError(error) {
|
|
|
79
92
|
if (typeof message === "string" && TRANSIENT_CONNECTION_MESSAGE_PATTERN.test(message)) return true;
|
|
80
93
|
return false;
|
|
81
94
|
}
|
|
82
|
-
function
|
|
95
|
+
function isTransientServerError(error) {
|
|
96
|
+
if (!error) return false;
|
|
97
|
+
const errorObj = typeof error === "object" ? error : void 0;
|
|
98
|
+
if (typeof errorObj?.status === "number" && TRANSIENT_SERVER_ERROR_STATUSES.has(errorObj.status) || typeof errorObj?.statusCode === "number" && TRANSIENT_SERVER_ERROR_STATUSES.has(errorObj.statusCode)) return true;
|
|
99
|
+
const message = error instanceof Error ? error.message : void 0;
|
|
100
|
+
return typeof message === "string" && TRANSIENT_SERVER_ERROR_MESSAGE_PATTERN.test(message);
|
|
101
|
+
}
|
|
102
|
+
function getTransientRetryDelay(retryCount) {
|
|
103
|
+
return Math.min(MASTRACODE_TRANSIENT_CONNECTION_RETRY_INITIAL_DELAY_MS * Math.pow(2, retryCount), MASTRACODE_TRANSIENT_CONNECTION_RETRY_MAX_DELAY_MS);
|
|
104
|
+
}
|
|
105
|
+
function emitTransientRetry(error, retryCount, delayMs, requestContext) {
|
|
83
106
|
(requestContext?.get("controller"))?.emitEvent?.({
|
|
84
107
|
type: "error",
|
|
85
108
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
@@ -377,24 +400,45 @@ async function createMastraCodeAgentController(config) {
|
|
|
377
400
|
inputProcessors: [
|
|
378
401
|
...config?.inputProcessors ?? [],
|
|
379
402
|
new PlanRejectionAbortProcessor(),
|
|
380
|
-
new AgentsMDInjector({
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
403
|
+
new AgentsMDInjector({
|
|
404
|
+
isEnabled: ({ requestContext }) => {
|
|
405
|
+
const state = getInjectorSessionState(requestContext);
|
|
406
|
+
return state?.untrustedCheckout !== true || typeof state?.baseRef === "string";
|
|
407
|
+
},
|
|
408
|
+
getReader: ({ requestContext }) => {
|
|
409
|
+
const state = getInjectorSessionState(requestContext);
|
|
410
|
+
if (state?.untrustedCheckout !== true || typeof state?.baseRef !== "string") return void 0;
|
|
411
|
+
return createGitRefReminderReader(state?.projectPath ?? project.rootPath, state.baseRef);
|
|
412
|
+
},
|
|
413
|
+
getIgnoredInstructionPaths: ({ requestContext }) => {
|
|
414
|
+
const state = getInjectorSessionState(requestContext);
|
|
415
|
+
const projectPath = state?.projectPath ?? project.rootPath;
|
|
416
|
+
return getStaticallyLoadedInstructionPaths(projectPath, void 0, state?.untrustedCheckout === true && typeof state?.baseRef === "string" ? createGitRefInstructionReader(projectPath, state.baseRef) : void 0);
|
|
417
|
+
}
|
|
418
|
+
}),
|
|
384
419
|
new ProviderHistoryCompat()
|
|
385
420
|
],
|
|
386
421
|
errorProcessors: [
|
|
387
422
|
new ProviderHistoryCompat(),
|
|
388
|
-
new StreamErrorRetryProcessor({ matchers: [
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
423
|
+
new StreamErrorRetryProcessor({ matchers: [
|
|
424
|
+
{
|
|
425
|
+
match: isBadRequestError,
|
|
426
|
+
maxRetries: 1,
|
|
427
|
+
delayMs: 2e3
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
match: isTransientConnectionError,
|
|
431
|
+
maxRetries: MASTRACODE_TRANSIENT_CONNECTION_MAX_RETRIES,
|
|
432
|
+
delayMs: ({ retryCount }) => getTransientRetryDelay(retryCount),
|
|
433
|
+
onRetry: ({ error, retryCount, delayMs, requestContext }) => emitTransientRetry(error, retryCount, delayMs, requestContext)
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
match: isTransientServerError,
|
|
437
|
+
maxRetries: MASTRACODE_TRANSIENT_CONNECTION_MAX_RETRIES,
|
|
438
|
+
delayMs: ({ retryCount }) => getTransientRetryDelay(retryCount),
|
|
439
|
+
onRetry: ({ error, retryCount, delayMs, requestContext }) => emitTransientRetry(error, retryCount, delayMs, requestContext)
|
|
440
|
+
}
|
|
441
|
+
] }),
|
|
398
442
|
new PrefillErrorHandler()
|
|
399
443
|
]
|
|
400
444
|
});
|