stitchkit 0.114.2 → 0.116.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 +54 -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/grammy.js +2 -2
- package/dist/entrypoints/telegram.d.ts +1 -1
- package/dist/entrypoints/telegram.d.ts.map +1 -1
- package/dist/entrypoints/telegram.js +30 -14
- package/dist/entrypoints/tools.js +5 -2
- package/dist/files/chunk-spool.d.ts.map +1 -1
- package/dist/{index-2f9r0jgr.js → index-364k2zwa.js} +4 -4
- package/dist/{index-dc9ere5p.js → index-4g6qmgdx.js} +1 -1
- package/dist/index-6f49krb5.js +107 -0
- package/dist/{index-912sza5h.js → index-90p34rts.js} +1 -1
- package/dist/{index-07dcf2yn.js → index-ac6vvm30.js} +5 -2
- package/dist/{index-zrtrjkbf.js → index-arjmb6de.js} +183 -172
- package/dist/{index-7r4knwf8.js → index-dr3t5n1v.js} +14 -4
- package/dist/{index-84bf5spd.js → index-f6m4c545.js} +5 -2
- package/dist/{index-qj1sy4ep.js → index-fa435yq2.js} +1 -1
- package/dist/{index-hy802jnr.js → index-fdk4r4r6.js} +6 -3
- package/dist/index-jj9228tt.js +6 -0
- package/dist/{index-a3462dqf.js → index-jq2ky8fw.js} +1 -1
- package/dist/{index-s47ac8zt.js → index-n5sv4z0w.js} +142 -156
- package/dist/{index-bh2ht9y5.js → index-n8z3rvzw.js} +4 -1
- package/dist/index-q968hy6y.js +100 -0
- package/dist/{index-j4zh647a.js → index-tt30h7mr.js} +4 -1
- package/dist/{index-tnxsq7cw.js → index-w7jq3fz9.js} +113 -38
- 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 +24 -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/process-instance.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/telegram/budget-transformer.d.ts +5 -2
- package/dist/telegram/budget-transformer.d.ts.map +1 -1
- package/dist/telegram/outbound-budget.d.ts +26 -11
- package/dist/telegram/outbound-budget.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 +7 -1
- package/dist/tools/cli/view.d.ts.map +1 -1
- package/llms/agent-runtime.txt +16 -6
- package/llms/cli.txt +37 -3
- package/llms/process.txt +2 -2
- package/llms/react-keyboard.txt +18 -2
- package/llms/stitchkit.txt +3 -3
- package/llms/telegram.txt +10 -3
- package/llms/{upgrading-0.104.0-0.114.0.txt → upgrading-0.105.0-0.116.0.txt} +85 -124
- package/llms/{upgrading-0.44.0-0.61.0.txt → upgrading-0.44.0-0.62.0.txt} +120 -3
- package/llms/{upgrading-0.62.0-0.78.0.txt → upgrading-0.63.0-0.83.0.txt} +181 -120
- package/llms/{upgrading-0.79.0-0.103.13.txt → upgrading-0.84.0-0.104.0.txt} +124 -181
- package/llms/upgrading.txt +4 -4
- package/llms-full.txt +168 -19
- package/llms.txt +9 -9
- 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
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadDarwinBinding
|
|
3
3
|
} from "./index-2kbysk9s.js";
|
|
4
|
+
import {
|
|
5
|
+
errnoOf
|
|
6
|
+
} from "./index-jj9228tt.js";
|
|
4
7
|
|
|
5
|
-
// src/
|
|
6
|
-
import path2 from "node:path";
|
|
7
|
-
|
|
8
|
-
// src/agent-runtime/contained-files.ts
|
|
8
|
+
// src/internal/contained-directory.ts
|
|
9
9
|
import { constants } from "node:fs";
|
|
10
|
-
import {
|
|
10
|
+
import { mkdir, open, realpath } from "node:fs/promises";
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
|
|
13
|
-
// src/
|
|
13
|
+
// src/internal/contained-handle.ts
|
|
14
14
|
import { close as closeDescriptor, fstat, read as readDescriptor } from "node:fs";
|
|
15
|
+
function descriptorPath(handle) {
|
|
16
|
+
if (process.platform === "linux")
|
|
17
|
+
return `/proc/self/fd/${handle.fd}`;
|
|
18
|
+
throw new Error("Descriptor paths are available only in the Linux contained-files backend");
|
|
19
|
+
}
|
|
15
20
|
var FILE_TYPE_MASK = 61440;
|
|
16
21
|
var FILE_TYPE_DIRECTORY = 16384;
|
|
17
22
|
var FILE_TYPE_REGULAR = 32768;
|
|
@@ -22,10 +27,14 @@ function modeIs(mode, type) {
|
|
|
22
27
|
|
|
23
28
|
class NumericFileHandle {
|
|
24
29
|
fd;
|
|
30
|
+
closed = false;
|
|
25
31
|
constructor(fd) {
|
|
26
32
|
this.fd = fd;
|
|
27
33
|
}
|
|
28
34
|
close() {
|
|
35
|
+
if (this.closed)
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
this.closed = true;
|
|
29
38
|
return new Promise((resolve, reject) => {
|
|
30
39
|
closeDescriptor(this.fd, (error) => error ? reject(error) : resolve());
|
|
31
40
|
});
|
|
@@ -42,55 +51,111 @@ class NumericFileHandle {
|
|
|
42
51
|
}
|
|
43
52
|
}
|
|
44
53
|
|
|
45
|
-
// src/
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
// src/internal/contained-directory.ts
|
|
55
|
+
var O_PATH_LINUX = 2097152;
|
|
56
|
+
var O_SEARCH_DARWIN = 1073741824;
|
|
57
|
+
function directoryFlags(searchOnly) {
|
|
58
|
+
const access = searchOnly ? process.platform === "linux" ? O_PATH_LINUX : O_SEARCH_DARWIN : constants.O_RDONLY;
|
|
59
|
+
return access | constants.O_DIRECTORY | constants.O_NOFOLLOW;
|
|
48
60
|
}
|
|
49
|
-
function
|
|
50
|
-
if (process.platform === "
|
|
51
|
-
return
|
|
52
|
-
|
|
61
|
+
async function openDirectoryAt(directory, name, searchOnly = false) {
|
|
62
|
+
if (process.platform === "darwin") {
|
|
63
|
+
return new NumericFileHandle(loadDarwinBinding().openDirectoryAt(directory.fd, name, searchOnly));
|
|
64
|
+
}
|
|
65
|
+
return open(path.join(descriptorPath(directory), name), directoryFlags(searchOnly));
|
|
53
66
|
}
|
|
54
|
-
function
|
|
55
|
-
|
|
67
|
+
async function descend(current, next) {
|
|
68
|
+
try {
|
|
69
|
+
await current.close();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
await next.close();
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
return next;
|
|
75
|
+
}
|
|
76
|
+
async function createDirectoryAt(directory, name) {
|
|
77
|
+
if (process.platform === "darwin") {
|
|
78
|
+
return loadDarwinBinding().createDirectoryAt(directory.fd, name, 511);
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
await mkdir(path.join(descriptorPath(directory), name));
|
|
82
|
+
return true;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (errnoOf(error) === "EEXIST")
|
|
85
|
+
return false;
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
56
88
|
}
|
|
57
|
-
async function openPinnedDirectory(absolute) {
|
|
89
|
+
async function openPinnedDirectory(absolute, options = {}, io = { realpath }) {
|
|
58
90
|
if (process.platform !== "linux" && process.platform !== "darwin") {
|
|
59
91
|
throw new Error("Contained filesystem operations support Linux and macOS only");
|
|
60
92
|
}
|
|
61
|
-
|
|
62
|
-
const
|
|
93
|
+
let prefix = path.resolve(absolute);
|
|
94
|
+
const missing = [];
|
|
95
|
+
let canonical;
|
|
96
|
+
for (;; ) {
|
|
97
|
+
try {
|
|
98
|
+
canonical = await io.realpath(prefix);
|
|
99
|
+
break;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (!options.create || errnoOf(error) !== "ENOENT")
|
|
102
|
+
throw error;
|
|
103
|
+
const parent = path.dirname(prefix);
|
|
104
|
+
if (parent === prefix)
|
|
105
|
+
throw error;
|
|
106
|
+
missing.unshift(path.basename(prefix));
|
|
107
|
+
prefix = parent;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const anchor = path.parse(canonical).root;
|
|
111
|
+
let current = await open(anchor, directoryFlags(true));
|
|
112
|
+
if (canonical === anchor && missing.length === 0 && options.readable !== false) {
|
|
113
|
+
await current.close();
|
|
114
|
+
return open(anchor, directoryFlags(false));
|
|
115
|
+
}
|
|
116
|
+
const existing = path.relative(anchor, canonical).split(path.sep).filter(Boolean);
|
|
63
117
|
try {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
118
|
+
const segments = [...existing, ...missing];
|
|
119
|
+
for (const [index, segment] of segments.entries()) {
|
|
120
|
+
if (index >= existing.length)
|
|
121
|
+
await createDirectoryAt(current, segment);
|
|
122
|
+
const next = await openDirectoryAt(current, segment, index < segments.length - 1 || options.readable === false);
|
|
123
|
+
current = await descend(current, next);
|
|
67
124
|
}
|
|
68
|
-
return
|
|
125
|
+
return current;
|
|
69
126
|
} catch (error) {
|
|
70
|
-
await
|
|
127
|
+
await current.close();
|
|
71
128
|
throw error;
|
|
72
129
|
}
|
|
73
130
|
}
|
|
131
|
+
|
|
132
|
+
// src/internal/contained-files.ts
|
|
133
|
+
import { constants as constants2 } from "node:fs";
|
|
134
|
+
import { lstat, open as open2, readdir } from "node:fs/promises";
|
|
135
|
+
import path2 from "node:path";
|
|
136
|
+
function containedEntryKind(entry) {
|
|
137
|
+
return entry.isDirectory() ? "directory" : entry.isSymbolicLink() ? "symlink" : entry.isFile() ? "file" : "other";
|
|
138
|
+
}
|
|
139
|
+
function sameIdentity(left, right) {
|
|
140
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
141
|
+
}
|
|
142
|
+
function isSafeEntryName(name) {
|
|
143
|
+
return name !== "" && name !== "." && name !== ".." && !name.includes("\x00");
|
|
144
|
+
}
|
|
74
145
|
function safeSegments(relative) {
|
|
75
|
-
if (
|
|
146
|
+
if (path2.isAbsolute(relative))
|
|
76
147
|
throw new Error("Contained paths must be relative");
|
|
77
148
|
const segments = relative.split(/[\\/]/u);
|
|
78
|
-
if (segments.
|
|
149
|
+
if (!segments.every(isSafeEntryName)) {
|
|
79
150
|
throw new Error("Contained path has invalid segments");
|
|
80
151
|
}
|
|
81
152
|
return segments;
|
|
82
153
|
}
|
|
83
|
-
async function openDirectoryAt(directory, name) {
|
|
84
|
-
if (process.platform === "darwin") {
|
|
85
|
-
return new NumericFileHandle(loadDarwinBinding().openDirectoryAt(directory.fd, name));
|
|
86
|
-
}
|
|
87
|
-
return open(path.join(descriptorPath(directory), name), constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
88
|
-
}
|
|
89
154
|
async function openFileAt(directory, name) {
|
|
90
155
|
if (process.platform === "darwin") {
|
|
91
156
|
return new NumericFileHandle(loadDarwinBinding().openFileAt(directory.fd, name));
|
|
92
157
|
}
|
|
93
|
-
return
|
|
158
|
+
return open2(path2.join(descriptorPath(directory), name), constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
|
|
94
159
|
}
|
|
95
160
|
function entryMetadata(mode, size) {
|
|
96
161
|
return {
|
|
@@ -106,8 +171,8 @@ async function statAt(directory, name) {
|
|
|
106
171
|
const metadata = loadDarwinBinding().statAt(directory.fd, name);
|
|
107
172
|
return metadata ? entryMetadata(metadata.mode, metadata.size) : null;
|
|
108
173
|
}
|
|
109
|
-
return lstat(
|
|
110
|
-
if (error
|
|
174
|
+
return lstat(path2.join(descriptorPath(directory), name)).catch((error) => {
|
|
175
|
+
if (errnoOf(error) === "ENOENT")
|
|
111
176
|
return null;
|
|
112
177
|
throw error;
|
|
113
178
|
});
|
|
@@ -123,14 +188,7 @@ async function listContainedDirectory(root, relative, maxEntries, authorizePath)
|
|
|
123
188
|
try {
|
|
124
189
|
if (relative !== ".") {
|
|
125
190
|
for (const segment of safeSegments(relative)) {
|
|
126
|
-
|
|
127
|
-
const metadata = await next.stat();
|
|
128
|
-
if (!metadata.isDirectory()) {
|
|
129
|
-
await next.close();
|
|
130
|
-
throw new Error("Contained ancestor is not a directory");
|
|
131
|
-
}
|
|
132
|
-
await current.close();
|
|
133
|
-
current = next;
|
|
191
|
+
current = await descend(current, await openDirectoryAt(current, segment));
|
|
134
192
|
}
|
|
135
193
|
}
|
|
136
194
|
const raw = [...await listAt(current)];
|
|
@@ -138,7 +196,7 @@ async function listContainedDirectory(root, relative, maxEntries, authorizePath)
|
|
|
138
196
|
const admitted = [];
|
|
139
197
|
const denied = [];
|
|
140
198
|
for (const entry of raw) {
|
|
141
|
-
const entryPath = relative === "." ? entry.name :
|
|
199
|
+
const entryPath = relative === "." ? entry.name : path2.join(relative, entry.name);
|
|
142
200
|
if (authorizePath && !await authorizePath(entryPath)) {
|
|
143
201
|
denied.push({ name: entry.name, kind: containedEntryKind(entry) });
|
|
144
202
|
continue;
|
|
@@ -174,19 +232,6 @@ async function listContainedDirectory(root, relative, maxEntries, authorizePath)
|
|
|
174
232
|
await current.close();
|
|
175
233
|
}
|
|
176
234
|
}
|
|
177
|
-
async function createDirectoryAt(directory, name) {
|
|
178
|
-
if (process.platform === "darwin") {
|
|
179
|
-
return loadDarwinBinding().createDirectoryAt(directory.fd, name, 511);
|
|
180
|
-
}
|
|
181
|
-
try {
|
|
182
|
-
await mkdir(path.join(descriptorPath(directory), name));
|
|
183
|
-
return true;
|
|
184
|
-
} catch (error) {
|
|
185
|
-
if (error.code === "EEXIST")
|
|
186
|
-
return false;
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
235
|
async function missingContainedDirectories(root, relative) {
|
|
191
236
|
const segments = safeSegments(relative);
|
|
192
237
|
segments.pop();
|
|
@@ -197,26 +242,69 @@ async function missingContainedDirectories(root, relative) {
|
|
|
197
242
|
for (const segment of segments) {
|
|
198
243
|
walked = [...walked, segment];
|
|
199
244
|
if (missing.length > 0) {
|
|
200
|
-
missing.push(walked.join(
|
|
245
|
+
missing.push(walked.join(path2.sep));
|
|
201
246
|
continue;
|
|
202
247
|
}
|
|
203
248
|
const next = await openDirectoryAt(current, segment).catch((error) => {
|
|
204
|
-
if (error
|
|
249
|
+
if (errnoOf(error) === "ENOENT")
|
|
205
250
|
return null;
|
|
206
251
|
throw error;
|
|
207
252
|
});
|
|
208
253
|
if (!next) {
|
|
209
|
-
missing.push(walked.join(
|
|
254
|
+
missing.push(walked.join(path2.sep));
|
|
210
255
|
continue;
|
|
211
256
|
}
|
|
212
|
-
await current
|
|
213
|
-
current = next;
|
|
257
|
+
current = await descend(current, next);
|
|
214
258
|
}
|
|
215
259
|
return missing;
|
|
216
260
|
} finally {
|
|
217
261
|
await current.close();
|
|
218
262
|
}
|
|
219
263
|
}
|
|
264
|
+
function alternateSpellings(name) {
|
|
265
|
+
const swapped = [...name].map((letter) => letter === letter.toLowerCase() ? letter.toUpperCase() : letter.toLowerCase()).join("");
|
|
266
|
+
return [...new Set([swapped, name.normalize("NFC"), name.normalize("NFD")])].filter((spelling) => spelling !== name);
|
|
267
|
+
}
|
|
268
|
+
async function misspelledContainedSegment(root, relative) {
|
|
269
|
+
const segments = safeSegments(relative);
|
|
270
|
+
let current = await openPinnedDirectory(root);
|
|
271
|
+
try {
|
|
272
|
+
for (const [index, segment] of segments.entries()) {
|
|
273
|
+
const exists = async (name) => await statAt(current, name).catch(() => null) !== null;
|
|
274
|
+
let folded = false;
|
|
275
|
+
for (const spelling of alternateSpellings(segment)) {
|
|
276
|
+
folded ||= await exists(spelling);
|
|
277
|
+
}
|
|
278
|
+
if (folded && await exists(segment)) {
|
|
279
|
+
const stored = (await listAt(current)).some(({ name }) => name === segment);
|
|
280
|
+
if (!stored)
|
|
281
|
+
return segment;
|
|
282
|
+
}
|
|
283
|
+
if (index === segments.length - 1)
|
|
284
|
+
return;
|
|
285
|
+
const next = await openDirectoryAt(current, segment).catch((error) => {
|
|
286
|
+
if (["ENOENT", "ENOTDIR", "ELOOP"].includes(errnoOf(error) ?? ""))
|
|
287
|
+
return null;
|
|
288
|
+
throw error;
|
|
289
|
+
});
|
|
290
|
+
if (!next)
|
|
291
|
+
return;
|
|
292
|
+
current = await descend(current, next);
|
|
293
|
+
}
|
|
294
|
+
return;
|
|
295
|
+
} finally {
|
|
296
|
+
await current.close();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
class UnapprovedContainedDirectoryError extends Error {
|
|
301
|
+
relative;
|
|
302
|
+
constructor(relative) {
|
|
303
|
+
super(`Contained directory creation was not authorized: ${relative}`);
|
|
304
|
+
this.relative = relative;
|
|
305
|
+
this.name = "UnapprovedContainedDirectoryError";
|
|
306
|
+
}
|
|
307
|
+
}
|
|
220
308
|
async function openContainedParent(root, relative, options = {}) {
|
|
221
309
|
const segments = safeSegments(relative);
|
|
222
310
|
const basename = segments.pop();
|
|
@@ -224,17 +312,20 @@ async function openContainedParent(root, relative, options = {}) {
|
|
|
224
312
|
throw new Error("Contained path is missing a basename");
|
|
225
313
|
let current = await openPinnedDirectory(root);
|
|
226
314
|
try {
|
|
315
|
+
const approved = new Set(options.createDirectories);
|
|
316
|
+
const walked = [];
|
|
227
317
|
for (const segment of segments) {
|
|
228
|
-
|
|
318
|
+
walked.push(segment);
|
|
319
|
+
const next = await openDirectoryAt(current, segment).catch(async (error) => {
|
|
320
|
+
if (options.createDirectories === undefined || errnoOf(error) !== "ENOENT")
|
|
321
|
+
throw error;
|
|
322
|
+
const directory = walked.join(path2.sep);
|
|
323
|
+
if (!approved.has(directory))
|
|
324
|
+
throw new UnapprovedContainedDirectoryError(directory);
|
|
229
325
|
await createDirectoryAt(current, segment);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
await next.close();
|
|
234
|
-
throw new Error("Contained ancestor is not a directory");
|
|
235
|
-
}
|
|
236
|
-
await current.close();
|
|
237
|
-
current = next;
|
|
326
|
+
return openDirectoryAt(current, segment);
|
|
327
|
+
});
|
|
328
|
+
current = await descend(current, next);
|
|
238
329
|
}
|
|
239
330
|
return { handle: current, basename };
|
|
240
331
|
} catch (error) {
|
|
@@ -256,21 +347,38 @@ async function openContainedFile(root, relative) {
|
|
|
256
347
|
await parent.handle.close();
|
|
257
348
|
}
|
|
258
349
|
}
|
|
350
|
+
|
|
351
|
+
class ContainedPathChangedError extends Error {
|
|
352
|
+
relative;
|
|
353
|
+
constructor(relative) {
|
|
354
|
+
super(`Contained path changed during authorization: ${relative}`);
|
|
355
|
+
this.relative = relative;
|
|
356
|
+
this.name = "ContainedPathChangedError";
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async function reopen(relative, open) {
|
|
360
|
+
return open().catch((error) => {
|
|
361
|
+
if (["ENOENT", "ENOTDIR", "ELOOP"].includes(errnoOf(error) ?? "")) {
|
|
362
|
+
throw new ContainedPathChangedError(relative);
|
|
363
|
+
}
|
|
364
|
+
throw error;
|
|
365
|
+
});
|
|
366
|
+
}
|
|
259
367
|
async function assertContainedFileCurrent(root, relative, expected) {
|
|
260
|
-
const current = await openContainedFile(root, relative);
|
|
368
|
+
const current = await reopen(relative, () => openContainedFile(root, relative));
|
|
261
369
|
try {
|
|
262
370
|
if (!sameIdentity(await expected.stat(), await current.stat())) {
|
|
263
|
-
throw new
|
|
371
|
+
throw new ContainedPathChangedError(relative);
|
|
264
372
|
}
|
|
265
373
|
} finally {
|
|
266
374
|
await current.close();
|
|
267
375
|
}
|
|
268
376
|
}
|
|
269
377
|
async function assertContainedParentCurrent(root, relative, expected) {
|
|
270
|
-
const current = await openContainedParent(root, relative);
|
|
378
|
+
const current = await reopen(relative, () => openContainedParent(root, relative));
|
|
271
379
|
try {
|
|
272
380
|
if (!sameIdentity(await expected.stat(), await current.handle.stat())) {
|
|
273
|
-
throw new
|
|
381
|
+
throw new ContainedPathChangedError(relative);
|
|
274
382
|
}
|
|
275
383
|
} finally {
|
|
276
384
|
await current.handle.close();
|
|
@@ -310,101 +418,4 @@ async function readContainedUtf8Handle(handle, maxBytes) {
|
|
|
310
418
|
};
|
|
311
419
|
}
|
|
312
420
|
|
|
313
|
-
|
|
314
|
-
async function walkContainedFiles(input) {
|
|
315
|
-
const scan = await scanContainedFiles({ ...input, symlinks: "refuse" });
|
|
316
|
-
if (scan.truncated)
|
|
317
|
-
throw new Error("Contained file traversal exceeded its bounds");
|
|
318
|
-
return scan.files;
|
|
319
|
-
}
|
|
320
|
-
async function scanContainedFiles(input) {
|
|
321
|
-
const files = [];
|
|
322
|
-
let truncated = false;
|
|
323
|
-
let skippedDirectories = 0;
|
|
324
|
-
let skippedSymlinks = 0;
|
|
325
|
-
const denied = [];
|
|
326
|
-
let deniedTruncated = false;
|
|
327
|
-
const root = await openPinnedDirectory(input.root);
|
|
328
|
-
const visit = async (directory, relativeDirectory, depth) => {
|
|
329
|
-
if (truncated)
|
|
330
|
-
return;
|
|
331
|
-
if (depth > input.maxDepth) {
|
|
332
|
-
truncated = true;
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
const entries = [...await listAt(directory)];
|
|
336
|
-
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
337
|
-
for (const entry of entries) {
|
|
338
|
-
const relative = relativeDirectory ? path2.join(relativeDirectory, entry.name) : entry.name;
|
|
339
|
-
const kind = entry.isDirectory() ? "directory" : entry.isSymbolicLink() ? "symlink" : entry.isFile() ? "file" : "other";
|
|
340
|
-
if (kind === "file" && input.includeFile && !input.includeFile(relative))
|
|
341
|
-
continue;
|
|
342
|
-
if (input.authorizePath && !await input.authorizePath(relative, kind)) {
|
|
343
|
-
if (denied.length < input.maxFiles)
|
|
344
|
-
denied.push({ relative, kind });
|
|
345
|
-
else
|
|
346
|
-
deniedTruncated = true;
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
if (entry.isSymbolicLink()) {
|
|
350
|
-
if (input.symlinks === "refuse") {
|
|
351
|
-
throw new Error(`Contained file traversal refuses symlink: ${relative}`);
|
|
352
|
-
}
|
|
353
|
-
skippedSymlinks += 1;
|
|
354
|
-
continue;
|
|
355
|
-
}
|
|
356
|
-
if (entry.isDirectory()) {
|
|
357
|
-
if (input.excludeDirectory?.(relative)) {
|
|
358
|
-
skippedDirectories += 1;
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
let child;
|
|
362
|
-
try {
|
|
363
|
-
child = await openDirectoryAt(directory, entry.name);
|
|
364
|
-
} catch (error) {
|
|
365
|
-
if (input.symlinks === "skip") {
|
|
366
|
-
skippedSymlinks += 1;
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
throw error;
|
|
370
|
-
}
|
|
371
|
-
try {
|
|
372
|
-
await visit(child, relative, depth + 1);
|
|
373
|
-
} finally {
|
|
374
|
-
await child.close();
|
|
375
|
-
}
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
if (!entry.isFile())
|
|
379
|
-
continue;
|
|
380
|
-
if (files.length >= input.maxFiles) {
|
|
381
|
-
truncated = true;
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
let content;
|
|
385
|
-
if (input.readMaxBytes !== undefined) {
|
|
386
|
-
try {
|
|
387
|
-
const handle = await openFileAt(directory, entry.name);
|
|
388
|
-
try {
|
|
389
|
-
content = await readContainedUtf8Handle(handle, input.readMaxBytes);
|
|
390
|
-
} finally {
|
|
391
|
-
await handle.close();
|
|
392
|
-
}
|
|
393
|
-
} catch (error) {
|
|
394
|
-
if (input.skipUnreadable)
|
|
395
|
-
continue;
|
|
396
|
-
throw error;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
files.push({ absolute: relative, relative, ...content && { content } });
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
try {
|
|
403
|
-
await visit(root, "", 0);
|
|
404
|
-
} finally {
|
|
405
|
-
await root.close();
|
|
406
|
-
}
|
|
407
|
-
return { files, truncated, skippedDirectories, skippedSymlinks, denied, deniedTruncated };
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
export { NumericFileHandle, descriptorPath, listContainedDirectory, missingContainedDirectories, openContainedParent, openContainedFile, assertContainedFileCurrent, assertContainedParentCurrent, containedEntryMetadata, openContainedParentFile, readContainedUtf8Handle, walkContainedFiles, scanContainedFiles };
|
|
421
|
+
export { descriptorPath, NumericFileHandle, openDirectoryAt, openPinnedDirectory, isSafeEntryName, openFileAt, listAt, listContainedDirectory, missingContainedDirectories, misspelledContainedSegment, UnapprovedContainedDirectoryError, openContainedParent, openContainedFile, ContainedPathChangedError, assertContainedFileCurrent, assertContainedParentCurrent, containedEntryMetadata, openContainedParentFile, readContainedUtf8Handle };
|
|
@@ -11,7 +11,10 @@ import {
|
|
|
11
11
|
spawnBunChild,
|
|
12
12
|
spawnBunInheritedChild,
|
|
13
13
|
ownerLossGuardEntry
|
|
14
|
-
} from "./index-
|
|
14
|
+
} from "./index-f6m4c545.js";
|
|
15
|
+
import {
|
|
16
|
+
errnoOf
|
|
17
|
+
} from "./index-jj9228tt.js";
|
|
15
18
|
import {
|
|
16
19
|
raceAbort
|
|
17
20
|
} from "./index-b0kddvzw.js";
|
|
@@ -30,7 +33,8 @@ var ObservationSchema = z.object({
|
|
|
30
33
|
groupId: z.number().int().positive(),
|
|
31
34
|
observations: z.number().int().nonnegative(),
|
|
32
35
|
lastStates: z.array(z.string().max(32)).max(16),
|
|
33
|
-
elapsedMs: z.number().int().nonnegative()
|
|
36
|
+
elapsedMs: z.number().int().nonnegative(),
|
|
37
|
+
reason: z.string().max(32).optional()
|
|
34
38
|
});
|
|
35
39
|
var observations = new WeakMap;
|
|
36
40
|
|
|
@@ -119,6 +123,12 @@ function processGroups(timeoutMs) {
|
|
|
119
123
|
});
|
|
120
124
|
});
|
|
121
125
|
}
|
|
126
|
+
function observationFailureReason(cause) {
|
|
127
|
+
if (!(cause instanceof Error))
|
|
128
|
+
return "unknown";
|
|
129
|
+
const signal = "signal" in cause && typeof cause.signal === "string" ? cause.signal : undefined;
|
|
130
|
+
return (errnoOf(cause) ?? signal ?? cause.name).slice(0, 32);
|
|
131
|
+
}
|
|
122
132
|
async function waitForProcessGroupExit(pid, deadline, killLiveMembers) {
|
|
123
133
|
if (pid === undefined)
|
|
124
134
|
return;
|
|
@@ -155,7 +165,7 @@ async function waitForProcessGroupExit(pid, deadline, killLiveMembers) {
|
|
|
155
165
|
} catch (cause) {
|
|
156
166
|
if (cause instanceof GroupSettlementError)
|
|
157
167
|
throw cause;
|
|
158
|
-
throw new GroupSettlementError("Could not observe command process group settlement", { ...observation(), failure: "observation" }, cause);
|
|
168
|
+
throw new GroupSettlementError("Could not observe command process group settlement", { ...observation(), failure: "observation", reason: observationFailureReason(cause) }, cause);
|
|
159
169
|
}
|
|
160
170
|
}
|
|
161
171
|
|
|
@@ -185,7 +195,7 @@ function deniedOnDarwin(error) {
|
|
|
185
195
|
return process.platform === "darwin" && error instanceof Error && "code" in error && error.code === "EPERM";
|
|
186
196
|
}
|
|
187
197
|
function isErrno(error, code) {
|
|
188
|
-
return error
|
|
198
|
+
return errnoOf(error) === code;
|
|
189
199
|
}
|
|
190
200
|
function signalGroup(pid, signal) {
|
|
191
201
|
if (pid === undefined)
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
errnoOf
|
|
3
|
+
} from "./index-jj9228tt.js";
|
|
1
4
|
import {
|
|
2
5
|
MAX_TIMER_MS
|
|
3
6
|
} from "./index-eemvahkc.js";
|
|
@@ -177,7 +180,7 @@ function abortOwnerLossLaunch(pid) {
|
|
|
177
180
|
try {
|
|
178
181
|
process.kill(-pid, "SIGKILL");
|
|
179
182
|
} catch (error) {
|
|
180
|
-
if (
|
|
183
|
+
if (errnoOf(error) !== "ESRCH")
|
|
181
184
|
throw error;
|
|
182
185
|
}
|
|
183
186
|
}
|
|
@@ -575,7 +578,7 @@ function runOwnerLossGuard(signalTarget, executable, args) {
|
|
|
575
578
|
try {
|
|
576
579
|
process.kill(targetPid, signal);
|
|
577
580
|
} catch (error) {
|
|
578
|
-
if (
|
|
581
|
+
if (errnoOf(error) !== "ESRCH")
|
|
579
582
|
throw error;
|
|
580
583
|
}
|
|
581
584
|
};
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
withExclusiveLock2
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-zqkz4af9.js";
|
|
4
4
|
import {
|
|
5
5
|
readBoundedFile
|
|
6
6
|
} from "./index-m616f0yz.js";
|
|
7
7
|
import {
|
|
8
8
|
writeAtomicFileData
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-ac6vvm30.js";
|
|
10
10
|
import {
|
|
11
11
|
publishAtomicFile
|
|
12
12
|
} from "./index-b56nnscm.js";
|
|
13
|
+
import {
|
|
14
|
+
errnoOf
|
|
15
|
+
} from "./index-jj9228tt.js";
|
|
13
16
|
import {
|
|
14
17
|
assertPositiveSafeInteger
|
|
15
18
|
} from "./index-0s4xebbg.js";
|
|
@@ -21,7 +24,7 @@ var NATIVE_IO = { write: writeAtomicFileData, lock: withExclusiveLock2 };
|
|
|
21
24
|
var DEFAULT_MAX_BYTES = 64 * 1024 * 1024;
|
|
22
25
|
var encode = (state) => `${JSON.stringify(state)}
|
|
23
26
|
`;
|
|
24
|
-
var missing = (error) =>
|
|
27
|
+
var missing = (error) => errnoOf(error) === "ENOENT";
|
|
25
28
|
function createFileStateStore2(path, options) {
|
|
26
29
|
return createFileStateStoreOn(path, options, NATIVE_IO);
|
|
27
30
|
}
|