toolcraft 0.0.762 → 0.0.764
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/composition.json +2 -2
- package/dist/composition.json +2 -2
- package/node_modules/@poe-code/safe-fs/README.md +1 -0
- package/node_modules/@poe-code/safe-fs/dist/contracts/filesystem.d.ts +5 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/devices/index.d.ts +1 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/devices/index.js +34 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/memory/index.d.ts +1 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/memory/index.js +20 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/read-file-stream.js +86 -60
- package/node_modules/@poe-code/safe-fs/dist/fs/readonly/index.d.ts +1 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/readonly/index.js +10 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/real/index.d.ts +1 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/real/index.js +27 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/scoped.js +9 -3
- package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
- package/node_modules/toolcraft-schema/package.json +1 -1
- package/package.json +2 -2
package/composition.json
CHANGED
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"name": "toolcraft",
|
|
136
|
-
"version": "0.0.
|
|
136
|
+
"version": "0.0.764",
|
|
137
137
|
"license": "MIT"
|
|
138
138
|
},
|
|
139
139
|
{
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
"name": "toolcraft-schema",
|
|
146
|
-
"version": "0.0.
|
|
146
|
+
"version": "0.0.764",
|
|
147
147
|
"license": "MIT"
|
|
148
148
|
},
|
|
149
149
|
{
|
package/dist/composition.json
CHANGED
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"name": "toolcraft",
|
|
136
|
-
"version": "0.0.
|
|
136
|
+
"version": "0.0.764",
|
|
137
137
|
"license": "MIT"
|
|
138
138
|
},
|
|
139
139
|
{
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
"name": "toolcraft-schema",
|
|
146
|
-
"version": "0.0.
|
|
146
|
+
"version": "0.0.764",
|
|
147
147
|
"license": "MIT"
|
|
148
148
|
},
|
|
149
149
|
{
|
|
@@ -86,6 +86,7 @@ cause. Preserve cancellation/control exceptions separately. Cross-family
|
|
|
86
86
|
| Change the namespace | `mkdir`, `rm`, `rename`, `copyFile` |
|
|
87
87
|
| Remove an empty directory | Optional `rmdir`; never a recursive-delete fallback |
|
|
88
88
|
| Links and metadata | Optional `readlink`, `symlink`, `link`, `chmod`, `utimes`, `truncate` |
|
|
89
|
+
| Enumerate directories lazily | Optional `iterateDirectory`; memory and native backends, with readonly/quota/device/scoped delegation; backend order, no sorted-array fallback |
|
|
89
90
|
| Stream bytes | Optional `readStream`, `writeStream`, using async iterables of byte chunks |
|
|
90
91
|
| Retain an open file | Optional `open` with positioned I/O and synchronization; memory and real backends support `noFollow: true` to atomically refuse a final symlink |
|
|
91
92
|
| Publish immutable objects atomically | Optional `publishFileConditional` with opaque identity/version stats and authoritative compare-and-publish |
|
|
@@ -352,6 +352,11 @@ export interface FileSystem {
|
|
|
352
352
|
lstat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
353
353
|
compareEntry?(path: string, peer: FileSystem, peerPath: string, options?: FsOptions): Promise<EntryComparison>;
|
|
354
354
|
readdir(path: string, options?: ReadDirectoryOptions): Promise<DirectoryEntry[]>;
|
|
355
|
+
/** Optional bounded, lazy directory enumeration in backend-defined order.
|
|
356
|
+
* No complete listing/sort fallback. Consumers must retire the iterator on
|
|
357
|
+
* early exit. Namespace changes may reject or follow the backend's live view;
|
|
358
|
+
* this is not a tree snapshot or a retained path-authority grant. */
|
|
359
|
+
iterateDirectory?(path: string, options?: FsOptions): AsyncIterable<DirectoryEntry>;
|
|
355
360
|
mkdir(path: string, options?: MkdirOptions): Promise<void>;
|
|
356
361
|
rm(path: string, options?: RemoveOptions): Promise<void>;
|
|
357
362
|
/** Atomic final-entry removal; every directory is refused, including raced replacements. */
|
|
@@ -25,6 +25,7 @@ export declare class DeviceFileSystem implements FileSystem {
|
|
|
25
25
|
writeFile(path: string, data: Uint8Array, options?: WriteFileOptions): Promise<void>;
|
|
26
26
|
appendFile(path: string, data: Uint8Array, options?: AppendFileOptions): Promise<void>;
|
|
27
27
|
writeStream(path: string, source: ByteSource, options?: WriteFileOptions): Promise<void>;
|
|
28
|
+
iterateDirectory(path: string, options?: FsOptions): AsyncIterable<DirectoryEntry>;
|
|
28
29
|
readdir(path: string, options?: ReadDirectoryOptions): Promise<DirectoryEntry[]>;
|
|
29
30
|
mkdir(path: string, options?: MkdirOptions): Promise<void>;
|
|
30
31
|
rm(path: string, options?: RemoveOptions): Promise<void>;
|
|
@@ -490,6 +490,40 @@ export class DeviceFileSystem {
|
|
|
490
490
|
throw new FsError("ENOTSUP", { path });
|
|
491
491
|
await this.#filesystem.writeStream(path, source, options);
|
|
492
492
|
}
|
|
493
|
+
async *iterateDirectory(path, options = {}) {
|
|
494
|
+
const resolved = await this.#resolve(path, options);
|
|
495
|
+
if (resolved === nullPath)
|
|
496
|
+
throw new FsError("ENOTDIR", { syscall: "iterateDirectory", path });
|
|
497
|
+
const virtual = resolved === "/" ? "dev" : resolved === deviceDirectory ? "null" : undefined;
|
|
498
|
+
if (!this.#filesystem.iterateDirectory)
|
|
499
|
+
throw new FsError("ENOTSUP", { syscall: "iterateDirectory", path });
|
|
500
|
+
let seen = false;
|
|
501
|
+
try {
|
|
502
|
+
for await (const entry of this.#filesystem.iterateDirectory(virtual ? resolved : path, options)) {
|
|
503
|
+
options.signal?.throwIfAborted();
|
|
504
|
+
if (entry.name === "." || entry.name === "..")
|
|
505
|
+
continue;
|
|
506
|
+
if (!entry.name || entry.name.includes("/") || entry.name.includes("\0"))
|
|
507
|
+
throw new FsError("EIO", { path, message: "invalid directory entry" });
|
|
508
|
+
if (entry.name === virtual) {
|
|
509
|
+
if (seen)
|
|
510
|
+
continue;
|
|
511
|
+
seen = true;
|
|
512
|
+
yield { name: virtual, type: virtual === "dev" ? "directory" : "character" };
|
|
513
|
+
}
|
|
514
|
+
else
|
|
515
|
+
yield { name: entry.name, type: entry.type };
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
options.signal?.throwIfAborted();
|
|
520
|
+
if (!virtual || !isFsError(error, "ENOENT") && !isFsError(error, "ENOTDIR"))
|
|
521
|
+
throw error;
|
|
522
|
+
}
|
|
523
|
+
options.signal?.throwIfAborted();
|
|
524
|
+
if (virtual && !seen)
|
|
525
|
+
yield { name: virtual, type: virtual === "dev" ? "directory" : "character" };
|
|
526
|
+
}
|
|
493
527
|
readdir(path, options = {}) {
|
|
494
528
|
const fast = this.#tryResolveSync(path, options);
|
|
495
529
|
if (fast !== undefined && fast !== "/") {
|
|
@@ -134,6 +134,7 @@ export declare class MemoryFileSystem implements FileSystem {
|
|
|
134
134
|
appendFile(path: string, data: Uint8Array, options?: AppendFileOptions): Promise<void>;
|
|
135
135
|
stat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
136
136
|
lstat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
137
|
+
iterateDirectory(path: string, options?: FsOptions): AsyncIterable<DirectoryEntry>;
|
|
137
138
|
readdir(path: string, options?: ReadDirectoryOptions): Promise<DirectoryEntry[]>;
|
|
138
139
|
tryMkdirFastSync(path: string, recursive: boolean, mode: number | undefined): boolean;
|
|
139
140
|
tryRmFastSync(path: string, recursive: boolean, force: boolean): boolean;
|
|
@@ -2508,6 +2508,26 @@ export class MemoryFileSystem {
|
|
|
2508
2508
|
ownedStats.set(stat, { filesystem: this, path, root: this.root });
|
|
2509
2509
|
return stat;
|
|
2510
2510
|
}
|
|
2511
|
+
async *iterateDirectory(path, options = {}) {
|
|
2512
|
+
options.signal?.throwIfAborted();
|
|
2513
|
+
const root = this.root, node = this.resolveNode(path, "iterateDirectory", true);
|
|
2514
|
+
if (node.type !== "directory")
|
|
2515
|
+
this.fail("ENOTDIR", "iterateDirectory", path);
|
|
2516
|
+
this.permission(node, 4, "iterateDirectory", path);
|
|
2517
|
+
const revision = node.revision, ino = node.ino;
|
|
2518
|
+
const check = () => {
|
|
2519
|
+
options.signal?.throwIfAborted();
|
|
2520
|
+
if (this.root !== root || node.ino !== ino || node.revision !== revision || this.resolveNode(path, "iterateDirectory", true) !== node)
|
|
2521
|
+
this.fail("EBUSY", "iterateDirectory", path);
|
|
2522
|
+
this.permission(node, 4, "iterateDirectory", path);
|
|
2523
|
+
};
|
|
2524
|
+
node.atimeMs = Date.now();
|
|
2525
|
+
for (const [name, entry] of node.entries) {
|
|
2526
|
+
check();
|
|
2527
|
+
yield { name, type: entry.type };
|
|
2528
|
+
}
|
|
2529
|
+
check();
|
|
2530
|
+
}
|
|
2511
2531
|
async readdir(path, options = {}) {
|
|
2512
2532
|
const limit = directoryEntryLimit(options, path);
|
|
2513
2533
|
const node = this.resolveNode(path, "readdir", true);
|
|
@@ -6,72 +6,98 @@ const byteKind = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Uint8Arra
|
|
|
6
6
|
/** Sequential payload access without a whole-file fallback. The injected backend
|
|
7
7
|
* must supply streaming reads or retained range reads; no private storage is used.
|
|
8
8
|
* Chunks are borrowed until the consumer advances the iterator. */
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const iterator = source[Symbol.asyncIterator]();
|
|
26
|
-
let done = false, failed = true;
|
|
9
|
+
export function readFileStream(fs, path, options = {}) {
|
|
10
|
+
let activeCleanup;
|
|
11
|
+
const generator = (async function* () {
|
|
12
|
+
const { signal } = options;
|
|
13
|
+
signal?.throwIfAborted();
|
|
14
|
+
const chunkSize = options.chunkSize ?? 65536;
|
|
15
|
+
let position = options.start ?? 0;
|
|
16
|
+
const end = options.endExclusive ?? Number.MAX_SAFE_INTEGER;
|
|
17
|
+
if (!Number.isSafeInteger(chunkSize) || chunkSize <= 0 || !Number.isSafeInteger(position) || position < 0
|
|
18
|
+
|| !Number.isSafeInteger(end) || end < position)
|
|
19
|
+
throw new FsError("EINVAL", { path, syscall: "readStream" });
|
|
20
|
+
const capabilities = await fs.capabilitiesFor?.(path, options) ?? fs.capabilities;
|
|
21
|
+
signal?.throwIfAborted();
|
|
22
|
+
if (!options.skipStream && fs.readStream && fs.capabilities?.streamingRead !== false && capabilities?.streamingRead !== false) {
|
|
23
|
+
let emitted = false;
|
|
24
|
+
let reading = true;
|
|
27
25
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
const source = fs.readStream(path, { ...options, chunkSize });
|
|
27
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
28
|
+
let done = false, failed = true;
|
|
29
|
+
let returned;
|
|
30
|
+
const closeIterator = () => returned ??= Promise.resolve().then(() => iterator.return?.());
|
|
31
|
+
activeCleanup = () => done ? Promise.resolve() : closeIterator();
|
|
32
|
+
try {
|
|
33
|
+
while (true) {
|
|
34
|
+
signal?.throwIfAborted();
|
|
35
|
+
const item = await iterator.next();
|
|
36
|
+
signal?.throwIfAborted();
|
|
37
|
+
if (item.done) {
|
|
38
|
+
done = true;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
reading = false;
|
|
42
|
+
if (byteLength.call(item.value))
|
|
43
|
+
emitted = true;
|
|
44
|
+
yield item.value;
|
|
45
|
+
reading = true;
|
|
35
46
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
failed = false;
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
activeCleanup = undefined;
|
|
51
|
+
if (!done)
|
|
52
|
+
await finishCleanup(closeIterator, failed);
|
|
41
53
|
}
|
|
42
|
-
|
|
54
|
+
return;
|
|
43
55
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
catch (error) {
|
|
57
|
+
signal?.throwIfAborted();
|
|
58
|
+
if (!reading || emitted || !(error instanceof FsError) || error.code !== "ENOTSUP")
|
|
59
|
+
throw error;
|
|
47
60
|
}
|
|
48
|
-
return;
|
|
49
61
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
const handle = await openRetainedReadFile(fs, path, options);
|
|
63
|
+
let failed = true;
|
|
64
|
+
let closed;
|
|
65
|
+
const closeHandle = () => closed ??= Promise.resolve().then(() => handle.close());
|
|
66
|
+
activeCleanup = closeHandle;
|
|
67
|
+
try {
|
|
68
|
+
while (position < end) {
|
|
69
|
+
signal?.throwIfAborted();
|
|
70
|
+
const maximum = Math.min(chunkSize, end - position);
|
|
71
|
+
const bytes = await handle.read(position, maximum, options);
|
|
72
|
+
signal?.throwIfAborted();
|
|
73
|
+
if (byteKind.call(bytes) !== "Uint8Array" || byteLength.call(bytes) > maximum)
|
|
74
|
+
throw new FsError("EIO", { path, syscall: "read" });
|
|
75
|
+
const length = byteLength.call(bytes);
|
|
76
|
+
if (!length)
|
|
77
|
+
break;
|
|
78
|
+
position += length;
|
|
79
|
+
yield bytes;
|
|
80
|
+
}
|
|
81
|
+
failed = false;
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
activeCleanup = undefined;
|
|
85
|
+
await finishCleanup(closeHandle, failed);
|
|
86
|
+
}
|
|
87
|
+
})();
|
|
88
|
+
const originalReturn = generator.return.bind(generator);
|
|
89
|
+
generator.return = async (value) => {
|
|
90
|
+
let cleanupError;
|
|
91
|
+
try {
|
|
92
|
+
await activeCleanup?.();
|
|
54
93
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
let failed = true;
|
|
58
|
-
try {
|
|
59
|
-
while (position < end) {
|
|
60
|
-
signal?.throwIfAborted();
|
|
61
|
-
const maximum = Math.min(chunkSize, end - position);
|
|
62
|
-
const bytes = await handle.read(position, maximum, options);
|
|
63
|
-
signal?.throwIfAborted();
|
|
64
|
-
if (byteKind.call(bytes) !== "Uint8Array" || byteLength.call(bytes) > maximum)
|
|
65
|
-
throw new FsError("EIO", { path, syscall: "read" });
|
|
66
|
-
const length = byteLength.call(bytes);
|
|
67
|
-
if (!length)
|
|
68
|
-
break;
|
|
69
|
-
position += length;
|
|
70
|
-
yield bytes;
|
|
94
|
+
catch (reason) {
|
|
95
|
+
cleanupError = { reason };
|
|
71
96
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
97
|
+
const result = await originalReturn(value);
|
|
98
|
+
if (cleanupError)
|
|
99
|
+
throw cleanupError.reason;
|
|
100
|
+
return result;
|
|
101
|
+
};
|
|
102
|
+
return generator;
|
|
77
103
|
}
|
|
@@ -13,6 +13,7 @@ export declare class ReadOnlyFileSystem implements FileSystem {
|
|
|
13
13
|
stat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
14
14
|
lstat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
15
15
|
compareEntry(path: string, peer: FileSystem, peerPath: string, options?: FsOptions): Promise<import("../../contracts/filesystem.js").EntryComparison>;
|
|
16
|
+
iterateDirectory(path: string, options?: FsOptions): AsyncIterable<DirectoryEntry>;
|
|
16
17
|
readdir(path: string, options?: ReadDirectoryOptions): Promise<DirectoryEntry[]>;
|
|
17
18
|
realpath(path: string, options?: FsOptions): Promise<string>;
|
|
18
19
|
access(path: string, mode?: number, options?: FsOptions): Promise<void>;
|
|
@@ -122,6 +122,16 @@ export class ReadOnlyFileSystem {
|
|
|
122
122
|
compareEntry(path, peer, peerPath, options = {}) {
|
|
123
123
|
return compareEntries(this, path, peer, peerPath, options);
|
|
124
124
|
}
|
|
125
|
+
async *iterateDirectory(path, options = {}) {
|
|
126
|
+
options.signal?.throwIfAborted();
|
|
127
|
+
if (!this.#filesystem.iterateDirectory)
|
|
128
|
+
throw new FsError("ENOTSUP", { syscall: "iterateDirectory", path });
|
|
129
|
+
for await (const entry of this.#filesystem.iterateDirectory(path, options)) {
|
|
130
|
+
options.signal?.throwIfAborted();
|
|
131
|
+
yield { name: entry.name, type: entry.type };
|
|
132
|
+
}
|
|
133
|
+
options.signal?.throwIfAborted();
|
|
134
|
+
}
|
|
125
135
|
async readdir(path, options) {
|
|
126
136
|
const limit = options?.maxEntries === undefined ? undefined : directoryEntryLimit(options, path);
|
|
127
137
|
const entries = await this.#filesystem.readdir(path, options);
|
|
@@ -81,6 +81,7 @@ export declare class RealFileSystem implements FileSystem {
|
|
|
81
81
|
appendFile(path: string, data: Uint8Array, options?: AppendFileOptions): Promise<void>;
|
|
82
82
|
stat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
83
83
|
lstat(path: string, options?: FsOptions): Promise<FileStat>;
|
|
84
|
+
iterateDirectory(path: string, options?: FsOptions): AsyncIterable<DirectoryEntry>;
|
|
84
85
|
readdir(path: string, options?: ReadDirectoryOptions): Promise<DirectoryEntry[]>;
|
|
85
86
|
mkdir(path: string, options?: MkdirOptions): Promise<void>;
|
|
86
87
|
rmdir(path: string, options?: FsOptions): Promise<void>;
|
|
@@ -638,6 +638,33 @@ export class RealFileSystem {
|
|
|
638
638
|
return fileStat(await native.lstat(target, { bigint: true }));
|
|
639
639
|
});
|
|
640
640
|
}
|
|
641
|
+
async *iterateDirectory(path, options = {}) {
|
|
642
|
+
let handle, failed = false;
|
|
643
|
+
try {
|
|
644
|
+
// Preserve the acquired handle even if cancellation arrives during open:
|
|
645
|
+
// the following read admission will observe it and finally will close it.
|
|
646
|
+
handle = await this.operation("iterateDirectory", path, options, async () => {
|
|
647
|
+
const target = await this.path(path, options);
|
|
648
|
+
options.signal?.throwIfAborted();
|
|
649
|
+
return native.opendir(target, { bufferSize: 1 });
|
|
650
|
+
}, undefined, true);
|
|
651
|
+
while (true) {
|
|
652
|
+
const entry = await this.operation("iterateDirectory", path, options, () => handle.read());
|
|
653
|
+
if (entry === null)
|
|
654
|
+
break;
|
|
655
|
+
yield { name: entry.name, type: fileType(entry) };
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
catch (error) {
|
|
659
|
+
failed = true;
|
|
660
|
+
options.signal?.throwIfAborted();
|
|
661
|
+
throw error;
|
|
662
|
+
}
|
|
663
|
+
finally {
|
|
664
|
+
if (handle)
|
|
665
|
+
await finishCleanup(() => handle.close(), failed);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
641
668
|
async readdir(path, options = {}) {
|
|
642
669
|
const limit = directoryEntryLimit(options, path);
|
|
643
670
|
return this.operation("readdir", path, options, async () => {
|
|
@@ -21,7 +21,7 @@ const operations = new Set([
|
|
|
21
21
|
"prepareDirectoryAncestry", "prepareStagingResolution", "publishStagedFileSet",
|
|
22
22
|
"publishFileConditional", "removeEntryConditional", "removeTreeConditional", "writeFileConditional", "removeFileConditional", "createStagedFile", "publishStagedFile", "removeStagedFile", "prepareDirectory",
|
|
23
23
|
"confineExtraction", "access", "appendFile", "canonicalizeMissingTarget", "capabilitiesFor", "chmod", "compareEntry",
|
|
24
|
-
"copyFile", "link", "lstat", "mkdir", "openReadFile", "openResizeFile", "readFile", "readStream", "readdir",
|
|
24
|
+
"copyFile", "link", "lstat", "mkdir", "openReadFile", "openResizeFile", "readFile", "readStream", "readdir", "iterateDirectory",
|
|
25
25
|
"readlink", "realpath", "rename", "resizeFile", "rm", "rmdir", "unlink", "stat", "symlink", "truncate", "utimes",
|
|
26
26
|
"writeFile", "writeStream",
|
|
27
27
|
]);
|
|
@@ -188,7 +188,7 @@ export function scopeFileSystem(filesystem, charge, signal, cleanupCharge = char
|
|
|
188
188
|
close: (options = {}) => closing ??= Promise.resolve().then(() => descriptor.close(options)),
|
|
189
189
|
};
|
|
190
190
|
};
|
|
191
|
-
const wrapStream = (source, options) => {
|
|
191
|
+
const wrapStream = (source, options, chargeNext = false) => {
|
|
192
192
|
const budgetFrames = getScopedTransportBudget();
|
|
193
193
|
return {
|
|
194
194
|
[Symbol.asyncIterator]() {
|
|
@@ -203,6 +203,8 @@ export function scopeFileSystem(filesystem, charge, signal, cleanupCharge = char
|
|
|
203
203
|
await closing;
|
|
204
204
|
return { done: true, value: undefined };
|
|
205
205
|
}
|
|
206
|
+
if (chargeNext)
|
|
207
|
+
admit(options);
|
|
206
208
|
const result = await withScopedTransportBudget(budgetFrames, operation);
|
|
207
209
|
assertOpen(options);
|
|
208
210
|
if (closing) {
|
|
@@ -430,7 +432,11 @@ export function scopeFileSystem(filesystem, charge, signal, cleanupCharge = char
|
|
|
430
432
|
});
|
|
431
433
|
return Reflect.apply(method, original, args);
|
|
432
434
|
})();
|
|
435
|
+
if (property === "iterateDirectory")
|
|
436
|
+
args[1] = { ...args[1], signal: combineSignal(args[1]?.signal) };
|
|
433
437
|
const result = Reflect.apply(method, original, args);
|
|
438
|
+
if (property === "iterateDirectory")
|
|
439
|
+
return wrapStream(result, args[1], true);
|
|
434
440
|
return property === "readStream" ? wrapStream(result, args[1]) : result;
|
|
435
441
|
};
|
|
436
442
|
const dispatch = (...args) => {
|
|
@@ -528,7 +534,7 @@ export function scopeFileSystem(filesystem, charge, signal, cleanupCharge = char
|
|
|
528
534
|
? async (...args) => ownedMutationCapabilities(original, retainedResizeCapabilities(original, await dispatch(...args)))
|
|
529
535
|
: property === "openReadFile"
|
|
530
536
|
? async (...args) => wrapHandle(await dispatch(...args))
|
|
531
|
-
: operations.has(property) && property !== "canonicalizeMissingTarget" && property !== "readStream"
|
|
537
|
+
: operations.has(property) && property !== "canonicalizeMissingTarget" && property !== "readStream" && property !== "iterateDirectory"
|
|
532
538
|
? (...args) => {
|
|
533
539
|
try {
|
|
534
540
|
const res = dispatch(...args);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.764",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
"@poe-code/terminal-text"
|
|
176
176
|
],
|
|
177
177
|
"optionalDependencies": {
|
|
178
|
-
"toolcraft-schema": "0.0.
|
|
178
|
+
"toolcraft-schema": "0.0.764",
|
|
179
179
|
"toolcraft-design": "*",
|
|
180
180
|
"@poe-code/frontmatter": "*",
|
|
181
181
|
"@poe-code/agent-mcp-config": "*",
|