@kuralle-agents/fs 0.6.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.
@@ -0,0 +1,73 @@
1
+ const textEncoder = new TextEncoder();
2
+ const textDecoder = new TextDecoder();
3
+ export function toBuffer(content, encoding) {
4
+ if (content instanceof Uint8Array) {
5
+ return content;
6
+ }
7
+ if (encoding === 'base64') {
8
+ return Uint8Array.from(atob(content), (c) => c.charCodeAt(0));
9
+ }
10
+ if (encoding === 'hex') {
11
+ const bytes = new Uint8Array(content.length / 2);
12
+ for (let i = 0; i < content.length; i += 2) {
13
+ bytes[i / 2] = parseInt(content.slice(i, i + 2), 16);
14
+ }
15
+ return bytes;
16
+ }
17
+ if (encoding === 'binary' || encoding === 'latin1') {
18
+ const chunkSize = 65536;
19
+ if (content.length <= chunkSize) {
20
+ return Uint8Array.from(content, (c) => c.charCodeAt(0));
21
+ }
22
+ const result = new Uint8Array(content.length);
23
+ for (let i = 0; i < content.length; i++) {
24
+ result[i] = content.charCodeAt(i);
25
+ }
26
+ return result;
27
+ }
28
+ return textEncoder.encode(content);
29
+ }
30
+ export function fromBuffer(buffer, encoding) {
31
+ if (encoding === 'base64') {
32
+ if (typeof Buffer !== 'undefined') {
33
+ return Buffer.from(buffer).toString('base64');
34
+ }
35
+ const chunkSize = 65536;
36
+ let binary = '';
37
+ for (let i = 0; i < buffer.length; i += chunkSize) {
38
+ const chunk = buffer.subarray(i, i + chunkSize);
39
+ binary += String.fromCharCode(...chunk);
40
+ }
41
+ return btoa(binary);
42
+ }
43
+ if (encoding === 'hex') {
44
+ return Array.from(buffer)
45
+ .map((b) => b.toString(16).padStart(2, '0'))
46
+ .join('');
47
+ }
48
+ if (encoding === 'binary' || encoding === 'latin1') {
49
+ if (typeof Buffer !== 'undefined') {
50
+ return Buffer.from(buffer).toString(encoding);
51
+ }
52
+ const chunkSize = 65536;
53
+ if (buffer.length <= chunkSize) {
54
+ return String.fromCharCode(...buffer);
55
+ }
56
+ let result = '';
57
+ for (let i = 0; i < buffer.length; i += chunkSize) {
58
+ const chunk = buffer.subarray(i, i + chunkSize);
59
+ result += String.fromCharCode(...chunk);
60
+ }
61
+ return result;
62
+ }
63
+ return textDecoder.decode(buffer);
64
+ }
65
+ export function getEncoding(options) {
66
+ if (options === null || options === undefined) {
67
+ return undefined;
68
+ }
69
+ if (typeof options === 'string') {
70
+ return options;
71
+ }
72
+ return options.encoding ?? undefined;
73
+ }
@@ -0,0 +1,48 @@
1
+ import type { BufferEncoding, CpOptions, FileContent, FileSystem, FileSystemDirent, FsStat, InitialFiles, MkdirOptions, ReadFileOptions, RmOptions, WriteFileOptions } from '@kuralle-agents/core';
2
+ export type { FileContent, FsStat, FileSystem };
3
+ export interface FsData {
4
+ [path: string]: import('@kuralle-agents/core').FsEntry;
5
+ }
6
+ export declare class InMemoryFs implements FileSystem {
7
+ private tree;
8
+ constructor(initialFiles?: InitialFiles);
9
+ writeFileSync(path: string, content: FileContent, options?: WriteFileOptions | BufferEncoding, metadata?: {
10
+ mode?: number;
11
+ mtime?: Date;
12
+ }): void;
13
+ writeFileLazy(path: string, lazy: () => string | Uint8Array | Promise<string | Uint8Array>, metadata?: {
14
+ mode?: number;
15
+ mtime?: Date;
16
+ }): void;
17
+ mkdirSync(path: string, options?: MkdirOptions): void;
18
+ readFile(path: string, options?: ReadFileOptions | BufferEncoding): Promise<string>;
19
+ readFileBytes(path: string): Promise<Uint8Array>;
20
+ writeFile(path: string, content: string, options?: WriteFileOptions | BufferEncoding): Promise<void>;
21
+ writeFileBytes(path: string, content: Uint8Array): Promise<void>;
22
+ appendFile(path: string, content: string | Uint8Array): Promise<void>;
23
+ exists(path: string): Promise<boolean>;
24
+ stat(path: string): Promise<FsStat>;
25
+ lstat(path: string): Promise<FsStat>;
26
+ mkdir(path: string, options?: MkdirOptions): Promise<void>;
27
+ readdir(path: string): Promise<string[]>;
28
+ readdirWithFileTypes(path: string): Promise<FileSystemDirent[]>;
29
+ rm(path: string, options?: RmOptions): Promise<void>;
30
+ cp(src: string, dest: string, options?: CpOptions): Promise<void>;
31
+ mv(src: string, dest: string): Promise<void>;
32
+ symlink(target: string, linkPath: string): Promise<void>;
33
+ readlink(path: string): Promise<string>;
34
+ realpath(path: string): Promise<string>;
35
+ resolvePath(base: string, path: string): string;
36
+ glob(pattern: string): Promise<string[]>;
37
+ private resolveNode;
38
+ private locate;
39
+ private canonicalize;
40
+ private insertContent;
41
+ private insertLazy;
42
+ private forceLazy;
43
+ private scaffold;
44
+ private placeNode;
45
+ private deepClone;
46
+ private gather;
47
+ private missing;
48
+ }
@@ -0,0 +1,523 @@
1
+ import { fromBuffer, getEncoding, toBuffer } from './encoding.js';
2
+ import { createGlobMatcher, sortPaths, DEFAULT_DIR_MODE, DEFAULT_FILE_MODE, MAX_SYMLINK_DEPTH, normalizePath, resolvePath, SYMLINK_MODE, validatePath, } from './path-utils.js';
3
+ const utf8 = new TextEncoder();
4
+ function split(normalized) {
5
+ return normalized === '/' ? [] : normalized.slice(1).split('/');
6
+ }
7
+ function freshDir() {
8
+ return {
9
+ kind: 'dir',
10
+ children: new Map(),
11
+ mode: DEFAULT_DIR_MODE,
12
+ mtime: new Date(),
13
+ };
14
+ }
15
+ function kindToType(entry) {
16
+ if (entry.kind === 'file' || entry.kind === 'lazy')
17
+ return 'file';
18
+ if (entry.kind === 'dir')
19
+ return 'directory';
20
+ return 'symlink';
21
+ }
22
+ function nodeSize(entry) {
23
+ if (entry.kind === 'file')
24
+ return entry.bytes.length;
25
+ if (entry.kind === 'symlink')
26
+ return entry.target.length;
27
+ return 0;
28
+ }
29
+ function isInitObj(v) {
30
+ return (typeof v === 'object' &&
31
+ v !== null &&
32
+ !(v instanceof Uint8Array) &&
33
+ 'content' in v);
34
+ }
35
+ export class InMemoryFs {
36
+ tree;
37
+ constructor(initialFiles) {
38
+ this.tree = freshDir();
39
+ if (!initialFiles)
40
+ return;
41
+ for (const [p, v] of Object.entries(initialFiles)) {
42
+ if (typeof v === 'function') {
43
+ this.insertLazy(p, v);
44
+ }
45
+ else if (isInitObj(v)) {
46
+ this.insertContent(p, v.content, getEncoding(undefined), v.mode, v.mtime);
47
+ }
48
+ else {
49
+ this.insertContent(p, v);
50
+ }
51
+ }
52
+ }
53
+ writeFileSync(path, content, options, metadata) {
54
+ this.insertContent(path, content, getEncoding(options), metadata?.mode, metadata?.mtime);
55
+ }
56
+ writeFileLazy(path, lazy, metadata) {
57
+ this.insertLazy(path, lazy, metadata?.mode, metadata?.mtime);
58
+ }
59
+ mkdirSync(path, options) {
60
+ validatePath(path, 'mkdir');
61
+ const norm = normalizePath(path);
62
+ if (norm === '/') {
63
+ if (!options?.recursive) {
64
+ throw new Error(`EEXIST: directory already exists, mkdir '${path}'`);
65
+ }
66
+ return;
67
+ }
68
+ const segs = split(norm);
69
+ let dir = this.tree;
70
+ for (let i = 0; i < segs.length; i++) {
71
+ const last = i === segs.length - 1;
72
+ const child = dir.children.get(segs[i]);
73
+ if (child) {
74
+ if (child.kind === 'dir') {
75
+ if (last) {
76
+ if (!options?.recursive) {
77
+ throw new Error(`EEXIST: directory already exists, mkdir '${path}'`);
78
+ }
79
+ return;
80
+ }
81
+ dir = child;
82
+ }
83
+ else if (last) {
84
+ throw new Error(`EEXIST: file already exists, mkdir '${path}'`);
85
+ }
86
+ else if (options?.recursive) {
87
+ const d = freshDir();
88
+ dir.children.set(segs[i], d);
89
+ dir = d;
90
+ }
91
+ else {
92
+ throw new Error(`ENOENT: no such file or directory, mkdir '${path}'`);
93
+ }
94
+ }
95
+ else if (last) {
96
+ dir.children.set(segs[i], freshDir());
97
+ }
98
+ else if (options?.recursive) {
99
+ const d = freshDir();
100
+ dir.children.set(segs[i], d);
101
+ dir = d;
102
+ }
103
+ else {
104
+ throw new Error(`ENOENT: no such file or directory, mkdir '${path}'`);
105
+ }
106
+ }
107
+ }
108
+ async readFile(path, options) {
109
+ return fromBuffer(await this.readFileBytes(path), getEncoding(options));
110
+ }
111
+ async readFileBytes(path) {
112
+ validatePath(path, 'open');
113
+ if (normalizePath(path) === '/') {
114
+ throw new Error(`EISDIR: illegal operation on a directory, read '${path}'`);
115
+ }
116
+ const loc = this.locate(path, true, 'open');
117
+ if (!loc)
118
+ throw this.missing('open', path);
119
+ if (loc.entry.kind === 'dir' || loc.entry.kind === 'symlink') {
120
+ throw new Error(`EISDIR: illegal operation on a directory, read '${path}'`);
121
+ }
122
+ if (loc.entry.kind === 'lazy')
123
+ return this.forceLazy(loc);
124
+ return loc.entry.bytes;
125
+ }
126
+ async writeFile(path, content, options) {
127
+ this.insertContent(path, content, getEncoding(options));
128
+ }
129
+ async writeFileBytes(path, content) {
130
+ this.insertContent(path, content);
131
+ }
132
+ async appendFile(path, content) {
133
+ validatePath(path, 'append');
134
+ const extra = typeof content === 'string' ? utf8.encode(content) : content;
135
+ const loc = this.locate(path, true, 'append');
136
+ if (loc?.entry.kind === 'dir') {
137
+ throw new Error(`EISDIR: illegal operation on a directory, write '${path}'`);
138
+ }
139
+ if (!loc) {
140
+ this.insertContent(path, content);
141
+ return;
142
+ }
143
+ let existing;
144
+ if (loc.entry.kind === 'lazy') {
145
+ existing = await this.forceLazy(loc);
146
+ }
147
+ else if (loc.entry.kind === 'file') {
148
+ existing = loc.entry.bytes;
149
+ }
150
+ else {
151
+ this.insertContent(path, content);
152
+ return;
153
+ }
154
+ const merged = new Uint8Array(existing.length + extra.length);
155
+ merged.set(existing);
156
+ merged.set(extra, existing.length);
157
+ const fresh = loc.parent.children.get(loc.key);
158
+ if (fresh && fresh.kind === 'file') {
159
+ fresh.bytes = merged;
160
+ fresh.mtime = new Date();
161
+ }
162
+ }
163
+ async exists(path) {
164
+ if (path.includes('\0'))
165
+ return false;
166
+ try {
167
+ if (normalizePath(path) === '/')
168
+ return true;
169
+ return this.locate(path, true, 'access') !== null;
170
+ }
171
+ catch {
172
+ return false;
173
+ }
174
+ }
175
+ async stat(path) {
176
+ validatePath(path, 'stat');
177
+ if (normalizePath(path) === '/') {
178
+ return {
179
+ type: 'directory',
180
+ size: 0,
181
+ mtime: this.tree.mtime,
182
+ mode: this.tree.mode,
183
+ };
184
+ }
185
+ const loc = this.locate(path, true, 'stat');
186
+ if (!loc)
187
+ throw this.missing('stat', path);
188
+ if (loc.entry.kind === 'lazy')
189
+ await this.forceLazy(loc);
190
+ const n = loc.parent.children.get(loc.key);
191
+ if (!n)
192
+ throw this.missing('stat', path);
193
+ return {
194
+ type: kindToType(n),
195
+ size: nodeSize(n),
196
+ mtime: n.mtime,
197
+ mode: n.mode,
198
+ };
199
+ }
200
+ async lstat(path) {
201
+ validatePath(path, 'lstat');
202
+ if (normalizePath(path) === '/') {
203
+ return {
204
+ type: 'directory',
205
+ size: 0,
206
+ mtime: this.tree.mtime,
207
+ mode: this.tree.mode,
208
+ };
209
+ }
210
+ const loc = this.locate(path, false, 'lstat');
211
+ if (!loc)
212
+ throw this.missing('lstat', path);
213
+ if (loc.entry.kind === 'symlink') {
214
+ return {
215
+ type: 'symlink',
216
+ size: loc.entry.target.length,
217
+ mtime: loc.entry.mtime,
218
+ mode: loc.entry.mode,
219
+ };
220
+ }
221
+ if (loc.entry.kind === 'lazy')
222
+ await this.forceLazy(loc);
223
+ const n = loc.parent.children.get(loc.key);
224
+ if (!n)
225
+ throw this.missing('lstat', path);
226
+ return {
227
+ type: kindToType(n),
228
+ size: nodeSize(n),
229
+ mtime: n.mtime,
230
+ mode: n.mode,
231
+ };
232
+ }
233
+ async mkdir(path, options) {
234
+ this.mkdirSync(path, options);
235
+ }
236
+ async readdir(path) {
237
+ return (await this.readdirWithFileTypes(path)).map((d) => d.name);
238
+ }
239
+ async readdirWithFileTypes(path) {
240
+ validatePath(path, 'scandir');
241
+ const dir = this.resolveNode(path, true, 'scandir');
242
+ if (!dir)
243
+ throw this.missing('scandir', path);
244
+ if (dir.kind !== 'dir') {
245
+ throw new Error(`ENOTDIR: not a directory, scandir '${path}'`);
246
+ }
247
+ const out = [];
248
+ for (const [name, child] of dir.children) {
249
+ out.push({ name, type: kindToType(child) });
250
+ }
251
+ return out.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
252
+ }
253
+ async rm(path, options) {
254
+ validatePath(path, 'rm');
255
+ const segs = split(normalizePath(path));
256
+ if (segs.length === 0) {
257
+ if (options?.force)
258
+ return;
259
+ throw new Error(`EPERM: cannot remove root, rm '${path}'`);
260
+ }
261
+ let dir = this.tree;
262
+ for (let i = 0; i < segs.length - 1; i++) {
263
+ const next = dir.children.get(segs[i]);
264
+ if (!next || next.kind !== 'dir') {
265
+ if (options?.force)
266
+ return;
267
+ throw this.missing('rm', path);
268
+ }
269
+ dir = next;
270
+ }
271
+ const name = segs[segs.length - 1];
272
+ const target = dir.children.get(name);
273
+ if (!target) {
274
+ if (options?.force)
275
+ return;
276
+ throw this.missing('rm', path);
277
+ }
278
+ if (target.kind === 'dir' &&
279
+ target.children.size > 0 &&
280
+ !options?.recursive) {
281
+ throw new Error(`ENOTEMPTY: directory not empty, rm '${path}'`);
282
+ }
283
+ dir.children.delete(name);
284
+ }
285
+ async cp(src, dest, options) {
286
+ validatePath(src, 'cp');
287
+ validatePath(dest, 'cp');
288
+ const srcNode = this.resolveNode(src, false, 'cp');
289
+ if (!srcNode)
290
+ throw this.missing('cp', src);
291
+ if (srcNode.kind === 'dir' && !options?.recursive) {
292
+ throw new Error(`EISDIR: is a directory, cp '${src}'`);
293
+ }
294
+ this.placeNode(normalizePath(dest), this.deepClone(srcNode));
295
+ }
296
+ async mv(src, dest) {
297
+ await this.cp(src, dest, { recursive: true });
298
+ await this.rm(src, { recursive: true });
299
+ }
300
+ async symlink(target, linkPath) {
301
+ validatePath(linkPath, 'symlink');
302
+ const segs = split(normalizePath(linkPath));
303
+ if (segs.length === 0) {
304
+ throw new Error(`EEXIST: file already exists, symlink '${linkPath}'`);
305
+ }
306
+ const parent = this.scaffold(segs);
307
+ const name = segs[segs.length - 1];
308
+ if (parent.children.has(name)) {
309
+ throw new Error(`EEXIST: file already exists, symlink '${linkPath}'`);
310
+ }
311
+ parent.children.set(name, {
312
+ kind: 'symlink',
313
+ target,
314
+ mode: SYMLINK_MODE,
315
+ mtime: new Date(),
316
+ });
317
+ }
318
+ async readlink(path) {
319
+ validatePath(path, 'readlink');
320
+ const loc = this.locate(path, false, 'readlink');
321
+ if (!loc)
322
+ throw this.missing('readlink', path);
323
+ if (loc.entry.kind !== 'symlink') {
324
+ throw new Error(`EINVAL: invalid argument, readlink '${path}'`);
325
+ }
326
+ return loc.entry.target;
327
+ }
328
+ async realpath(path) {
329
+ validatePath(path, 'realpath');
330
+ const canon = this.canonicalize(path);
331
+ if (canon === null)
332
+ throw this.missing('realpath', path);
333
+ return canon;
334
+ }
335
+ resolvePath(base, path) {
336
+ return resolvePath(base, path);
337
+ }
338
+ async glob(pattern) {
339
+ const re = createGlobMatcher(pattern);
340
+ const hits = [];
341
+ this.gather(this.tree, '', re, hits);
342
+ return sortPaths(hits);
343
+ }
344
+ resolveNode(rawPath, followLast, op) {
345
+ if (normalizePath(rawPath) === '/')
346
+ return this.tree;
347
+ const loc = this.locate(rawPath, followLast, op);
348
+ return loc ? loc.entry : null;
349
+ }
350
+ locate(rawPath, followLast, op) {
351
+ const norm = normalizePath(rawPath);
352
+ if (norm === '/')
353
+ return null;
354
+ const pending = split(norm);
355
+ const trail = [];
356
+ let dir = this.tree;
357
+ let budget = MAX_SYMLINK_DEPTH;
358
+ while (pending.length > 0) {
359
+ const seg = pending.shift();
360
+ const child = dir.children.get(seg);
361
+ if (!child)
362
+ return null;
363
+ const last = pending.length === 0;
364
+ if (child.kind === 'symlink' && (!last || followLast)) {
365
+ if (--budget < 0) {
366
+ throw new Error(`ELOOP: too many levels of symbolic links, ${op} '${rawPath}'`);
367
+ }
368
+ const base = trail.length > 0 ? '/' + trail.join('/') : '';
369
+ const abs = child.target.startsWith('/')
370
+ ? normalizePath(child.target)
371
+ : normalizePath(base + '/' + child.target);
372
+ pending.unshift(...split(abs));
373
+ trail.length = 0;
374
+ dir = this.tree;
375
+ continue;
376
+ }
377
+ if (last)
378
+ return { entry: child, parent: dir, key: seg };
379
+ if (child.kind !== 'dir')
380
+ return null;
381
+ trail.push(seg);
382
+ dir = child;
383
+ }
384
+ return null;
385
+ }
386
+ canonicalize(rawPath) {
387
+ const norm = normalizePath(rawPath);
388
+ if (norm === '/')
389
+ return '/';
390
+ const pending = split(norm);
391
+ const resolved = [];
392
+ let dir = this.tree;
393
+ let budget = MAX_SYMLINK_DEPTH;
394
+ while (pending.length > 0) {
395
+ const seg = pending.shift();
396
+ const child = dir.children.get(seg);
397
+ if (!child)
398
+ return null;
399
+ if (child.kind === 'symlink') {
400
+ if (--budget < 0) {
401
+ throw new Error(`ELOOP: too many levels of symbolic links, realpath '${rawPath}'`);
402
+ }
403
+ const base = resolved.length > 0 ? '/' + resolved.join('/') : '';
404
+ const abs = child.target.startsWith('/')
405
+ ? normalizePath(child.target)
406
+ : normalizePath(base + '/' + child.target);
407
+ pending.unshift(...split(abs));
408
+ resolved.length = 0;
409
+ dir = this.tree;
410
+ continue;
411
+ }
412
+ resolved.push(seg);
413
+ if (child.kind === 'dir' && pending.length > 0) {
414
+ dir = child;
415
+ }
416
+ else if (pending.length > 0) {
417
+ return null;
418
+ }
419
+ }
420
+ return '/' + resolved.join('/');
421
+ }
422
+ insertContent(rawPath, content, encoding, mode, mtime) {
423
+ validatePath(rawPath, 'write');
424
+ const segs = split(normalizePath(rawPath));
425
+ if (segs.length === 0) {
426
+ throw new Error(`EISDIR: illegal operation on a directory, write '${rawPath}'`);
427
+ }
428
+ const parent = this.scaffold(segs);
429
+ parent.children.set(segs[segs.length - 1], {
430
+ kind: 'file',
431
+ bytes: toBuffer(content, encoding),
432
+ mode: mode ?? DEFAULT_FILE_MODE,
433
+ mtime: mtime ?? new Date(),
434
+ });
435
+ }
436
+ insertLazy(rawPath, provider, mode, mtime) {
437
+ validatePath(rawPath, 'write');
438
+ const segs = split(normalizePath(rawPath));
439
+ if (segs.length === 0)
440
+ return;
441
+ const parent = this.scaffold(segs);
442
+ parent.children.set(segs[segs.length - 1], {
443
+ kind: 'lazy',
444
+ provider,
445
+ mode: mode ?? DEFAULT_FILE_MODE,
446
+ mtime: mtime ?? new Date(),
447
+ });
448
+ }
449
+ async forceLazy(loc) {
450
+ const lazy = loc.entry;
451
+ const raw = await lazy.provider();
452
+ const bytes = typeof raw === 'string' ? utf8.encode(raw) : raw;
453
+ loc.parent.children.set(loc.key, {
454
+ kind: 'file',
455
+ bytes,
456
+ mode: lazy.mode,
457
+ mtime: lazy.mtime,
458
+ });
459
+ return bytes;
460
+ }
461
+ scaffold(segs) {
462
+ let dir = this.tree;
463
+ for (let i = 0; i < segs.length - 1; i++) {
464
+ const child = dir.children.get(segs[i]);
465
+ if (child && child.kind === 'dir') {
466
+ dir = child;
467
+ }
468
+ else {
469
+ const d = freshDir();
470
+ dir.children.set(segs[i], d);
471
+ dir = d;
472
+ }
473
+ }
474
+ return dir;
475
+ }
476
+ placeNode(normalized, entry) {
477
+ const segs = split(normalized);
478
+ if (segs.length === 0) {
479
+ throw new Error(`EISDIR: illegal operation on a directory, write '${normalized}'`);
480
+ }
481
+ const parent = this.scaffold(segs);
482
+ parent.children.set(segs[segs.length - 1], entry);
483
+ }
484
+ deepClone(entry) {
485
+ switch (entry.kind) {
486
+ case 'file':
487
+ return {
488
+ kind: 'file',
489
+ bytes: new Uint8Array(entry.bytes),
490
+ mode: entry.mode,
491
+ mtime: entry.mtime,
492
+ };
493
+ case 'lazy':
494
+ return { ...entry };
495
+ case 'symlink':
496
+ return { ...entry };
497
+ case 'dir': {
498
+ const clone = {
499
+ kind: 'dir',
500
+ children: new Map(),
501
+ mode: entry.mode,
502
+ mtime: entry.mtime,
503
+ };
504
+ for (const [k, v] of entry.children) {
505
+ clone.children.set(k, this.deepClone(v));
506
+ }
507
+ return clone;
508
+ }
509
+ }
510
+ }
511
+ gather(dir, prefix, re, out) {
512
+ for (const [name, child] of dir.children) {
513
+ const full = prefix + '/' + name;
514
+ if (re.test(full))
515
+ out.push(full);
516
+ if (child.kind === 'dir')
517
+ this.gather(child, full, re, out);
518
+ }
519
+ }
520
+ missing(op, path) {
521
+ return new Error(`ENOENT: no such file or directory, ${op} '${path}'`);
522
+ }
523
+ }
@@ -0,0 +1,6 @@
1
+ export type { FileSystem, FsStat, FileSystemDirent, FileSystemEntryType, BufferEncoding, FileContent, MkdirOptions, RmOptions, CpOptions, ReadFileOptions, WriteFileOptions, FileEntry, DirectoryEntry, SymlinkEntry, LazyFileEntry, FsEntry, FileInit, LazyFileProvider, InitialFiles, } from '@kuralle-agents/core';
2
+ export { InMemoryFs, type FsData } from './in-memory-fs.js';
3
+ export { CompositeFileSystem, type CompositeFileSystemConfig } from './composite-fs.js';
4
+ export { normalizePath, validatePath, dirname, resolvePath, joinPath, resolveSymlinkTarget, createGlobMatcher, sortPaths, MAX_SYMLINK_DEPTH, DEFAULT_DIR_MODE, DEFAULT_FILE_MODE, SYMLINK_MODE, } from './path-utils.js';
5
+ export { toBuffer, fromBuffer, getEncoding } from './encoding.js';
6
+ export { createFsTool } from './tool.js';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { InMemoryFs } from './in-memory-fs.js';
2
+ export { CompositeFileSystem } from './composite-fs.js';
3
+ export { normalizePath, validatePath, dirname, resolvePath, joinPath, resolveSymlinkTarget, createGlobMatcher, sortPaths, MAX_SYMLINK_DEPTH, DEFAULT_DIR_MODE, DEFAULT_FILE_MODE, SYMLINK_MODE, } from './path-utils.js';
4
+ export { toBuffer, fromBuffer, getEncoding } from './encoding.js';
5
+ export { createFsTool } from './tool.js';
@@ -0,0 +1 @@
1
+ export type { FileSystem, FsStat, FileSystemDirent, FileSystemEntryType, BufferEncoding, FileContent, MkdirOptions, RmOptions, CpOptions, ReadFileOptions, WriteFileOptions, FileEntry, DirectoryEntry, SymlinkEntry, LazyFileEntry, FsEntry, FileInit, LazyFileProvider, InitialFiles, FsError, } from '@kuralle-agents/core';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ export declare const MAX_SYMLINK_DEPTH = 40;
2
+ export declare const DEFAULT_DIR_MODE = 493;
3
+ export declare const DEFAULT_FILE_MODE = 420;
4
+ export declare const SYMLINK_MODE = 511;
5
+ export declare function normalizePath(path: string): string;
6
+ export declare function validatePath(path: string, operation: string): void;
7
+ export declare function dirname(path: string): string;
8
+ export declare function resolvePath(base: string, path: string): string;
9
+ export declare function joinPath(parent: string, child: string): string;
10
+ export declare function resolveSymlinkTarget(symlinkPath: string, target: string): string;
11
+ export declare function createGlobMatcher(pattern: string): RegExp;
12
+ export declare function sortPaths(paths: string[]): string[];