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,33 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
loadDarwinBinding
|
|
3
|
-
} from "./index-2kbysk9s.js";
|
|
4
1
|
import {
|
|
5
2
|
NativeCommandError2
|
|
6
|
-
} from "./index-
|
|
3
|
+
} from "./index-f6m4c545.js";
|
|
7
4
|
import {
|
|
8
5
|
CommandStopped,
|
|
9
6
|
startNativeCommand
|
|
10
|
-
} from "./index-
|
|
7
|
+
} from "./index-dr3t5n1v.js";
|
|
8
|
+
import {
|
|
9
|
+
scanContainedFiles
|
|
10
|
+
} from "./index-6f49krb5.js";
|
|
11
|
+
import {
|
|
12
|
+
writeContainedFile
|
|
13
|
+
} from "./index-q968hy6y.js";
|
|
11
14
|
import {
|
|
12
|
-
NumericFileHandle,
|
|
13
|
-
descriptorPath,
|
|
14
15
|
listContainedDirectory,
|
|
15
16
|
missingContainedDirectories,
|
|
17
|
+
misspelledContainedSegment,
|
|
18
|
+
UnapprovedContainedDirectoryError,
|
|
16
19
|
openContainedParent,
|
|
17
20
|
openContainedFile,
|
|
21
|
+
ContainedPathChangedError,
|
|
18
22
|
assertContainedFileCurrent,
|
|
19
23
|
assertContainedParentCurrent,
|
|
20
24
|
containedEntryMetadata,
|
|
21
25
|
openContainedParentFile,
|
|
22
|
-
readContainedUtf8Handle
|
|
23
|
-
|
|
24
|
-
} from "./index-zrtrjkbf.js";
|
|
26
|
+
readContainedUtf8Handle
|
|
27
|
+
} from "./index-arjmb6de.js";
|
|
25
28
|
import {
|
|
26
29
|
defineRuntimeTool2
|
|
27
30
|
} from "./index-ega3yz4c.js";
|
|
28
31
|
import {
|
|
29
|
-
|
|
30
|
-
} from "./index-
|
|
32
|
+
errnoOf
|
|
33
|
+
} from "./index-jj9228tt.js";
|
|
31
34
|
import {
|
|
32
35
|
AppError2,
|
|
33
36
|
forbidden2,
|
|
@@ -250,7 +253,7 @@ async function recordAgentSandboxProbe2(input) {
|
|
|
250
253
|
}
|
|
251
254
|
|
|
252
255
|
// src/agent-runtime/coding-tools.ts
|
|
253
|
-
import
|
|
256
|
+
import path4 from "node:path";
|
|
254
257
|
import { z as z5 } from "zod";
|
|
255
258
|
|
|
256
259
|
// src/agent-runtime/coding-tool-files.ts
|
|
@@ -278,7 +281,8 @@ function codingPathRefusal(code, message, path, options = {}) {
|
|
|
278
281
|
});
|
|
279
282
|
}
|
|
280
283
|
function refuseMissingCodingPath(error, relative) {
|
|
281
|
-
|
|
284
|
+
refuseChangedPath(error, relative);
|
|
285
|
+
const code = errnoOf(error);
|
|
282
286
|
if (error instanceof Error && error.message.includes("is not a regular file")) {
|
|
283
287
|
codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
|
|
284
288
|
hint: "Use list_directory to see what is here."
|
|
@@ -299,13 +303,55 @@ function refuseMissingCodingPath(error, relative) {
|
|
|
299
303
|
hint: "Read or write the target directly, by its own workspace-relative path."
|
|
300
304
|
});
|
|
301
305
|
}
|
|
302
|
-
if (code === "EISDIR") {
|
|
306
|
+
if (code === "EISDIR" || code === "ENXIO" || code === "EOPNOTSUPP") {
|
|
303
307
|
codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
|
|
304
308
|
hint: "Use list_directory to see what is here."
|
|
305
309
|
});
|
|
306
310
|
}
|
|
307
311
|
throw error;
|
|
308
312
|
}
|
|
313
|
+
function refuseChangedPath(error, relative) {
|
|
314
|
+
if (error instanceof ContainedPathChangedError) {
|
|
315
|
+
codingPathRefusal("CONFLICT", "This path changed while it was being authorized", relative, {
|
|
316
|
+
hint: "Read it again and retry."
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function refuseWriteConflict(error, relative, details = {}) {
|
|
321
|
+
refuseChangedPath(error, relative);
|
|
322
|
+
const code = errnoOf(error);
|
|
323
|
+
if (code === "ENOENT") {
|
|
324
|
+
codingPathRefusal("CONFLICT", "This path changed while it was being written", relative, {
|
|
325
|
+
details,
|
|
326
|
+
hint: "Read it again and retry."
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
if (code === "ENOTDIR") {
|
|
330
|
+
codingPathRefusal("CONFLICT", "A segment of this path is not a directory", relative, {
|
|
331
|
+
details,
|
|
332
|
+
hint: "Write under a different path, or remove the file blocking it."
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
if (code === "ELOOP") {
|
|
336
|
+
codingPathRefusal("FORBIDDEN", "This path is a symlink, which is not followed", relative, {
|
|
337
|
+
details,
|
|
338
|
+
hint: "Write to the target directly, by its own workspace-relative path."
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
if (code === "EISDIR") {
|
|
342
|
+
codingPathRefusal("CONFLICT", "This path is a directory", relative, {
|
|
343
|
+
details,
|
|
344
|
+
hint: "Write to a file path inside it, or choose another name."
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
if (code === "EEXIST") {
|
|
348
|
+
codingPathRefusal("CONFLICT", "This file already exists", relative, {
|
|
349
|
+
details,
|
|
350
|
+
hint: "Pass overwrite: true to replace it, or edit_file to change part of it."
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
309
355
|
function refuseUnknownSpillReference(reference) {
|
|
310
356
|
codingRefusal("SPILL_REFERENCE_UNKNOWN", `No spilled output is held under \`${reference}\``, {
|
|
311
357
|
details: { reference },
|
|
@@ -343,6 +389,12 @@ function inputPath(root, requested, maxPathBytes) {
|
|
|
343
389
|
return resolved;
|
|
344
390
|
}
|
|
345
391
|
function boundedCodingRelativePath(root, requested, maxPathBytes) {
|
|
392
|
+
if (requested.includes("\x00")) {
|
|
393
|
+
codingRefusal("BAD_REQUEST", "Path segments cannot contain a NUL byte", {
|
|
394
|
+
details: { path: requested },
|
|
395
|
+
hint: "Pass the exact workspace-relative entry name without NUL bytes."
|
|
396
|
+
});
|
|
397
|
+
}
|
|
346
398
|
if (path.isAbsolute(requested))
|
|
347
399
|
inputPath(root, requested, maxPathBytes);
|
|
348
400
|
if (requested.includes("\\")) {
|
|
@@ -387,6 +439,14 @@ async function authorizeCodingPath(config, path2) {
|
|
|
387
439
|
}
|
|
388
440
|
}
|
|
389
441
|
async function authorizeCodingPathChain(config, relative) {
|
|
442
|
+
if (relative !== ".") {
|
|
443
|
+
const misspelled = await misspelledContainedSegment(await realpath(config.root), relative);
|
|
444
|
+
if (misspelled !== undefined) {
|
|
445
|
+
codingPathRefusal("BAD_REQUEST", "This path differs from the name stored on disk", relative, {
|
|
446
|
+
hint: "Use list_directory to see the stored spelling."
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}
|
|
390
450
|
if (!config.authorizePath)
|
|
391
451
|
return;
|
|
392
452
|
const segments = relative === "." ? ["."] : relative.split("/");
|
|
@@ -462,86 +522,6 @@ function utf8AlignedStart(data, start, end) {
|
|
|
462
522
|
return safe;
|
|
463
523
|
}
|
|
464
524
|
|
|
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
525
|
// src/agent-runtime/coding-tool-files.ts
|
|
546
526
|
async function digestFile(handle, size) {
|
|
547
527
|
const hash = createHash("sha256");
|
|
@@ -556,6 +536,17 @@ async function digestFile(handle, size) {
|
|
|
556
536
|
}
|
|
557
537
|
return hash.digest("hex");
|
|
558
538
|
}
|
|
539
|
+
async function openAuthorizedWriteParent(root, relative, createsDirectories) {
|
|
540
|
+
return openContainedParent(root, relative, { createDirectories: createsDirectories }).catch((error) => {
|
|
541
|
+
if (error instanceof UnapprovedContainedDirectoryError) {
|
|
542
|
+
codingPathRefusal("CONFLICT", "The directory creation plan changed during authorization", relative, {
|
|
543
|
+
details: { createsDirectories },
|
|
544
|
+
hint: "Retry the write so the host can authorize the current directories."
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
refuseWriteConflict(error, relative, { createsDirectories });
|
|
548
|
+
});
|
|
549
|
+
}
|
|
559
550
|
function createFileCodingTools(config, limits) {
|
|
560
551
|
const read = defineRuntimeTool2({
|
|
561
552
|
name: "read_file",
|
|
@@ -576,7 +567,7 @@ function createFileCodingTools(config, limits) {
|
|
|
576
567
|
let sha256;
|
|
577
568
|
try {
|
|
578
569
|
await authorizeCodingTool(config, { operation: "read", path: relative });
|
|
579
|
-
await assertContainedFileCurrent(root, relative, handle);
|
|
570
|
+
await assertContainedFileCurrent(root, relative, handle).catch((error) => refuseMissingCodingPath(error, relative));
|
|
580
571
|
const metadata = await handle.stat();
|
|
581
572
|
if (!metadata.isFile()) {
|
|
582
573
|
codingPathRefusal("BAD_REQUEST", "This path is not a regular file", relative, {
|
|
@@ -639,14 +630,7 @@ function createFileCodingTools(config, limits) {
|
|
|
639
630
|
hint: "Write a smaller file, or split it."
|
|
640
631
|
});
|
|
641
632
|
}
|
|
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
|
-
});
|
|
633
|
+
const createsDirectories = await missingContainedDirectories(root, relative).catch((error) => refuseWriteConflict(error, relative));
|
|
650
634
|
await authorizeCodingTool(config, {
|
|
651
635
|
operation: "write",
|
|
652
636
|
path: relative,
|
|
@@ -654,42 +638,39 @@ function createFileCodingTools(config, limits) {
|
|
|
654
638
|
overwrite: input.overwrite,
|
|
655
639
|
createsDirectories
|
|
656
640
|
});
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
hint: "Pass overwrite: true to replace it, or edit_file to change part of it."
|
|
686
|
-
});
|
|
641
|
+
await withCodingPathLock(`${root}:${relative}`, async () => {
|
|
642
|
+
const parent = await openAuthorizedWriteParent(root, relative, createsDirectories);
|
|
643
|
+
try {
|
|
644
|
+
await assertContainedParentCurrent(root, relative, parent.handle).catch((error) => refuseWriteConflict(error, relative));
|
|
645
|
+
const current = await containedEntryMetadata(parent);
|
|
646
|
+
if (input.overwrite) {
|
|
647
|
+
if (current?.isSymbolicLink()) {
|
|
648
|
+
codingPathRefusal("FORBIDDEN", "This path is a symlink", relative, {
|
|
649
|
+
hint: "Coding tools never write through symlinks; write to the target directly."
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
await writeContainedFile({
|
|
653
|
+
parent,
|
|
654
|
+
content: input.content,
|
|
655
|
+
replace: true,
|
|
656
|
+
...current && { mode: current.mode }
|
|
657
|
+
}).catch((error) => refuseWriteConflict(error, relative));
|
|
658
|
+
} else {
|
|
659
|
+
if (current) {
|
|
660
|
+
codingPathRefusal("CONFLICT", "This file already exists", relative, {
|
|
661
|
+
hint: "Pass overwrite: true to replace it, or edit_file to change part of it."
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
await writeContainedFile({
|
|
665
|
+
parent,
|
|
666
|
+
content: input.content,
|
|
667
|
+
replace: false
|
|
668
|
+
}).catch((error) => refuseWriteConflict(error, relative));
|
|
687
669
|
}
|
|
688
|
-
|
|
670
|
+
} finally {
|
|
671
|
+
await parent.handle.close();
|
|
689
672
|
}
|
|
690
|
-
}
|
|
691
|
-
await parent.handle.close();
|
|
692
|
-
}
|
|
673
|
+
});
|
|
693
674
|
return { path: relative, bytes, createdDirectories: createsDirectories };
|
|
694
675
|
}
|
|
695
676
|
});
|
|
@@ -698,7 +679,7 @@ function createFileCodingTools(config, limits) {
|
|
|
698
679
|
|
|
699
680
|
// src/agent-runtime/coding-tool-listing.ts
|
|
700
681
|
import { realpath as realpath3 } from "node:fs/promises";
|
|
701
|
-
import
|
|
682
|
+
import path2 from "node:path";
|
|
702
683
|
import { z as z3 } from "zod";
|
|
703
684
|
var DEFAULT_EXCLUDED_DIRECTORIES = [
|
|
704
685
|
".git",
|
|
@@ -773,12 +754,7 @@ function createListingCodingTools(config, limits) {
|
|
|
773
754
|
await authorizeCodingPathChain(config, relative);
|
|
774
755
|
await authorizeCodingTool(config, { operation: "list", path: relative });
|
|
775
756
|
const listing = await listContainedDirectory(root, relative, limits.maxListEntries, (candidate) => isCodingPathAuthorized(config, candidate)).catch((error) => {
|
|
776
|
-
if (error
|
|
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") {
|
|
757
|
+
if (errnoOf(error) === "ENOENT") {
|
|
782
758
|
codingPathRefusal("NOT_FOUND", "This directory does not exist", relative, {
|
|
783
759
|
hint: "List a parent directory to see what is there."
|
|
784
760
|
});
|
|
@@ -794,7 +770,7 @@ function createListingCodingTools(config, limits) {
|
|
|
794
770
|
truncated: listing.truncated,
|
|
795
771
|
...listing.denied.length > 0 && {
|
|
796
772
|
denied: listing.denied.map((entry) => ({
|
|
797
|
-
path: relative === "." ? entry.name :
|
|
773
|
+
path: relative === "." ? entry.name : path2.join(relative, entry.name),
|
|
798
774
|
kind: entry.kind
|
|
799
775
|
})),
|
|
800
776
|
deniedTruncated: listing.deniedTruncated
|
|
@@ -832,10 +808,10 @@ function createListingCodingTools(config, limits) {
|
|
|
832
808
|
maxDepth: limits.maxSearchDepth,
|
|
833
809
|
maxFiles: limits.maxSearchFiles,
|
|
834
810
|
symlinks: "skip",
|
|
835
|
-
excludeDirectory: (directory) => directory.split(
|
|
811
|
+
excludeDirectory: (directory) => directory.split(path2.sep).some((segment) => excluded.has(segment)),
|
|
836
812
|
authorizePath: (candidate) => isCodingPathAuthorized(config, candidate)
|
|
837
813
|
});
|
|
838
|
-
const prefix = relative === "." ? "" : `${relative}${
|
|
814
|
+
const prefix = relative === "." ? "" : `${relative}${path2.sep}`;
|
|
839
815
|
const matched = scan.files.filter((file) => file.relative.startsWith(prefix)).map((file) => file.relative).filter((candidate) => matcher.test(candidate.slice(prefix.length))).sort();
|
|
840
816
|
const paths = matched.slice(0, limits.maxSearchResults);
|
|
841
817
|
const scopedDenied = scan.denied.filter((entry) => entry.relative.startsWith(prefix));
|
|
@@ -862,7 +838,7 @@ function createListingCodingTools(config, limits) {
|
|
|
862
838
|
// src/agent-runtime/coding-tool-search-patch.ts
|
|
863
839
|
import { createHash as createHash2 } from "node:crypto";
|
|
864
840
|
import { realpath as realpath4 } from "node:fs/promises";
|
|
865
|
-
import
|
|
841
|
+
import path3 from "node:path";
|
|
866
842
|
import { z as z4 } from "zod";
|
|
867
843
|
var SearchInputSchema = z4.object({
|
|
868
844
|
query: z4.string().min(1),
|
|
@@ -943,7 +919,7 @@ async function searchFiles(config, limits, input) {
|
|
|
943
919
|
readMaxBytes: limits.maxReadBytes,
|
|
944
920
|
skipUnreadable: true
|
|
945
921
|
},
|
|
946
|
-
excludeDirectory: (relative) => relative.split(
|
|
922
|
+
excludeDirectory: (relative) => relative.split(path3.sep).some((segment) => excluded.has(segment)),
|
|
947
923
|
includeFile: (candidate) => {
|
|
948
924
|
if (included && !included.test(candidate)) {
|
|
949
925
|
rejectedByInclude += 1;
|
|
@@ -1019,8 +995,12 @@ async function editFile(config, limits, input) {
|
|
|
1019
995
|
const parent = await openContainedParent(root, relative).catch((error) => refuseMissingCodingPath(error, relative));
|
|
1020
996
|
try {
|
|
1021
997
|
return await withCodingPathLock(`${root}:${relative}`, async () => {
|
|
1022
|
-
const
|
|
1023
|
-
|
|
998
|
+
const readCurrent = async () => {
|
|
999
|
+
const handle = await openContainedParentFile(parent).catch((error) => refuseMissingCodingPath(error, relative));
|
|
1000
|
+
return readContainedUtf8Handle(handle, limits.maxWriteBytes).finally(() => handle.close());
|
|
1001
|
+
};
|
|
1002
|
+
await authorizeCodingTool(config, { operation: "read", path: relative });
|
|
1003
|
+
const read = await readCurrent();
|
|
1024
1004
|
const source = read.text;
|
|
1025
1005
|
const baseSha256 = sha256(source);
|
|
1026
1006
|
if (input.expectedSha256 !== undefined && baseSha256 !== input.expectedSha256) {
|
|
@@ -1064,14 +1044,20 @@ async function editFile(config, limits, input) {
|
|
|
1064
1044
|
replacements,
|
|
1065
1045
|
dryRun: input.dryRun
|
|
1066
1046
|
});
|
|
1067
|
-
await assertContainedParentCurrent(root, relative, parent.handle);
|
|
1047
|
+
await assertContainedParentCurrent(root, relative, parent.handle).catch((error) => refuseWriteConflict(error, relative));
|
|
1068
1048
|
if (!input.dryRun) {
|
|
1049
|
+
if (sha256((await readCurrent()).text) !== baseSha256) {
|
|
1050
|
+
conflict2("The file changed since it was read", {
|
|
1051
|
+
message: "The file changed since it was read",
|
|
1052
|
+
path: relative
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1069
1055
|
await writeContainedFile({
|
|
1070
1056
|
parent,
|
|
1071
1057
|
content: changed,
|
|
1072
1058
|
replace: true,
|
|
1073
1059
|
mode: read.mode
|
|
1074
|
-
});
|
|
1060
|
+
}).catch((error) => refuseWriteConflict(error, relative));
|
|
1075
1061
|
}
|
|
1076
1062
|
return {
|
|
1077
1063
|
path: relative,
|
|
@@ -1383,10 +1369,10 @@ var AGENT_CODING_TOOL_NAMES = {
|
|
|
1383
1369
|
writeFile: "write_file"
|
|
1384
1370
|
};
|
|
1385
1371
|
function createAgentCodingTools2(config) {
|
|
1386
|
-
if (!
|
|
1372
|
+
if (!path4.isAbsolute(config.root))
|
|
1387
1373
|
throw new Error("Coding tool root must be absolute");
|
|
1388
1374
|
for (const executable of Object.values(config.executables ?? {})) {
|
|
1389
|
-
if (!
|
|
1375
|
+
if (!path4.isAbsolute(executable)) {
|
|
1390
1376
|
throw new Error("Coding tool executables must be absolute paths");
|
|
1391
1377
|
}
|
|
1392
1378
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadDarwinBinding
|
|
3
3
|
} from "./index-2kbysk9s.js";
|
|
4
|
+
import {
|
|
5
|
+
errnoOf
|
|
6
|
+
} from "./index-jj9228tt.js";
|
|
4
7
|
import {
|
|
5
8
|
isRecord
|
|
6
9
|
} from "./index-9jfdm5tg.js";
|
|
@@ -126,7 +129,7 @@ async function observeProcessInstanceAt(pid, procRoot) {
|
|
|
126
129
|
readlink(`${procRoot}/self/ns/pid`),
|
|
127
130
|
readFile2(`${procRoot}/self/status`, "utf8"),
|
|
128
131
|
readlink(`${procRoot}/self/ns/time`).catch((error) => {
|
|
129
|
-
if (error
|
|
132
|
+
if (errnoOf(error) === "ENOENT")
|
|
130
133
|
return "";
|
|
131
134
|
throw error;
|
|
132
135
|
}),
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadDarwinBinding
|
|
3
|
+
} from "./index-2kbysk9s.js";
|
|
4
|
+
import {
|
|
5
|
+
descriptorPath,
|
|
6
|
+
NumericFileHandle
|
|
7
|
+
} from "./index-arjmb6de.js";
|
|
8
|
+
import {
|
|
9
|
+
stagingName
|
|
10
|
+
} from "./index-tt30h7mr.js";
|
|
11
|
+
|
|
12
|
+
// src/internal/contained-write.ts
|
|
13
|
+
import { constants, fchmod, open as openDescriptor, write as writeDescriptor } from "node:fs";
|
|
14
|
+
import { rename, unlink } from "node:fs/promises";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
function entryPath(directory, name) {
|
|
17
|
+
return path.join(descriptorPath(directory), name);
|
|
18
|
+
}
|
|
19
|
+
async function openExclusive(directory, name, mode) {
|
|
20
|
+
if (process.platform === "darwin") {
|
|
21
|
+
return loadDarwinBinding().createFileAt(directory.fd, name, mode);
|
|
22
|
+
}
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
openDescriptor(entryPath(directory, name), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, mode, (error, descriptor) => error ? reject(error) : resolve(descriptor));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async function renameEntry(directory, source, target) {
|
|
28
|
+
if (process.platform === "darwin") {
|
|
29
|
+
loadDarwinBinding().renameAt(directory.fd, source, target);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
await rename(entryPath(directory, source), entryPath(directory, target));
|
|
33
|
+
}
|
|
34
|
+
async function discardEntry(directory, name) {
|
|
35
|
+
try {
|
|
36
|
+
if (process.platform === "darwin")
|
|
37
|
+
loadDarwinBinding().unlinkAt(directory.fd, name);
|
|
38
|
+
else
|
|
39
|
+
await unlink(entryPath(directory, name));
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
42
|
+
async function writeDescriptorFully(descriptor, content) {
|
|
43
|
+
const bytes = typeof content === "string" ? Buffer.from(content) : content;
|
|
44
|
+
let offset = 0;
|
|
45
|
+
while (offset < bytes.byteLength) {
|
|
46
|
+
const written = await new Promise((resolve, reject) => {
|
|
47
|
+
writeDescriptor(descriptor, bytes, offset, bytes.byteLength - offset, null, (error, bytesWritten) => error ? reject(error) : resolve(bytesWritten));
|
|
48
|
+
});
|
|
49
|
+
if (written === 0)
|
|
50
|
+
throw new Error("Contained file write made no progress");
|
|
51
|
+
offset += written;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function applyMode(file, mode) {
|
|
55
|
+
if (((await file.stat()).mode & 511) === mode)
|
|
56
|
+
return;
|
|
57
|
+
await new Promise((resolve, reject) => {
|
|
58
|
+
fchmod(file.fd, mode, (error) => error ? reject(error) : resolve());
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async function createFile(directory, name, content, mode) {
|
|
62
|
+
const descriptor = await openExclusive(directory, name, mode ?? 438);
|
|
63
|
+
const file = new NumericFileHandle(descriptor);
|
|
64
|
+
let failed;
|
|
65
|
+
try {
|
|
66
|
+
await writeDescriptorFully(descriptor, content);
|
|
67
|
+
if (mode !== undefined)
|
|
68
|
+
await applyMode(file, mode);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
failed = error;
|
|
71
|
+
} finally {
|
|
72
|
+
try {
|
|
73
|
+
await file.close();
|
|
74
|
+
} catch (error) {
|
|
75
|
+
failed ??= error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (failed) {
|
|
79
|
+
await discardEntry(directory, name);
|
|
80
|
+
throw failed;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function writeContainedFile(input) {
|
|
84
|
+
const { handle, basename } = input.parent;
|
|
85
|
+
const mode = input.mode === undefined ? undefined : input.mode & 511;
|
|
86
|
+
if (!input.replace) {
|
|
87
|
+
await createFile(handle, basename, input.content, mode);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const temporary = stagingName();
|
|
91
|
+
await createFile(handle, temporary, input.content, mode);
|
|
92
|
+
try {
|
|
93
|
+
await renameEntry(handle, temporary, basename);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
await discardEntry(handle, temporary);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { writeContainedFile };
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
errnoOf
|
|
3
|
+
} from "./index-jj9228tt.js";
|
|
1
4
|
import {
|
|
2
5
|
assertPositiveSafeInteger
|
|
3
6
|
} from "./index-0s4xebbg.js";
|
|
@@ -21,7 +24,7 @@ function isAtomicStagingName2(name) {
|
|
|
21
24
|
return NAME.test(name);
|
|
22
25
|
}
|
|
23
26
|
function isMissing(error) {
|
|
24
|
-
return
|
|
27
|
+
return errnoOf(error) === "ENOENT";
|
|
25
28
|
}
|
|
26
29
|
async function sweepAtomicStaging2(options) {
|
|
27
30
|
const { directory, olderThanMs, signal } = options;
|