stitchkit 0.114.2 → 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.
Files changed (103) hide show
  1. package/CHANGELOG.md +29 -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.js +8 -5
  32. package/dist/entrypoints/tools.js +5 -2
  33. package/dist/files/chunk-spool.d.ts.map +1 -1
  34. package/dist/{index-2f9r0jgr.js → index-364k2zwa.js} +4 -4
  35. package/dist/{index-tnxsq7cw.js → index-3qqdqwxe.js} +90 -35
  36. package/dist/{index-s47ac8zt.js → index-7yx8j6ay.js} +133 -156
  37. package/dist/{index-912sza5h.js → index-90p34rts.js} +1 -1
  38. package/dist/{index-a3462dqf.js → index-944x38nv.js} +1 -1
  39. package/dist/{index-07dcf2yn.js → index-ac6vvm30.js} +5 -2
  40. package/dist/{index-qj1sy4ep.js → index-crmswbrt.js} +1 -1
  41. package/dist/{index-7r4knwf8.js → index-dr3t5n1v.js} +14 -4
  42. package/dist/{index-dc9ere5p.js → index-dx5cm9pc.js} +1 -1
  43. package/dist/{index-84bf5spd.js → index-f6m4c545.js} +5 -2
  44. package/dist/{index-hy802jnr.js → index-fdk4r4r6.js} +6 -3
  45. package/dist/index-j8kf56wx.js +100 -0
  46. package/dist/index-jj9228tt.js +6 -0
  47. package/dist/{index-bh2ht9y5.js → index-n8z3rvzw.js} +4 -1
  48. package/dist/index-nregbbsc.js +107 -0
  49. package/dist/{index-j4zh647a.js → index-tt30h7mr.js} +4 -1
  50. package/dist/{index-zrtrjkbf.js → index-x0ddbj85.js} +148 -172
  51. package/dist/{index-p02zgk8x.js → index-y4rxnvgp.js} +6 -0
  52. package/dist/{index-5v5a9k2n.js → index-z3d6smer.js} +1 -1
  53. package/dist/{index-6b3pcq5z.js → index-zqkz4af9.js} +1 -1
  54. package/dist/internal/atomic-file.d.ts.map +1 -1
  55. package/dist/internal/atomic-staging.d.ts.map +1 -1
  56. package/dist/internal/contained-directory.d.ts +20 -0
  57. package/dist/internal/contained-directory.d.ts.map +1 -0
  58. package/dist/{agent-runtime → internal}/contained-files.d.ts +14 -13
  59. package/dist/internal/contained-files.d.ts.map +1 -0
  60. package/dist/internal/contained-handle.d.ts +30 -0
  61. package/dist/internal/contained-handle.d.ts.map +1 -0
  62. package/dist/internal/contained-write.d.ts +12 -0
  63. package/dist/internal/contained-write.d.ts.map +1 -0
  64. package/dist/internal/darwin-binding.d.ts +1 -1
  65. package/dist/internal/darwin-binding.d.ts.map +1 -1
  66. package/dist/internal/errno.d.ts +3 -0
  67. package/dist/internal/errno.d.ts.map +1 -0
  68. package/dist/internal/process-instance.d.ts.map +1 -1
  69. package/dist/internal/write-download.d.ts +5 -14
  70. package/dist/internal/write-download.d.ts.map +1 -1
  71. package/dist/process/group-diagnostics.d.ts +1 -0
  72. package/dist/process/group-diagnostics.d.ts.map +1 -1
  73. package/dist/process/group-settlement.d.ts +2 -0
  74. package/dist/process/group-settlement.d.ts.map +1 -1
  75. package/dist/process/group.d.ts.map +1 -1
  76. package/dist/process/owner-loss-control.d.ts.map +1 -1
  77. package/dist/react/keyboard/hooks.d.ts +2 -2
  78. package/dist/react/keyboard/hooks.d.ts.map +1 -1
  79. package/dist/react/keyboard/layers.d.ts +2 -0
  80. package/dist/react/keyboard/layers.d.ts.map +1 -1
  81. package/dist/telegram/broadcast-state.d.ts.map +1 -1
  82. package/dist/tools/cli/download.d.ts.map +1 -1
  83. package/dist/tools/cli/publication-storage.d.ts.map +1 -1
  84. package/dist/tools/cli/publication.d.ts.map +1 -1
  85. package/dist/tools/cli/view.d.ts.map +1 -1
  86. package/llms/agent-runtime.txt +16 -6
  87. package/llms/cli.txt +34 -2
  88. package/llms/process.txt +2 -2
  89. package/llms/react-keyboard.txt +18 -2
  90. package/llms/stitchkit.txt +3 -3
  91. package/llms/{upgrading-0.104.0-0.114.0.txt → upgrading-0.104.0-0.115.0.txt} +62 -3
  92. package/llms/upgrading.txt +1 -1
  93. package/llms-full.txt +132 -15
  94. package/llms.txt +5 -5
  95. package/native/darwin-arm64.node +0 -0
  96. package/native/darwin-x64.node +0 -0
  97. package/native-assets.json +4 -4
  98. package/package.json +1 -1
  99. package/dist/agent-runtime/contained-darwin.d.ts +0 -21
  100. package/dist/agent-runtime/contained-darwin.d.ts.map +0 -1
  101. package/dist/agent-runtime/contained-files.d.ts.map +0 -1
  102. package/dist/agent-runtime/contained-write.d.ts +0 -9
  103. package/dist/agent-runtime/contained-write.d.ts.map +0 -1
@@ -1,33 +1,35 @@
1
- import {
2
- loadDarwinBinding
3
- } from "./index-2kbysk9s.js";
4
1
  import {
5
2
  NativeCommandError2
6
- } from "./index-84bf5spd.js";
3
+ } from "./index-f6m4c545.js";
7
4
  import {
8
5
  CommandStopped,
9
6
  startNativeCommand
10
- } from "./index-7r4knwf8.js";
7
+ } from "./index-dr3t5n1v.js";
8
+ import {
9
+ scanContainedFiles
10
+ } from "./index-nregbbsc.js";
11
+ import {
12
+ writeContainedFile
13
+ } from "./index-j8kf56wx.js";
11
14
  import {
12
- NumericFileHandle,
13
- descriptorPath,
14
15
  listContainedDirectory,
15
16
  missingContainedDirectories,
17
+ UnapprovedContainedDirectoryError,
16
18
  openContainedParent,
17
19
  openContainedFile,
20
+ ContainedPathChangedError,
18
21
  assertContainedFileCurrent,
19
22
  assertContainedParentCurrent,
20
23
  containedEntryMetadata,
21
24
  openContainedParentFile,
22
- readContainedUtf8Handle,
23
- scanContainedFiles
24
- } from "./index-zrtrjkbf.js";
25
+ readContainedUtf8Handle
26
+ } from "./index-x0ddbj85.js";
25
27
  import {
26
28
  defineRuntimeTool2
27
29
  } from "./index-ega3yz4c.js";
28
30
  import {
29
- stagingName
30
- } from "./index-j4zh647a.js";
31
+ errnoOf
32
+ } from "./index-jj9228tt.js";
31
33
  import {
32
34
  AppError2,
33
35
  forbidden2,
@@ -250,7 +252,7 @@ async function recordAgentSandboxProbe2(input) {
250
252
  }
251
253
 
252
254
  // src/agent-runtime/coding-tools.ts
253
- import path5 from "node:path";
255
+ import path4 from "node:path";
254
256
  import { z as z5 } from "zod";
255
257
 
256
258
  // src/agent-runtime/coding-tool-files.ts
@@ -278,7 +280,8 @@ function codingPathRefusal(code, message, path, options = {}) {
278
280
  });
279
281
  }
280
282
  function refuseMissingCodingPath(error, relative) {
281
- const code = error?.code;
283
+ refuseChangedPath(error, relative);
284
+ const code = errnoOf(error);
282
285
  if (error instanceof Error && error.message.includes("is not a regular file")) {
283
286
  codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
284
287
  hint: "Use list_directory to see what is here."
@@ -299,13 +302,55 @@ function refuseMissingCodingPath(error, relative) {
299
302
  hint: "Read or write the target directly, by its own workspace-relative path."
300
303
  });
301
304
  }
302
- if (code === "EISDIR") {
305
+ if (code === "EISDIR" || code === "ENXIO" || code === "EOPNOTSUPP") {
303
306
  codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
304
307
  hint: "Use list_directory to see what is here."
305
308
  });
306
309
  }
307
310
  throw error;
308
311
  }
312
+ function refuseChangedPath(error, relative) {
313
+ if (error instanceof ContainedPathChangedError) {
314
+ codingPathRefusal("CONFLICT", "This path changed while it was being authorized", relative, {
315
+ hint: "Read it again and retry."
316
+ });
317
+ }
318
+ }
319
+ function refuseWriteConflict(error, relative, details = {}) {
320
+ refuseChangedPath(error, relative);
321
+ const code = errnoOf(error);
322
+ if (code === "ENOENT") {
323
+ codingPathRefusal("CONFLICT", "This path changed while it was being written", relative, {
324
+ details,
325
+ hint: "Read it again and retry."
326
+ });
327
+ }
328
+ if (code === "ENOTDIR") {
329
+ codingPathRefusal("CONFLICT", "A segment of this path is not a directory", relative, {
330
+ details,
331
+ hint: "Write under a different path, or remove the file blocking it."
332
+ });
333
+ }
334
+ if (code === "ELOOP") {
335
+ codingPathRefusal("FORBIDDEN", "This path is a symlink, which is not followed", relative, {
336
+ details,
337
+ hint: "Write to the target directly, by its own workspace-relative path."
338
+ });
339
+ }
340
+ if (code === "EISDIR") {
341
+ codingPathRefusal("CONFLICT", "This path is a directory", relative, {
342
+ details,
343
+ hint: "Write to a file path inside it, or choose another name."
344
+ });
345
+ }
346
+ if (code === "EEXIST") {
347
+ codingPathRefusal("CONFLICT", "This file already exists", relative, {
348
+ details,
349
+ hint: "Pass overwrite: true to replace it, or edit_file to change part of it."
350
+ });
351
+ }
352
+ throw error;
353
+ }
309
354
  function refuseUnknownSpillReference(reference) {
310
355
  codingRefusal("SPILL_REFERENCE_UNKNOWN", `No spilled output is held under \`${reference}\``, {
311
356
  details: { reference },
@@ -343,6 +388,12 @@ function inputPath(root, requested, maxPathBytes) {
343
388
  return resolved;
344
389
  }
345
390
  function boundedCodingRelativePath(root, requested, maxPathBytes) {
391
+ if (requested.includes("\x00")) {
392
+ codingRefusal("BAD_REQUEST", "Path segments cannot contain a NUL byte", {
393
+ details: { path: requested },
394
+ hint: "Pass the exact workspace-relative entry name without NUL bytes."
395
+ });
396
+ }
346
397
  if (path.isAbsolute(requested))
347
398
  inputPath(root, requested, maxPathBytes);
348
399
  if (requested.includes("\\")) {
@@ -462,86 +513,6 @@ function utf8AlignedStart(data, start, end) {
462
513
  return safe;
463
514
  }
464
515
 
465
- // src/agent-runtime/contained-write.ts
466
- import { fchmod, write as writeDescriptor } from "node:fs";
467
- import { rename, unlink, writeFile } from "node:fs/promises";
468
- import path2 from "node:path";
469
- async function writeDescriptorFully(descriptor, content) {
470
- const bytes = Buffer.from(content);
471
- let offset = 0;
472
- while (offset < bytes.byteLength) {
473
- const written = await new Promise((resolve, reject) => {
474
- writeDescriptor(descriptor, bytes, offset, bytes.byteLength - offset, null, (error, bytesWritten) => error ? reject(error) : resolve(bytesWritten));
475
- });
476
- if (written === 0)
477
- throw new Error("Contained file write made no progress");
478
- offset += written;
479
- }
480
- }
481
- async function chmodDescriptor(descriptor, mode) {
482
- await new Promise((resolve, reject) => {
483
- fchmod(descriptor, mode & 4095, (error) => error ? reject(error) : resolve());
484
- });
485
- }
486
- async function createDarwinFile(parent, name, content, mode) {
487
- const binding = loadDarwinBinding();
488
- const descriptor = binding.createFileAt(parent.fd, name, mode & 4095);
489
- let failed;
490
- try {
491
- await writeDescriptorFully(descriptor, content);
492
- await chmodDescriptor(descriptor, mode);
493
- } catch (error) {
494
- failed = error;
495
- } finally {
496
- try {
497
- await new NumericFileHandle(descriptor).close();
498
- } catch (error) {
499
- failed ??= error;
500
- }
501
- }
502
- if (failed) {
503
- binding.unlinkAt(parent.fd, name);
504
- throw failed;
505
- }
506
- }
507
- async function writeContainedFile(input) {
508
- const mode = input.mode ?? 438;
509
- if (!input.replace) {
510
- if (process.platform === "darwin") {
511
- await createDarwinFile(input.parent.handle, input.parent.basename, input.content, mode);
512
- return;
513
- }
514
- await writeFile(path2.join(descriptorPath(input.parent.handle), input.parent.basename), input.content, { flag: "wx", mode });
515
- return;
516
- }
517
- const temporary = stagingName();
518
- if (process.platform === "darwin") {
519
- const binding = loadDarwinBinding();
520
- let created = false;
521
- try {
522
- await createDarwinFile(input.parent.handle, temporary, input.content, mode);
523
- created = true;
524
- binding.renameAt(input.parent.handle.fd, temporary, input.parent.basename);
525
- } catch (error) {
526
- if (created)
527
- binding.unlinkAt(input.parent.handle.fd, temporary);
528
- throw error;
529
- }
530
- return;
531
- }
532
- const directory = descriptorPath(input.parent.handle);
533
- const temporaryPath = path2.join(directory, temporary);
534
- try {
535
- await writeFile(temporaryPath, input.content, { flag: "wx", mode });
536
- await rename(temporaryPath, path2.join(directory, input.parent.basename));
537
- } catch (error) {
538
- await unlink(temporaryPath).catch(() => {
539
- return;
540
- });
541
- throw error;
542
- }
543
- }
544
-
545
516
  // src/agent-runtime/coding-tool-files.ts
546
517
  async function digestFile(handle, size) {
547
518
  const hash = createHash("sha256");
@@ -556,6 +527,17 @@ async function digestFile(handle, size) {
556
527
  }
557
528
  return hash.digest("hex");
558
529
  }
530
+ async function openAuthorizedWriteParent(root, relative, createsDirectories) {
531
+ return openContainedParent(root, relative, { createDirectories: createsDirectories }).catch((error) => {
532
+ if (error instanceof UnapprovedContainedDirectoryError) {
533
+ codingPathRefusal("CONFLICT", "The directory creation plan changed during authorization", relative, {
534
+ details: { createsDirectories },
535
+ hint: "Retry the write so the host can authorize the current directories."
536
+ });
537
+ }
538
+ refuseWriteConflict(error, relative, { createsDirectories });
539
+ });
540
+ }
559
541
  function createFileCodingTools(config, limits) {
560
542
  const read = defineRuntimeTool2({
561
543
  name: "read_file",
@@ -576,7 +558,7 @@ function createFileCodingTools(config, limits) {
576
558
  let sha256;
577
559
  try {
578
560
  await authorizeCodingTool(config, { operation: "read", path: relative });
579
- await assertContainedFileCurrent(root, relative, handle);
561
+ await assertContainedFileCurrent(root, relative, handle).catch((error) => refuseMissingCodingPath(error, relative));
580
562
  const metadata = await handle.stat();
581
563
  if (!metadata.isFile()) {
582
564
  codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
@@ -639,14 +621,7 @@ function createFileCodingTools(config, limits) {
639
621
  hint: "Write a smaller file, or split it."
640
622
  });
641
623
  }
642
- const createsDirectories = await missingContainedDirectories(root, relative).catch((error) => {
643
- if (error.code === "ENOTDIR") {
644
- codingPathRefusal("CONFLICT", "A segment of this path is not a directory", relative, {
645
- hint: "Write under a different path, or remove the file blocking it."
646
- });
647
- }
648
- throw error;
649
- });
624
+ const createsDirectories = await missingContainedDirectories(root, relative).catch((error) => refuseWriteConflict(error, relative));
650
625
  await authorizeCodingTool(config, {
651
626
  operation: "write",
652
627
  path: relative,
@@ -654,42 +629,39 @@ function createFileCodingTools(config, limits) {
654
629
  overwrite: input.overwrite,
655
630
  createsDirectories
656
631
  });
657
- const parent = await openContainedParent(root, relative, { create: true }).catch((error) => {
658
- const code = error.code;
659
- if (code === "ENOTDIR" || error instanceof Error && error.message.includes("ancestor is not a directory")) {
660
- codingPathRefusal("CONFLICT", "A segment of this path is not a directory", relative, {
661
- details: { createsDirectories },
662
- hint: "Write under a different path, or remove the file blocking it."
663
- });
664
- }
665
- throw error;
666
- });
667
- try {
668
- await assertContainedParentCurrent(root, relative, parent.handle);
669
- const current = await containedEntryMetadata(parent);
670
- if (input.overwrite) {
671
- if (current?.isSymbolicLink()) {
672
- codingPathRefusal("FORBIDDEN", "This path is a symlink", relative, {
673
- hint: "Coding tools never write through symlinks; write to the target directly."
674
- });
675
- }
676
- await writeContainedFile({
677
- parent,
678
- content: input.content,
679
- replace: true,
680
- ...current && { mode: current.mode }
681
- });
682
- } else {
683
- if (current) {
684
- codingPathRefusal("CONFLICT", "This file already exists", relative, {
685
- hint: "Pass overwrite: true to replace it, or edit_file to change part of it."
686
- });
632
+ await withCodingPathLock(`${root}:${relative}`, async () => {
633
+ const parent = await openAuthorizedWriteParent(root, relative, createsDirectories);
634
+ try {
635
+ await assertContainedParentCurrent(root, relative, parent.handle).catch((error) => refuseWriteConflict(error, relative));
636
+ const current = await containedEntryMetadata(parent);
637
+ if (input.overwrite) {
638
+ if (current?.isSymbolicLink()) {
639
+ codingPathRefusal("FORBIDDEN", "This path is a symlink", relative, {
640
+ hint: "Coding tools never write through symlinks; write to the target directly."
641
+ });
642
+ }
643
+ await writeContainedFile({
644
+ parent,
645
+ content: input.content,
646
+ replace: true,
647
+ ...current && { mode: current.mode }
648
+ }).catch((error) => refuseWriteConflict(error, relative));
649
+ } else {
650
+ if (current) {
651
+ codingPathRefusal("CONFLICT", "This file already exists", relative, {
652
+ hint: "Pass overwrite: true to replace it, or edit_file to change part of it."
653
+ });
654
+ }
655
+ await writeContainedFile({
656
+ parent,
657
+ content: input.content,
658
+ replace: false
659
+ }).catch((error) => refuseWriteConflict(error, relative));
687
660
  }
688
- await writeContainedFile({ parent, content: input.content, replace: false });
661
+ } finally {
662
+ await parent.handle.close();
689
663
  }
690
- } finally {
691
- await parent.handle.close();
692
- }
664
+ });
693
665
  return { path: relative, bytes, createdDirectories: createsDirectories };
694
666
  }
695
667
  });
@@ -698,7 +670,7 @@ function createFileCodingTools(config, limits) {
698
670
 
699
671
  // src/agent-runtime/coding-tool-listing.ts
700
672
  import { realpath as realpath3 } from "node:fs/promises";
701
- import path3 from "node:path";
673
+ import path2 from "node:path";
702
674
  import { z as z3 } from "zod";
703
675
  var DEFAULT_EXCLUDED_DIRECTORIES = [
704
676
  ".git",
@@ -773,12 +745,7 @@ function createListingCodingTools(config, limits) {
773
745
  await authorizeCodingPathChain(config, relative);
774
746
  await authorizeCodingTool(config, { operation: "list", path: relative });
775
747
  const listing = await listContainedDirectory(root, relative, limits.maxListEntries, (candidate) => isCodingPathAuthorized(config, candidate)).catch((error) => {
776
- if (error instanceof Error && error.message.includes("ancestor is not a directory")) {
777
- codingPathRefusal("BAD_REQUEST", "This path is not a directory", relative, {
778
- hint: "Pass a directory; use read_file for a file."
779
- });
780
- }
781
- if (error.code === "ENOENT") {
748
+ if (errnoOf(error) === "ENOENT") {
782
749
  codingPathRefusal("NOT_FOUND", "This directory does not exist", relative, {
783
750
  hint: "List a parent directory to see what is there."
784
751
  });
@@ -794,7 +761,7 @@ function createListingCodingTools(config, limits) {
794
761
  truncated: listing.truncated,
795
762
  ...listing.denied.length > 0 && {
796
763
  denied: listing.denied.map((entry) => ({
797
- path: relative === "." ? entry.name : path3.join(relative, entry.name),
764
+ path: relative === "." ? entry.name : path2.join(relative, entry.name),
798
765
  kind: entry.kind
799
766
  })),
800
767
  deniedTruncated: listing.deniedTruncated
@@ -832,10 +799,10 @@ function createListingCodingTools(config, limits) {
832
799
  maxDepth: limits.maxSearchDepth,
833
800
  maxFiles: limits.maxSearchFiles,
834
801
  symlinks: "skip",
835
- excludeDirectory: (directory) => directory.split(path3.sep).some((segment) => excluded.has(segment)),
802
+ excludeDirectory: (directory) => directory.split(path2.sep).some((segment) => excluded.has(segment)),
836
803
  authorizePath: (candidate) => isCodingPathAuthorized(config, candidate)
837
804
  });
838
- const prefix = relative === "." ? "" : `${relative}${path3.sep}`;
805
+ const prefix = relative === "." ? "" : `${relative}${path2.sep}`;
839
806
  const matched = scan.files.filter((file) => file.relative.startsWith(prefix)).map((file) => file.relative).filter((candidate) => matcher.test(candidate.slice(prefix.length))).sort();
840
807
  const paths = matched.slice(0, limits.maxSearchResults);
841
808
  const scopedDenied = scan.denied.filter((entry) => entry.relative.startsWith(prefix));
@@ -862,7 +829,7 @@ function createListingCodingTools(config, limits) {
862
829
  // src/agent-runtime/coding-tool-search-patch.ts
863
830
  import { createHash as createHash2 } from "node:crypto";
864
831
  import { realpath as realpath4 } from "node:fs/promises";
865
- import path4 from "node:path";
832
+ import path3 from "node:path";
866
833
  import { z as z4 } from "zod";
867
834
  var SearchInputSchema = z4.object({
868
835
  query: z4.string().min(1),
@@ -943,7 +910,7 @@ async function searchFiles(config, limits, input) {
943
910
  readMaxBytes: limits.maxReadBytes,
944
911
  skipUnreadable: true
945
912
  },
946
- excludeDirectory: (relative) => relative.split(path4.sep).some((segment) => excluded.has(segment)),
913
+ excludeDirectory: (relative) => relative.split(path3.sep).some((segment) => excluded.has(segment)),
947
914
  includeFile: (candidate) => {
948
915
  if (included && !included.test(candidate)) {
949
916
  rejectedByInclude += 1;
@@ -1019,8 +986,12 @@ async function editFile(config, limits, input) {
1019
986
  const parent = await openContainedParent(root, relative).catch((error) => refuseMissingCodingPath(error, relative));
1020
987
  try {
1021
988
  return await withCodingPathLock(`${root}:${relative}`, async () => {
1022
- const handle = await openContainedParentFile(parent).catch((error) => refuseMissingCodingPath(error, relative));
1023
- const read = await readContainedUtf8Handle(handle, limits.maxWriteBytes).finally(() => handle.close());
989
+ const readCurrent = async () => {
990
+ const handle = await openContainedParentFile(parent).catch((error) => refuseMissingCodingPath(error, relative));
991
+ return readContainedUtf8Handle(handle, limits.maxWriteBytes).finally(() => handle.close());
992
+ };
993
+ await authorizeCodingTool(config, { operation: "read", path: relative });
994
+ const read = await readCurrent();
1024
995
  const source = read.text;
1025
996
  const baseSha256 = sha256(source);
1026
997
  if (input.expectedSha256 !== undefined && baseSha256 !== input.expectedSha256) {
@@ -1064,14 +1035,20 @@ async function editFile(config, limits, input) {
1064
1035
  replacements,
1065
1036
  dryRun: input.dryRun
1066
1037
  });
1067
- await assertContainedParentCurrent(root, relative, parent.handle);
1038
+ await assertContainedParentCurrent(root, relative, parent.handle).catch((error) => refuseWriteConflict(error, relative));
1068
1039
  if (!input.dryRun) {
1040
+ if (sha256((await readCurrent()).text) !== baseSha256) {
1041
+ conflict2("The file changed since it was read", {
1042
+ message: "The file changed since it was read",
1043
+ path: relative
1044
+ });
1045
+ }
1069
1046
  await writeContainedFile({
1070
1047
  parent,
1071
1048
  content: changed,
1072
1049
  replace: true,
1073
1050
  mode: read.mode
1074
- });
1051
+ }).catch((error) => refuseWriteConflict(error, relative));
1075
1052
  }
1076
1053
  return {
1077
1054
  path: relative,
@@ -1383,10 +1360,10 @@ var AGENT_CODING_TOOL_NAMES = {
1383
1360
  writeFile: "write_file"
1384
1361
  };
1385
1362
  function createAgentCodingTools2(config) {
1386
- if (!path5.isAbsolute(config.root))
1363
+ if (!path4.isAbsolute(config.root))
1387
1364
  throw new Error("Coding tool root must be absolute");
1388
1365
  for (const executable of Object.values(config.executables ?? {})) {
1389
- if (!path5.isAbsolute(executable)) {
1366
+ if (!path4.isAbsolute(executable)) {
1390
1367
  throw new Error("Coding tool executables must be absolute paths");
1391
1368
  }
1392
1369
  }
@@ -8,7 +8,7 @@ import {
8
8
  } from "./index-mgb7r8b8.js";
9
9
  import {
10
10
  writeFileAtomicSync2
11
- } from "./index-07dcf2yn.js";
11
+ } from "./index-ac6vvm30.js";
12
12
  import {
13
13
  raceAbort
14
14
  } from "./index-b0kddvzw.js";
@@ -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-7yx8j6ay.js";
8
8
  import {
9
9
  AgentRecordIdSchema2,
10
10
  AgentRecordVersionSchema2,
@@ -6,7 +6,10 @@ import {
6
6
  } from "./index-b56nnscm.js";
7
7
  import {
8
8
  stagingPath
9
- } from "./index-j4zh647a.js";
9
+ } from "./index-tt30h7mr.js";
10
+ import {
11
+ errnoOf
12
+ } from "./index-jj9228tt.js";
10
13
 
11
14
  // src/internal/atomic-file.ts
12
15
  import { closeSync, fchmodSync, fsyncSync, openSync, unlinkSync, writeSync } from "node:fs";
@@ -27,7 +30,7 @@ async function writeFileAtomic2(target, data, options = {}) {
27
30
  return writeAtomicFileData(target, data, options);
28
31
  }
29
32
  function isMissing(error) {
30
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
33
+ return errnoOf(error) === "ENOENT";
31
34
  }
32
35
  async function writeAtomicFileStaged(target, stage, options, io = { open, unlink, publish: publishAtomicFile }) {
33
36
  const mode = options.mode ?? DEFAULT_MODE;
@@ -19,7 +19,7 @@ import {
19
19
  appendEventIn,
20
20
  ArchiveProjectionSchema,
21
21
  createAgentRuntimeStore2
22
- } from "./index-a3462dqf.js";
22
+ } from "./index-944x38nv.js";
23
23
  import {
24
24
  AgentConversationPageSchema2,
25
25
  AgentConversationMessagePageSchema2
@@ -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)
@@ -17,7 +17,7 @@ import {
17
17
  replaceMessage,
18
18
  ArchiveSpillSchema,
19
19
  createAgentRuntimeStore2
20
- } from "./index-a3462dqf.js";
20
+ } from "./index-944x38nv.js";
21
21
 
22
22
  // src/agent-runtime/store-memory.ts
23
23
  import { z as z2 } from "zod";
@@ -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
  };
@@ -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
  }