@odla-ai/harness 0.11.11 → 0.11.13
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-B2PQAORN.js} +206 -77
- package/dist/chunk-B2PQAORN.js.map +1 -0
- package/dist/{chunk-GNNAQ2JX.js → chunk-EXSEQEZ6.js} +2 -2
- package/dist/{chunk-INL642J5.js → chunk-OXWLPB7P.js} +5 -2
- package/dist/{chunk-INL642J5.js.map → chunk-OXWLPB7P.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/code-runtime-cli.cjs +197 -104
- package/dist/code-runtime-cli.cjs.map +1 -1
- package/dist/code-runtime-cli.js +3 -3
- package/dist/index.cjs +4 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/node.cjs +337 -170
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +66 -10
- package/dist/node.d.ts +66 -10
- package/dist/node.js +119 -77
- 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
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
observedBroker
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-OXWLPB7P.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
|
}
|
|
@@ -924,10 +1040,14 @@ function parseMemory(value) {
|
|
|
924
1040
|
function execute(engine, args, name, recipe2, signal) {
|
|
925
1041
|
return runContainerCommand(engine, args, name, { timeoutMs: recipe2.timeoutMs, maxOutputBytes: recipe2.maxOutputBytes }, signal);
|
|
926
1042
|
}
|
|
1043
|
+
var CONTAINER_PROGRESS = /^\[\d+\/\d+\] .*$/gm;
|
|
1044
|
+
function recipeOutput(engine, stderr) {
|
|
1045
|
+
return engine === "container" ? stderr.replace(CONTAINER_PROGRESS, "").replace(/^\n+/, "") : stderr;
|
|
1046
|
+
}
|
|
927
1047
|
function runContainerCommand(engine, args, name, recipe2, signal) {
|
|
928
1048
|
return new Promise((accept, reject) => {
|
|
929
1049
|
const started = Date.now();
|
|
930
|
-
const child =
|
|
1050
|
+
const child = spawn3(engine, args, { shell: false, stdio: ["ignore", "pipe", "pipe"] });
|
|
931
1051
|
const stdout = [];
|
|
932
1052
|
const stderr = [];
|
|
933
1053
|
let bytes = 0;
|
|
@@ -940,7 +1060,7 @@ function runContainerCommand(engine, args, name, recipe2, signal) {
|
|
|
940
1060
|
timedOut = reason === "timeout";
|
|
941
1061
|
outputLimitExceeded = reason === "output";
|
|
942
1062
|
const remove = engine === "container" ? ["delete", "--force", name] : ["rm", "-f", name];
|
|
943
|
-
const killer =
|
|
1063
|
+
const killer = spawn3(engine, remove, { shell: false, stdio: "ignore" });
|
|
944
1064
|
killer.unref();
|
|
945
1065
|
child.kill("SIGTERM");
|
|
946
1066
|
};
|
|
@@ -966,7 +1086,7 @@ function runContainerCommand(engine, args, name, recipe2, signal) {
|
|
|
966
1086
|
accept({
|
|
967
1087
|
exitCode: code ?? 1,
|
|
968
1088
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
969
|
-
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
1089
|
+
stderr: recipeOutput(engine, Buffer.concat(stderr).toString("utf8")),
|
|
970
1090
|
durationMs: Date.now() - started,
|
|
971
1091
|
outputLimitExceeded,
|
|
972
1092
|
timedOut
|
|
@@ -978,8 +1098,8 @@ function runContainerCommand(engine, args, name, recipe2, signal) {
|
|
|
978
1098
|
// src/code-verifier.ts
|
|
979
1099
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
|
|
980
1100
|
import { createReadStream } from "fs";
|
|
981
|
-
import { lstat as
|
|
982
|
-
import { join } from "path";
|
|
1101
|
+
import { lstat as lstat3 } from "fs/promises";
|
|
1102
|
+
import { join as join3 } from "path";
|
|
983
1103
|
import {
|
|
984
1104
|
digestCodeVerificationReceipt
|
|
985
1105
|
} from "@odla-ai/camel/code";
|
|
@@ -1091,8 +1211,8 @@ async function inspectArtifacts(workspaceDir, recipe2) {
|
|
|
1091
1211
|
const receipts = [];
|
|
1092
1212
|
for (const artifact of recipe2.expectedArtifacts ?? []) {
|
|
1093
1213
|
try {
|
|
1094
|
-
const path =
|
|
1095
|
-
const info = await
|
|
1214
|
+
const path = join3(workspaceDir, artifact.path);
|
|
1215
|
+
const info = await lstat3(path);
|
|
1096
1216
|
if (!info.isFile() || info.isSymbolicLink()) {
|
|
1097
1217
|
receipts.push({ artifactId: artifact.id, status: "invalid", bytes: null, digest: null });
|
|
1098
1218
|
} else if (info.size > artifact.maximumBytes) {
|
|
@@ -1316,9 +1436,9 @@ var CodeRuntimeCheckpointManager = class {
|
|
|
1316
1436
|
|
|
1317
1437
|
// src/code-runtime-archive.ts
|
|
1318
1438
|
import { gunzipSync } from "zlib";
|
|
1319
|
-
import { mkdir, mkdtemp, rm, writeFile } from "fs/promises";
|
|
1439
|
+
import { mkdir as mkdir2, mkdtemp, rm as rm3, writeFile } from "fs/promises";
|
|
1320
1440
|
import { tmpdir } from "os";
|
|
1321
|
-
import { dirname, join as
|
|
1441
|
+
import { dirname as dirname2, join as join4, resolve as resolve4, sep as sep3 } from "path";
|
|
1322
1442
|
var RESERVED2 = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
1323
1443
|
var SECRET2 = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
1324
1444
|
var MAX_NUL_SHARE = 0.1;
|
|
@@ -1336,9 +1456,9 @@ async function materializeCodeRuntimeArchive(archive, visiblePaths, tempRoot = t
|
|
|
1336
1456
|
throw new TypeError("Code source archive exceeds its decompressed byte bound");
|
|
1337
1457
|
}
|
|
1338
1458
|
const entries = parseTar(bytes, archive.limits);
|
|
1339
|
-
const root = await mkdtemp(
|
|
1340
|
-
const sourceDir =
|
|
1341
|
-
await
|
|
1459
|
+
const root = await mkdtemp(join4(tempRoot, "odla-code-archive-"));
|
|
1460
|
+
const sourceDir = join4(root, "source");
|
|
1461
|
+
await mkdir2(sourceDir);
|
|
1342
1462
|
let visible = 0;
|
|
1343
1463
|
try {
|
|
1344
1464
|
for (const entry of entries) {
|
|
@@ -1351,16 +1471,16 @@ async function materializeCodeRuntimeArchive(archive, visiblePaths, tempRoot = t
|
|
|
1351
1471
|
continue;
|
|
1352
1472
|
}
|
|
1353
1473
|
if (nulShare(content) > MAX_NUL_SHARE) continue;
|
|
1354
|
-
const target =
|
|
1355
|
-
if (!target.startsWith(`${
|
|
1356
|
-
await
|
|
1474
|
+
const target = resolve4(sourceDir, entry.path);
|
|
1475
|
+
if (!target.startsWith(`${resolve4(sourceDir)}${sep3}`)) throw new TypeError("Code source path escapes its root");
|
|
1476
|
+
await mkdir2(dirname2(target), { recursive: true });
|
|
1357
1477
|
await writeFile(target, content, { flag: "wx", mode: 420 });
|
|
1358
1478
|
visible += 1;
|
|
1359
1479
|
}
|
|
1360
1480
|
if (!visible && !visiblePaths) throw new TypeError("GitHub commit has no Code-visible text source");
|
|
1361
|
-
return { sourceDir, cleanup: () =>
|
|
1481
|
+
return { sourceDir, cleanup: () => rm3(root, { recursive: true, force: true }) };
|
|
1362
1482
|
} catch (cause) {
|
|
1363
|
-
await
|
|
1483
|
+
await rm3(root, { recursive: true, force: true });
|
|
1364
1484
|
throw cause;
|
|
1365
1485
|
}
|
|
1366
1486
|
}
|
|
@@ -1663,13 +1783,13 @@ async function prepareRuntimeLocalSource(input) {
|
|
|
1663
1783
|
}
|
|
1664
1784
|
|
|
1665
1785
|
// src/code-runtime-source.ts
|
|
1666
|
-
import { mkdir as
|
|
1786
|
+
import { mkdir as mkdir4, mkdtemp as mkdtemp2, rm as rm4, writeFile as writeFile2 } from "fs/promises";
|
|
1667
1787
|
import { tmpdir as tmpdir2 } from "os";
|
|
1668
|
-
import { dirname as
|
|
1788
|
+
import { dirname as dirname4, join as join6, resolve as resolve5, sep as sep4 } from "path";
|
|
1669
1789
|
|
|
1670
1790
|
// src/code-runtime-selected-source.ts
|
|
1671
|
-
import { chmod, cp, mkdir as
|
|
1672
|
-
import { dirname as
|
|
1791
|
+
import { chmod, cp, mkdir as mkdir3, readdir as readdir2 } from "fs/promises";
|
|
1792
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
1673
1793
|
function selectedSourceSet(payload) {
|
|
1674
1794
|
if (!payload.sourceSet) return null;
|
|
1675
1795
|
const set = payload.sourceSet && typeof payload.sourceSet === "object" && !Array.isArray(payload.sourceSet) ? payload.sourceSet : null;
|
|
@@ -1706,8 +1826,8 @@ async function attachReferenceDirectories(workspace, references) {
|
|
|
1706
1826
|
for (const reference of references) {
|
|
1707
1827
|
validateAlias(reference.alias);
|
|
1708
1828
|
for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
|
|
1709
|
-
const target =
|
|
1710
|
-
await
|
|
1829
|
+
const target = join5(root, ".odla-references", reference.alias);
|
|
1830
|
+
await mkdir3(dirname3(target), { recursive: true });
|
|
1711
1831
|
await cp(reference.sourceDir, target, { recursive: true, errorOnExist: true, force: false });
|
|
1712
1832
|
await makeTreeReadOnly(target);
|
|
1713
1833
|
}
|
|
@@ -1720,7 +1840,7 @@ function validateAlias(alias) {
|
|
|
1720
1840
|
}
|
|
1721
1841
|
async function makeTreeReadOnly(root) {
|
|
1722
1842
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
1723
|
-
const target =
|
|
1843
|
+
const target = join5(root, entry.name);
|
|
1724
1844
|
if (entry.isDirectory()) await makeTreeReadOnly(target);
|
|
1725
1845
|
else if (entry.isFile()) await chmod(target, 292);
|
|
1726
1846
|
}
|
|
@@ -1734,9 +1854,9 @@ var SOURCE_MAX_BYTES = 80 * 1024 * 1024;
|
|
|
1734
1854
|
var SOURCE_SET_MAX_BYTES = 480 * 1024 * 1024;
|
|
1735
1855
|
async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir2()) {
|
|
1736
1856
|
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
|
|
1857
|
+
const root = await mkdtemp2(join6(tempRoot, "odla-code-source-"));
|
|
1858
|
+
const sourceDir = join6(root, "source");
|
|
1859
|
+
await mkdir4(sourceDir);
|
|
1740
1860
|
const seen = /* @__PURE__ */ new Set();
|
|
1741
1861
|
let bytes = 0;
|
|
1742
1862
|
try {
|
|
@@ -1746,9 +1866,9 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir2()) {
|
|
|
1746
1866
|
seen.add(file.path);
|
|
1747
1867
|
bytes += Buffer.byteLength(file.path) + Buffer.byteLength(file.content);
|
|
1748
1868
|
if (bytes > SOURCE_MAX_BYTES) throw new TypeError("Code source exceeds its byte bound");
|
|
1749
|
-
const target =
|
|
1750
|
-
if (!target.startsWith(`${
|
|
1751
|
-
await
|
|
1869
|
+
const target = resolve5(sourceDir, file.path);
|
|
1870
|
+
if (!target.startsWith(`${resolve5(sourceDir)}${sep4}`)) throw new TypeError("Code source path escapes its root");
|
|
1871
|
+
await mkdir4(dirname4(target), { recursive: true });
|
|
1752
1872
|
await writeFile2(target, file.content, { flag: "wx", mode: 420 });
|
|
1753
1873
|
}
|
|
1754
1874
|
for (const reference of snapshot.references ?? []) {
|
|
@@ -1761,15 +1881,15 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir2()) {
|
|
|
1761
1881
|
seen.add(path);
|
|
1762
1882
|
bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
|
|
1763
1883
|
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
|
|
1884
|
+
const target = resolve5(sourceDir, path);
|
|
1885
|
+
if (!target.startsWith(`${resolve5(sourceDir)}${sep4}`)) throw new TypeError("Code reference path escapes its root");
|
|
1886
|
+
await mkdir4(dirname4(target), { recursive: true });
|
|
1767
1887
|
await writeFile2(target, file.content, { flag: "wx", mode: 292 });
|
|
1768
1888
|
}
|
|
1769
1889
|
}
|
|
1770
|
-
return { sourceDir, cleanup: () =>
|
|
1890
|
+
return { sourceDir, cleanup: () => rm4(root, { recursive: true, force: true }) };
|
|
1771
1891
|
} catch (cause) {
|
|
1772
|
-
await
|
|
1892
|
+
await rm4(root, { recursive: true, force: true });
|
|
1773
1893
|
throw cause;
|
|
1774
1894
|
}
|
|
1775
1895
|
}
|
|
@@ -1788,9 +1908,9 @@ async function attachCodeRuntimeReferences(workspace, references) {
|
|
|
1788
1908
|
bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
|
|
1789
1909
|
if (bytes > SOURCE_SET_MAX_BYTES - SOURCE_MAX_BYTES) throw new TypeError("Code reference set exceeds its byte bound");
|
|
1790
1910
|
for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
|
|
1791
|
-
const target =
|
|
1792
|
-
if (!target.startsWith(`${
|
|
1793
|
-
await
|
|
1911
|
+
const target = resolve5(root, path);
|
|
1912
|
+
if (!target.startsWith(`${resolve5(root)}${sep4}`)) throw new TypeError("Code reference path escapes its root");
|
|
1913
|
+
await mkdir4(dirname4(target), { recursive: true });
|
|
1794
1914
|
await writeFile2(target, file.content, { flag: "wx", mode: 292 });
|
|
1795
1915
|
}
|
|
1796
1916
|
}
|
|
@@ -2236,7 +2356,7 @@ Finish with a concise, non-empty answer to the owner. Do not call tools or promi
|
|
|
2236
2356
|
}
|
|
2237
2357
|
|
|
2238
2358
|
// src/code-runtime-session-skills.ts
|
|
2239
|
-
var sleep2 = (ms) => new Promise((
|
|
2359
|
+
var sleep2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
2240
2360
|
function createCodeRuntimeSessionSkillLoader(control, options = {}) {
|
|
2241
2361
|
const wait2 = options.wait ?? sleep2;
|
|
2242
2362
|
const load = control.collaborationSkills?.bind(control);
|
|
@@ -2295,7 +2415,7 @@ var inferWithBackoff = (infer, wait2, onRetry) => withOverloadRetry(infer, wait2
|
|
|
2295
2415
|
async function handleCodeRuntimeInference(input) {
|
|
2296
2416
|
const { command, request, state } = input;
|
|
2297
2417
|
const startedAt = Date.now();
|
|
2298
|
-
const wait2 = input.wait ?? ((ms) => new Promise((
|
|
2418
|
+
const wait2 = input.wait ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
2299
2419
|
const response2 = await inferWithBackoff(
|
|
2300
2420
|
() => input.control.infer(command.sessionId, {
|
|
2301
2421
|
requestId: request.requestId,
|
|
@@ -2363,9 +2483,9 @@ function createCodeRuntimeInference(options) {
|
|
|
2363
2483
|
}
|
|
2364
2484
|
|
|
2365
2485
|
// src/code-tool-discovery.ts
|
|
2366
|
-
import { spawn as
|
|
2486
|
+
import { spawn as spawn4 } from "child_process";
|
|
2367
2487
|
import { readFile as readFile2, readdir as readdir3 } from "fs/promises";
|
|
2368
|
-
import { relative as relative2, resolve as
|
|
2488
|
+
import { relative as relative2, resolve as resolve6 } from "path";
|
|
2369
2489
|
var DEFAULT_MAX_FILES = 2e4;
|
|
2370
2490
|
var DEFAULT_MAX_RESULTS = 100;
|
|
2371
2491
|
var DEFAULT_MAX_FILE_BYTES = 512 * 1024;
|
|
@@ -2393,7 +2513,7 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
|
2393
2513
|
for (const entry of await readdir3(directory, { withFileTypes: true })) {
|
|
2394
2514
|
if (SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
|
|
2395
2515
|
if (entry.isSymbolicLink()) throw new TypeError("workspace contains a symbolic link");
|
|
2396
|
-
const target =
|
|
2516
|
+
const target = resolve6(directory, entry.name);
|
|
2397
2517
|
if (entry.isDirectory()) await walk(target);
|
|
2398
2518
|
else if (entry.isFile()) {
|
|
2399
2519
|
const path = relative2(root, target).split("\\").join("/");
|
|
@@ -2407,7 +2527,7 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
|
2407
2527
|
}
|
|
2408
2528
|
}
|
|
2409
2529
|
};
|
|
2410
|
-
await walk(
|
|
2530
|
+
await walk(resolve6(root));
|
|
2411
2531
|
return paths.sort();
|
|
2412
2532
|
}
|
|
2413
2533
|
function listWorkspace(paths, options = {}) {
|
|
@@ -2469,7 +2589,7 @@ function nativeSearchBatch(root, paths, options, remaining) {
|
|
|
2469
2589
|
options.query,
|
|
2470
2590
|
...paths
|
|
2471
2591
|
];
|
|
2472
|
-
const child =
|
|
2592
|
+
const child = spawn4("rg", args, {
|
|
2473
2593
|
cwd: root,
|
|
2474
2594
|
stdio: ["ignore", "pipe", "ignore"],
|
|
2475
2595
|
...options.signal ? { signal: options.signal } : {}
|
|
@@ -2521,7 +2641,7 @@ async function fallbackSearch(root, scoped, options) {
|
|
|
2521
2641
|
if (matches.length >= options.maxResults) break;
|
|
2522
2642
|
let source;
|
|
2523
2643
|
try {
|
|
2524
|
-
source = await readFile2(
|
|
2644
|
+
source = await readFile2(resolve6(root, path));
|
|
2525
2645
|
} catch {
|
|
2526
2646
|
continue;
|
|
2527
2647
|
}
|
|
@@ -2825,7 +2945,7 @@ import { readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
|
2825
2945
|
|
|
2826
2946
|
// src/code-tool-graph.ts
|
|
2827
2947
|
import { readFile as readFile3 } from "fs/promises";
|
|
2828
|
-
import { join as
|
|
2948
|
+
import { join as join7 } from "path";
|
|
2829
2949
|
import {
|
|
2830
2950
|
hubs,
|
|
2831
2951
|
incident,
|
|
@@ -2839,7 +2959,7 @@ var cache = /* @__PURE__ */ new Map();
|
|
|
2839
2959
|
function workspaceGraphs(workspaceDir, paths) {
|
|
2840
2960
|
const existing = cache.get(workspaceDir);
|
|
2841
2961
|
if (existing) return existing;
|
|
2842
|
-
const read2 = (path) => readFile3(
|
|
2962
|
+
const read2 = (path) => readFile3(join7(workspaceDir, path), "utf8");
|
|
2843
2963
|
const built = (async () => ({
|
|
2844
2964
|
// No knownTables: a staged workspace may not carry migrations, and a filter
|
|
2845
2965
|
// that silently drops every table is worse than an unfiltered one. Callers
|
|
@@ -2949,8 +3069,8 @@ async function edit(context, request, options, policy, registry) {
|
|
|
2949
3069
|
}
|
|
2950
3070
|
|
|
2951
3071
|
// src/code-tool-write.ts
|
|
2952
|
-
import { mkdir as
|
|
2953
|
-
import { dirname as
|
|
3072
|
+
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
3073
|
+
import { dirname as dirname5 } from "path";
|
|
2954
3074
|
var MAX_WRITE_BYTES = 256 * 1024;
|
|
2955
3075
|
var lines = (text) => text === "" ? [] : text.replace(/\n$/, "").split("\n");
|
|
2956
3076
|
function writeAsDiff(path, current, content) {
|
|
@@ -2975,7 +3095,7 @@ async function writeCodeFile(workspaceDir, path, content, current) {
|
|
|
2975
3095
|
}
|
|
2976
3096
|
if (content.includes("\0")) throw new TypeError("content contains NUL bytes; use plain text");
|
|
2977
3097
|
const target = resolveCodePath(workspaceDir, path);
|
|
2978
|
-
await
|
|
3098
|
+
await mkdir5(dirname5(target), { recursive: true });
|
|
2979
3099
|
await writeFile4(target, content, "utf8");
|
|
2980
3100
|
return { created: current === null, deletions: current === null ? 0 : lines(current).length, additions: lines(content).length };
|
|
2981
3101
|
}
|
|
@@ -3003,7 +3123,7 @@ async function write(context, request, options, policy, registry) {
|
|
|
3003
3123
|
}
|
|
3004
3124
|
|
|
3005
3125
|
// src/code-tool-reads.ts
|
|
3006
|
-
import { readFile as readFile6, stat } from "fs/promises";
|
|
3126
|
+
import { readFile as readFile6, stat as stat2 } from "fs/promises";
|
|
3007
3127
|
var GRAPH_TOOLS = /* @__PURE__ */ new Set([
|
|
3008
3128
|
"sandbox.overview",
|
|
3009
3129
|
"sandbox.where_is",
|
|
@@ -3025,7 +3145,7 @@ async function read(context, request, options, policy, registry) {
|
|
|
3025
3145
|
const allowed = await policy.read(policyContext(context, request, options, { paths, path, startLine, endLine }));
|
|
3026
3146
|
if (!allowed) return response(request, false, "tool denied by CaMeL policy");
|
|
3027
3147
|
const target = resolveCodePath(context.workspaceDir, path);
|
|
3028
|
-
const info = await
|
|
3148
|
+
const info = await stat2(target);
|
|
3029
3149
|
if (!info.isFile() || info.size > Math.max(options.maxReadBytes ?? 128 * 1024, 2 * 1024 * 1024)) {
|
|
3030
3150
|
throw new TypeError("file is not a bounded regular source file");
|
|
3031
3151
|
}
|
|
@@ -3382,7 +3502,7 @@ function assertBudget(budget) {
|
|
|
3382
3502
|
|
|
3383
3503
|
// src/code-repository-recipes.ts
|
|
3384
3504
|
import { readFile as readFile7 } from "fs/promises";
|
|
3385
|
-
import { join as
|
|
3505
|
+
import { join as join8 } from "path";
|
|
3386
3506
|
|
|
3387
3507
|
// src/code-runtime-events.ts
|
|
3388
3508
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -3457,7 +3577,7 @@ function parseRepositoryRecipes(text, envelope) {
|
|
|
3457
3577
|
async function readRepositoryRecipes(baselineDir, envelope) {
|
|
3458
3578
|
let text;
|
|
3459
3579
|
try {
|
|
3460
|
-
text = await readFile7(
|
|
3580
|
+
text = await readFile7(join8(baselineDir, REPOSITORY_RECIPES_FILE), "utf8");
|
|
3461
3581
|
} catch (cause) {
|
|
3462
3582
|
if (cause.code === "ENOENT") return null;
|
|
3463
3583
|
throw cause;
|
|
@@ -3690,8 +3810,8 @@ async function startGoalPursuit(input) {
|
|
|
3690
3810
|
function codeRuntimeAcknowledgementGate(signal) {
|
|
3691
3811
|
let settle;
|
|
3692
3812
|
let settled = false;
|
|
3693
|
-
const ready = new Promise((
|
|
3694
|
-
settle =
|
|
3813
|
+
const ready = new Promise((resolve7) => {
|
|
3814
|
+
settle = resolve7;
|
|
3695
3815
|
});
|
|
3696
3816
|
const release = (run) => {
|
|
3697
3817
|
if (settled) return;
|
|
@@ -4062,9 +4182,18 @@ export {
|
|
|
4062
4182
|
createCodeWorkspaceCheckpoint,
|
|
4063
4183
|
restoreCodeWorkspaceCheckpoint,
|
|
4064
4184
|
isCheckpointEffectCompleted,
|
|
4185
|
+
assertLentPath,
|
|
4186
|
+
assertReservedMount,
|
|
4187
|
+
lentDirectories,
|
|
4188
|
+
withRecipeDependencies,
|
|
4189
|
+
installedDependencies,
|
|
4190
|
+
cloneTree,
|
|
4191
|
+
lendDependencies,
|
|
4192
|
+
lendBuildProducts,
|
|
4065
4193
|
buildRecipeContainerArgs,
|
|
4066
4194
|
createContainerRecipeExecutor,
|
|
4067
4195
|
assertCodeBuildRecipe,
|
|
4196
|
+
recipeOutput,
|
|
4068
4197
|
runContainerCommand,
|
|
4069
4198
|
verifyCodeCandidate,
|
|
4070
4199
|
prepareRuntimeCheckpoint,
|
|
@@ -4103,4 +4232,4 @@ export {
|
|
|
4103
4232
|
withProofRecipes,
|
|
4104
4233
|
TheseusRuntimeEngine
|
|
4105
4234
|
};
|
|
4106
|
-
//# sourceMappingURL=chunk-
|
|
4235
|
+
//# sourceMappingURL=chunk-B2PQAORN.js.map
|