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.
Files changed (115) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/agent-runtime/coding-tool-files.d.ts.map +1 -1
  3. package/dist/agent-runtime/coding-tool-listing.d.ts.map +1 -1
  4. package/dist/agent-runtime/coding-tool-paths.d.ts.map +1 -1
  5. package/dist/agent-runtime/coding-tool-refusals.d.ts +6 -0
  6. package/dist/agent-runtime/coding-tool-refusals.d.ts.map +1 -1
  7. package/dist/agent-runtime/coding-tool-search-patch.d.ts.map +1 -1
  8. package/dist/agent-runtime/contained-scan.d.ts +1 -1
  9. package/dist/agent-runtime/contained-scan.d.ts.map +1 -1
  10. package/dist/agent-runtime/sandbox-broker.d.ts.map +1 -1
  11. package/dist/agent-runtime/sandbox-bubblewrap-storage.d.ts.map +1 -1
  12. package/dist/application/directory-inbox-files.d.ts.map +1 -1
  13. package/dist/application/file-state-store.d.ts.map +1 -1
  14. package/dist/entrypoints/agent-runtime/coding-tools.js +6 -4
  15. package/dist/entrypoints/agent-runtime/harness.js +2 -1
  16. package/dist/entrypoints/agent-runtime/sandbox.js +13 -8
  17. package/dist/entrypoints/agent-runtime/sqlite/bun.js +8 -6
  18. package/dist/entrypoints/agent-runtime/sqlite/node.js +8 -6
  19. package/dist/entrypoints/agent-runtime/testing.js +8 -6
  20. package/dist/entrypoints/agent-runtime.js +8 -6
  21. package/dist/entrypoints/application/diagnostic-journal.js +2 -2
  22. package/dist/entrypoints/application/directory-inbox.js +10 -7
  23. package/dist/entrypoints/cli/publish.js +11 -8
  24. package/dist/entrypoints/cli.js +6 -3
  25. package/dist/entrypoints/files.js +10 -7
  26. package/dist/entrypoints/process/owner-loss.js +1 -1
  27. package/dist/entrypoints/process.js +3 -3
  28. package/dist/entrypoints/react/keyboard/testing.js +1 -1
  29. package/dist/entrypoints/react/keyboard.js +11 -11
  30. package/dist/entrypoints/server.js +4 -4
  31. package/dist/entrypoints/telegram/grammy.js +2 -2
  32. package/dist/entrypoints/telegram.d.ts +1 -1
  33. package/dist/entrypoints/telegram.d.ts.map +1 -1
  34. package/dist/entrypoints/telegram.js +30 -14
  35. package/dist/entrypoints/tools.js +5 -2
  36. package/dist/files/chunk-spool.d.ts.map +1 -1
  37. package/dist/{index-2f9r0jgr.js → index-364k2zwa.js} +4 -4
  38. package/dist/{index-dc9ere5p.js → index-4g6qmgdx.js} +1 -1
  39. package/dist/index-6f49krb5.js +107 -0
  40. package/dist/{index-912sza5h.js → index-90p34rts.js} +1 -1
  41. package/dist/{index-07dcf2yn.js → index-ac6vvm30.js} +5 -2
  42. package/dist/{index-zrtrjkbf.js → index-arjmb6de.js} +183 -172
  43. package/dist/{index-7r4knwf8.js → index-dr3t5n1v.js} +14 -4
  44. package/dist/{index-84bf5spd.js → index-f6m4c545.js} +5 -2
  45. package/dist/{index-qj1sy4ep.js → index-fa435yq2.js} +1 -1
  46. package/dist/{index-hy802jnr.js → index-fdk4r4r6.js} +6 -3
  47. package/dist/index-jj9228tt.js +6 -0
  48. package/dist/{index-a3462dqf.js → index-jq2ky8fw.js} +1 -1
  49. package/dist/{index-s47ac8zt.js → index-n5sv4z0w.js} +142 -156
  50. package/dist/{index-bh2ht9y5.js → index-n8z3rvzw.js} +4 -1
  51. package/dist/index-q968hy6y.js +100 -0
  52. package/dist/{index-j4zh647a.js → index-tt30h7mr.js} +4 -1
  53. package/dist/{index-tnxsq7cw.js → index-w7jq3fz9.js} +113 -38
  54. package/dist/{index-p02zgk8x.js → index-y4rxnvgp.js} +6 -0
  55. package/dist/{index-5v5a9k2n.js → index-z3d6smer.js} +1 -1
  56. package/dist/{index-6b3pcq5z.js → index-zqkz4af9.js} +1 -1
  57. package/dist/internal/atomic-file.d.ts.map +1 -1
  58. package/dist/internal/atomic-staging.d.ts.map +1 -1
  59. package/dist/internal/contained-directory.d.ts +20 -0
  60. package/dist/internal/contained-directory.d.ts.map +1 -0
  61. package/dist/{agent-runtime → internal}/contained-files.d.ts +24 -13
  62. package/dist/internal/contained-files.d.ts.map +1 -0
  63. package/dist/internal/contained-handle.d.ts +30 -0
  64. package/dist/internal/contained-handle.d.ts.map +1 -0
  65. package/dist/internal/contained-write.d.ts +12 -0
  66. package/dist/internal/contained-write.d.ts.map +1 -0
  67. package/dist/internal/darwin-binding.d.ts +1 -1
  68. package/dist/internal/darwin-binding.d.ts.map +1 -1
  69. package/dist/internal/errno.d.ts +3 -0
  70. package/dist/internal/errno.d.ts.map +1 -0
  71. package/dist/internal/process-instance.d.ts.map +1 -1
  72. package/dist/internal/write-download.d.ts +5 -14
  73. package/dist/internal/write-download.d.ts.map +1 -1
  74. package/dist/process/group-diagnostics.d.ts +1 -0
  75. package/dist/process/group-diagnostics.d.ts.map +1 -1
  76. package/dist/process/group-settlement.d.ts +2 -0
  77. package/dist/process/group-settlement.d.ts.map +1 -1
  78. package/dist/process/group.d.ts.map +1 -1
  79. package/dist/process/owner-loss-control.d.ts.map +1 -1
  80. package/dist/react/keyboard/hooks.d.ts +2 -2
  81. package/dist/react/keyboard/hooks.d.ts.map +1 -1
  82. package/dist/react/keyboard/layers.d.ts +2 -0
  83. package/dist/react/keyboard/layers.d.ts.map +1 -1
  84. package/dist/telegram/broadcast-state.d.ts.map +1 -1
  85. package/dist/telegram/budget-transformer.d.ts +5 -2
  86. package/dist/telegram/budget-transformer.d.ts.map +1 -1
  87. package/dist/telegram/outbound-budget.d.ts +26 -11
  88. package/dist/telegram/outbound-budget.d.ts.map +1 -1
  89. package/dist/tools/cli/download.d.ts.map +1 -1
  90. package/dist/tools/cli/publication-storage.d.ts.map +1 -1
  91. package/dist/tools/cli/publication.d.ts.map +1 -1
  92. package/dist/tools/cli/view.d.ts +7 -1
  93. package/dist/tools/cli/view.d.ts.map +1 -1
  94. package/llms/agent-runtime.txt +16 -6
  95. package/llms/cli.txt +37 -3
  96. package/llms/process.txt +2 -2
  97. package/llms/react-keyboard.txt +18 -2
  98. package/llms/stitchkit.txt +3 -3
  99. package/llms/telegram.txt +10 -3
  100. package/llms/{upgrading-0.104.0-0.114.0.txt → upgrading-0.105.0-0.116.0.txt} +85 -124
  101. package/llms/{upgrading-0.44.0-0.61.0.txt → upgrading-0.44.0-0.62.0.txt} +120 -3
  102. package/llms/{upgrading-0.62.0-0.78.0.txt → upgrading-0.63.0-0.83.0.txt} +181 -120
  103. package/llms/{upgrading-0.79.0-0.103.13.txt → upgrading-0.84.0-0.104.0.txt} +124 -181
  104. package/llms/upgrading.txt +4 -4
  105. package/llms-full.txt +168 -19
  106. package/llms.txt +9 -9
  107. package/native/darwin-arm64.node +0 -0
  108. package/native/darwin-x64.node +0 -0
  109. package/native-assets.json +4 -4
  110. package/package.json +1 -1
  111. package/dist/agent-runtime/contained-darwin.d.ts +0 -21
  112. package/dist/agent-runtime/contained-darwin.d.ts.map +0 -1
  113. package/dist/agent-runtime/contained-files.d.ts.map +0 -1
  114. package/dist/agent-runtime/contained-write.d.ts +0 -9
  115. 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/agent-runtime/contained-scan.ts
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 { lstat, mkdir, open, readdir, realpath } from "node:fs/promises";
10
+ import { mkdir, open, realpath } from "node:fs/promises";
11
11
  import path from "node:path";
12
12
 
13
- // src/agent-runtime/contained-darwin.ts
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/agent-runtime/contained-files.ts
46
- function containedEntryKind(entry) {
47
- return entry.isDirectory() ? "directory" : entry.isSymbolicLink() ? "symlink" : entry.isFile() ? "file" : "other";
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 descriptorPath(handle) {
50
- if (process.platform === "linux")
51
- return `/proc/self/fd/${handle.fd}`;
52
- throw new Error("Descriptor paths are available only in the Linux contained-files backend");
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 sameIdentity(left, right) {
55
- return left.dev === right.dev && left.ino === right.ino;
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
- const expected = await realpath(absolute);
62
- const handle = await open(expected, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
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 [pathMetadata, handleMetadata] = await Promise.all([lstat(expected), handle.stat()]);
65
- if (!pathMetadata.isDirectory() || !sameIdentity(pathMetadata, handleMetadata)) {
66
- throw new Error("Contained directory identity changed while opening");
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 handle;
125
+ return current;
69
126
  } catch (error) {
70
- await handle.close();
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 (path.isAbsolute(relative))
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.length === 0 || segments.some((segment) => segment === "" || segment === "." || segment === "..")) {
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 open(path.join(descriptorPath(directory), name), constants.O_RDONLY | constants.O_NOFOLLOW);
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(path.join(descriptorPath(directory), name)).catch((error) => {
110
- if (error.code === "ENOENT")
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
- const next = await openDirectoryAt(current, segment);
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 : path.join(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(path.sep));
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.code === "ENOENT")
249
+ if (errnoOf(error) === "ENOENT")
205
250
  return null;
206
251
  throw error;
207
252
  });
208
253
  if (!next) {
209
- missing.push(walked.join(path.sep));
254
+ missing.push(walked.join(path2.sep));
210
255
  continue;
211
256
  }
212
- await current.close();
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
- if (options.create)
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
- const next = await openDirectoryAt(current, segment);
231
- const metadata = await next.stat();
232
- if (!metadata.isDirectory()) {
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 Error("Contained file identity changed during authorization");
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 Error("Contained parent identity changed during authorization");
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
- // src/agent-runtime/contained-scan.ts
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-84bf5spd.js";
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 instanceof Error && "code" in error && error.code === code;
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 (!(error instanceof Error && ("code" in error) && error.code === "ESRCH"))
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 (!(error instanceof Error && ("code" in error) && error.code === "ESRCH"))
581
+ if (errnoOf(error) !== "ESRCH")
579
582
  throw error;
580
583
  }
581
584
  };
@@ -19,7 +19,7 @@ import {
19
19
  appendEventIn,
20
20
  ArchiveProjectionSchema,
21
21
  createAgentRuntimeStore2
22
- } from "./index-a3462dqf.js";
22
+ } from "./index-jq2ky8fw.js";
23
23
  import {
24
24
  AgentConversationPageSchema2,
25
25
  AgentConversationMessagePageSchema2
@@ -1,15 +1,18 @@
1
1
  import {
2
2
  withExclusiveLock2
3
- } from "./index-6b3pcq5z.js";
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-07dcf2yn.js";
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) => error instanceof Error && ("code" in error) && error.code === "ENOENT";
27
+ var missing = (error) => errnoOf(error) === "ENOENT";
25
28
  function createFileStateStore2(path, options) {
26
29
  return createFileStateStoreOn(path, options, NATIVE_IO);
27
30
  }
@@ -0,0 +1,6 @@
1
+ // src/internal/errno.ts
2
+ function errnoOf(error) {
3
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : undefined;
4
+ }
5
+
6
+ export { errnoOf };
@@ -4,7 +4,7 @@ import {
4
4
  AgentSandboxRestrictionSchema2,
5
5
  AgentSandboxGradeSchema2,
6
6
  AGENT_CODING_TOOL_NAMES
7
- } from "./index-s47ac8zt.js";
7
+ } from "./index-n5sv4z0w.js";
8
8
  import {
9
9
  AgentRecordIdSchema2,
10
10
  AgentRecordVersionSchema2,