@mastra/agentfs 0.2.0-alpha.0 → 0.2.1-alpha.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.cjs CHANGED
@@ -1,524 +1,501 @@
1
- 'use strict';
2
-
3
- var fs = require('fs');
4
- var os = require('os');
5
- var nodePath = require('path');
6
- var workspace = require('@mastra/core/workspace');
7
- var agentfsSdk = require('agentfs-sdk');
8
-
9
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
-
11
- var os__default = /*#__PURE__*/_interopDefault(os);
12
- var nodePath__default = /*#__PURE__*/_interopDefault(nodePath);
13
-
14
- // src/filesystem/index.ts
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let fs = require("fs");
25
+ let os = require("os");
26
+ os = __toESM(os, 1);
27
+ let path = require("path");
28
+ path = __toESM(path, 1);
29
+ let _mastra_core_workspace = require("@mastra/core/workspace");
30
+ let agentfs_sdk = require("agentfs-sdk");
31
+ //#region src/filesystem/index.ts
32
+ /**
33
+ * AgentFS Filesystem Provider
34
+ *
35
+ * Implements WorkspaceFilesystem backed by AgentFS (Turso/SQLite).
36
+ * Follows the same pattern as S3Filesystem.
37
+ */
38
+ /**
39
+ * Expand a leading `~` to the user's home directory.
40
+ * Node.js path APIs don't handle tilde — only the shell does.
41
+ */
15
42
  function expandTilde(p) {
16
- if (p === "~") return os__default.default.homedir();
17
- if (p.startsWith("~/") || p.startsWith("~\\")) {
18
- return nodePath__default.default.join(os__default.default.homedir(), p.slice(2));
19
- }
20
- return p;
43
+ if (p === "~") return os.default.homedir();
44
+ if (p.startsWith("~/") || p.startsWith("~\\")) return path.default.join(os.default.homedir(), p.slice(2));
45
+ return p;
21
46
  }
47
+ /**
48
+ * Resolve a database path to an absolute path.
49
+ * Expands tilde and resolves relative paths against cwd (at construction time).
50
+ */
22
51
  function resolveDbPath(p) {
23
- return nodePath__default.default.resolve(expandTilde(p));
52
+ return path.default.resolve(expandTilde(p));
24
53
  }
25
54
  function normalizePath(input) {
26
- if (input === "" || input === ".") return "/";
27
- let path = input.startsWith("/") ? input : "/" + input;
28
- let result = "";
29
- let prevSlash = false;
30
- for (let i = 0; i < path.length; i++) {
31
- const ch = path[i];
32
- if (ch === "/") {
33
- if (!prevSlash) {
34
- result += ch;
35
- }
36
- prevSlash = true;
37
- } else {
38
- result += ch;
39
- prevSlash = false;
40
- }
41
- }
42
- if (result.length > 1 && result.endsWith("/")) {
43
- result = result.slice(0, -1);
44
- }
45
- return result;
55
+ if (input === "" || input === ".") return "/";
56
+ let path$1 = input.startsWith("/") ? input : "/" + input;
57
+ let result = "";
58
+ let prevSlash = false;
59
+ for (let i = 0; i < path$1.length; i++) {
60
+ const ch = path$1[i];
61
+ if (ch === "/") {
62
+ if (!prevSlash) result += ch;
63
+ prevSlash = true;
64
+ } else {
65
+ result += ch;
66
+ prevSlash = false;
67
+ }
68
+ }
69
+ if (result.length > 1 && result.endsWith("/")) result = result.slice(0, -1);
70
+ return result;
46
71
  }
47
- function getParentPath(path) {
48
- const normalized = normalizePath(path);
49
- if (normalized === "/") return "/";
50
- const lastSlash = normalized.lastIndexOf("/");
51
- return lastSlash <= 0 ? "/" : normalized.slice(0, lastSlash);
72
+ function getParentPath(path$2) {
73
+ const normalized = normalizePath(path$2);
74
+ if (normalized === "/") return "/";
75
+ const lastSlash = normalized.lastIndexOf("/");
76
+ return lastSlash <= 0 ? "/" : normalized.slice(0, lastSlash);
52
77
  }
53
78
  function joinPath(base, name) {
54
- if (base === "/") return normalizePath("/" + name);
55
- return normalizePath(base + "/" + name);
79
+ if (base === "/") return normalizePath("/" + name);
80
+ return normalizePath(base + "/" + name);
56
81
  }
57
- function getBaseName(path) {
58
- const normalized = normalizePath(path);
59
- if (normalized === "/") return "";
60
- const lastSlash = normalized.lastIndexOf("/");
61
- return normalized.slice(lastSlash + 1);
82
+ function getBaseName(path$3) {
83
+ const normalized = normalizePath(path$3);
84
+ if (normalized === "/") return "";
85
+ const lastSlash = normalized.lastIndexOf("/");
86
+ return normalized.slice(lastSlash + 1);
62
87
  }
63
88
  function isErrnoError(error) {
64
- return typeof error === "object" && error !== null && "code" in error;
89
+ return typeof error === "object" && error !== null && "code" in error;
65
90
  }
66
- function mapError(error, path, context = "file") {
67
- if (!isErrnoError(error)) {
68
- return error instanceof Error ? error : new Error(String(error));
69
- }
70
- switch (error.code) {
71
- case "ENOENT":
72
- return context === "directory" ? new workspace.DirectoryNotFoundError(path) : new workspace.FileNotFoundError(path);
73
- case "EEXIST":
74
- return new workspace.FileExistsError(path);
75
- case "EISDIR":
76
- return new workspace.IsDirectoryError(path);
77
- case "ENOTDIR":
78
- return new workspace.NotDirectoryError(path);
79
- case "ENOTEMPTY":
80
- return new workspace.DirectoryNotEmptyError(path);
81
- case "EPERM":
82
- case "EACCES":
83
- return new workspace.PermissionError(path, "access");
84
- default:
85
- return error instanceof Error ? error : new Error(String(error));
86
- }
91
+ function mapError(error, path$4, context = "file") {
92
+ if (!isErrnoError(error)) return error instanceof Error ? error : new Error(String(error));
93
+ switch (error.code) {
94
+ case "ENOENT": return context === "directory" ? new _mastra_core_workspace.DirectoryNotFoundError(path$4) : new _mastra_core_workspace.FileNotFoundError(path$4);
95
+ case "EEXIST": return new _mastra_core_workspace.FileExistsError(path$4);
96
+ case "EISDIR": return new _mastra_core_workspace.IsDirectoryError(path$4);
97
+ case "ENOTDIR": return new _mastra_core_workspace.NotDirectoryError(path$4);
98
+ case "ENOTEMPTY": return new _mastra_core_workspace.DirectoryNotEmptyError(path$4);
99
+ case "EPERM":
100
+ case "EACCES": return new _mastra_core_workspace.PermissionError(path$4, "access");
101
+ default: return error instanceof Error ? error : new Error(String(error));
102
+ }
87
103
  }
88
104
  function hasCode(error, code) {
89
- return isErrnoError(error) && error.code === code;
105
+ return isErrnoError(error) && error.code === code;
90
106
  }
91
- var AgentFSFilesystem = class extends workspace.MastraFilesystem {
92
- id;
93
- name = "AgentFSFilesystem";
94
- provider = "agentfs";
95
- readOnly;
96
- status = "pending";
97
- // Display metadata
98
- displayName;
99
- icon;
100
- description;
101
- _agent = null;
102
- _ownsAgent;
103
- _agentId;
104
- _path;
105
- constructor(options) {
106
- if (!options.agentId && !options.path && !options.agent) {
107
- throw new Error("AgentFSFilesystem requires at least one of 'agentId', 'path', or 'agent'.");
108
- }
109
- super({ ...options, name: "AgentFSFilesystem" });
110
- this.id = options.id ?? `agentfs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
111
- this._agentId = options.agentId;
112
- this._path = options.path ? resolveDbPath(options.path) : void 0;
113
- this.readOnly = options.readOnly;
114
- if (options.agent) {
115
- this._agent = options.agent;
116
- this._ownsAgent = false;
117
- } else {
118
- this._ownsAgent = true;
119
- }
120
- this.icon = options.icon ?? "database";
121
- this.displayName = options.displayName ?? "AgentFS";
122
- this.description = options.description;
123
- }
124
- /** The underlying AgentFS instance, or null if not yet initialized. */
125
- get agent() {
126
- return this._agent;
127
- }
128
- // ---------------------------------------------------------------------------
129
- // Info
130
- // ---------------------------------------------------------------------------
131
- getInfo() {
132
- return {
133
- id: this.id,
134
- name: this.name,
135
- provider: this.provider,
136
- status: this.status,
137
- error: this.error,
138
- readOnly: this.readOnly,
139
- icon: this.icon,
140
- metadata: {
141
- ...this._agentId && { agentId: this._agentId },
142
- ...this._path && { dbPath: this._path }
143
- }
144
- };
145
- }
146
- getInstructions() {
147
- const label = this._agentId ? `agent "${this._agentId}"` : "database";
148
- const access = this.readOnly ? "Read-only" : "Persistent";
149
- return `AgentFS storage for ${label}. ${access} SQLite-backed filesystem \u2014 files are retained across sessions.`;
150
- }
151
- // ---------------------------------------------------------------------------
152
- // Lifecycle
153
- // ---------------------------------------------------------------------------
154
- async init() {
155
- if (this._agent) return;
156
- const openOptions = {};
157
- if (this._agentId) openOptions.id = this._agentId;
158
- if (this._path) {
159
- openOptions.path = this._path;
160
- fs.mkdirSync(nodePath__default.default.dirname(this._path), { recursive: true });
161
- }
162
- this._agent = await agentfsSdk.AgentFS.open(openOptions);
163
- }
164
- async destroy() {
165
- if (this._agent && this._ownsAgent) {
166
- await this._agent.close();
167
- }
168
- this._agent = null;
169
- }
170
- // ---------------------------------------------------------------------------
171
- // Internal helpers
172
- // ---------------------------------------------------------------------------
173
- async getAgent() {
174
- await this.ensureReady();
175
- return this._agent;
176
- }
177
- assertWritable(operation) {
178
- if (this.readOnly) {
179
- throw new workspace.WorkspaceReadOnlyError(operation);
180
- }
181
- }
182
- // ---------------------------------------------------------------------------
183
- // File Operations
184
- // ---------------------------------------------------------------------------
185
- async readFile(path, options) {
186
- const agent = await this.getAgent();
187
- const normalized = normalizePath(path);
188
- try {
189
- if (options?.encoding) {
190
- return await agent.fs.readFile(normalized, options.encoding);
191
- }
192
- return await agent.fs.readFile(normalized);
193
- } catch (error) {
194
- throw mapError(error, normalized, "file");
195
- }
196
- }
197
- async writeFile(path, content, options) {
198
- this.assertWritable("writeFile");
199
- const agent = await this.getAgent();
200
- const normalized = normalizePath(path);
201
- if (options?.recursive !== false) {
202
- await this.mkdirRecursive(agent, getParentPath(normalized));
203
- }
204
- if (options?.overwrite === false) {
205
- try {
206
- await agent.fs.access(normalized);
207
- throw new workspace.FileExistsError(normalized);
208
- } catch (error) {
209
- if (error instanceof workspace.FileExistsError) throw error;
210
- if (!hasCode(error, "ENOENT")) throw mapError(error, normalized, "file");
211
- }
212
- }
213
- try {
214
- const data = typeof content === "string" ? content : Buffer.from(content);
215
- await agent.fs.writeFile(normalized, data);
216
- } catch (error) {
217
- throw mapError(error, normalized, "file");
218
- }
219
- }
220
- async appendFile(path, content) {
221
- this.assertWritable("appendFile");
222
- let existing = Buffer.alloc(0);
223
- try {
224
- const current = await this.readFile(path);
225
- existing = Buffer.isBuffer(current) ? Buffer.from(current) : Buffer.from(current);
226
- } catch (error) {
227
- if (error instanceof workspace.FileNotFoundError) ; else {
228
- throw error;
229
- }
230
- }
231
- const appendBuffer = typeof content === "string" ? Buffer.from(content, "utf-8") : Buffer.from(content);
232
- await this.writeFile(path, Buffer.concat([existing, appendBuffer]));
233
- }
234
- async deleteFile(path, options) {
235
- this.assertWritable("deleteFile");
236
- const agent = await this.getAgent();
237
- const normalized = normalizePath(path);
238
- try {
239
- const st = await agent.fs.stat(normalized);
240
- if (st.isDirectory()) {
241
- throw new workspace.IsDirectoryError(normalized);
242
- }
243
- } catch (error) {
244
- if (error instanceof workspace.IsDirectoryError) throw error;
245
- if (hasCode(error, "ENOENT")) {
246
- if (options?.force) return;
247
- throw new workspace.FileNotFoundError(normalized);
248
- }
249
- throw mapError(error, normalized, "file");
250
- }
251
- try {
252
- await agent.fs.unlink(normalized);
253
- } catch (error) {
254
- if (options?.force && hasCode(error, "ENOENT")) return;
255
- throw mapError(error, normalized, "file");
256
- }
257
- }
258
- async copyFile(src, dest, options) {
259
- this.assertWritable("copyFile");
260
- const agent = await this.getAgent();
261
- const normalizedSrc = normalizePath(src);
262
- const normalizedDest = normalizePath(dest);
263
- if (options?.overwrite === false) {
264
- try {
265
- await agent.fs.access(normalizedDest);
266
- throw new workspace.FileExistsError(normalizedDest);
267
- } catch (error) {
268
- if (error instanceof workspace.FileExistsError) throw error;
269
- if (!hasCode(error, "ENOENT")) throw mapError(error, normalizedDest, "file");
270
- }
271
- }
272
- try {
273
- const st = await agent.fs.stat(normalizedSrc);
274
- if (st.isDirectory()) {
275
- if (!options?.recursive) {
276
- throw new workspace.IsDirectoryError(normalizedSrc);
277
- }
278
- await this.copyDirRecursive(agent, normalizedSrc, normalizedDest, options);
279
- return;
280
- }
281
- await this.mkdirRecursive(agent, getParentPath(normalizedDest));
282
- await agent.fs.copyFile(normalizedSrc, normalizedDest);
283
- } catch (error) {
284
- if (error instanceof workspace.IsDirectoryError || error instanceof workspace.FileExistsError) throw error;
285
- throw mapError(error, normalizedSrc, "file");
286
- }
287
- }
288
- async moveFile(src, dest, options) {
289
- this.assertWritable("moveFile");
290
- const agent = await this.getAgent();
291
- const normalizedSrc = normalizePath(src);
292
- const normalizedDest = normalizePath(dest);
293
- if (options?.overwrite === false) {
294
- try {
295
- await agent.fs.access(normalizedDest);
296
- throw new workspace.FileExistsError(normalizedDest);
297
- } catch (error) {
298
- if (error instanceof workspace.FileExistsError) throw error;
299
- if (!hasCode(error, "ENOENT")) throw mapError(error, normalizedDest, "file");
300
- }
301
- }
302
- await this.mkdirRecursive(agent, getParentPath(normalizedDest));
303
- try {
304
- await agent.fs.rename(normalizedSrc, normalizedDest);
305
- } catch (error) {
306
- throw mapError(error, normalizedSrc, "file");
307
- }
308
- }
309
- // ---------------------------------------------------------------------------
310
- // Directory Operations
311
- // ---------------------------------------------------------------------------
312
- async mkdir(path, options) {
313
- this.assertWritable("mkdir");
314
- const agent = await this.getAgent();
315
- const normalized = normalizePath(path);
316
- if (options?.recursive !== false) {
317
- await this.mkdirRecursive(agent, normalized);
318
- return;
319
- }
320
- try {
321
- await agent.fs.mkdir(normalized);
322
- } catch (error) {
323
- throw mapError(error, normalized, "directory");
324
- }
325
- }
326
- async rmdir(path, options) {
327
- this.assertWritable("rmdir");
328
- const agent = await this.getAgent();
329
- const normalized = normalizePath(path);
330
- if (options?.recursive) {
331
- try {
332
- await agent.fs.rm(normalized, { recursive: true });
333
- } catch (error) {
334
- if (options?.force && hasCode(error, "ENOENT")) return;
335
- throw mapError(error, normalized, "directory");
336
- }
337
- return;
338
- }
339
- try {
340
- const entries = await agent.fs.readdir(normalized);
341
- if (entries.length > 0) {
342
- throw new workspace.DirectoryNotEmptyError(normalized);
343
- }
344
- await agent.fs.rmdir(normalized);
345
- } catch (error) {
346
- if (error instanceof workspace.DirectoryNotEmptyError) throw error;
347
- if (options?.force && hasCode(error, "ENOENT")) return;
348
- throw mapError(error, normalized, "directory");
349
- }
350
- }
351
- async readdir(path, options) {
352
- const agent = await this.getAgent();
353
- const normalized = normalizePath(path);
354
- try {
355
- const st = await agent.fs.stat(normalized);
356
- if (!st.isDirectory()) {
357
- throw new workspace.NotDirectoryError(normalized);
358
- }
359
- const dirEntries = await agent.fs.readdirPlus(normalized);
360
- let entries = dirEntries.map((entry) => ({
361
- name: entry.name,
362
- type: entry.stats.isDirectory() ? "directory" : "file",
363
- size: entry.stats.size
364
- }));
365
- if (options?.extension) {
366
- const extensions = Array.isArray(options.extension) ? options.extension : [options.extension];
367
- entries = entries.filter((entry) => {
368
- if (entry.type === "directory") return true;
369
- return extensions.some((ext) => entry.name.endsWith(ext));
370
- });
371
- }
372
- if (options?.recursive) {
373
- const maxDepth = options.maxDepth ?? Infinity;
374
- const subdirs = entries.filter((e) => e.type === "directory");
375
- for (const dir of subdirs) {
376
- if (maxDepth > 1) {
377
- const subEntries = await this.readdir(joinPath(normalized, dir.name), {
378
- ...options,
379
- maxDepth: maxDepth - 1
380
- });
381
- for (const sub of subEntries) {
382
- entries.push({
383
- ...sub,
384
- name: dir.name + "/" + sub.name
385
- });
386
- }
387
- }
388
- }
389
- }
390
- return entries;
391
- } catch (error) {
392
- if (error instanceof workspace.NotDirectoryError || error instanceof workspace.DirectoryNotFoundError) {
393
- throw error;
394
- }
395
- throw mapError(error, normalized, "directory");
396
- }
397
- }
398
- // ---------------------------------------------------------------------------
399
- // Path Operations
400
- // ---------------------------------------------------------------------------
401
- async exists(path) {
402
- const agent = await this.getAgent();
403
- const normalized = normalizePath(path);
404
- try {
405
- await agent.fs.access(normalized);
406
- return true;
407
- } catch {
408
- return false;
409
- }
410
- }
411
- async stat(path) {
412
- const agent = await this.getAgent();
413
- const normalized = normalizePath(path);
414
- try {
415
- const st = await agent.fs.stat(normalized);
416
- return {
417
- name: getBaseName(normalized) || "",
418
- path: normalized,
419
- type: st.isDirectory() ? "directory" : "file",
420
- size: st.size,
421
- createdAt: new Date(st.ctime * 1e3),
422
- modifiedAt: new Date(st.mtime * 1e3)
423
- };
424
- } catch (error) {
425
- throw mapError(error, normalized, "file");
426
- }
427
- }
428
- // ---------------------------------------------------------------------------
429
- // Type checks
430
- // ---------------------------------------------------------------------------
431
- /**
432
- * Check if the path points to a file.
433
- * Returns `false` if the path doesn't exist.
434
- */
435
- async isFile(path) {
436
- try {
437
- const st = await this.stat(path);
438
- return st.type === "file";
439
- } catch (error) {
440
- if (error instanceof workspace.FileNotFoundError) return false;
441
- throw error;
442
- }
443
- }
444
- /**
445
- * Check if the path points to a directory.
446
- * Returns `false` if the path doesn't exist.
447
- */
448
- async isDirectory(path) {
449
- try {
450
- const st = await this.stat(path);
451
- return st.type === "directory";
452
- } catch (error) {
453
- if (error instanceof workspace.FileNotFoundError) return false;
454
- throw error;
455
- }
456
- }
457
- // ---------------------------------------------------------------------------
458
- // Private helpers
459
- // ---------------------------------------------------------------------------
460
- /**
461
- * Recursively create directories, ignoring EEXIST errors.
462
- */
463
- async mkdirRecursive(agent, path) {
464
- if (path === "/") return;
465
- const segments = path.split("/").filter(Boolean);
466
- let current = "";
467
- for (const segment of segments) {
468
- current += "/" + segment;
469
- try {
470
- await agent.fs.mkdir(current);
471
- } catch (error) {
472
- if (!hasCode(error, "EEXIST")) {
473
- throw mapError(error, current, "directory");
474
- }
475
- }
476
- }
477
- }
478
- /**
479
- * Recursively copy a directory tree.
480
- */
481
- async copyDirRecursive(agent, src, dest, options) {
482
- await this.mkdirRecursive(agent, dest);
483
- const entries = await agent.fs.readdirPlus(src);
484
- for (const entry of entries) {
485
- const srcChild = joinPath(src, entry.name);
486
- const destChild = joinPath(dest, entry.name);
487
- if (entry.stats.isDirectory()) {
488
- await this.copyDirRecursive(agent, srcChild, destChild, options);
489
- } else {
490
- if (options?.overwrite === false) {
491
- try {
492
- await agent.fs.access(destChild);
493
- throw new workspace.FileExistsError(destChild);
494
- } catch (error) {
495
- if (error instanceof workspace.FileExistsError) throw error;
496
- if (!hasCode(error, "ENOENT")) throw mapError(error, destChild, "file");
497
- }
498
- }
499
- await agent.fs.copyFile(srcChild, destChild);
500
- }
501
- }
502
- }
107
+ /**
108
+ * AgentFS filesystem implementation.
109
+ *
110
+ * Stores files in a Turso/SQLite database via the AgentFS SDK.
111
+ *
112
+ * @example Using agentId
113
+ * ```typescript
114
+ * import { AgentFSFilesystem } from '@mastra/agentfs';
115
+ *
116
+ * const fs = new AgentFSFilesystem({ agentId: 'my-agent' });
117
+ * ```
118
+ *
119
+ * @example Using a pre-opened instance
120
+ * ```typescript
121
+ * import { AgentFS } from 'agentfs-sdk';
122
+ * import { AgentFSFilesystem } from '@mastra/agentfs';
123
+ *
124
+ * const agent = await AgentFS.open({ id: 'my-agent' });
125
+ * const fs = new AgentFSFilesystem({ agent });
126
+ * ```
127
+ */
128
+ var AgentFSFilesystem = class extends _mastra_core_workspace.MastraFilesystem {
129
+ id;
130
+ name = "AgentFSFilesystem";
131
+ provider = "agentfs";
132
+ readOnly;
133
+ status = "pending";
134
+ displayName;
135
+ icon;
136
+ description;
137
+ _agent = null;
138
+ _ownsAgent;
139
+ _agentId;
140
+ _path;
141
+ constructor(options) {
142
+ if (!options.agentId && !options.path && !options.agent) throw new Error("AgentFSFilesystem requires at least one of 'agentId', 'path', or 'agent'.");
143
+ super({
144
+ ...options,
145
+ name: "AgentFSFilesystem"
146
+ });
147
+ this.id = options.id ?? `agentfs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
148
+ this._agentId = options.agentId;
149
+ this._path = options.path ? resolveDbPath(options.path) : void 0;
150
+ this.readOnly = options.readOnly;
151
+ if (options.agent) {
152
+ this._agent = options.agent;
153
+ this._ownsAgent = false;
154
+ } else this._ownsAgent = true;
155
+ this.icon = options.icon ?? "database";
156
+ this.displayName = options.displayName ?? "AgentFS";
157
+ this.description = options.description;
158
+ }
159
+ /** The underlying AgentFS instance, or null if not yet initialized. */
160
+ get agent() {
161
+ return this._agent;
162
+ }
163
+ getInfo() {
164
+ return {
165
+ id: this.id,
166
+ name: this.name,
167
+ provider: this.provider,
168
+ status: this.status,
169
+ error: this.error,
170
+ readOnly: this.readOnly,
171
+ icon: this.icon,
172
+ metadata: {
173
+ ...this._agentId && { agentId: this._agentId },
174
+ ...this._path && { dbPath: this._path }
175
+ }
176
+ };
177
+ }
178
+ getInstructions() {
179
+ return `AgentFS storage for ${this._agentId ? `agent "${this._agentId}"` : "database"}. ${this.readOnly ? "Read-only" : "Persistent"} SQLite-backed filesystem — files are retained across sessions.`;
180
+ }
181
+ async init() {
182
+ if (this._agent) return;
183
+ const openOptions = {};
184
+ if (this._agentId) openOptions.id = this._agentId;
185
+ if (this._path) {
186
+ openOptions.path = this._path;
187
+ (0, fs.mkdirSync)(path.default.dirname(this._path), { recursive: true });
188
+ }
189
+ this._agent = await agentfs_sdk.AgentFS.open(openOptions);
190
+ }
191
+ async destroy() {
192
+ if (this._agent && this._ownsAgent) await this._agent.close();
193
+ this._agent = null;
194
+ }
195
+ async getAgent() {
196
+ await this.ensureReady();
197
+ return this._agent;
198
+ }
199
+ assertWritable(operation) {
200
+ if (this.readOnly) throw new _mastra_core_workspace.WorkspaceReadOnlyError(operation);
201
+ }
202
+ async readFile(path$5, options) {
203
+ const agent = await this.getAgent();
204
+ const normalized = normalizePath(path$5);
205
+ try {
206
+ if (options?.encoding) return await agent.fs.readFile(normalized, options.encoding);
207
+ return await agent.fs.readFile(normalized);
208
+ } catch (error) {
209
+ throw mapError(error, normalized, "file");
210
+ }
211
+ }
212
+ async writeFile(path$6, content, options) {
213
+ this.assertWritable("writeFile");
214
+ const agent = await this.getAgent();
215
+ const normalized = normalizePath(path$6);
216
+ if (options?.recursive !== false) await this.mkdirRecursive(agent, getParentPath(normalized));
217
+ if (options?.overwrite === false) try {
218
+ await agent.fs.access(normalized);
219
+ throw new _mastra_core_workspace.FileExistsError(normalized);
220
+ } catch (error) {
221
+ if (error instanceof _mastra_core_workspace.FileExistsError) throw error;
222
+ if (!hasCode(error, "ENOENT")) throw mapError(error, normalized, "file");
223
+ }
224
+ try {
225
+ const data = typeof content === "string" ? content : Buffer.from(content);
226
+ await agent.fs.writeFile(normalized, data);
227
+ } catch (error) {
228
+ throw mapError(error, normalized, "file");
229
+ }
230
+ }
231
+ async appendFile(path$7, content) {
232
+ this.assertWritable("appendFile");
233
+ let existing = Buffer.alloc(0);
234
+ try {
235
+ const current = await this.readFile(path$7);
236
+ existing = Buffer.isBuffer(current) ? Buffer.from(current) : Buffer.from(current);
237
+ } catch (error) {
238
+ if (error instanceof _mastra_core_workspace.FileNotFoundError) {} else throw error;
239
+ }
240
+ const appendBuffer = typeof content === "string" ? Buffer.from(content, "utf-8") : Buffer.from(content);
241
+ await this.writeFile(path$7, Buffer.concat([existing, appendBuffer]));
242
+ }
243
+ async deleteFile(path$8, options) {
244
+ this.assertWritable("deleteFile");
245
+ const agent = await this.getAgent();
246
+ const normalized = normalizePath(path$8);
247
+ try {
248
+ if ((await agent.fs.stat(normalized)).isDirectory()) throw new _mastra_core_workspace.IsDirectoryError(normalized);
249
+ } catch (error) {
250
+ if (error instanceof _mastra_core_workspace.IsDirectoryError) throw error;
251
+ if (hasCode(error, "ENOENT")) {
252
+ if (options?.force) return;
253
+ throw new _mastra_core_workspace.FileNotFoundError(normalized);
254
+ }
255
+ throw mapError(error, normalized, "file");
256
+ }
257
+ try {
258
+ await agent.fs.unlink(normalized);
259
+ } catch (error) {
260
+ if (options?.force && hasCode(error, "ENOENT")) return;
261
+ throw mapError(error, normalized, "file");
262
+ }
263
+ }
264
+ async copyFile(src, dest, options) {
265
+ this.assertWritable("copyFile");
266
+ const agent = await this.getAgent();
267
+ const normalizedSrc = normalizePath(src);
268
+ const normalizedDest = normalizePath(dest);
269
+ if (options?.overwrite === false) try {
270
+ await agent.fs.access(normalizedDest);
271
+ throw new _mastra_core_workspace.FileExistsError(normalizedDest);
272
+ } catch (error) {
273
+ if (error instanceof _mastra_core_workspace.FileExistsError) throw error;
274
+ if (!hasCode(error, "ENOENT")) throw mapError(error, normalizedDest, "file");
275
+ }
276
+ try {
277
+ if ((await agent.fs.stat(normalizedSrc)).isDirectory()) {
278
+ if (!options?.recursive) throw new _mastra_core_workspace.IsDirectoryError(normalizedSrc);
279
+ await this.copyDirRecursive(agent, normalizedSrc, normalizedDest, options);
280
+ return;
281
+ }
282
+ await this.mkdirRecursive(agent, getParentPath(normalizedDest));
283
+ await agent.fs.copyFile(normalizedSrc, normalizedDest);
284
+ } catch (error) {
285
+ if (error instanceof _mastra_core_workspace.IsDirectoryError || error instanceof _mastra_core_workspace.FileExistsError) throw error;
286
+ throw mapError(error, normalizedSrc, "file");
287
+ }
288
+ }
289
+ async moveFile(src, dest, options) {
290
+ this.assertWritable("moveFile");
291
+ const agent = await this.getAgent();
292
+ const normalizedSrc = normalizePath(src);
293
+ const normalizedDest = normalizePath(dest);
294
+ if (options?.overwrite === false) try {
295
+ await agent.fs.access(normalizedDest);
296
+ throw new _mastra_core_workspace.FileExistsError(normalizedDest);
297
+ } catch (error) {
298
+ if (error instanceof _mastra_core_workspace.FileExistsError) throw error;
299
+ if (!hasCode(error, "ENOENT")) throw mapError(error, normalizedDest, "file");
300
+ }
301
+ await this.mkdirRecursive(agent, getParentPath(normalizedDest));
302
+ try {
303
+ await agent.fs.rename(normalizedSrc, normalizedDest);
304
+ } catch (error) {
305
+ throw mapError(error, normalizedSrc, "file");
306
+ }
307
+ }
308
+ async mkdir(path$9, options) {
309
+ this.assertWritable("mkdir");
310
+ const agent = await this.getAgent();
311
+ const normalized = normalizePath(path$9);
312
+ if (options?.recursive !== false) {
313
+ await this.mkdirRecursive(agent, normalized);
314
+ return;
315
+ }
316
+ try {
317
+ await agent.fs.mkdir(normalized);
318
+ } catch (error) {
319
+ throw mapError(error, normalized, "directory");
320
+ }
321
+ }
322
+ async rmdir(path$10, options) {
323
+ this.assertWritable("rmdir");
324
+ const agent = await this.getAgent();
325
+ const normalized = normalizePath(path$10);
326
+ if (options?.recursive) {
327
+ try {
328
+ await agent.fs.rm(normalized, { recursive: true });
329
+ } catch (error) {
330
+ if (options?.force && hasCode(error, "ENOENT")) return;
331
+ throw mapError(error, normalized, "directory");
332
+ }
333
+ return;
334
+ }
335
+ try {
336
+ if ((await agent.fs.readdir(normalized)).length > 0) throw new _mastra_core_workspace.DirectoryNotEmptyError(normalized);
337
+ await agent.fs.rmdir(normalized);
338
+ } catch (error) {
339
+ if (error instanceof _mastra_core_workspace.DirectoryNotEmptyError) throw error;
340
+ if (options?.force && hasCode(error, "ENOENT")) return;
341
+ throw mapError(error, normalized, "directory");
342
+ }
343
+ }
344
+ async readdir(path$11, options) {
345
+ const agent = await this.getAgent();
346
+ const normalized = normalizePath(path$11);
347
+ try {
348
+ if (!(await agent.fs.stat(normalized)).isDirectory()) throw new _mastra_core_workspace.NotDirectoryError(normalized);
349
+ let entries = (await agent.fs.readdirPlus(normalized)).map((entry) => ({
350
+ name: entry.name,
351
+ type: entry.stats.isDirectory() ? "directory" : "file",
352
+ size: entry.stats.size
353
+ }));
354
+ if (options?.extension) {
355
+ const extensions = Array.isArray(options.extension) ? options.extension : [options.extension];
356
+ entries = entries.filter((entry) => {
357
+ if (entry.type === "directory") return true;
358
+ return extensions.some((ext) => entry.name.endsWith(ext));
359
+ });
360
+ }
361
+ if (options?.recursive) {
362
+ const maxDepth = options.maxDepth ?? Infinity;
363
+ const subdirs = entries.filter((e) => e.type === "directory");
364
+ for (const dir of subdirs) if (maxDepth > 1) {
365
+ const subEntries = await this.readdir(joinPath(normalized, dir.name), {
366
+ ...options,
367
+ maxDepth: maxDepth - 1
368
+ });
369
+ for (const sub of subEntries) entries.push({
370
+ ...sub,
371
+ name: dir.name + "/" + sub.name
372
+ });
373
+ }
374
+ }
375
+ return entries;
376
+ } catch (error) {
377
+ if (error instanceof _mastra_core_workspace.NotDirectoryError || error instanceof _mastra_core_workspace.DirectoryNotFoundError) throw error;
378
+ throw mapError(error, normalized, "directory");
379
+ }
380
+ }
381
+ async exists(path$12) {
382
+ const agent = await this.getAgent();
383
+ const normalized = normalizePath(path$12);
384
+ try {
385
+ await agent.fs.access(normalized);
386
+ return true;
387
+ } catch {
388
+ return false;
389
+ }
390
+ }
391
+ async stat(path$13) {
392
+ const agent = await this.getAgent();
393
+ const normalized = normalizePath(path$13);
394
+ try {
395
+ const st = await agent.fs.stat(normalized);
396
+ return {
397
+ name: getBaseName(normalized) || "",
398
+ path: normalized,
399
+ type: st.isDirectory() ? "directory" : "file",
400
+ size: st.size,
401
+ createdAt: /* @__PURE__ */ new Date(st.ctime * 1e3),
402
+ modifiedAt: /* @__PURE__ */ new Date(st.mtime * 1e3)
403
+ };
404
+ } catch (error) {
405
+ throw mapError(error, normalized, "file");
406
+ }
407
+ }
408
+ /**
409
+ * Check if the path points to a file.
410
+ * Returns `false` if the path doesn't exist.
411
+ */
412
+ async isFile(path$14) {
413
+ try {
414
+ return (await this.stat(path$14)).type === "file";
415
+ } catch (error) {
416
+ if (error instanceof _mastra_core_workspace.FileNotFoundError) return false;
417
+ throw error;
418
+ }
419
+ }
420
+ /**
421
+ * Check if the path points to a directory.
422
+ * Returns `false` if the path doesn't exist.
423
+ */
424
+ async isDirectory(path$15) {
425
+ try {
426
+ return (await this.stat(path$15)).type === "directory";
427
+ } catch (error) {
428
+ if (error instanceof _mastra_core_workspace.FileNotFoundError) return false;
429
+ throw error;
430
+ }
431
+ }
432
+ /**
433
+ * Recursively create directories, ignoring EEXIST errors.
434
+ */
435
+ async mkdirRecursive(agent, path$16) {
436
+ if (path$16 === "/") return;
437
+ const segments = path$16.split("/").filter(Boolean);
438
+ let current = "";
439
+ for (const segment of segments) {
440
+ current += "/" + segment;
441
+ try {
442
+ await agent.fs.mkdir(current);
443
+ } catch (error) {
444
+ if (!hasCode(error, "EEXIST")) throw mapError(error, current, "directory");
445
+ }
446
+ }
447
+ }
448
+ /**
449
+ * Recursively copy a directory tree.
450
+ */
451
+ async copyDirRecursive(agent, src, dest, options) {
452
+ await this.mkdirRecursive(agent, dest);
453
+ const entries = await agent.fs.readdirPlus(src);
454
+ for (const entry of entries) {
455
+ const srcChild = joinPath(src, entry.name);
456
+ const destChild = joinPath(dest, entry.name);
457
+ if (entry.stats.isDirectory()) await this.copyDirRecursive(agent, srcChild, destChild, options);
458
+ else {
459
+ if (options?.overwrite === false) try {
460
+ await agent.fs.access(destChild);
461
+ throw new _mastra_core_workspace.FileExistsError(destChild);
462
+ } catch (error) {
463
+ if (error instanceof _mastra_core_workspace.FileExistsError) throw error;
464
+ if (!hasCode(error, "ENOENT")) throw mapError(error, destChild, "file");
465
+ }
466
+ await agent.fs.copyFile(srcChild, destChild);
467
+ }
468
+ }
469
+ }
503
470
  };
504
-
505
- // src/provider.ts
506
- var agentfsFilesystemProvider = {
507
- id: "agentfs",
508
- name: "AgentFS",
509
- description: "Turso/SQLite-backed filesystem via AgentFS",
510
- configSchema: {
511
- type: "object",
512
- properties: {
513
- agentId: { type: "string", description: "Agent ID \u2014 creates database at .agentfs/<agentId>.db" },
514
- path: { type: "string", description: "Explicit database file path (alternative to agentId)" },
515
- readOnly: { type: "boolean", description: "Mount as read-only", default: false }
516
- }
517
- },
518
- createFilesystem: (config) => new AgentFSFilesystem(config)
471
+ //#endregion
472
+ //#region src/provider.ts
473
+ const agentfsFilesystemProvider = {
474
+ id: "agentfs",
475
+ name: "AgentFS",
476
+ description: "Turso/SQLite-backed filesystem via AgentFS",
477
+ configSchema: {
478
+ type: "object",
479
+ properties: {
480
+ agentId: {
481
+ type: "string",
482
+ description: "Agent ID — creates database at .agentfs/<agentId>.db"
483
+ },
484
+ path: {
485
+ type: "string",
486
+ description: "Explicit database file path (alternative to agentId)"
487
+ },
488
+ readOnly: {
489
+ type: "boolean",
490
+ description: "Mount as read-only",
491
+ default: false
492
+ }
493
+ }
494
+ },
495
+ createFilesystem: (config) => new AgentFSFilesystem(config)
519
496
  };
520
-
497
+ //#endregion
521
498
  exports.AgentFSFilesystem = AgentFSFilesystem;
522
499
  exports.agentfsFilesystemProvider = agentfsFilesystemProvider;
523
- //# sourceMappingURL=index.cjs.map
500
+
524
501
  //# sourceMappingURL=index.cjs.map