stitchkit 0.114.1 → 0.115.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/CHANGELOG.md +37 -0
- package/dist/agent-runtime/coding-tool-files.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-listing.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-paths.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-refusals.d.ts +6 -0
- package/dist/agent-runtime/coding-tool-refusals.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-search-patch.d.ts.map +1 -1
- package/dist/agent-runtime/contained-scan.d.ts +1 -1
- package/dist/agent-runtime/contained-scan.d.ts.map +1 -1
- package/dist/agent-runtime/sandbox-broker.d.ts.map +1 -1
- package/dist/agent-runtime/sandbox-bubblewrap-storage.d.ts.map +1 -1
- package/dist/application/directory-inbox-files.d.ts.map +1 -1
- package/dist/application/file-state-store.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/coding-tools.js +6 -4
- package/dist/entrypoints/agent-runtime/harness.js +2 -1
- package/dist/entrypoints/agent-runtime/sandbox.js +13 -8
- package/dist/entrypoints/agent-runtime/sqlite/bun.js +8 -6
- package/dist/entrypoints/agent-runtime/sqlite/node.js +8 -6
- package/dist/entrypoints/agent-runtime/testing.js +8 -6
- package/dist/entrypoints/agent-runtime.js +8 -6
- package/dist/entrypoints/application/diagnostic-journal.js +2 -2
- package/dist/entrypoints/application/directory-inbox.js +10 -7
- package/dist/entrypoints/cli/publish.js +11 -8
- package/dist/entrypoints/cli.js +6 -3
- package/dist/entrypoints/files.js +10 -7
- package/dist/entrypoints/process/owner-loss.js +1 -1
- package/dist/entrypoints/process.js +3 -3
- package/dist/entrypoints/react/keyboard/testing.js +1 -1
- package/dist/entrypoints/react/keyboard.js +11 -11
- package/dist/entrypoints/server.js +4 -4
- package/dist/entrypoints/telegram.js +8 -5
- package/dist/entrypoints/tools.js +6 -3
- package/dist/files/chunk-spool.d.ts.map +1 -1
- package/dist/{index-2f9r0jgr.js → index-364k2zwa.js} +4 -4
- package/dist/{index-km2qw407.js → index-3qqdqwxe.js} +91 -36
- package/dist/{index-s47ac8zt.js → index-7yx8j6ay.js} +133 -156
- package/dist/{index-kdnfe0sr.js → index-90p34rts.js} +2 -2
- package/dist/{index-a3462dqf.js → index-944x38nv.js} +1 -1
- package/dist/{index-07dcf2yn.js → index-ac6vvm30.js} +5 -2
- package/dist/{index-qj1sy4ep.js → index-crmswbrt.js} +1 -1
- package/dist/{index-7r4knwf8.js → index-dr3t5n1v.js} +14 -4
- package/dist/{index-dc9ere5p.js → index-dx5cm9pc.js} +1 -1
- package/dist/{index-84bf5spd.js → index-f6m4c545.js} +5 -2
- package/dist/{index-hy802jnr.js → index-fdk4r4r6.js} +6 -3
- package/dist/index-j8kf56wx.js +100 -0
- package/dist/index-jj9228tt.js +6 -0
- package/dist/{index-t65erk4z.js → index-mgb7r8b8.js} +122 -62
- package/dist/{index-bh2ht9y5.js → index-n8z3rvzw.js} +4 -1
- package/dist/index-nregbbsc.js +107 -0
- package/dist/{index-j4zh647a.js → index-tt30h7mr.js} +4 -1
- package/dist/{index-zrtrjkbf.js → index-x0ddbj85.js} +148 -172
- package/dist/{index-p02zgk8x.js → index-y4rxnvgp.js} +6 -0
- package/dist/{index-5v5a9k2n.js → index-z3d6smer.js} +1 -1
- package/dist/{index-6b3pcq5z.js → index-zqkz4af9.js} +1 -1
- package/dist/internal/atomic-file.d.ts.map +1 -1
- package/dist/internal/atomic-staging.d.ts.map +1 -1
- package/dist/internal/contained-directory.d.ts +20 -0
- package/dist/internal/contained-directory.d.ts.map +1 -0
- package/dist/{agent-runtime → internal}/contained-files.d.ts +14 -13
- package/dist/internal/contained-files.d.ts.map +1 -0
- package/dist/internal/contained-handle.d.ts +30 -0
- package/dist/internal/contained-handle.d.ts.map +1 -0
- package/dist/internal/contained-write.d.ts +12 -0
- package/dist/internal/contained-write.d.ts.map +1 -0
- package/dist/internal/darwin-binding.d.ts +1 -1
- package/dist/internal/darwin-binding.d.ts.map +1 -1
- package/dist/internal/errno.d.ts +3 -0
- package/dist/internal/errno.d.ts.map +1 -0
- package/dist/internal/pinned-http.d.ts +27 -0
- package/dist/internal/pinned-http.d.ts.map +1 -0
- package/dist/internal/process-instance.d.ts.map +1 -1
- package/dist/internal/secure-fetch.d.ts +26 -6
- package/dist/internal/secure-fetch.d.ts.map +1 -1
- package/dist/internal/write-download.d.ts +5 -14
- package/dist/internal/write-download.d.ts.map +1 -1
- package/dist/process/group-diagnostics.d.ts +1 -0
- package/dist/process/group-diagnostics.d.ts.map +1 -1
- package/dist/process/group-settlement.d.ts +2 -0
- package/dist/process/group-settlement.d.ts.map +1 -1
- package/dist/process/group.d.ts.map +1 -1
- package/dist/process/owner-loss-control.d.ts.map +1 -1
- package/dist/react/keyboard/hooks.d.ts +2 -2
- package/dist/react/keyboard/hooks.d.ts.map +1 -1
- package/dist/react/keyboard/layers.d.ts +2 -0
- package/dist/react/keyboard/layers.d.ts.map +1 -1
- package/dist/telegram/broadcast-state.d.ts.map +1 -1
- package/dist/tools/cli/download.d.ts.map +1 -1
- package/dist/tools/cli/publication-storage.d.ts.map +1 -1
- package/dist/tools/cli/publication.d.ts.map +1 -1
- package/dist/tools/cli/view.d.ts.map +1 -1
- package/llms/agent-runtime.txt +16 -6
- package/llms/cli.txt +34 -2
- package/llms/process.txt +2 -2
- package/llms/react-keyboard.txt +18 -2
- package/llms/stitchkit.txt +3 -3
- package/llms/{upgrading-0.104.0-0.114.0.txt → upgrading-0.104.0-0.115.0.txt} +62 -3
- package/llms/upgrading.txt +1 -1
- package/llms-full.txt +132 -15
- package/llms.txt +5 -5
- package/native/darwin-arm64.node +0 -0
- package/native/darwin-x64.node +0 -0
- package/native-assets.json +4 -4
- package/package.json +1 -1
- package/dist/agent-runtime/contained-darwin.d.ts +0 -21
- package/dist/agent-runtime/contained-darwin.d.ts.map +0 -1
- package/dist/agent-runtime/contained-files.d.ts.map +0 -1
- package/dist/agent-runtime/contained-write.d.ts +0 -9
- package/dist/agent-runtime/contained-write.d.ts.map +0 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadDarwinBinding
|
|
3
|
+
} from "./index-2kbysk9s.js";
|
|
4
|
+
import {
|
|
5
|
+
descriptorPath,
|
|
6
|
+
NumericFileHandle
|
|
7
|
+
} from "./index-x0ddbj85.js";
|
|
8
|
+
import {
|
|
9
|
+
stagingName
|
|
10
|
+
} from "./index-tt30h7mr.js";
|
|
11
|
+
|
|
12
|
+
// src/internal/contained-write.ts
|
|
13
|
+
import { constants, fchmod, open as openDescriptor, write as writeDescriptor } from "node:fs";
|
|
14
|
+
import { rename, unlink } from "node:fs/promises";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
function entryPath(directory, name) {
|
|
17
|
+
return path.join(descriptorPath(directory), name);
|
|
18
|
+
}
|
|
19
|
+
async function openExclusive(directory, name, mode) {
|
|
20
|
+
if (process.platform === "darwin") {
|
|
21
|
+
return loadDarwinBinding().createFileAt(directory.fd, name, mode);
|
|
22
|
+
}
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
openDescriptor(entryPath(directory, name), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, mode, (error, descriptor) => error ? reject(error) : resolve(descriptor));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async function renameEntry(directory, source, target) {
|
|
28
|
+
if (process.platform === "darwin") {
|
|
29
|
+
loadDarwinBinding().renameAt(directory.fd, source, target);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
await rename(entryPath(directory, source), entryPath(directory, target));
|
|
33
|
+
}
|
|
34
|
+
async function discardEntry(directory, name) {
|
|
35
|
+
try {
|
|
36
|
+
if (process.platform === "darwin")
|
|
37
|
+
loadDarwinBinding().unlinkAt(directory.fd, name);
|
|
38
|
+
else
|
|
39
|
+
await unlink(entryPath(directory, name));
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
42
|
+
async function writeDescriptorFully(descriptor, content) {
|
|
43
|
+
const bytes = typeof content === "string" ? Buffer.from(content) : content;
|
|
44
|
+
let offset = 0;
|
|
45
|
+
while (offset < bytes.byteLength) {
|
|
46
|
+
const written = await new Promise((resolve, reject) => {
|
|
47
|
+
writeDescriptor(descriptor, bytes, offset, bytes.byteLength - offset, null, (error, bytesWritten) => error ? reject(error) : resolve(bytesWritten));
|
|
48
|
+
});
|
|
49
|
+
if (written === 0)
|
|
50
|
+
throw new Error("Contained file write made no progress");
|
|
51
|
+
offset += written;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function applyMode(file, mode) {
|
|
55
|
+
if (((await file.stat()).mode & 511) === mode)
|
|
56
|
+
return;
|
|
57
|
+
await new Promise((resolve, reject) => {
|
|
58
|
+
fchmod(file.fd, mode, (error) => error ? reject(error) : resolve());
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async function createFile(directory, name, content, mode) {
|
|
62
|
+
const descriptor = await openExclusive(directory, name, mode ?? 438);
|
|
63
|
+
const file = new NumericFileHandle(descriptor);
|
|
64
|
+
let failed;
|
|
65
|
+
try {
|
|
66
|
+
await writeDescriptorFully(descriptor, content);
|
|
67
|
+
if (mode !== undefined)
|
|
68
|
+
await applyMode(file, mode);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
failed = error;
|
|
71
|
+
} finally {
|
|
72
|
+
try {
|
|
73
|
+
await file.close();
|
|
74
|
+
} catch (error) {
|
|
75
|
+
failed ??= error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (failed) {
|
|
79
|
+
await discardEntry(directory, name);
|
|
80
|
+
throw failed;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function writeContainedFile(input) {
|
|
84
|
+
const { handle, basename } = input.parent;
|
|
85
|
+
const mode = input.mode === undefined ? undefined : input.mode & 511;
|
|
86
|
+
if (!input.replace) {
|
|
87
|
+
await createFile(handle, basename, input.content, mode);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const temporary = stagingName();
|
|
91
|
+
await createFile(handle, temporary, input.content, mode);
|
|
92
|
+
try {
|
|
93
|
+
await renameEntry(handle, temporary, basename);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
await discardEntry(handle, temporary);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { writeContainedFile };
|
|
@@ -7,9 +7,88 @@ import {
|
|
|
7
7
|
|
|
8
8
|
// src/internal/secure-fetch.ts
|
|
9
9
|
import { lookup } from "node:dns/promises";
|
|
10
|
+
import { isIP } from "node:net";
|
|
11
|
+
|
|
12
|
+
// src/internal/pinned-http.ts
|
|
10
13
|
import { request as httpRequest } from "node:http";
|
|
11
14
|
import { request as httpsRequest } from "node:https";
|
|
12
|
-
|
|
15
|
+
async function requestPinned(url, resolved, signal, headers = {}) {
|
|
16
|
+
const transport = url.protocol === "https:" ? httpsRequest : httpRequest;
|
|
17
|
+
const incoming = await new Promise((resolve, reject) => {
|
|
18
|
+
let answered = false;
|
|
19
|
+
const request = transport({
|
|
20
|
+
protocol: url.protocol,
|
|
21
|
+
hostname: resolved.address,
|
|
22
|
+
family: resolved.family,
|
|
23
|
+
port: url.port || undefined,
|
|
24
|
+
path: `${url.pathname}${url.search}`,
|
|
25
|
+
method: "GET",
|
|
26
|
+
signal,
|
|
27
|
+
...url.protocol === "https:" ? { servername: url.hostname } : {},
|
|
28
|
+
headers: { host: url.host, accept: "*/*", ...headers }
|
|
29
|
+
}, (response) => {
|
|
30
|
+
answered = true;
|
|
31
|
+
resolve(response);
|
|
32
|
+
});
|
|
33
|
+
request.once("error", (error) => {
|
|
34
|
+
if (answered)
|
|
35
|
+
return;
|
|
36
|
+
reject(signal?.aborted && signal.reason !== undefined ? signal.reason : error);
|
|
37
|
+
});
|
|
38
|
+
request.end();
|
|
39
|
+
});
|
|
40
|
+
return pinnedResponse(incoming);
|
|
41
|
+
}
|
|
42
|
+
function pinnedResponse(incoming) {
|
|
43
|
+
const status = incoming.statusCode ?? 0;
|
|
44
|
+
const headers = new Headers;
|
|
45
|
+
for (const [name, value] of Object.entries(incoming.headers)) {
|
|
46
|
+
if (Array.isArray(value)) {
|
|
47
|
+
for (const item of value)
|
|
48
|
+
headers.append(name, item);
|
|
49
|
+
} else if (value !== undefined) {
|
|
50
|
+
headers.set(name, value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (status === 204 || status === 205 || status === 304) {
|
|
54
|
+
incoming.resume();
|
|
55
|
+
return new Response(null, { status, statusText: incoming.statusMessage, headers });
|
|
56
|
+
}
|
|
57
|
+
let done = false;
|
|
58
|
+
const body = new ReadableStream({
|
|
59
|
+
start(controller) {
|
|
60
|
+
incoming.on("data", (chunk) => {
|
|
61
|
+
if (done)
|
|
62
|
+
return;
|
|
63
|
+
controller.enqueue(chunk);
|
|
64
|
+
if ((controller.desiredSize ?? 1) <= 0)
|
|
65
|
+
incoming.pause();
|
|
66
|
+
});
|
|
67
|
+
incoming.once("end", () => {
|
|
68
|
+
if (done)
|
|
69
|
+
return;
|
|
70
|
+
done = true;
|
|
71
|
+
controller.close();
|
|
72
|
+
});
|
|
73
|
+
incoming.once("error", (error) => {
|
|
74
|
+
if (done)
|
|
75
|
+
return;
|
|
76
|
+
done = true;
|
|
77
|
+
controller.error(error);
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
pull() {
|
|
81
|
+
incoming.resume();
|
|
82
|
+
},
|
|
83
|
+
cancel() {
|
|
84
|
+
done = true;
|
|
85
|
+
incoming.destroy();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
return new Response(body, { status, statusText: incoming.statusMessage, headers });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/internal/secure-fetch.ts
|
|
13
92
|
var NUMERIC_HOST = /^(0x[0-9a-f]+|[0-9.]+)$/i;
|
|
14
93
|
var MAX_REDIRECTS = 5;
|
|
15
94
|
function assertHttpUrl(url) {
|
|
@@ -102,9 +181,10 @@ function isPrivateIp(ip) {
|
|
|
102
181
|
}
|
|
103
182
|
return false;
|
|
104
183
|
}
|
|
105
|
-
async
|
|
106
|
-
await
|
|
107
|
-
|
|
184
|
+
var defaultLookup = async (host) => {
|
|
185
|
+
const records = await lookup(host, { all: true });
|
|
186
|
+
return Array.isArray(records) ? records : [records];
|
|
187
|
+
};
|
|
108
188
|
async function fetchGuarded(start, allowPrivate, options = {}) {
|
|
109
189
|
const timeoutMs = options.timeoutMs ?? 15000;
|
|
110
190
|
const bodyTimeoutMs = options.bodyTimeoutMs ?? 120000;
|
|
@@ -120,15 +200,16 @@ async function fetchGuarded(start, allowPrivate, options = {}) {
|
|
|
120
200
|
controller.abort(new Error(`fetch did not produce response headers within ${timeoutMs}ms`));
|
|
121
201
|
}, timeoutMs);
|
|
122
202
|
headerTimer.unref?.();
|
|
203
|
+
const transport = options.transport ?? requestPinned;
|
|
123
204
|
let settled = false;
|
|
124
205
|
try {
|
|
125
206
|
let url = start;
|
|
126
207
|
for (let hop = 0;hop <= MAX_REDIRECTS; hop++) {
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const res = await
|
|
208
|
+
if (url.username || url.password) {
|
|
209
|
+
throw new Error("refusing to fetch a URL that carries credentials");
|
|
210
|
+
}
|
|
211
|
+
const resolved = await resolveAddress(url, allowPrivate, signal, options.dns);
|
|
212
|
+
const res = await transport(url, resolved, signal);
|
|
132
213
|
const location = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
|
|
133
214
|
if (location === null) {
|
|
134
215
|
settled = true;
|
|
@@ -148,11 +229,27 @@ async function fetchGuarded(start, allowPrivate, options = {}) {
|
|
|
148
229
|
clearTimeout(headerTimer);
|
|
149
230
|
}
|
|
150
231
|
}
|
|
232
|
+
async function resolveAddress(url, allowPrivate, signal, dns) {
|
|
233
|
+
if (!allowPrivate)
|
|
234
|
+
return resolvePublicAddress(url, signal, dns);
|
|
235
|
+
assertHttpUrl(url);
|
|
236
|
+
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
237
|
+
if (!host)
|
|
238
|
+
throw new Error("refusing to fetch a URL with no host");
|
|
239
|
+
const ipFamily = isIP(host);
|
|
240
|
+
if (ipFamily)
|
|
241
|
+
return { address: host, family: ipFamily === 6 ? 6 : 4 };
|
|
242
|
+
const records = await (dns ?? defaultLookup)(host, { all: true });
|
|
243
|
+
const record = records[0];
|
|
244
|
+
if (!record)
|
|
245
|
+
throw new Error("host resolved to no addresses");
|
|
246
|
+
return { address: record.address, family: record.family === 6 ? 6 : 4 };
|
|
247
|
+
}
|
|
151
248
|
|
|
152
249
|
class PrivateAddressRefusal extends Error {
|
|
153
250
|
name = "PrivateAddressRefusal";
|
|
154
251
|
}
|
|
155
|
-
async function resolvePublicAddress(url, signal) {
|
|
252
|
+
async function resolvePublicAddress(url, signal, dns) {
|
|
156
253
|
assertHttpUrl(url);
|
|
157
254
|
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
158
255
|
if (!host)
|
|
@@ -169,7 +266,7 @@ async function resolvePublicAddress(url, signal) {
|
|
|
169
266
|
if (host === "localhost" || host.endsWith(".local") || host.endsWith(".internal")) {
|
|
170
267
|
throw new PrivateAddressRefusal("refusing to fetch an internal host");
|
|
171
268
|
}
|
|
172
|
-
const pending =
|
|
269
|
+
const pending = (dns ?? defaultLookup)(host, { all: true });
|
|
173
270
|
const records = signal ? await raceAbort(pending, signal) : await pending;
|
|
174
271
|
for (const record of records) {
|
|
175
272
|
if (isPrivateIp(record.address)) {
|
|
@@ -202,61 +299,24 @@ async function fetchPinnedDocument(start, options) {
|
|
|
202
299
|
throw new Error("document URL cannot contain credentials");
|
|
203
300
|
}
|
|
204
301
|
const resolved = await resolvePublicAddress(url, signal);
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
protocol: url.protocol,
|
|
209
|
-
hostname: resolved.address,
|
|
210
|
-
family: resolved.family,
|
|
211
|
-
port: url.port || undefined,
|
|
212
|
-
path: `${url.pathname}${url.search}`,
|
|
213
|
-
method: "GET",
|
|
214
|
-
signal,
|
|
215
|
-
servername: url.hostname,
|
|
216
|
-
headers: {
|
|
217
|
-
host: url.host,
|
|
218
|
-
accept: "application/json",
|
|
219
|
-
...options.headers
|
|
220
|
-
}
|
|
221
|
-
}, (incoming) => {
|
|
222
|
-
const headers = new Headers;
|
|
223
|
-
for (const [name, value] of Object.entries(incoming.headers)) {
|
|
224
|
-
if (Array.isArray(value)) {
|
|
225
|
-
for (const item of value)
|
|
226
|
-
headers.append(name, item);
|
|
227
|
-
} else if (value !== undefined) {
|
|
228
|
-
headers.set(name, value);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const chunks = [];
|
|
232
|
-
let total = 0;
|
|
233
|
-
incoming.on("data", (chunk) => {
|
|
234
|
-
total += chunk.byteLength;
|
|
235
|
-
if (total > options.maxBytes) {
|
|
236
|
-
incoming.destroy(new Error("response body exceeds configured byte limit"));
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
chunks.push(chunk);
|
|
240
|
-
});
|
|
241
|
-
incoming.once("error", reject);
|
|
242
|
-
incoming.once("end", () => {
|
|
243
|
-
const body = new Uint8Array(total);
|
|
244
|
-
let offset = 0;
|
|
245
|
-
for (const chunk of chunks) {
|
|
246
|
-
body.set(chunk, offset);
|
|
247
|
-
offset += chunk.byteLength;
|
|
248
|
-
}
|
|
249
|
-
resolve({ status: incoming.statusCode ?? 0, headers, body, url });
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
request.once("error", reject);
|
|
253
|
-
request.end();
|
|
302
|
+
const response = await requestPinned(url, resolved, signal, {
|
|
303
|
+
accept: "application/json",
|
|
304
|
+
...options.headers
|
|
254
305
|
});
|
|
306
|
+
const body = await readCapped(response, options.maxBytes);
|
|
307
|
+
if (body === null)
|
|
308
|
+
throw new Error("response body exceeds configured byte limit");
|
|
309
|
+
const document = {
|
|
310
|
+
status: response.status,
|
|
311
|
+
headers: response.headers,
|
|
312
|
+
body: new Uint8Array(body),
|
|
313
|
+
url
|
|
314
|
+
};
|
|
255
315
|
if (response.status < 300 || response.status >= 400)
|
|
256
|
-
return
|
|
316
|
+
return document;
|
|
257
317
|
const location = response.headers.get("location");
|
|
258
318
|
if (!location)
|
|
259
|
-
return
|
|
319
|
+
return document;
|
|
260
320
|
url = new URL(location, url);
|
|
261
321
|
}
|
|
262
322
|
throw new Error("too many redirects");
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadDarwinBinding
|
|
3
3
|
} from "./index-2kbysk9s.js";
|
|
4
|
+
import {
|
|
5
|
+
errnoOf
|
|
6
|
+
} from "./index-jj9228tt.js";
|
|
4
7
|
import {
|
|
5
8
|
isRecord
|
|
6
9
|
} from "./index-9jfdm5tg.js";
|
|
@@ -126,7 +129,7 @@ async function observeProcessInstanceAt(pid, procRoot) {
|
|
|
126
129
|
readlink(`${procRoot}/self/ns/pid`),
|
|
127
130
|
readFile2(`${procRoot}/self/status`, "utf8"),
|
|
128
131
|
readlink(`${procRoot}/self/ns/time`).catch((error) => {
|
|
129
|
-
if (error
|
|
132
|
+
if (errnoOf(error) === "ENOENT")
|
|
130
133
|
return "";
|
|
131
134
|
throw error;
|
|
132
135
|
}),
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {
|
|
2
|
+
openDirectoryAt,
|
|
3
|
+
openPinnedDirectory,
|
|
4
|
+
openFileAt,
|
|
5
|
+
listAt,
|
|
6
|
+
readContainedUtf8Handle
|
|
7
|
+
} from "./index-x0ddbj85.js";
|
|
8
|
+
|
|
9
|
+
// src/agent-runtime/contained-scan.ts
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
async function walkContainedFiles(input) {
|
|
12
|
+
const scan = await scanContainedFiles({ ...input, symlinks: "refuse" });
|
|
13
|
+
if (scan.truncated)
|
|
14
|
+
throw new Error("Contained file traversal exceeded its bounds");
|
|
15
|
+
return scan.files;
|
|
16
|
+
}
|
|
17
|
+
async function scanContainedFiles(input) {
|
|
18
|
+
const files = [];
|
|
19
|
+
let truncated = false;
|
|
20
|
+
let skippedDirectories = 0;
|
|
21
|
+
let skippedSymlinks = 0;
|
|
22
|
+
const denied = [];
|
|
23
|
+
let deniedTruncated = false;
|
|
24
|
+
const root = await openPinnedDirectory(input.root);
|
|
25
|
+
const visit = async (directory, relativeDirectory, depth) => {
|
|
26
|
+
if (truncated)
|
|
27
|
+
return;
|
|
28
|
+
if (depth > input.maxDepth) {
|
|
29
|
+
truncated = true;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const entries = [...await listAt(directory)];
|
|
33
|
+
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
const relative = relativeDirectory ? path.join(relativeDirectory, entry.name) : entry.name;
|
|
36
|
+
const kind = entry.isDirectory() ? "directory" : entry.isSymbolicLink() ? "symlink" : entry.isFile() ? "file" : "other";
|
|
37
|
+
if (kind === "file" && input.includeFile && !input.includeFile(relative))
|
|
38
|
+
continue;
|
|
39
|
+
if (input.authorizePath && !await input.authorizePath(relative, kind)) {
|
|
40
|
+
if (denied.length < input.maxFiles)
|
|
41
|
+
denied.push({ relative, kind });
|
|
42
|
+
else
|
|
43
|
+
deniedTruncated = true;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (entry.isSymbolicLink()) {
|
|
47
|
+
if (input.symlinks === "refuse") {
|
|
48
|
+
throw new Error(`Contained file traversal refuses symlink: ${relative}`);
|
|
49
|
+
}
|
|
50
|
+
skippedSymlinks += 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (entry.isDirectory()) {
|
|
54
|
+
if (input.excludeDirectory?.(relative)) {
|
|
55
|
+
skippedDirectories += 1;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
let child;
|
|
59
|
+
try {
|
|
60
|
+
child = await openDirectoryAt(directory, entry.name);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
if (input.symlinks === "skip") {
|
|
63
|
+
skippedSymlinks += 1;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
await visit(child, relative, depth + 1);
|
|
70
|
+
} finally {
|
|
71
|
+
await child.close();
|
|
72
|
+
}
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (!entry.isFile())
|
|
76
|
+
continue;
|
|
77
|
+
if (files.length >= input.maxFiles) {
|
|
78
|
+
truncated = true;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
let content;
|
|
82
|
+
if (input.readMaxBytes !== undefined) {
|
|
83
|
+
try {
|
|
84
|
+
const handle = await openFileAt(directory, entry.name);
|
|
85
|
+
try {
|
|
86
|
+
content = await readContainedUtf8Handle(handle, input.readMaxBytes);
|
|
87
|
+
} finally {
|
|
88
|
+
await handle.close();
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (input.skipUnreadable)
|
|
92
|
+
continue;
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
files.push({ absolute: relative, relative, ...content && { content } });
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
try {
|
|
100
|
+
await visit(root, "", 0);
|
|
101
|
+
} finally {
|
|
102
|
+
await root.close();
|
|
103
|
+
}
|
|
104
|
+
return { files, truncated, skippedDirectories, skippedSymlinks, denied, deniedTruncated };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export { walkContainedFiles, scanContainedFiles };
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
errnoOf
|
|
3
|
+
} from "./index-jj9228tt.js";
|
|
1
4
|
import {
|
|
2
5
|
assertPositiveSafeInteger
|
|
3
6
|
} from "./index-0s4xebbg.js";
|
|
@@ -21,7 +24,7 @@ function isAtomicStagingName2(name) {
|
|
|
21
24
|
return NAME.test(name);
|
|
22
25
|
}
|
|
23
26
|
function isMissing(error) {
|
|
24
|
-
return
|
|
27
|
+
return errnoOf(error) === "ENOENT";
|
|
25
28
|
}
|
|
26
29
|
async function sweepAtomicStaging2(options) {
|
|
27
30
|
const { directory, olderThanMs, signal } = options;
|