@odla-ai/harness 0.11.10 → 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.
- package/dist/{chunk-ZM6AITC2.js → chunk-3ON6UAOV.js} +3 -1
- package/dist/{chunk-4IGSN53G.js → chunk-6QILNLBY.js} +199 -75
- package/dist/chunk-6QILNLBY.js.map +1 -0
- package/dist/{chunk-GNNAQ2JX.js → chunk-EXSEQEZ6.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/code-runtime-cli.cjs +188 -102
- package/dist/code-runtime-cli.cjs.map +1 -1
- package/dist/code-runtime-cli.js +2 -2
- package/dist/node.cjs +326 -168
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +62 -10
- package/dist/node.d.ts +62 -10
- package/dist/node.js +116 -76
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4IGSN53G.js.map +0 -1
- /package/dist/{chunk-ZM6AITC2.js.map → chunk-3ON6UAOV.js.map} +0 -0
- /package/dist/{chunk-GNNAQ2JX.js.map → chunk-EXSEQEZ6.js.map} +0 -0
|
@@ -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-
|
|
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-
|
|
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((
|
|
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((
|
|
396
|
-
if (signal?.aborted) return
|
|
397
|
-
const timer = setTimeout(
|
|
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
|
-
|
|
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-
|
|
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 ?
|
|
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
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
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
|
|
905
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
1095
|
-
const info = await
|
|
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
|
|
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(
|
|
1340
|
-
const sourceDir =
|
|
1341
|
-
await
|
|
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 =
|
|
1355
|
-
if (!target.startsWith(`${
|
|
1356
|
-
await
|
|
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: () =>
|
|
1477
|
+
return { sourceDir, cleanup: () => rm3(root, { recursive: true, force: true }) };
|
|
1362
1478
|
} catch (cause) {
|
|
1363
|
-
await
|
|
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
|
|
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
|
|
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
|
|
1672
|
-
import { dirname as
|
|
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 =
|
|
1710
|
-
await
|
|
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 =
|
|
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(
|
|
1738
|
-
const sourceDir =
|
|
1739
|
-
await
|
|
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 =
|
|
1750
|
-
if (!target.startsWith(`${
|
|
1751
|
-
await
|
|
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 =
|
|
1765
|
-
if (!target.startsWith(`${
|
|
1766
|
-
await
|
|
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: () =>
|
|
1886
|
+
return { sourceDir, cleanup: () => rm4(root, { recursive: true, force: true }) };
|
|
1771
1887
|
} catch (cause) {
|
|
1772
|
-
await
|
|
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 =
|
|
1792
|
-
if (!target.startsWith(`${
|
|
1793
|
-
await
|
|
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((
|
|
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((
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
2953
|
-
import { dirname as
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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((
|
|
3694
|
-
settle =
|
|
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-
|
|
4230
|
+
//# sourceMappingURL=chunk-6QILNLBY.js.map
|