@mastra/archil 0.2.0 → 0.2.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,491 +1,443 @@
1
- 'use strict';
2
-
3
- var workspace = require('@mastra/core/workspace');
4
- var disk = require('disk');
5
-
6
- // src/filesystem.ts
7
- var MIME_TYPES = {
8
- ".txt": "text/plain",
9
- ".md": "text/markdown",
10
- ".html": "text/html",
11
- ".css": "text/css",
12
- ".csv": "text/csv",
13
- ".xml": "text/xml",
14
- ".js": "text/javascript",
15
- ".mjs": "text/javascript",
16
- ".ts": "text/typescript",
17
- ".tsx": "text/typescript",
18
- ".jsx": "text/javascript",
19
- ".json": "application/json",
20
- ".yaml": "text/yaml",
21
- ".yml": "text/yaml",
22
- ".py": "text/x-python",
23
- ".sh": "text/x-shellscript",
24
- ".png": "image/png",
25
- ".jpg": "image/jpeg",
26
- ".jpeg": "image/jpeg",
27
- ".gif": "image/gif",
28
- ".svg": "image/svg+xml",
29
- ".webp": "image/webp",
30
- ".pdf": "application/pdf",
31
- ".zip": "application/zip",
32
- ".gz": "application/gzip",
33
- ".tar": "application/x-tar"
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _mastra_core_workspace = require("@mastra/core/workspace");
3
+ let disk = require("disk");
4
+ //#region src/filesystem.ts
5
+ const MIME_TYPES = {
6
+ ".txt": "text/plain",
7
+ ".md": "text/markdown",
8
+ ".html": "text/html",
9
+ ".css": "text/css",
10
+ ".csv": "text/csv",
11
+ ".xml": "text/xml",
12
+ ".js": "text/javascript",
13
+ ".mjs": "text/javascript",
14
+ ".ts": "text/typescript",
15
+ ".tsx": "text/typescript",
16
+ ".jsx": "text/javascript",
17
+ ".json": "application/json",
18
+ ".yaml": "text/yaml",
19
+ ".yml": "text/yaml",
20
+ ".py": "text/x-python",
21
+ ".sh": "text/x-shellscript",
22
+ ".png": "image/png",
23
+ ".jpg": "image/jpeg",
24
+ ".jpeg": "image/jpeg",
25
+ ".gif": "image/gif",
26
+ ".svg": "image/svg+xml",
27
+ ".webp": "image/webp",
28
+ ".pdf": "application/pdf",
29
+ ".zip": "application/zip",
30
+ ".gz": "application/gzip",
31
+ ".tar": "application/x-tar"
34
32
  };
35
33
  function getMimeType(path) {
36
- const ext = path.toLowerCase().match(/\.[^.]+$/)?.[0];
37
- return ext ? MIME_TYPES[ext] ?? "application/octet-stream" : "application/octet-stream";
34
+ const ext = path.toLowerCase().match(/\.[^.]+$/)?.[0];
35
+ return ext ? MIME_TYPES[ext] ?? "application/octet-stream" : "application/octet-stream";
38
36
  }
37
+ /** Trim leading and trailing slashes. */
39
38
  function trimSlashes(s) {
40
- let start = 0;
41
- let end = s.length;
42
- while (start < end && s[start] === "/") start++;
43
- while (end > start && s[end - 1] === "/") end--;
44
- return s.slice(start, end);
39
+ let start = 0;
40
+ let end = s.length;
41
+ while (start < end && s[start] === "/") start++;
42
+ while (end > start && s[end - 1] === "/") end--;
43
+ return s.slice(start, end);
45
44
  }
45
+ /** Normalize a workspace path to a key (no leading slash). */
46
46
  function toKey(path) {
47
- return trimSlashes(path) || "";
47
+ return trimSlashes(path) || "";
48
48
  }
49
+ /** Get the basename from a path. */
49
50
  function basename(path) {
50
- const key = toKey(path);
51
- const idx = key.lastIndexOf("/");
52
- return idx === -1 ? key : key.slice(idx + 1);
51
+ const key = toKey(path);
52
+ const idx = key.lastIndexOf("/");
53
+ return idx === -1 ? key : key.slice(idx + 1);
53
54
  }
55
+ /** Get the parent directory key (empty = root). */
54
56
  function dirname(path) {
55
- const key = toKey(path);
56
- const idx = key.lastIndexOf("/");
57
- return idx === -1 ? "" : key.slice(0, idx);
57
+ const key = toKey(path);
58
+ const idx = key.lastIndexOf("/");
59
+ return idx === -1 ? "" : key.slice(0, idx);
58
60
  }
61
+ /** Shell-escape a string for use in exec commands. */
59
62
  function shellEscape(s) {
60
- return "'" + s.replace(/'/g, "'\\''") + "'";
63
+ return "'" + s.replace(/'/g, "'\\''") + "'";
61
64
  }
62
- var ArchilFilesystem = class extends workspace.MastraFilesystem {
63
- id;
64
- name = "ArchilFilesystem";
65
- provider = "archil";
66
- readOnly;
67
- displayName;
68
- icon;
69
- description;
70
- status = "pending";
71
- _disk = null;
72
- _archil = null;
73
- _diskId;
74
- _createDiskOptions;
75
- _archilOptions;
76
- constructor(options) {
77
- super({ ...options, name: "ArchilFilesystem" });
78
- this.id = options.id ?? `archil-fs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
79
- this.readOnly = options.readOnly;
80
- this.displayName = options.displayName ?? "Archil";
81
- this.icon = options.icon ?? "cloud";
82
- this.description = options.description ?? "Elastic serverless filesystem powered by Archil";
83
- this._diskId = options.diskId;
84
- this._createDiskOptions = options.createDiskOptions;
85
- this._archilOptions = {
86
- apiKey: options.apiKey,
87
- region: options.region,
88
- baseUrl: options.baseUrl,
89
- s3BaseUrl: options.s3BaseUrl
90
- };
91
- }
92
- // ---------------------------------------------------------------------------
93
- // Public accessors
94
- // ---------------------------------------------------------------------------
95
- /** The underlying Archil Disk instance (available after init). */
96
- get disk() {
97
- if (!this._disk) {
98
- throw new Error("ArchilFilesystem not initialized \u2014 call init() first");
99
- }
100
- return this._disk;
101
- }
102
- /** The Archil SDK client instance. */
103
- get archil() {
104
- if (!this._archil) {
105
- this._archil = new disk.Archil(this._archilOptions);
106
- }
107
- return this._archil;
108
- }
109
- // ---------------------------------------------------------------------------
110
- // Lifecycle
111
- // ---------------------------------------------------------------------------
112
- async init() {
113
- try {
114
- if (this._diskId && this._createDiskOptions) {
115
- throw new Error("diskId and createDiskOptions are mutually exclusive");
116
- }
117
- if (this._diskId) {
118
- this._disk = await this.archil.disks.get(this._diskId);
119
- } else if (this._createDiskOptions) {
120
- const result = await this.archil.disks.create(this._createDiskOptions);
121
- this._disk = result.disk;
122
- } else {
123
- throw new Error("Either diskId or createDiskOptions must be provided");
124
- }
125
- this.status = "ready";
126
- } catch (err) {
127
- this.status = "error";
128
- this.error = err instanceof Error ? err.message : String(err);
129
- throw err;
130
- }
131
- }
132
- async destroy() {
133
- this._disk = null;
134
- this._archil = null;
135
- }
136
- isReady() {
137
- return this.status === "ready" && this._disk !== null;
138
- }
139
- getInfo() {
140
- return {
141
- id: this.id,
142
- name: this.name,
143
- provider: this.provider,
144
- status: this.status,
145
- error: this.error,
146
- readOnly: this.readOnly,
147
- icon: this.icon,
148
- metadata: {
149
- diskId: this._disk?.id ?? "",
150
- region: this._disk?.region ?? "",
151
- diskName: this._disk?.name ?? ""
152
- }
153
- };
154
- }
155
- getInstructions() {
156
- const access = this.readOnly ? "Read-only" : "Persistent";
157
- const diskName = this._disk?.name ?? "Archil disk";
158
- return `Archil elastic filesystem "${diskName}". ${access} storage \u2014 files persist across sessions. Supports serverless execution via exec().`;
159
- }
160
- // ---------------------------------------------------------------------------
161
- // Archil-specific operations
162
- // ---------------------------------------------------------------------------
163
- /**
164
- * Execute a shell command on the disk's filesystem.
165
- * The disk is mounted as the working directory.
166
- */
167
- async exec(command) {
168
- await this.ensureReady();
169
- this.assertWritable();
170
- return this.disk.exec(command);
171
- }
172
- /**
173
- * Parallel grep across files on the disk.
174
- */
175
- async grep(opts) {
176
- await this.ensureReady();
177
- return this.disk.grep(opts);
178
- }
179
- /**
180
- * Create a signed, time-limited download URL for a file.
181
- */
182
- async share(key, opts) {
183
- await this.ensureReady();
184
- return this.disk.share(key, opts);
185
- }
186
- /**
187
- * List objects using the S3-compatible API directly.
188
- */
189
- async listObjects(prefix, opts) {
190
- await this.ensureReady();
191
- return this.disk.listObjects(prefix, opts);
192
- }
193
- /**
194
- * Get object metadata without downloading.
195
- */
196
- async headObject(key) {
197
- await this.ensureReady();
198
- return this.disk.headObject(key);
199
- }
200
- // ---------------------------------------------------------------------------
201
- // File Operations (WorkspaceFilesystem interface)
202
- // ---------------------------------------------------------------------------
203
- async readFile(path, options) {
204
- await this.ensureReady();
205
- const key = toKey(path);
206
- if (!key) {
207
- throw new Error("Cannot read file at root path");
208
- }
209
- try {
210
- const data = await this.disk.getObject(key);
211
- if (options?.encoding) {
212
- return Buffer.from(data).toString(options.encoding);
213
- }
214
- return Buffer.from(data);
215
- } catch (err) {
216
- if (isNotFound(err)) {
217
- throw new workspace.FileNotFoundError(path);
218
- }
219
- throw err;
220
- }
221
- }
222
- async writeFile(path, content, options) {
223
- await this.ensureReady();
224
- this.assertWritable();
225
- const key = toKey(path);
226
- if (!key) {
227
- throw new Error("Cannot write file at root path");
228
- }
229
- if (options?.overwrite === false) {
230
- const exists = await this.disk.objectExists(key);
231
- if (exists) {
232
- throw new workspace.FileExistsError(path);
233
- }
234
- }
235
- if (options?.recursive) {
236
- const dir = dirname(path);
237
- if (dir) {
238
- await this.disk.exec(`mkdir -p ${shellEscape(dir)}`);
239
- }
240
- }
241
- const body = typeof content === "string" ? content : content instanceof Uint8Array ? content : new Uint8Array(content);
242
- const mimeType = options?.mimeType ?? getMimeType(path);
243
- await this.disk.putObject(key, body, mimeType);
244
- }
245
- async appendFile(path, content) {
246
- await this.ensureReady();
247
- this.assertWritable();
248
- const key = toKey(path);
249
- if (!key) {
250
- throw new Error("Cannot append to root path");
251
- }
252
- const data = typeof content === "string" ? content : Buffer.from(content).toString("base64");
253
- if (typeof content === "string") {
254
- await this.disk.exec(`printf '%s' ${shellEscape(data)} >> ${shellEscape(key)}`);
255
- } else {
256
- await this.disk.exec(`printf '%s' ${shellEscape(data)} | base64 -d >> ${shellEscape(key)}`);
257
- }
258
- }
259
- async deleteFile(path, options) {
260
- await this.ensureReady();
261
- this.assertWritable();
262
- const key = toKey(path);
263
- if (!key) {
264
- throw new Error("Cannot delete root path");
265
- }
266
- if (!options?.force) {
267
- const exists = await this.disk.objectExists(key);
268
- if (!exists) {
269
- throw new workspace.FileNotFoundError(path);
270
- }
271
- }
272
- await this.disk.deleteObject(key);
273
- }
274
- async copyFile(src, dest, options) {
275
- await this.ensureReady();
276
- this.assertWritable();
277
- const srcKey = toKey(src);
278
- const destKey = toKey(dest);
279
- if (!options?.overwrite) {
280
- const exists = await this.disk.objectExists(destKey);
281
- if (exists) {
282
- throw new workspace.FileExistsError(dest);
283
- }
284
- }
285
- const flags = options?.recursive ? "-r" : "";
286
- const result = await this.disk.exec(`cp ${flags} ${shellEscape(srcKey)} ${shellEscape(destKey)}`);
287
- if (result.exitCode !== 0) {
288
- if (result.stderr.includes("No such file")) {
289
- throw new workspace.FileNotFoundError(src);
290
- }
291
- throw new Error(`cp failed: ${result.stderr}`);
292
- }
293
- }
294
- async moveFile(src, dest, options) {
295
- await this.ensureReady();
296
- this.assertWritable();
297
- const srcKey = toKey(src);
298
- const destKey = toKey(dest);
299
- if (!options?.overwrite) {
300
- const exists = await this.disk.objectExists(destKey);
301
- if (exists) {
302
- throw new workspace.FileExistsError(dest);
303
- }
304
- }
305
- const result = await this.disk.exec(`mv ${shellEscape(srcKey)} ${shellEscape(destKey)}`);
306
- if (result.exitCode !== 0) {
307
- if (result.stderr.includes("No such file")) {
308
- throw new workspace.FileNotFoundError(src);
309
- }
310
- throw new Error(`mv failed: ${result.stderr}`);
311
- }
312
- }
313
- // ---------------------------------------------------------------------------
314
- // Directory Operations
315
- // ---------------------------------------------------------------------------
316
- async mkdir(path, options) {
317
- await this.ensureReady();
318
- this.assertWritable();
319
- const key = toKey(path);
320
- if (!key) return;
321
- const flag = options?.recursive ? "-p" : "";
322
- const result = await this.disk.exec(`mkdir ${flag} ${shellEscape(key)}`);
323
- if (result.exitCode !== 0) {
324
- if (result.stderr.includes("File exists")) {
325
- throw new workspace.FileExistsError(path);
326
- }
327
- throw new Error(`mkdir failed: ${result.stderr}`);
328
- }
329
- }
330
- async rmdir(path, options) {
331
- await this.ensureReady();
332
- this.assertWritable();
333
- const key = toKey(path);
334
- if (!key) {
335
- throw new Error("Cannot remove root directory");
336
- }
337
- const cmd = options?.recursive ? `rm -r${options?.force ? "f" : ""} ${shellEscape(key)}` : `rmdir ${shellEscape(key)}`;
338
- const result = await this.disk.exec(options?.force ? `${cmd} 2>/dev/null; true` : cmd);
339
- if (result.exitCode !== 0 && !options?.force) {
340
- if (result.stderr.includes("No such file") || result.stderr.includes("not found")) {
341
- throw new workspace.FileNotFoundError(path);
342
- }
343
- throw new Error(`rmdir failed: ${result.stderr}`);
344
- }
345
- }
346
- async readdir(path, options) {
347
- await this.ensureReady();
348
- const key = toKey(path);
349
- const prefix = key ? key + "/" : "";
350
- if (options?.recursive) {
351
- return this.readdirRecursive(prefix, options);
352
- }
353
- const result = await this.disk.listObjects(prefix, { recursive: false });
354
- const entries = [];
355
- for (const obj of result.objects) {
356
- const name = obj.key.slice(prefix.length);
357
- if (!name || name.includes("/")) continue;
358
- if (options?.extension) {
359
- const extensions = Array.isArray(options.extension) ? options.extension : [options.extension];
360
- const ext = name.match(/\.[^.]+$/)?.[0] ?? "";
361
- if (!extensions.includes(ext)) continue;
362
- }
363
- entries.push({
364
- name,
365
- type: "file",
366
- size: obj.size
367
- });
368
- }
369
- for (const cp of result.commonPrefixes) {
370
- const name = trimSlashes(cp.slice(prefix.length));
371
- if (!name) continue;
372
- entries.push({
373
- name,
374
- type: "directory"
375
- });
376
- }
377
- return entries;
378
- }
379
- async readdirRecursive(prefix, options) {
380
- const result = await this.disk.listObjects(prefix, { recursive: true });
381
- const entries = [];
382
- for (const obj of result.objects) {
383
- const relativePath = obj.key.slice(prefix.length);
384
- if (!relativePath) continue;
385
- if (options?.maxDepth !== void 0) {
386
- const depth = relativePath.split("/").length - 1;
387
- if (depth > options.maxDepth) continue;
388
- }
389
- if (options?.extension) {
390
- const extensions = Array.isArray(options.extension) ? options.extension : [options.extension];
391
- const ext = relativePath.match(/\.[^.]+$/)?.[0] ?? "";
392
- if (!extensions.includes(ext)) continue;
393
- }
394
- entries.push({
395
- name: relativePath,
396
- type: "file",
397
- size: obj.size
398
- });
399
- }
400
- return entries;
401
- }
402
- // ---------------------------------------------------------------------------
403
- // Path Operations
404
- // ---------------------------------------------------------------------------
405
- async exists(path) {
406
- await this.ensureReady();
407
- const key = toKey(path);
408
- if (!key) return true;
409
- const fileExists = await this.disk.objectExists(key);
410
- if (fileExists) return true;
411
- const result = await this.disk.listObjects(key + "/", { singlePage: true, limit: 1 });
412
- return result.objects.length > 0 || result.commonPrefixes.length > 0;
413
- }
414
- async stat(path) {
415
- await this.ensureReady();
416
- const key = toKey(path);
417
- if (!key) {
418
- return {
419
- name: "",
420
- path: "/",
421
- type: "directory",
422
- size: 0,
423
- createdAt: /* @__PURE__ */ new Date(0),
424
- modifiedAt: /* @__PURE__ */ new Date(0)
425
- };
426
- }
427
- const meta = await this.disk.headObject(key);
428
- if (meta) {
429
- return {
430
- name: basename(path),
431
- path: "/" + key,
432
- type: "file",
433
- size: meta.size,
434
- createdAt: meta.lastModified ?? /* @__PURE__ */ new Date(0),
435
- modifiedAt: meta.lastModified ?? /* @__PURE__ */ new Date(0),
436
- mimeType: meta.contentType
437
- };
438
- }
439
- const result = await this.disk.listObjects(key + "/", { singlePage: true, limit: 1 });
440
- if (result.objects.length > 0 || result.commonPrefixes.length > 0) {
441
- return {
442
- name: basename(path),
443
- path: "/" + key,
444
- type: "directory",
445
- size: 0,
446
- createdAt: /* @__PURE__ */ new Date(0),
447
- modifiedAt: /* @__PURE__ */ new Date(0)
448
- };
449
- }
450
- throw new workspace.FileNotFoundError(path);
451
- }
452
- // ---------------------------------------------------------------------------
453
- // Helpers
454
- // ---------------------------------------------------------------------------
455
- assertWritable() {
456
- if (this.readOnly) {
457
- throw new Error("Filesystem is read-only");
458
- }
459
- }
65
+ var ArchilFilesystem = class extends _mastra_core_workspace.MastraFilesystem {
66
+ id;
67
+ name = "ArchilFilesystem";
68
+ provider = "archil";
69
+ readOnly;
70
+ displayName;
71
+ icon;
72
+ description;
73
+ status = "pending";
74
+ _disk = null;
75
+ _archil = null;
76
+ _diskId;
77
+ _createDiskOptions;
78
+ _archilOptions;
79
+ constructor(options) {
80
+ super({
81
+ ...options,
82
+ name: "ArchilFilesystem"
83
+ });
84
+ this.id = options.id ?? `archil-fs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
85
+ this.readOnly = options.readOnly;
86
+ this.displayName = options.displayName ?? "Archil";
87
+ this.icon = options.icon ?? "cloud";
88
+ this.description = options.description ?? "Elastic serverless filesystem powered by Archil";
89
+ this._diskId = options.diskId;
90
+ this._createDiskOptions = options.createDiskOptions;
91
+ this._archilOptions = {
92
+ apiKey: options.apiKey,
93
+ region: options.region,
94
+ baseUrl: options.baseUrl,
95
+ s3BaseUrl: options.s3BaseUrl
96
+ };
97
+ }
98
+ /** The underlying Archil Disk instance (available after init). */
99
+ get disk() {
100
+ if (!this._disk) throw new Error("ArchilFilesystem not initialized — call init() first");
101
+ return this._disk;
102
+ }
103
+ /** The Archil SDK client instance. */
104
+ get archil() {
105
+ if (!this._archil) this._archil = new disk.Archil(this._archilOptions);
106
+ return this._archil;
107
+ }
108
+ async init() {
109
+ try {
110
+ if (this._diskId && this._createDiskOptions) throw new Error("diskId and createDiskOptions are mutually exclusive");
111
+ if (this._diskId) this._disk = await this.archil.disks.get(this._diskId);
112
+ else if (this._createDiskOptions) {
113
+ const result = await this.archil.disks.create(this._createDiskOptions);
114
+ this._disk = result.disk;
115
+ } else throw new Error("Either diskId or createDiskOptions must be provided");
116
+ this.status = "ready";
117
+ } catch (err) {
118
+ this.status = "error";
119
+ this.error = err instanceof Error ? err.message : String(err);
120
+ throw err;
121
+ }
122
+ }
123
+ async destroy() {
124
+ this._disk = null;
125
+ this._archil = null;
126
+ }
127
+ isReady() {
128
+ return this.status === "ready" && this._disk !== null;
129
+ }
130
+ getInfo() {
131
+ return {
132
+ id: this.id,
133
+ name: this.name,
134
+ provider: this.provider,
135
+ status: this.status,
136
+ error: this.error,
137
+ readOnly: this.readOnly,
138
+ icon: this.icon,
139
+ metadata: {
140
+ diskId: this._disk?.id ?? "",
141
+ region: this._disk?.region ?? "",
142
+ diskName: this._disk?.name ?? ""
143
+ }
144
+ };
145
+ }
146
+ getInstructions() {
147
+ const access = this.readOnly ? "Read-only" : "Persistent";
148
+ return `Archil elastic filesystem "${this._disk?.name ?? "Archil disk"}". ${access} storage — files persist across sessions. Supports serverless execution via exec().`;
149
+ }
150
+ /**
151
+ * Execute a shell command on the disk's filesystem.
152
+ * The disk is mounted as the working directory.
153
+ */
154
+ async exec(command) {
155
+ await this.ensureReady();
156
+ this.assertWritable();
157
+ return this.disk.exec(command);
158
+ }
159
+ /**
160
+ * Parallel grep across files on the disk.
161
+ */
162
+ async grep(opts) {
163
+ await this.ensureReady();
164
+ return this.disk.grep(opts);
165
+ }
166
+ /**
167
+ * Create a signed, time-limited download URL for a file.
168
+ */
169
+ async share(key, opts) {
170
+ await this.ensureReady();
171
+ return this.disk.share(key, opts);
172
+ }
173
+ /**
174
+ * List objects using the S3-compatible API directly.
175
+ */
176
+ async listObjects(prefix, opts) {
177
+ await this.ensureReady();
178
+ return this.disk.listObjects(prefix, opts);
179
+ }
180
+ /**
181
+ * Get object metadata without downloading.
182
+ */
183
+ async headObject(key) {
184
+ await this.ensureReady();
185
+ return this.disk.headObject(key);
186
+ }
187
+ async readFile(path, options) {
188
+ await this.ensureReady();
189
+ const key = toKey(path);
190
+ if (!key) throw new Error("Cannot read file at root path");
191
+ try {
192
+ const data = await this.disk.getObject(key);
193
+ if (options?.encoding) return Buffer.from(data).toString(options.encoding);
194
+ return Buffer.from(data);
195
+ } catch (err) {
196
+ if (isNotFound(err)) throw new _mastra_core_workspace.FileNotFoundError(path);
197
+ throw err;
198
+ }
199
+ }
200
+ async writeFile(path, content, options) {
201
+ await this.ensureReady();
202
+ this.assertWritable();
203
+ const key = toKey(path);
204
+ if (!key) throw new Error("Cannot write file at root path");
205
+ if (options?.overwrite === false) {
206
+ if (await this.disk.objectExists(key)) throw new _mastra_core_workspace.FileExistsError(path);
207
+ }
208
+ if (options?.recursive) {
209
+ const dir = dirname(path);
210
+ if (dir) await this.disk.exec(`mkdir -p ${shellEscape(dir)}`);
211
+ }
212
+ const body = typeof content === "string" ? content : content instanceof Uint8Array ? content : new Uint8Array(content);
213
+ const mimeType = options?.mimeType ?? getMimeType(path);
214
+ await this.disk.putObject(key, body, mimeType);
215
+ }
216
+ async appendFile(path, content) {
217
+ await this.ensureReady();
218
+ this.assertWritable();
219
+ const key = toKey(path);
220
+ if (!key) throw new Error("Cannot append to root path");
221
+ const data = typeof content === "string" ? content : Buffer.from(content).toString("base64");
222
+ if (typeof content === "string") await this.disk.exec(`printf '%s' ${shellEscape(data)} >> ${shellEscape(key)}`);
223
+ else await this.disk.exec(`printf '%s' ${shellEscape(data)} | base64 -d >> ${shellEscape(key)}`);
224
+ }
225
+ async deleteFile(path, options) {
226
+ await this.ensureReady();
227
+ this.assertWritable();
228
+ const key = toKey(path);
229
+ if (!key) throw new Error("Cannot delete root path");
230
+ if (!options?.force) {
231
+ if (!await this.disk.objectExists(key)) throw new _mastra_core_workspace.FileNotFoundError(path);
232
+ }
233
+ await this.disk.deleteObject(key);
234
+ }
235
+ async copyFile(src, dest, options) {
236
+ await this.ensureReady();
237
+ this.assertWritable();
238
+ const srcKey = toKey(src);
239
+ const destKey = toKey(dest);
240
+ if (!options?.overwrite) {
241
+ if (await this.disk.objectExists(destKey)) throw new _mastra_core_workspace.FileExistsError(dest);
242
+ }
243
+ const flags = options?.recursive ? "-r" : "";
244
+ const result = await this.disk.exec(`cp ${flags} ${shellEscape(srcKey)} ${shellEscape(destKey)}`);
245
+ if (result.exitCode !== 0) {
246
+ if (result.stderr.includes("No such file")) throw new _mastra_core_workspace.FileNotFoundError(src);
247
+ throw new Error(`cp failed: ${result.stderr}`);
248
+ }
249
+ }
250
+ async moveFile(src, dest, options) {
251
+ await this.ensureReady();
252
+ this.assertWritable();
253
+ const srcKey = toKey(src);
254
+ const destKey = toKey(dest);
255
+ if (!options?.overwrite) {
256
+ if (await this.disk.objectExists(destKey)) throw new _mastra_core_workspace.FileExistsError(dest);
257
+ }
258
+ const result = await this.disk.exec(`mv ${shellEscape(srcKey)} ${shellEscape(destKey)}`);
259
+ if (result.exitCode !== 0) {
260
+ if (result.stderr.includes("No such file")) throw new _mastra_core_workspace.FileNotFoundError(src);
261
+ throw new Error(`mv failed: ${result.stderr}`);
262
+ }
263
+ }
264
+ async mkdir(path, options) {
265
+ await this.ensureReady();
266
+ this.assertWritable();
267
+ const key = toKey(path);
268
+ if (!key) return;
269
+ const flag = options?.recursive ? "-p" : "";
270
+ const result = await this.disk.exec(`mkdir ${flag} ${shellEscape(key)}`);
271
+ if (result.exitCode !== 0) {
272
+ if (result.stderr.includes("File exists")) throw new _mastra_core_workspace.FileExistsError(path);
273
+ throw new Error(`mkdir failed: ${result.stderr}`);
274
+ }
275
+ }
276
+ async rmdir(path, options) {
277
+ await this.ensureReady();
278
+ this.assertWritable();
279
+ const key = toKey(path);
280
+ if (!key) throw new Error("Cannot remove root directory");
281
+ const cmd = options?.recursive ? `rm -r${options?.force ? "f" : ""} ${shellEscape(key)}` : `rmdir ${shellEscape(key)}`;
282
+ const result = await this.disk.exec(options?.force ? `${cmd} 2>/dev/null; true` : cmd);
283
+ if (result.exitCode !== 0 && !options?.force) {
284
+ if (result.stderr.includes("No such file") || result.stderr.includes("not found")) throw new _mastra_core_workspace.FileNotFoundError(path);
285
+ throw new Error(`rmdir failed: ${result.stderr}`);
286
+ }
287
+ }
288
+ async readdir(path, options) {
289
+ await this.ensureReady();
290
+ const key = toKey(path);
291
+ const prefix = key ? key + "/" : "";
292
+ if (options?.recursive) return this.readdirRecursive(prefix, options);
293
+ const result = await this.disk.listObjects(prefix, { recursive: false });
294
+ const entries = [];
295
+ for (const obj of result.objects) {
296
+ const name = obj.key.slice(prefix.length);
297
+ if (!name || name.includes("/")) continue;
298
+ if (options?.extension) {
299
+ const extensions = Array.isArray(options.extension) ? options.extension : [options.extension];
300
+ const ext = name.match(/\.[^.]+$/)?.[0] ?? "";
301
+ if (!extensions.includes(ext)) continue;
302
+ }
303
+ entries.push({
304
+ name,
305
+ type: "file",
306
+ size: obj.size
307
+ });
308
+ }
309
+ for (const cp of result.commonPrefixes) {
310
+ const name = trimSlashes(cp.slice(prefix.length));
311
+ if (!name) continue;
312
+ entries.push({
313
+ name,
314
+ type: "directory"
315
+ });
316
+ }
317
+ return entries;
318
+ }
319
+ async readdirRecursive(prefix, options) {
320
+ const result = await this.disk.listObjects(prefix, { recursive: true });
321
+ const entries = [];
322
+ for (const obj of result.objects) {
323
+ const relativePath = obj.key.slice(prefix.length);
324
+ if (!relativePath) continue;
325
+ if (options?.maxDepth !== void 0) {
326
+ if (relativePath.split("/").length - 1 > options.maxDepth) continue;
327
+ }
328
+ if (options?.extension) {
329
+ const extensions = Array.isArray(options.extension) ? options.extension : [options.extension];
330
+ const ext = relativePath.match(/\.[^.]+$/)?.[0] ?? "";
331
+ if (!extensions.includes(ext)) continue;
332
+ }
333
+ entries.push({
334
+ name: relativePath,
335
+ type: "file",
336
+ size: obj.size
337
+ });
338
+ }
339
+ return entries;
340
+ }
341
+ async exists(path) {
342
+ await this.ensureReady();
343
+ const key = toKey(path);
344
+ if (!key) return true;
345
+ if (await this.disk.objectExists(key)) return true;
346
+ const result = await this.disk.listObjects(key + "/", {
347
+ singlePage: true,
348
+ limit: 1
349
+ });
350
+ return result.objects.length > 0 || result.commonPrefixes.length > 0;
351
+ }
352
+ async stat(path) {
353
+ await this.ensureReady();
354
+ const key = toKey(path);
355
+ if (!key) return {
356
+ name: "",
357
+ path: "/",
358
+ type: "directory",
359
+ size: 0,
360
+ createdAt: /* @__PURE__ */ new Date(0),
361
+ modifiedAt: /* @__PURE__ */ new Date(0)
362
+ };
363
+ const meta = await this.disk.headObject(key);
364
+ if (meta) return {
365
+ name: basename(path),
366
+ path: "/" + key,
367
+ type: "file",
368
+ size: meta.size,
369
+ createdAt: meta.lastModified ?? /* @__PURE__ */ new Date(0),
370
+ modifiedAt: meta.lastModified ?? /* @__PURE__ */ new Date(0),
371
+ mimeType: meta.contentType
372
+ };
373
+ const result = await this.disk.listObjects(key + "/", {
374
+ singlePage: true,
375
+ limit: 1
376
+ });
377
+ if (result.objects.length > 0 || result.commonPrefixes.length > 0) return {
378
+ name: basename(path),
379
+ path: "/" + key,
380
+ type: "directory",
381
+ size: 0,
382
+ createdAt: /* @__PURE__ */ new Date(0),
383
+ modifiedAt: /* @__PURE__ */ new Date(0)
384
+ };
385
+ throw new _mastra_core_workspace.FileNotFoundError(path);
386
+ }
387
+ assertWritable() {
388
+ if (this.readOnly) throw new Error("Filesystem is read-only");
389
+ }
460
390
  };
461
391
  function isNotFound(err) {
462
- if (!err || typeof err !== "object") return false;
463
- const e = err;
464
- return e.status === 404 || e.code === "NoSuchKey";
392
+ if (!err || typeof err !== "object") return false;
393
+ const e = err;
394
+ return e.status === 404 || e.code === "NoSuchKey";
465
395
  }
466
-
467
- // src/provider.ts
468
- var archilFilesystemProvider = {
469
- id: "archil",
470
- name: "Archil",
471
- description: "Elastic, serverless filesystem for AI agents (Archil)",
472
- configSchema: {
473
- type: "object",
474
- oneOf: [{ required: ["diskId"] }, { required: ["createDiskOptions"] }],
475
- properties: {
476
- diskId: { type: "string", description: 'Existing Archil disk ID (e.g. "dsk-0123456789abcdef")' },
477
- createDiskOptions: { type: "object", description: "Options used to create a new Archil disk on init" },
478
- apiKey: { type: "string", description: "Archil API key (falls back to ARCHIL_API_KEY env var)" },
479
- region: { type: "string", description: 'Archil region (e.g. "aws-us-east-1")' },
480
- readOnly: { type: "boolean", description: "Mount as read-only", default: false },
481
- baseUrl: { type: "string", description: "Custom control-plane URL (for testing)" },
482
- s3BaseUrl: { type: "string", description: "Custom S3 API URL" }
483
- }
484
- },
485
- createFilesystem: (config) => new ArchilFilesystem(config)
396
+ //#endregion
397
+ //#region src/provider.ts
398
+ const archilFilesystemProvider = {
399
+ id: "archil",
400
+ name: "Archil",
401
+ description: "Elastic, serverless filesystem for AI agents (Archil)",
402
+ configSchema: {
403
+ type: "object",
404
+ oneOf: [{ required: ["diskId"] }, { required: ["createDiskOptions"] }],
405
+ properties: {
406
+ diskId: {
407
+ type: "string",
408
+ description: "Existing Archil disk ID (e.g. \"dsk-0123456789abcdef\")"
409
+ },
410
+ createDiskOptions: {
411
+ type: "object",
412
+ description: "Options used to create a new Archil disk on init"
413
+ },
414
+ apiKey: {
415
+ type: "string",
416
+ description: "Archil API key (falls back to ARCHIL_API_KEY env var)"
417
+ },
418
+ region: {
419
+ type: "string",
420
+ description: "Archil region (e.g. \"aws-us-east-1\")"
421
+ },
422
+ readOnly: {
423
+ type: "boolean",
424
+ description: "Mount as read-only",
425
+ default: false
426
+ },
427
+ baseUrl: {
428
+ type: "string",
429
+ description: "Custom control-plane URL (for testing)"
430
+ },
431
+ s3BaseUrl: {
432
+ type: "string",
433
+ description: "Custom S3 API URL"
434
+ }
435
+ }
436
+ },
437
+ createFilesystem: (config) => new ArchilFilesystem(config)
486
438
  };
487
-
439
+ //#endregion
488
440
  exports.ArchilFilesystem = ArchilFilesystem;
489
441
  exports.archilFilesystemProvider = archilFilesystemProvider;
490
- //# sourceMappingURL=index.cjs.map
442
+
491
443
  //# sourceMappingURL=index.cjs.map