@odla-ai/harness 0.11.11 → 0.11.12

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.
@@ -543,9 +543,11 @@ export {
543
543
  buildContainerRunArgs,
544
544
  runContainerAttempt,
545
545
  SKIP_WORKSPACE_DIRS,
546
+ SECRET_WORKSPACE_FILE,
547
+ allowedWorkspacePath,
546
548
  materializeGitTree,
547
549
  stageWorkspace,
548
550
  stageWorkspacePair,
549
551
  safeWorkspaceLabel
550
552
  };
551
- //# sourceMappingURL=chunk-ZM6AITC2.js.map
553
+ //# sourceMappingURL=chunk-3ON6UAOV.js.map
@@ -2,12 +2,13 @@ import {
2
2
  observedBroker
3
3
  } from "./chunk-INL642J5.js";
4
4
  import {
5
+ SECRET_WORKSPACE_FILE,
5
6
  SKIP_WORKSPACE_DIRS,
6
7
  assertPinnedImage,
7
8
  stageWorkspace,
8
9
  stageWorkspacePair,
9
10
  verifyContainerEngineBoundary
10
- } from "./chunk-ZM6AITC2.js";
11
+ } from "./chunk-3ON6UAOV.js";
11
12
  import {
12
13
  HARNESS_PROTOCOL_VERSION
13
14
  } from "./chunk-ONYW2VSB.js";
@@ -290,7 +291,7 @@ async function withOverloadRetry(call, wait2, onRetry = () => void 0, retryable
290
291
  }
291
292
 
292
293
  // src/code-runtime-reconciler.ts
293
- var sleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
294
+ var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
294
295
  var POST_ACK_RETRY_TICKS = 40;
295
296
  var CodeRuntimeReconciler = class {
296
297
  constructor(control, engine, onDiagnostic, options = {}) {
@@ -392,12 +393,12 @@ function retryableControlFailure(value) {
392
393
  return failure.status === 408 || failure.status === 425 || failure.status === 429 || failure.status >= 500;
393
394
  }
394
395
  function wait(ms, signal) {
395
- return new Promise((resolve6) => {
396
- if (signal?.aborted) return resolve6();
397
- const timer = setTimeout(resolve6, ms);
396
+ return new Promise((resolve7) => {
397
+ if (signal?.aborted) return resolve7();
398
+ const timer = setTimeout(resolve7, ms);
398
399
  signal?.addEventListener("abort", () => {
399
400
  clearTimeout(timer);
400
- resolve6();
401
+ resolve7();
401
402
  }, { once: true });
402
403
  });
403
404
  }
@@ -827,15 +828,121 @@ function isCheckpointEffectCompleted(checkpoint, effectId, actionDigest) {
827
828
  return true;
828
829
  }
829
830
 
830
- // src/recipe-container.ts
831
+ // src/code-recipe-dependencies.ts
832
+ import { lstat as lstat2, rm, symlink } from "fs/promises";
833
+ import { isAbsolute, join } from "path";
834
+ var RESERVED_MOUNTS = /* @__PURE__ */ new Set(["node_modules", "dist", "coverage"]);
835
+ function assertLentPath(mountAs) {
836
+ const parts = mountAs.split("/");
837
+ if (isAbsolute(mountAs) || mountAs.includes("\\") || parts.some((part) => !part || part === "." || part === "..")) {
838
+ throw new TypeError(`recipe dependencies must mount inside the workspace, not at "${mountAs}"`);
839
+ }
840
+ }
841
+ function assertReservedMount(mountAs) {
842
+ assertLentPath(mountAs);
843
+ if (!RESERVED_MOUNTS.has(mountAs.split("/").at(-1))) {
844
+ throw new TypeError(`recipe dependencies must mount at a reserved name, not "${mountAs}"`);
845
+ }
846
+ }
847
+ function lentDirectories(dependencies) {
848
+ return [{ source: dependencies.source, mountAs: dependencies.mountAs ?? "node_modules" }, ...dependencies.nested ?? []];
849
+ }
850
+ function withRecipeDependencies(executor, dependencies) {
851
+ const lent = lentDirectories(dependencies);
852
+ for (const entry of lent) {
853
+ if (!isAbsolute(entry.source)) {
854
+ throw new TypeError("recipe dependency source must be an absolute path");
855
+ }
856
+ assertReservedMount(entry.mountAs);
857
+ }
858
+ return {
859
+ run: async (input) => {
860
+ const linked = [];
861
+ try {
862
+ for (const entry of lent) {
863
+ const target = join(input.workspaceDir, entry.mountAs);
864
+ if (await lstat2(target).catch(() => null)) continue;
865
+ await symlink(entry.source, target, "dir").then(() => linked.push(target), () => void 0);
866
+ }
867
+ return await executor.run(input);
868
+ } finally {
869
+ for (const target of linked) await rm(target, { force: true, recursive: false }).catch(() => void 0);
870
+ }
871
+ }
872
+ };
873
+ }
874
+ async function installedDependencies(repoRoot) {
875
+ const source = join(repoRoot, "node_modules");
876
+ const info = await lstat2(source).catch(() => null);
877
+ return info?.isDirectory() ? { source } : null;
878
+ }
879
+
880
+ // src/recipe-container-lending.ts
831
881
  import { spawn as spawn2 } from "child_process";
882
+ import { mkdir, rm as rm2, stat } from "fs/promises";
883
+ import { dirname, join as join2, resolve as resolve3, sep as sep2 } from "path";
884
+ var RUN_ID = /^[A-Za-z0-9_.-]{1,64}$/;
885
+ function copy(args) {
886
+ return new Promise((accept, reject) => {
887
+ const child = spawn2("cp", args, { shell: false, stdio: "ignore" });
888
+ child.once("error", reject);
889
+ child.once("exit", (code) => accept(code ?? 1));
890
+ });
891
+ }
892
+ async function cloneTree(source, target, platform = process.platform) {
893
+ await mkdir(dirname(target), { recursive: true });
894
+ const fast = platform === "darwin" ? ["-Rc", source, target] : platform === "linux" ? ["-R", "--reflink=auto", source, target] : null;
895
+ if (fast && await copy(fast) === 0) return;
896
+ await rm2(target, { recursive: true, force: true });
897
+ if (await copy(["-R", source, target]) !== 0) throw new Error(`could not clone ${source}`);
898
+ }
899
+ async function lendDependencies(dependencies, runId) {
900
+ if (!dependencies?.runsDir) return { dependencies, release: async () => void 0 };
901
+ if (!RUN_ID.test(runId)) throw new TypeError("run id is not a safe directory name");
902
+ const treeRoot = dirname(dependencies.source);
903
+ for (const entry of lentDirectories(dependencies)) {
904
+ if (entry.source !== join2(treeRoot, entry.mountAs)) {
905
+ throw new TypeError("every directory of a cloned set must lie under its tree root at its mount path");
906
+ }
907
+ }
908
+ const runDir = join2(dependencies.runsDir, runId);
909
+ await cloneTree(treeRoot, runDir);
910
+ const rebase = (entry) => ({ source: join2(runDir, entry.mountAs), mountAs: entry.mountAs });
911
+ return {
912
+ dependencies: {
913
+ ...dependencies,
914
+ source: join2(runDir, dependencies.mountAs ?? "node_modules"),
915
+ nested: (dependencies.nested ?? []).map(rebase),
916
+ writable: true
917
+ },
918
+ release: () => rm2(runDir, { recursive: true, force: true })
919
+ };
920
+ }
921
+ async function lendBuildProducts(products, workspaceDir) {
922
+ const root = resolve3(workspaceDir);
923
+ const lent = [];
924
+ for (const product of products) {
925
+ assertLentPath(product.mountAs);
926
+ if (SECRET_WORKSPACE_FILE.test(product.mountAs.split("/").at(-1))) throw new TypeError("a secret is never a build product");
927
+ const target = resolve3(root, product.mountAs);
928
+ if (!target.startsWith(`${root}${sep2}`)) throw new TypeError("build product escapes the workspace");
929
+ if (await stat(target).catch(() => null)) continue;
930
+ if (!await stat(join2(root, product.within ?? dirname(product.mountAs))).catch(() => null)) continue;
931
+ await cloneTree(product.source, target);
932
+ lent.push(product.mountAs);
933
+ }
934
+ return lent;
935
+ }
936
+
937
+ // src/recipe-container.ts
938
+ import { spawn as spawn3 } from "child_process";
832
939
  import { getgid, getuid } from "process";
833
940
  import { randomUUID } from "crypto";
834
941
  var ARTIFACT_PATH = /^[A-Za-z0-9_@+.,-]+(?:\/[A-Za-z0-9_@+.,-]+)*$/;
835
942
  var PRIVATE_ARTIFACT_PART = /^(?:\.git|\.odla|\.wrangler|\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json)$/i;
836
943
  function buildRecipeContainerArgs(engine, workspaceDir, recipe2, name = `odla-recipe-${randomUUID().slice(0, 12)}`, dependencies = null) {
837
944
  assertCodeBuildRecipe(recipe2);
838
- const mounts = dependencies ? [dependencyMount(engine, dependencies)] : [];
945
+ const mounts = dependencies ? dependencyMounts(engine, dependencies) : [];
839
946
  if (/[,\r\n]/.test(workspaceDir)) throw new TypeError("workspace path contains unsupported mount characters");
840
947
  const uid = typeof getuid === "function" ? getuid() : 1e3;
841
948
  const gid = typeof getgid === "function" ? getgid() : 1e3;
@@ -861,6 +968,7 @@ function buildRecipeContainerArgs(engine, workspaceDir, recipe2, name = `odla-re
861
968
  ...mounts,
862
969
  "--workdir=/workspace",
863
970
  "--env=CI=1",
971
+ "--env=HOME=/tmp",
864
972
  recipe2.image,
865
973
  ...recipe2.command
866
974
  ];
@@ -883,26 +991,34 @@ function buildRecipeContainerArgs(engine, workspaceDir, recipe2, name = `odla-re
883
991
  ...mounts,
884
992
  "--workdir=/workspace",
885
993
  "--env=CI=1",
994
+ "--env=HOME=/tmp",
886
995
  recipe2.image,
887
996
  ...recipe2.command
888
997
  ];
889
998
  }
890
- var LENDABLE = /* @__PURE__ */ new Set(["node_modules", "dist", "coverage"]);
891
- function dependencyMount(engine, dependencies) {
892
- const mountAs = dependencies.mountAs ?? "node_modules";
893
- if (!dependencies.source.startsWith("/") || /[,\r\n]/.test(dependencies.source)) {
894
- throw new TypeError("recipe dependency source must be an absolute path without mount separators");
895
- }
896
- if (!LENDABLE.has(mountAs)) throw new TypeError(`recipe dependencies must mount at a reserved name, not "${mountAs}"`);
897
- return engine === "container" ? `--mount=type=bind,source=${dependencies.source},target=/workspace/${mountAs},readonly` : `--mount=type=bind,src=${dependencies.source},dst=/workspace/${mountAs},readonly`;
999
+ function dependencyMounts(engine, dependencies) {
1000
+ const readonly = dependencies.writable ? "" : ",readonly";
1001
+ return lentDirectories(dependencies).map(({ source, mountAs }) => {
1002
+ if (!source.startsWith("/") || /[,\r\n]/.test(source)) {
1003
+ throw new TypeError("recipe dependency source must be an absolute path without mount separators");
1004
+ }
1005
+ assertReservedMount(mountAs);
1006
+ return engine === "container" ? `--mount=type=bind,source=${source},target=/workspace/${mountAs}${readonly}` : `--mount=type=bind,src=${source},dst=/workspace/${mountAs}${readonly}`;
1007
+ });
898
1008
  }
899
1009
  function createContainerRecipeExecutor(engine, options = {}) {
900
1010
  return {
901
1011
  async run(input) {
902
1012
  await verifyContainerEngineBoundary(engine);
903
1013
  const name = `odla-recipe-${randomUUID().slice(0, 12)}`;
904
- const args = buildRecipeContainerArgs(engine, input.workspaceDir, input.recipe, name, options.dependencies ?? null);
905
- return execute(engine, args, name, input.recipe, input.signal);
1014
+ const lent = await lendDependencies(options.dependencies ?? null, name);
1015
+ try {
1016
+ if (lent.dependencies?.products?.length) await lendBuildProducts(lent.dependencies.products, input.workspaceDir);
1017
+ const args = buildRecipeContainerArgs(engine, input.workspaceDir, input.recipe, name, lent.dependencies);
1018
+ return await execute(engine, args, name, input.recipe, input.signal);
1019
+ } finally {
1020
+ await lent.release();
1021
+ }
906
1022
  }
907
1023
  };
908
1024
  }
@@ -927,7 +1043,7 @@ function execute(engine, args, name, recipe2, signal) {
927
1043
  function runContainerCommand(engine, args, name, recipe2, signal) {
928
1044
  return new Promise((accept, reject) => {
929
1045
  const started = Date.now();
930
- const child = spawn2(engine, args, { shell: false, stdio: ["ignore", "pipe", "pipe"] });
1046
+ const child = spawn3(engine, args, { shell: false, stdio: ["ignore", "pipe", "pipe"] });
931
1047
  const stdout = [];
932
1048
  const stderr = [];
933
1049
  let bytes = 0;
@@ -940,7 +1056,7 @@ function runContainerCommand(engine, args, name, recipe2, signal) {
940
1056
  timedOut = reason === "timeout";
941
1057
  outputLimitExceeded = reason === "output";
942
1058
  const remove = engine === "container" ? ["delete", "--force", name] : ["rm", "-f", name];
943
- const killer = spawn2(engine, remove, { shell: false, stdio: "ignore" });
1059
+ const killer = spawn3(engine, remove, { shell: false, stdio: "ignore" });
944
1060
  killer.unref();
945
1061
  child.kill("SIGTERM");
946
1062
  };
@@ -978,8 +1094,8 @@ function runContainerCommand(engine, args, name, recipe2, signal) {
978
1094
  // src/code-verifier.ts
979
1095
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
980
1096
  import { createReadStream } from "fs";
981
- import { lstat as lstat2 } from "fs/promises";
982
- import { join } from "path";
1097
+ import { lstat as lstat3 } from "fs/promises";
1098
+ import { join as join3 } from "path";
983
1099
  import {
984
1100
  digestCodeVerificationReceipt
985
1101
  } from "@odla-ai/camel/code";
@@ -1091,8 +1207,8 @@ async function inspectArtifacts(workspaceDir, recipe2) {
1091
1207
  const receipts = [];
1092
1208
  for (const artifact of recipe2.expectedArtifacts ?? []) {
1093
1209
  try {
1094
- const path = join(workspaceDir, artifact.path);
1095
- const info = await lstat2(path);
1210
+ const path = join3(workspaceDir, artifact.path);
1211
+ const info = await lstat3(path);
1096
1212
  if (!info.isFile() || info.isSymbolicLink()) {
1097
1213
  receipts.push({ artifactId: artifact.id, status: "invalid", bytes: null, digest: null });
1098
1214
  } else if (info.size > artifact.maximumBytes) {
@@ -1316,9 +1432,9 @@ var CodeRuntimeCheckpointManager = class {
1316
1432
 
1317
1433
  // src/code-runtime-archive.ts
1318
1434
  import { gunzipSync } from "zlib";
1319
- import { mkdir, mkdtemp, rm, writeFile } from "fs/promises";
1435
+ import { mkdir as mkdir2, mkdtemp, rm as rm3, writeFile } from "fs/promises";
1320
1436
  import { tmpdir } from "os";
1321
- import { dirname, join as join2, resolve as resolve3, sep as sep2 } from "path";
1437
+ import { dirname as dirname2, join as join4, resolve as resolve4, sep as sep3 } from "path";
1322
1438
  var RESERVED2 = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
1323
1439
  var SECRET2 = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
1324
1440
  var MAX_NUL_SHARE = 0.1;
@@ -1336,9 +1452,9 @@ async function materializeCodeRuntimeArchive(archive, visiblePaths, tempRoot = t
1336
1452
  throw new TypeError("Code source archive exceeds its decompressed byte bound");
1337
1453
  }
1338
1454
  const entries = parseTar(bytes, archive.limits);
1339
- const root = await mkdtemp(join2(tempRoot, "odla-code-archive-"));
1340
- const sourceDir = join2(root, "source");
1341
- await mkdir(sourceDir);
1455
+ const root = await mkdtemp(join4(tempRoot, "odla-code-archive-"));
1456
+ const sourceDir = join4(root, "source");
1457
+ await mkdir2(sourceDir);
1342
1458
  let visible = 0;
1343
1459
  try {
1344
1460
  for (const entry of entries) {
@@ -1351,16 +1467,16 @@ async function materializeCodeRuntimeArchive(archive, visiblePaths, tempRoot = t
1351
1467
  continue;
1352
1468
  }
1353
1469
  if (nulShare(content) > MAX_NUL_SHARE) continue;
1354
- const target = resolve3(sourceDir, entry.path);
1355
- if (!target.startsWith(`${resolve3(sourceDir)}${sep2}`)) throw new TypeError("Code source path escapes its root");
1356
- await mkdir(dirname(target), { recursive: true });
1470
+ const target = resolve4(sourceDir, entry.path);
1471
+ if (!target.startsWith(`${resolve4(sourceDir)}${sep3}`)) throw new TypeError("Code source path escapes its root");
1472
+ await mkdir2(dirname2(target), { recursive: true });
1357
1473
  await writeFile(target, content, { flag: "wx", mode: 420 });
1358
1474
  visible += 1;
1359
1475
  }
1360
1476
  if (!visible && !visiblePaths) throw new TypeError("GitHub commit has no Code-visible text source");
1361
- return { sourceDir, cleanup: () => rm(root, { recursive: true, force: true }) };
1477
+ return { sourceDir, cleanup: () => rm3(root, { recursive: true, force: true }) };
1362
1478
  } catch (cause) {
1363
- await rm(root, { recursive: true, force: true });
1479
+ await rm3(root, { recursive: true, force: true });
1364
1480
  throw cause;
1365
1481
  }
1366
1482
  }
@@ -1663,13 +1779,13 @@ async function prepareRuntimeLocalSource(input) {
1663
1779
  }
1664
1780
 
1665
1781
  // src/code-runtime-source.ts
1666
- import { mkdir as mkdir3, mkdtemp as mkdtemp2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
1782
+ import { mkdir as mkdir4, mkdtemp as mkdtemp2, rm as rm4, writeFile as writeFile2 } from "fs/promises";
1667
1783
  import { tmpdir as tmpdir2 } from "os";
1668
- import { dirname as dirname3, join as join4, resolve as resolve4, sep as sep3 } from "path";
1784
+ import { dirname as dirname4, join as join6, resolve as resolve5, sep as sep4 } from "path";
1669
1785
 
1670
1786
  // src/code-runtime-selected-source.ts
1671
- import { chmod, cp, mkdir as mkdir2, readdir as readdir2 } from "fs/promises";
1672
- import { dirname as dirname2, join as join3 } from "path";
1787
+ import { chmod, cp, mkdir as mkdir3, readdir as readdir2 } from "fs/promises";
1788
+ import { dirname as dirname3, join as join5 } from "path";
1673
1789
  function selectedSourceSet(payload) {
1674
1790
  if (!payload.sourceSet) return null;
1675
1791
  const set = payload.sourceSet && typeof payload.sourceSet === "object" && !Array.isArray(payload.sourceSet) ? payload.sourceSet : null;
@@ -1706,8 +1822,8 @@ async function attachReferenceDirectories(workspace, references) {
1706
1822
  for (const reference of references) {
1707
1823
  validateAlias(reference.alias);
1708
1824
  for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
1709
- const target = join3(root, ".odla-references", reference.alias);
1710
- await mkdir2(dirname2(target), { recursive: true });
1825
+ const target = join5(root, ".odla-references", reference.alias);
1826
+ await mkdir3(dirname3(target), { recursive: true });
1711
1827
  await cp(reference.sourceDir, target, { recursive: true, errorOnExist: true, force: false });
1712
1828
  await makeTreeReadOnly(target);
1713
1829
  }
@@ -1720,7 +1836,7 @@ function validateAlias(alias) {
1720
1836
  }
1721
1837
  async function makeTreeReadOnly(root) {
1722
1838
  for (const entry of await readdir2(root, { withFileTypes: true })) {
1723
- const target = join3(root, entry.name);
1839
+ const target = join5(root, entry.name);
1724
1840
  if (entry.isDirectory()) await makeTreeReadOnly(target);
1725
1841
  else if (entry.isFile()) await chmod(target, 292);
1726
1842
  }
@@ -1734,9 +1850,9 @@ var SOURCE_MAX_BYTES = 80 * 1024 * 1024;
1734
1850
  var SOURCE_SET_MAX_BYTES = 480 * 1024 * 1024;
1735
1851
  async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir2()) {
1736
1852
  if (!snapshot.files.length || snapshot.files.length > SOURCE_MAX_FILES) throw new TypeError("Code source file count is invalid");
1737
- const root = await mkdtemp2(join4(tempRoot, "odla-code-source-"));
1738
- const sourceDir = join4(root, "source");
1739
- await mkdir3(sourceDir);
1853
+ const root = await mkdtemp2(join6(tempRoot, "odla-code-source-"));
1854
+ const sourceDir = join6(root, "source");
1855
+ await mkdir4(sourceDir);
1740
1856
  const seen = /* @__PURE__ */ new Set();
1741
1857
  let bytes = 0;
1742
1858
  try {
@@ -1746,9 +1862,9 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir2()) {
1746
1862
  seen.add(file.path);
1747
1863
  bytes += Buffer.byteLength(file.path) + Buffer.byteLength(file.content);
1748
1864
  if (bytes > SOURCE_MAX_BYTES) throw new TypeError("Code source exceeds its byte bound");
1749
- const target = resolve4(sourceDir, file.path);
1750
- if (!target.startsWith(`${resolve4(sourceDir)}${sep3}`)) throw new TypeError("Code source path escapes its root");
1751
- await mkdir3(dirname3(target), { recursive: true });
1865
+ const target = resolve5(sourceDir, file.path);
1866
+ if (!target.startsWith(`${resolve5(sourceDir)}${sep4}`)) throw new TypeError("Code source path escapes its root");
1867
+ await mkdir4(dirname4(target), { recursive: true });
1752
1868
  await writeFile2(target, file.content, { flag: "wx", mode: 420 });
1753
1869
  }
1754
1870
  for (const reference of snapshot.references ?? []) {
@@ -1761,15 +1877,15 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir2()) {
1761
1877
  seen.add(path);
1762
1878
  bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
1763
1879
  if (bytes > SOURCE_SET_MAX_BYTES) throw new TypeError("Code source set exceeds its byte bound");
1764
- const target = resolve4(sourceDir, path);
1765
- if (!target.startsWith(`${resolve4(sourceDir)}${sep3}`)) throw new TypeError("Code reference path escapes its root");
1766
- await mkdir3(dirname3(target), { recursive: true });
1880
+ const target = resolve5(sourceDir, path);
1881
+ if (!target.startsWith(`${resolve5(sourceDir)}${sep4}`)) throw new TypeError("Code reference path escapes its root");
1882
+ await mkdir4(dirname4(target), { recursive: true });
1767
1883
  await writeFile2(target, file.content, { flag: "wx", mode: 292 });
1768
1884
  }
1769
1885
  }
1770
- return { sourceDir, cleanup: () => rm2(root, { recursive: true, force: true }) };
1886
+ return { sourceDir, cleanup: () => rm4(root, { recursive: true, force: true }) };
1771
1887
  } catch (cause) {
1772
- await rm2(root, { recursive: true, force: true });
1888
+ await rm4(root, { recursive: true, force: true });
1773
1889
  throw cause;
1774
1890
  }
1775
1891
  }
@@ -1788,9 +1904,9 @@ async function attachCodeRuntimeReferences(workspace, references) {
1788
1904
  bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
1789
1905
  if (bytes > SOURCE_SET_MAX_BYTES - SOURCE_MAX_BYTES) throw new TypeError("Code reference set exceeds its byte bound");
1790
1906
  for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
1791
- const target = resolve4(root, path);
1792
- if (!target.startsWith(`${resolve4(root)}${sep3}`)) throw new TypeError("Code reference path escapes its root");
1793
- await mkdir3(dirname3(target), { recursive: true });
1907
+ const target = resolve5(root, path);
1908
+ if (!target.startsWith(`${resolve5(root)}${sep4}`)) throw new TypeError("Code reference path escapes its root");
1909
+ await mkdir4(dirname4(target), { recursive: true });
1794
1910
  await writeFile2(target, file.content, { flag: "wx", mode: 292 });
1795
1911
  }
1796
1912
  }
@@ -2236,7 +2352,7 @@ Finish with a concise, non-empty answer to the owner. Do not call tools or promi
2236
2352
  }
2237
2353
 
2238
2354
  // src/code-runtime-session-skills.ts
2239
- var sleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
2355
+ var sleep2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
2240
2356
  function createCodeRuntimeSessionSkillLoader(control, options = {}) {
2241
2357
  const wait2 = options.wait ?? sleep2;
2242
2358
  const load = control.collaborationSkills?.bind(control);
@@ -2295,7 +2411,7 @@ var inferWithBackoff = (infer, wait2, onRetry) => withOverloadRetry(infer, wait2
2295
2411
  async function handleCodeRuntimeInference(input) {
2296
2412
  const { command, request, state } = input;
2297
2413
  const startedAt = Date.now();
2298
- const wait2 = input.wait ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
2414
+ const wait2 = input.wait ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
2299
2415
  const response2 = await inferWithBackoff(
2300
2416
  () => input.control.infer(command.sessionId, {
2301
2417
  requestId: request.requestId,
@@ -2363,9 +2479,9 @@ function createCodeRuntimeInference(options) {
2363
2479
  }
2364
2480
 
2365
2481
  // src/code-tool-discovery.ts
2366
- import { spawn as spawn3 } from "child_process";
2482
+ import { spawn as spawn4 } from "child_process";
2367
2483
  import { readFile as readFile2, readdir as readdir3 } from "fs/promises";
2368
- import { relative as relative2, resolve as resolve5 } from "path";
2484
+ import { relative as relative2, resolve as resolve6 } from "path";
2369
2485
  var DEFAULT_MAX_FILES = 2e4;
2370
2486
  var DEFAULT_MAX_RESULTS = 100;
2371
2487
  var DEFAULT_MAX_FILE_BYTES = 512 * 1024;
@@ -2393,7 +2509,7 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
2393
2509
  for (const entry of await readdir3(directory, { withFileTypes: true })) {
2394
2510
  if (SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
2395
2511
  if (entry.isSymbolicLink()) throw new TypeError("workspace contains a symbolic link");
2396
- const target = resolve5(directory, entry.name);
2512
+ const target = resolve6(directory, entry.name);
2397
2513
  if (entry.isDirectory()) await walk(target);
2398
2514
  else if (entry.isFile()) {
2399
2515
  const path = relative2(root, target).split("\\").join("/");
@@ -2407,7 +2523,7 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
2407
2523
  }
2408
2524
  }
2409
2525
  };
2410
- await walk(resolve5(root));
2526
+ await walk(resolve6(root));
2411
2527
  return paths.sort();
2412
2528
  }
2413
2529
  function listWorkspace(paths, options = {}) {
@@ -2469,7 +2585,7 @@ function nativeSearchBatch(root, paths, options, remaining) {
2469
2585
  options.query,
2470
2586
  ...paths
2471
2587
  ];
2472
- const child = spawn3("rg", args, {
2588
+ const child = spawn4("rg", args, {
2473
2589
  cwd: root,
2474
2590
  stdio: ["ignore", "pipe", "ignore"],
2475
2591
  ...options.signal ? { signal: options.signal } : {}
@@ -2521,7 +2637,7 @@ async function fallbackSearch(root, scoped, options) {
2521
2637
  if (matches.length >= options.maxResults) break;
2522
2638
  let source;
2523
2639
  try {
2524
- source = await readFile2(resolve5(root, path));
2640
+ source = await readFile2(resolve6(root, path));
2525
2641
  } catch {
2526
2642
  continue;
2527
2643
  }
@@ -2825,7 +2941,7 @@ import { readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
2825
2941
 
2826
2942
  // src/code-tool-graph.ts
2827
2943
  import { readFile as readFile3 } from "fs/promises";
2828
- import { join as join5 } from "path";
2944
+ import { join as join7 } from "path";
2829
2945
  import {
2830
2946
  hubs,
2831
2947
  incident,
@@ -2839,7 +2955,7 @@ var cache = /* @__PURE__ */ new Map();
2839
2955
  function workspaceGraphs(workspaceDir, paths) {
2840
2956
  const existing = cache.get(workspaceDir);
2841
2957
  if (existing) return existing;
2842
- const read2 = (path) => readFile3(join5(workspaceDir, path), "utf8");
2958
+ const read2 = (path) => readFile3(join7(workspaceDir, path), "utf8");
2843
2959
  const built = (async () => ({
2844
2960
  // No knownTables: a staged workspace may not carry migrations, and a filter
2845
2961
  // that silently drops every table is worse than an unfiltered one. Callers
@@ -2949,8 +3065,8 @@ async function edit(context, request, options, policy, registry) {
2949
3065
  }
2950
3066
 
2951
3067
  // src/code-tool-write.ts
2952
- import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
2953
- import { dirname as dirname4 } from "path";
3068
+ import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
3069
+ import { dirname as dirname5 } from "path";
2954
3070
  var MAX_WRITE_BYTES = 256 * 1024;
2955
3071
  var lines = (text) => text === "" ? [] : text.replace(/\n$/, "").split("\n");
2956
3072
  function writeAsDiff(path, current, content) {
@@ -2975,7 +3091,7 @@ async function writeCodeFile(workspaceDir, path, content, current) {
2975
3091
  }
2976
3092
  if (content.includes("\0")) throw new TypeError("content contains NUL bytes; use plain text");
2977
3093
  const target = resolveCodePath(workspaceDir, path);
2978
- await mkdir4(dirname4(target), { recursive: true });
3094
+ await mkdir5(dirname5(target), { recursive: true });
2979
3095
  await writeFile4(target, content, "utf8");
2980
3096
  return { created: current === null, deletions: current === null ? 0 : lines(current).length, additions: lines(content).length };
2981
3097
  }
@@ -3003,7 +3119,7 @@ async function write(context, request, options, policy, registry) {
3003
3119
  }
3004
3120
 
3005
3121
  // src/code-tool-reads.ts
3006
- import { readFile as readFile6, stat } from "fs/promises";
3122
+ import { readFile as readFile6, stat as stat2 } from "fs/promises";
3007
3123
  var GRAPH_TOOLS = /* @__PURE__ */ new Set([
3008
3124
  "sandbox.overview",
3009
3125
  "sandbox.where_is",
@@ -3025,7 +3141,7 @@ async function read(context, request, options, policy, registry) {
3025
3141
  const allowed = await policy.read(policyContext(context, request, options, { paths, path, startLine, endLine }));
3026
3142
  if (!allowed) return response(request, false, "tool denied by CaMeL policy");
3027
3143
  const target = resolveCodePath(context.workspaceDir, path);
3028
- const info = await stat(target);
3144
+ const info = await stat2(target);
3029
3145
  if (!info.isFile() || info.size > Math.max(options.maxReadBytes ?? 128 * 1024, 2 * 1024 * 1024)) {
3030
3146
  throw new TypeError("file is not a bounded regular source file");
3031
3147
  }
@@ -3382,7 +3498,7 @@ function assertBudget(budget) {
3382
3498
 
3383
3499
  // src/code-repository-recipes.ts
3384
3500
  import { readFile as readFile7 } from "fs/promises";
3385
- import { join as join6 } from "path";
3501
+ import { join as join8 } from "path";
3386
3502
 
3387
3503
  // src/code-runtime-events.ts
3388
3504
  import { createHash as createHash3 } from "crypto";
@@ -3457,7 +3573,7 @@ function parseRepositoryRecipes(text, envelope) {
3457
3573
  async function readRepositoryRecipes(baselineDir, envelope) {
3458
3574
  let text;
3459
3575
  try {
3460
- text = await readFile7(join6(baselineDir, REPOSITORY_RECIPES_FILE), "utf8");
3576
+ text = await readFile7(join8(baselineDir, REPOSITORY_RECIPES_FILE), "utf8");
3461
3577
  } catch (cause) {
3462
3578
  if (cause.code === "ENOENT") return null;
3463
3579
  throw cause;
@@ -3690,8 +3806,8 @@ async function startGoalPursuit(input) {
3690
3806
  function codeRuntimeAcknowledgementGate(signal) {
3691
3807
  let settle;
3692
3808
  let settled = false;
3693
- const ready = new Promise((resolve6) => {
3694
- settle = resolve6;
3809
+ const ready = new Promise((resolve7) => {
3810
+ settle = resolve7;
3695
3811
  });
3696
3812
  const release = (run) => {
3697
3813
  if (settled) return;
@@ -4062,6 +4178,14 @@ export {
4062
4178
  createCodeWorkspaceCheckpoint,
4063
4179
  restoreCodeWorkspaceCheckpoint,
4064
4180
  isCheckpointEffectCompleted,
4181
+ assertLentPath,
4182
+ assertReservedMount,
4183
+ lentDirectories,
4184
+ withRecipeDependencies,
4185
+ installedDependencies,
4186
+ cloneTree,
4187
+ lendDependencies,
4188
+ lendBuildProducts,
4065
4189
  buildRecipeContainerArgs,
4066
4190
  createContainerRecipeExecutor,
4067
4191
  assertCodeBuildRecipe,
@@ -4103,4 +4227,4 @@ export {
4103
4227
  withProofRecipes,
4104
4228
  TheseusRuntimeEngine
4105
4229
  };
4106
- //# sourceMappingURL=chunk-4IGSN53G.js.map
4230
+ //# sourceMappingURL=chunk-6QILNLBY.js.map