toolcraft 0.0.763 → 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 CHANGED
@@ -133,7 +133,7 @@
133
133
  },
134
134
  {
135
135
  "name": "toolcraft",
136
- "version": "0.0.763",
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.763",
146
+ "version": "0.0.764",
147
147
  "license": "MIT"
148
148
  },
149
149
  {
@@ -133,7 +133,7 @@
133
133
  },
134
134
  {
135
135
  "name": "toolcraft",
136
- "version": "0.0.763",
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.763",
146
+ "version": "0.0.764",
147
147
  "license": "MIT"
148
148
  },
149
149
  {
@@ -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 async function* readFileStream(fs, path, options = {}) {
10
- const { signal } = options;
11
- signal?.throwIfAborted();
12
- const chunkSize = options.chunkSize ?? 65536;
13
- let position = options.start ?? 0;
14
- const end = options.endExclusive ?? Number.MAX_SAFE_INTEGER;
15
- if (!Number.isSafeInteger(chunkSize) || chunkSize <= 0 || !Number.isSafeInteger(position) || position < 0
16
- || !Number.isSafeInteger(end) || end < position)
17
- throw new FsError("EINVAL", { path, syscall: "readStream" });
18
- const capabilities = await fs.capabilitiesFor?.(path, options) ?? fs.capabilities;
19
- signal?.throwIfAborted();
20
- if (!options.skipStream && fs.readStream && fs.capabilities?.streamingRead !== false && capabilities?.streamingRead !== false) {
21
- let emitted = false;
22
- let reading = true;
23
- try {
24
- const source = fs.readStream(path, { ...options, chunkSize });
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
- while (true) {
29
- signal?.throwIfAborted();
30
- const item = await iterator.next();
31
- signal?.throwIfAborted();
32
- if (item.done) {
33
- done = true;
34
- break;
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
- reading = false;
37
- if (byteLength.call(item.value))
38
- emitted = true;
39
- yield item.value;
40
- reading = true;
47
+ failed = false;
48
+ }
49
+ finally {
50
+ activeCleanup = undefined;
51
+ if (!done)
52
+ await finishCleanup(closeIterator, failed);
41
53
  }
42
- failed = false;
54
+ return;
43
55
  }
44
- finally {
45
- if (!done)
46
- await finishCleanup(() => iterator.return?.(), failed);
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
- catch (error) {
51
- signal?.throwIfAborted();
52
- if (!reading || emitted || !(error instanceof FsError) || error.code !== "ENOTSUP")
53
- throw error;
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
- const handle = await openRetainedReadFile(fs, path, options);
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
- failed = false;
73
- }
74
- finally {
75
- await finishCleanup(() => handle.close(), failed);
76
- }
97
+ const result = await originalReturn(value);
98
+ if (cleanupError)
99
+ throw cleanupError.reason;
100
+ return result;
101
+ };
102
+ return generator;
77
103
  }
@@ -8,7 +8,7 @@
8
8
  },
9
9
  {
10
10
  "name": "toolcraft-schema",
11
- "version": "0.0.763",
11
+ "version": "0.0.764",
12
12
  "license": "MIT"
13
13
  }
14
14
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-schema",
3
- "version": "0.0.763",
3
+ "version": "0.0.764",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft",
3
- "version": "0.0.763",
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.763",
178
+ "toolcraft-schema": "0.0.764",
179
179
  "toolcraft-design": "*",
180
180
  "@poe-code/frontmatter": "*",
181
181
  "@poe-code/agent-mcp-config": "*",