@tangle-network/agent-runtime 0.317.0 → 0.319.3
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/{activation-CvdE2HIU.js → activation-ClcJ6wO1.js} +3 -3
- package/dist/{activation-CvdE2HIU.js.map → activation-ClcJ6wO1.js.map} +1 -1
- package/dist/{activation-BFDmjaKP.d.ts → activation-OColGsfd.d.ts} +2 -2
- package/dist/agent.d.ts +3 -3
- package/dist/agent.js +3 -3
- package/dist/{bundle-RgHpAFDY.js → bundle-Cw-QdGmH.js} +2 -2
- package/dist/{bundle-RgHpAFDY.js.map → bundle-Cw-QdGmH.js.map} +1 -1
- package/dist/candidate-execution/index.d.ts +40 -3
- package/dist/candidate-execution/index.js +86 -7
- package/dist/candidate-execution/index.js.map +1 -1
- package/dist/{coordination-driver-DGhN8GO9.js → coordination-driver-Culvomn2.js} +3 -3
- package/dist/{coordination-driver-DGhN8GO9.js.map → coordination-driver-Culvomn2.js.map} +1 -1
- package/dist/{delegate-B5pmSbQa.js → delegate-CpMbpiIR.js} +2 -2
- package/dist/{delegate-B5pmSbQa.js.map → delegate-CpMbpiIR.js.map} +1 -1
- package/dist/durable.d.ts +1 -1
- package/dist/durable.js +4 -4
- package/dist/{graph-G0j1ysqe.js → graph-DnfSGUM8.js} +5 -5
- package/dist/{graph-G0j1ysqe.js.map → graph-DnfSGUM8.js.map} +1 -1
- package/dist/graph-registry-BuJbzTzF.js +211 -0
- package/dist/graph-registry-BuJbzTzF.js.map +1 -0
- package/dist/{improvement-cycle-D7yR6GC2.js → improvement-cycle-xnQwUaC3.js} +7 -7
- package/dist/{improvement-cycle-D7yR6GC2.js.map → improvement-cycle-xnQwUaC3.js.map} +1 -1
- package/dist/{index-CUh40yUJ.d.ts → index-Da7w2H86.d.ts} +351 -132
- package/dist/index.d.ts +5 -5
- package/dist/index.js +10 -10
- package/dist/intelligence.d.ts +4 -4
- package/dist/intelligence.js +7 -7
- package/dist/kernel.d.ts +3 -2
- package/dist/kernel.js +12 -11
- package/dist/{loop-runner-bin-DQKLUt0l.d.ts → loop-runner-bin-CbBoLC9D.d.ts} +2 -2
- package/dist/{loop-runner-bin-CFVX4oi0.js → loop-runner-bin-uoeGHNZA.js} +3 -3
- package/dist/{loop-runner-bin-CFVX4oi0.js.map → loop-runner-bin-uoeGHNZA.js.map} +1 -1
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.js +6 -6
- package/dist/{model-policy-DhvyZ8-O.js → model-policy-CNe257pB.js} +37 -2
- package/dist/model-policy-CNe257pB.js.map +1 -0
- package/dist/{openai-tools-u3gWBi3x.d.ts → openai-tools-Cu9E1Bda.d.ts} +2 -2
- package/dist/placement.d.ts +1 -1
- package/dist/{prepare-CD9kR0gS.js → prepare-DjCLEN-q.js} +3 -3
- package/dist/prepare-DjCLEN-q.js.map +1 -0
- package/dist/{profile-CHXYmpGd.js → profile-DmVM4Gxb.js} +9 -2
- package/dist/profile-DmVM4Gxb.js.map +1 -0
- package/dist/{profile-materialization-Cca615eu.d.ts → profile-materialization-C5-t3HJ7.d.ts} +14 -3
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.js +1 -1
- package/dist/{protected-model-port-C9QtEf3y.d.ts → protected-model-port-CQg2gstJ.d.ts} +3 -3
- package/dist/{protected-model-port-B0pHd65J.js → protected-model-port-D1fcnYdj.js} +4 -4
- package/dist/{protected-model-port-B0pHd65J.js.map → protected-model-port-D1fcnYdj.js.map} +1 -1
- package/dist/{provision-supervisor-BQLLrUtn.js → provision-supervisor-DiZTjzdp.js} +5 -5
- package/dist/{provision-supervisor-BQLLrUtn.js.map → provision-supervisor-DiZTjzdp.js.map} +1 -1
- package/dist/{runtime-B9BOFyEp.js → runtime-6qzuLTJ7.js} +514 -277
- package/dist/runtime-6qzuLTJ7.js.map +1 -0
- package/dist/{search-executor-B5ZVFsDV.js → search-executor-DlaLafvy.js} +4 -4
- package/dist/{search-executor-B5ZVFsDV.js.map → search-executor-DlaLafvy.js.map} +1 -1
- package/dist/{server-TwpH9aik.js → server-sLrmWqKw.js} +4 -4
- package/dist/{server-TwpH9aik.js.map → server-sLrmWqKw.js.map} +1 -1
- package/dist/{supervise-CU6AuxWY.js → supervise-D4CnC-cl.js} +5 -5
- package/dist/{supervise-CU6AuxWY.js.map → supervise-D4CnC-cl.js.map} +1 -1
- package/dist/{supervisor-CbFyf48U.js → supervisor-Cqhu3xH-.js} +709 -80
- package/dist/supervisor-Cqhu3xH-.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +14 -14
- package/dist/tool-loop.d.ts +5 -1
- package/dist/tool-loop.js +4 -3
- package/dist/tool-loop.js.map +1 -1
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +1 -1
- package/dist/workspace-store/index.d.ts +171 -3
- package/dist/workspace-store/index.js +529 -8
- package/dist/workspace-store/index.js.map +1 -1
- package/dist/{workspace-streams-DkijayqX.js → workspace-streams-DFAhW7hF.js} +300 -42
- package/dist/workspace-streams-DFAhW7hF.js.map +1 -0
- package/dist/{workspace-streams-CpSmt3zx.d.ts → workspace-streams-U6_UfOXu.d.ts} +10 -2
- package/package.json +15 -11
- package/skills/agent-graphs/references/authoring.md +7 -0
- package/skills/codemode/SKILL.md +6 -4
- package/skills/codemode/references/runtime-execution.md +63 -11
- package/skills/graph-designer/SKILL.md +57 -0
- package/skills/profile-authoring/SKILL.md +17 -15
- package/dist/model-policy-DhvyZ8-O.js.map +0 -1
- package/dist/prepare-CD9kR0gS.js.map +0 -1
- package/dist/profile-CHXYmpGd.js.map +0 -1
- package/dist/runtime-B9BOFyEp.js.map +0 -1
- package/dist/supervisor-CbFyf48U.js.map +0 -1
- package/dist/workspace-streams-DkijayqX.js.map +0 -1
|
@@ -6,7 +6,7 @@ import { spawn } from "node:child_process";
|
|
|
6
6
|
import { constants } from "node:fs";
|
|
7
7
|
import { dirname, isAbsolute, join, relative, resolve, sep, win32 } from "node:path";
|
|
8
8
|
import { lstat, mkdir, mkdtemp, open, readFile, readdir, readlink, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
9
|
-
import { tmpdir } from "node:os";
|
|
9
|
+
import { homedir, tmpdir } from "node:os";
|
|
10
10
|
import { Readable } from "node:stream";
|
|
11
11
|
import { pipeline } from "node:stream/promises";
|
|
12
12
|
import { extract, pack } from "tar-stream";
|
|
@@ -879,6 +879,16 @@ async function verifyMaterializedProfileWorkspace(root, expected, fileRoot = "wo
|
|
|
879
879
|
async function walkWorkspace(root, options, keepBytes) {
|
|
880
880
|
const ignoredProtectedRootEntries = new Set(options.ignoredProtectedRootEntries ?? []);
|
|
881
881
|
const limits = options.limits;
|
|
882
|
+
const selected = options.selectedPaths ? new Set(options.selectedPaths) : void 0;
|
|
883
|
+
const selectedDirectories = /* @__PURE__ */ new Set();
|
|
884
|
+
for (const path of selected ?? []) {
|
|
885
|
+
if (!path || path.includes("\\") || path.includes("\0") || isAbsolute(path) || path.split("/").some((part) => !part || part === "." || part === "..")) throw new Error("workspace selected path must be a safe relative file path");
|
|
886
|
+
let parent = dirname(path);
|
|
887
|
+
while (parent !== ".") {
|
|
888
|
+
selectedDirectories.add(parent);
|
|
889
|
+
parent = dirname(parent);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
882
892
|
const requestedRoot = resolve(root);
|
|
883
893
|
const rootStats = await lstat(requestedRoot);
|
|
884
894
|
if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) throw new Error("workspace root must be a real directory");
|
|
@@ -898,9 +908,11 @@ async function walkWorkspace(root, options, keepBytes) {
|
|
|
898
908
|
const absolute = resolve(directory, entry.name);
|
|
899
909
|
const relPath = relative(absoluteRoot, absolute).split(sep).join("/");
|
|
900
910
|
if (!relPath || relPath.startsWith("../") || relPath.includes("/../")) throw new Error(`workspace entry escapes root: ${relPath}`);
|
|
911
|
+
if (selected && !selected.has(relPath) && !selectedDirectories.has(relPath)) continue;
|
|
901
912
|
const stats = await lstat(absolute);
|
|
902
913
|
if (stats.isSymbolicLink()) throw new Error(await symlinkRefusal(absolute, relPath, absoluteRoot));
|
|
903
914
|
if (stats.isDirectory()) {
|
|
915
|
+
if (selected?.has(relPath)) throw new Error(`workspace selected file is a directory: ${relPath}`);
|
|
904
916
|
await visit(absolute);
|
|
905
917
|
continue;
|
|
906
918
|
}
|
|
@@ -930,6 +942,7 @@ async function walkWorkspace(root, options, keepBytes) {
|
|
|
930
942
|
}
|
|
931
943
|
}
|
|
932
944
|
await visit(absoluteRoot);
|
|
945
|
+
if (selected && scanned.length !== selected.size) throw new Error("workspace selected files changed during capture");
|
|
933
946
|
return scanned;
|
|
934
947
|
}
|
|
935
948
|
/**
|
|
@@ -1269,7 +1282,9 @@ function parseGitHubRemote(value) {
|
|
|
1269
1282
|
repo: match[2]
|
|
1270
1283
|
};
|
|
1271
1284
|
}
|
|
1272
|
-
async function runCandidateGit(repositoryRoot, args, input, extraEnv = {}) {
|
|
1285
|
+
async function runCandidateGit(repositoryRoot, args, input, extraEnv = {}, options = {}) {
|
|
1286
|
+
if (options.readUserExclusions && (args.length !== 7 || args.slice(0, 4).join(",") !== "config,--includes,--path,--default" || args.slice(5).join(",") !== "--get,core.excludesFile")) throw new Error("user Git configuration may only supply the effective exclusion path");
|
|
1287
|
+
if (options.maxOutputBytes !== void 0 && (!Number.isSafeInteger(options.maxOutputBytes) || options.maxOutputBytes < 0)) throw new Error("candidate Git maxOutputBytes must be a nonnegative safe integer");
|
|
1273
1288
|
const env = Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.startsWith("GIT_")));
|
|
1274
1289
|
Object.assign(env, {
|
|
1275
1290
|
GIT_CONFIG_NOSYSTEM: "1",
|
|
@@ -1280,6 +1295,14 @@ async function runCandidateGit(repositoryRoot, args, input, extraEnv = {}) {
|
|
|
1280
1295
|
LC_ALL: "C",
|
|
1281
1296
|
...extraEnv
|
|
1282
1297
|
});
|
|
1298
|
+
if (options.readUserExclusions) for (const name of [
|
|
1299
|
+
"GIT_CONFIG_GLOBAL",
|
|
1300
|
+
"GIT_CONFIG_SYSTEM",
|
|
1301
|
+
"GIT_CONFIG_NOSYSTEM"
|
|
1302
|
+
]) {
|
|
1303
|
+
delete env[name];
|
|
1304
|
+
if (process.env[name] !== void 0) env[name] = process.env[name];
|
|
1305
|
+
}
|
|
1283
1306
|
const fullArgs = [
|
|
1284
1307
|
"-c",
|
|
1285
1308
|
"core.hooksPath=/dev/null",
|
|
@@ -1304,10 +1327,27 @@ async function runCandidateGit(repositoryRoot, args, input, extraEnv = {}) {
|
|
|
1304
1327
|
});
|
|
1305
1328
|
const stdout = [];
|
|
1306
1329
|
const stderr = [];
|
|
1307
|
-
|
|
1308
|
-
|
|
1330
|
+
let outputBytes = 0;
|
|
1331
|
+
let exceeded = false;
|
|
1332
|
+
function retain(chunks, chunk) {
|
|
1333
|
+
if (exceeded) return;
|
|
1334
|
+
outputBytes += chunk.byteLength;
|
|
1335
|
+
if (options.maxOutputBytes !== void 0 && outputBytes > options.maxOutputBytes) {
|
|
1336
|
+
exceeded = true;
|
|
1337
|
+
child.kill("SIGKILL");
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
chunks.push(chunk);
|
|
1341
|
+
}
|
|
1342
|
+
child.stdout.on("data", (chunk) => retain(stdout, chunk));
|
|
1343
|
+
child.stderr.on("data", (chunk) => retain(stderr, chunk));
|
|
1309
1344
|
child.on("error", reject);
|
|
1345
|
+
child.stdin.on("error", reject);
|
|
1310
1346
|
child.on("close", (code, signal) => {
|
|
1347
|
+
if (exceeded) {
|
|
1348
|
+
reject(/* @__PURE__ */ new Error("candidate Git command exceeds maxOutputBytes"));
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1311
1351
|
const out = Buffer.concat(stdout);
|
|
1312
1352
|
const err = Buffer.concat(stderr);
|
|
1313
1353
|
if (code !== 0) {
|
|
@@ -1352,6 +1392,8 @@ const archiveKind = "agent-candidate-workspace-archive";
|
|
|
1352
1392
|
const workspaceEntryPrefix = "workspace/";
|
|
1353
1393
|
const repositoryMetadataEntry = "metadata/repository.json";
|
|
1354
1394
|
const repositoryBundleEntry = "metadata/repository.bundle";
|
|
1395
|
+
const repositoryIndexEntry = "metadata/repository.index.json";
|
|
1396
|
+
const repositoryIndexPrefix = "index/";
|
|
1355
1397
|
const fixedTarTime = /* @__PURE__ */ new Date(0);
|
|
1356
1398
|
const defaultLimits = Object.freeze({
|
|
1357
1399
|
maxArchiveBytes: 512 * 1024 * 1024,
|
|
@@ -1366,7 +1408,9 @@ const defaultLimits = Object.freeze({
|
|
|
1366
1408
|
async function captureAgentCandidateWorkspace(rootInput, options = {}) {
|
|
1367
1409
|
const root = resolve(rootInput);
|
|
1368
1410
|
const limits = workspaceLimits(options.limits);
|
|
1369
|
-
|
|
1411
|
+
if (options.repositoryContents !== void 0 && options.repositoryContents !== "head" && options.repositoryContents !== "working-tree") throw new Error("candidate repositoryContents is invalid");
|
|
1412
|
+
if (options.repositoryContents !== void 0 && !options.includeRepository) throw new Error("candidate repositoryContents requires includeRepository");
|
|
1413
|
+
const captured = options.includeRepository ? await captureRepository(root, limits, options.repositoryContents === "working-tree") : await captureMaterializedWorkspace(root, { limits: {
|
|
1370
1414
|
maxFiles: limits.maxFiles,
|
|
1371
1415
|
maxFileBytes: limits.maxFileBytes,
|
|
1372
1416
|
maxTotalFileBytes: limits.maxTotalFileBytes
|
|
@@ -1412,35 +1456,38 @@ async function captureWorkspaceArtifact(kind, bytes, persistence) {
|
|
|
1412
1456
|
/** Create the standard bounded materializer for candidate execution ports. */
|
|
1413
1457
|
function createAgentCandidateWorkspacePort(options = {}) {
|
|
1414
1458
|
const limits = workspaceLimits(options.limits);
|
|
1415
|
-
return Object.freeze({ materialize: async ({ role, snapshot, archive, destination }) => {
|
|
1459
|
+
return Object.freeze({ materialize: async ({ role, snapshot, archive, destination, signal }) => {
|
|
1416
1460
|
await materializeAgentCandidateWorkspace({
|
|
1417
1461
|
role,
|
|
1418
1462
|
snapshot,
|
|
1419
1463
|
archive,
|
|
1420
1464
|
destination,
|
|
1421
|
-
limits
|
|
1465
|
+
limits,
|
|
1466
|
+
signal
|
|
1422
1467
|
});
|
|
1423
1468
|
} });
|
|
1424
1469
|
}
|
|
1425
1470
|
async function materializeAgentCandidateWorkspace(input) {
|
|
1471
|
+
input.signal?.throwIfAborted();
|
|
1426
1472
|
const decoded = await decodeVerifiedWorkspaceArchive(input);
|
|
1473
|
+
input.signal?.throwIfAborted();
|
|
1427
1474
|
const destination = resolve(input.destination);
|
|
1428
|
-
await prepareEmptyDestination(destination);
|
|
1475
|
+
await prepareEmptyDestination(destination, { createDestination: false });
|
|
1476
|
+
input.signal?.throwIfAborted();
|
|
1429
1477
|
const staging = await mkdtemp(`${destination}.materializing-`);
|
|
1430
1478
|
try {
|
|
1431
|
-
|
|
1432
|
-
|
|
1479
|
+
input.signal?.throwIfAborted();
|
|
1480
|
+
await writeWorkspaceFiles(staging, decoded.files, input.signal);
|
|
1481
|
+
if (decoded.repository) await materializeRepository(decoded.repository, staging, input.limits, input.signal);
|
|
1482
|
+
input.signal?.throwIfAborted();
|
|
1433
1483
|
await verifyMaterializedWorkspace(staging, input.snapshot.material, { ignoredProtectedRootEntries: decoded.repository ? [".git"] : [] });
|
|
1484
|
+
input.signal?.throwIfAborted();
|
|
1434
1485
|
await rename(staging, destination);
|
|
1435
1486
|
} catch (error) {
|
|
1436
1487
|
await rm(staging, {
|
|
1437
1488
|
recursive: true,
|
|
1438
1489
|
force: true
|
|
1439
1490
|
});
|
|
1440
|
-
await rm(destination, {
|
|
1441
|
-
recursive: true,
|
|
1442
|
-
force: true
|
|
1443
|
-
});
|
|
1444
1491
|
throw error;
|
|
1445
1492
|
}
|
|
1446
1493
|
}
|
|
@@ -1458,7 +1505,7 @@ async function decodeVerifiedWorkspaceArchive(input) {
|
|
|
1458
1505
|
assertArchiveMatchesSnapshot(decoded.files, input.snapshot);
|
|
1459
1506
|
return decoded;
|
|
1460
1507
|
}
|
|
1461
|
-
async function captureRepository(requestedRoot, limits) {
|
|
1508
|
+
async function captureRepository(requestedRoot, limits, workingTree) {
|
|
1462
1509
|
const requestedStats = await lstat(requestedRoot);
|
|
1463
1510
|
if (!requestedStats.isDirectory() || requestedStats.isSymbolicLink()) throw new Error("candidate repository root must be a real directory");
|
|
1464
1511
|
const root = await realpath(requestedRoot);
|
|
@@ -1473,7 +1520,8 @@ async function captureRepository(requestedRoot, limits) {
|
|
|
1473
1520
|
assertGitObjectId(headCommit, "HEAD");
|
|
1474
1521
|
assertGitObjectId(headTree, "HEAD tree");
|
|
1475
1522
|
if (headCommit.length !== headTree.length) throw new Error("candidate repository HEAD and tree use different object formats");
|
|
1476
|
-
const
|
|
1523
|
+
const working = workingTree ? await captureRepositoryWorkingTree(root, limits) : void 0;
|
|
1524
|
+
const files = working?.files ?? await readCandidateGitTreeFiles(root, headTree, {}, limits);
|
|
1477
1525
|
assertWorkspaceFilesWithinLimits(files, limits);
|
|
1478
1526
|
const reachableBytesText = (await runCandidateGit(root, [
|
|
1479
1527
|
"rev-list",
|
|
@@ -1495,6 +1543,15 @@ async function captureRepository(requestedRoot, limits) {
|
|
|
1495
1543
|
]);
|
|
1496
1544
|
const bundle = Uint8Array.from(await readFile(bundlePath));
|
|
1497
1545
|
if (bundle.byteLength > limits.maxRepositoryBundleBytes) throw new Error("candidate repository bundle exceeds maxRepositoryBundleBytes");
|
|
1546
|
+
if (working) {
|
|
1547
|
+
const after = await readRepositoryWorkingState(root, limits);
|
|
1548
|
+
if (after.paths !== working.state.paths || after.index !== working.state.index || (await runCandidateGit(root, ["rev-parse", "HEAD"])).stdout.toString("utf8").trim() !== headCommit) throw new Error("candidate repository changed during working-tree capture");
|
|
1549
|
+
if ((await existingRepositoryPaths(root, after.paths, limits)).join("\0") !== files.map((file) => file.path).join("\0")) throw new Error("candidate repository files changed during working-tree capture");
|
|
1550
|
+
await verifyMaterializedWorkspace(root, candidateWorkspaceManifest(files), {
|
|
1551
|
+
ignoredProtectedRootEntries: [".git"],
|
|
1552
|
+
selectedPaths: files.map((file) => file.path)
|
|
1553
|
+
});
|
|
1554
|
+
}
|
|
1498
1555
|
return {
|
|
1499
1556
|
files,
|
|
1500
1557
|
repository: {
|
|
@@ -1504,7 +1561,8 @@ async function captureRepository(requestedRoot, limits) {
|
|
|
1504
1561
|
sha256: sha256Bytes$1(bundle),
|
|
1505
1562
|
byteLength: bundle.byteLength,
|
|
1506
1563
|
bytes: bundle
|
|
1507
|
-
}
|
|
1564
|
+
},
|
|
1565
|
+
...working ? { workingTree: { files: working.state.files } } : {}
|
|
1508
1566
|
}
|
|
1509
1567
|
};
|
|
1510
1568
|
} finally {
|
|
@@ -1514,6 +1572,114 @@ async function captureRepository(requestedRoot, limits) {
|
|
|
1514
1572
|
});
|
|
1515
1573
|
}
|
|
1516
1574
|
}
|
|
1575
|
+
async function readRepositoryWorkingState(root, limits) {
|
|
1576
|
+
const env = { GIT_OPTIONAL_LOCKS: "0" };
|
|
1577
|
+
const listingLimit = Math.min(limits.maxArchiveBytes, limits.maxFiles * (limits.maxPathBytes + 256));
|
|
1578
|
+
const index = new TextDecoder("utf-8", { fatal: true }).decode((await runCandidateGit(root, [
|
|
1579
|
+
"ls-files",
|
|
1580
|
+
"--stage",
|
|
1581
|
+
"-z"
|
|
1582
|
+
], void 0, env, { maxOutputBytes: listingLimit })).stdout);
|
|
1583
|
+
const entries = index.split("\0").filter(Boolean).map((entry) => {
|
|
1584
|
+
const match = /^(100644|100755) ([a-f0-9]{40}|[a-f0-9]{64}) 0\t(.+)$/u.exec(entry);
|
|
1585
|
+
if (!match) throw new Error("candidate working-tree capture requires a resolved regular-file Git index");
|
|
1586
|
+
const [, mode, object, path] = match;
|
|
1587
|
+
if (!object || !path) throw new Error("candidate Git index is invalid");
|
|
1588
|
+
return {
|
|
1589
|
+
path: safeArchivePath(path, limits.maxPathBytes),
|
|
1590
|
+
mode: mode === "100755" ? 493 : 420,
|
|
1591
|
+
object
|
|
1592
|
+
};
|
|
1593
|
+
});
|
|
1594
|
+
if (entries.length > limits.maxFiles) throw new Error("candidate Git index exceeds maxFiles");
|
|
1595
|
+
if ([...(await runCandidateGit(root, [
|
|
1596
|
+
"ls-files",
|
|
1597
|
+
"--debug",
|
|
1598
|
+
"-z"
|
|
1599
|
+
], void 0, env, { maxOutputBytes: listingLimit })).stdout.toString("utf8").matchAll(/\tflags: ([a-f0-9]+)\n/gu)].some((match) => match[1] !== "0")) throw new Error("candidate working-tree capture does not support special Git index flags");
|
|
1600
|
+
const sizes = entries.length ? (await runCandidateGit(root, ["cat-file", "--batch-check"], Buffer.from(entries.map((entry) => entry.object).join("\n") + "\n"), env, { maxOutputBytes: listingLimit })).stdout.toString("utf8").trimEnd().split("\n") : [];
|
|
1601
|
+
if (sizes.length !== entries.length) throw new Error("candidate Git index blob metadata is incomplete");
|
|
1602
|
+
let totalBytes = 0;
|
|
1603
|
+
const byteLengths = entries.map((entry, index) => {
|
|
1604
|
+
const match = /^([a-f0-9]{40}|[a-f0-9]{64}) blob (\d+)$/u.exec(sizes[index] ?? "");
|
|
1605
|
+
const size = Number(match?.[2]);
|
|
1606
|
+
if (!match || match[1] !== entry.object || !Number.isSafeInteger(size) || size < 0) throw new Error("candidate Git index blob metadata is invalid");
|
|
1607
|
+
if (size > limits.maxFileBytes) throw new Error(`candidate Git index file exceeds maxFileBytes: ${entry.path}`);
|
|
1608
|
+
if (size > limits.maxTotalFileBytes - totalBytes) throw new Error("candidate Git index exceeds maxTotalFileBytes");
|
|
1609
|
+
totalBytes += size;
|
|
1610
|
+
return size;
|
|
1611
|
+
});
|
|
1612
|
+
const files = [];
|
|
1613
|
+
for (const [index, entry] of entries.entries()) {
|
|
1614
|
+
const bytes = (await runCandidateGit(root, [
|
|
1615
|
+
"cat-file",
|
|
1616
|
+
"blob",
|
|
1617
|
+
entry.object
|
|
1618
|
+
], void 0, env, { maxOutputBytes: limits.maxFileBytes })).stdout;
|
|
1619
|
+
if (bytes.byteLength !== byteLengths[index]) throw new Error("candidate Git index blob size changed");
|
|
1620
|
+
files.push({
|
|
1621
|
+
path: entry.path,
|
|
1622
|
+
mode: entry.mode,
|
|
1623
|
+
bytes: Uint8Array.from(bytes)
|
|
1624
|
+
});
|
|
1625
|
+
}
|
|
1626
|
+
files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
1627
|
+
assertWorkspaceFilesWithinLimits(files, limits);
|
|
1628
|
+
const defaultExcludes = join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "git", "ignore");
|
|
1629
|
+
const excludes = new TextDecoder("utf-8", { fatal: true }).decode((await runCandidateGit(root, [
|
|
1630
|
+
"config",
|
|
1631
|
+
"--includes",
|
|
1632
|
+
"--path",
|
|
1633
|
+
"--default",
|
|
1634
|
+
defaultExcludes,
|
|
1635
|
+
"--get",
|
|
1636
|
+
"core.excludesFile"
|
|
1637
|
+
], void 0, {}, {
|
|
1638
|
+
maxOutputBytes: limits.maxPathBytes,
|
|
1639
|
+
readUserExclusions: true
|
|
1640
|
+
})).stdout).replace(/\n$/u, "");
|
|
1641
|
+
const paths = new TextDecoder("utf-8", { fatal: true }).decode((await runCandidateGit(root, [
|
|
1642
|
+
"-c",
|
|
1643
|
+
`core.excludesFile=${excludes}`,
|
|
1644
|
+
"ls-files",
|
|
1645
|
+
"--cached",
|
|
1646
|
+
"--others",
|
|
1647
|
+
"--exclude-standard",
|
|
1648
|
+
"-z"
|
|
1649
|
+
], void 0, env, { maxOutputBytes: listingLimit })).stdout);
|
|
1650
|
+
for (const path of paths.split("\0").filter(Boolean)) safeArchivePath(path, limits.maxPathBytes);
|
|
1651
|
+
return {
|
|
1652
|
+
paths,
|
|
1653
|
+
index,
|
|
1654
|
+
files
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
async function captureRepositoryWorkingTree(root, limits) {
|
|
1658
|
+
const state = await readRepositoryWorkingState(root, limits);
|
|
1659
|
+
return {
|
|
1660
|
+
state,
|
|
1661
|
+
files: [...(await captureMaterializedWorkspace(root, {
|
|
1662
|
+
ignoredProtectedRootEntries: [".git"],
|
|
1663
|
+
selectedPaths: await existingRepositoryPaths(root, state.paths, limits),
|
|
1664
|
+
limits
|
|
1665
|
+
})).files].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0)
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
async function existingRepositoryPaths(root, listing, limits) {
|
|
1669
|
+
const paths = [...new Set(listing.split("\0").filter(Boolean))].sort();
|
|
1670
|
+
if (paths.length > limits.maxFiles) throw new Error("candidate workspace exceeds maxFiles");
|
|
1671
|
+
const selectedPaths = [];
|
|
1672
|
+
for (const path of paths) {
|
|
1673
|
+
const safe = safeArchivePath(path, limits.maxPathBytes);
|
|
1674
|
+
try {
|
|
1675
|
+
await lstat(workspacePath(root, safe));
|
|
1676
|
+
selectedPaths.push(safe);
|
|
1677
|
+
} catch (error) {
|
|
1678
|
+
if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) throw error;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
return selectedPaths;
|
|
1682
|
+
}
|
|
1517
1683
|
async function encodeWorkspaceArchive(files, repository, maxArchiveBytes) {
|
|
1518
1684
|
const archive = pack();
|
|
1519
1685
|
const output = collectStream(archive, maxArchiveBytes, "candidate workspace archive");
|
|
@@ -1543,6 +1709,7 @@ async function verifyCanonicalWorkspaceArchive(files, repository, expected, maxA
|
|
|
1543
1709
|
async function writeWorkspaceArchiveEntries(archive, files, repository) {
|
|
1544
1710
|
for (const file of files) await writeTarEntry(archive, `${workspaceEntryPrefix}${file.path}`, file.mode, file.bytes);
|
|
1545
1711
|
if (!repository) return;
|
|
1712
|
+
const indexManifest = repository.workingTree ? canonicalCandidateBytes$1(candidateWorkspaceManifest(repository.workingTree.files)) : void 0;
|
|
1546
1713
|
const metadata = canonicalCandidateBytes$1({
|
|
1547
1714
|
kind: archiveKind,
|
|
1548
1715
|
headCommit: repository.headCommit,
|
|
@@ -1550,10 +1717,18 @@ async function writeWorkspaceArchiveEntries(archive, files, repository) {
|
|
|
1550
1717
|
bundle: {
|
|
1551
1718
|
sha256: repository.bundle.sha256,
|
|
1552
1719
|
byteLength: repository.bundle.byteLength
|
|
1553
|
-
}
|
|
1720
|
+
},
|
|
1721
|
+
...indexManifest ? { workingTree: { indexManifest: {
|
|
1722
|
+
sha256: sha256Bytes$1(indexManifest),
|
|
1723
|
+
byteLength: indexManifest.byteLength
|
|
1724
|
+
} } } : {}
|
|
1554
1725
|
});
|
|
1555
1726
|
await writeTarEntry(archive, repositoryMetadataEntry, 384, metadata);
|
|
1556
1727
|
await writeTarEntry(archive, repositoryBundleEntry, 384, repository.bundle.bytes);
|
|
1728
|
+
if (repository.workingTree && indexManifest) {
|
|
1729
|
+
await writeTarEntry(archive, repositoryIndexEntry, 384, indexManifest);
|
|
1730
|
+
for (const file of repository.workingTree.files) await writeTarEntry(archive, `${repositoryIndexPrefix}${file.path}`, file.mode, file.bytes);
|
|
1731
|
+
}
|
|
1557
1732
|
}
|
|
1558
1733
|
async function parseWorkspaceArchive(bytes, limits) {
|
|
1559
1734
|
if (bytes.byteLength > limits.maxArchiveBytes) throw new Error("candidate workspace archive exceeds maxArchiveBytes");
|
|
@@ -1566,6 +1741,11 @@ async function parseWorkspaceArchive(bytes, limits) {
|
|
|
1566
1741
|
let previousPath;
|
|
1567
1742
|
let repositoryMetadata;
|
|
1568
1743
|
let repositoryBundle;
|
|
1744
|
+
let repositoryIndex;
|
|
1745
|
+
const indexFiles = [];
|
|
1746
|
+
const indexPaths = /* @__PURE__ */ new Set();
|
|
1747
|
+
let previousIndexPath;
|
|
1748
|
+
let indexBytes = 0;
|
|
1569
1749
|
const decoded = (async () => {
|
|
1570
1750
|
for await (const entry of parser) {
|
|
1571
1751
|
const name = entry.header.name;
|
|
@@ -1592,16 +1772,39 @@ async function parseWorkspaceArchive(bytes, limits) {
|
|
|
1592
1772
|
assertRetainedArchiveSize(bytes.byteLength, retainedEntryBytes, entry.header.size, limits);
|
|
1593
1773
|
const metadataBytes = await readTarEntry(entry, limits.maxPathBytes, "candidate repository metadata");
|
|
1594
1774
|
retainedEntryBytes += metadataBytes.byteLength;
|
|
1595
|
-
repositoryMetadata = parseRepositoryMetadata(metadataBytes, limits
|
|
1775
|
+
repositoryMetadata = parseRepositoryMetadata(metadataBytes, limits);
|
|
1596
1776
|
} else if (name === repositoryBundleEntry) {
|
|
1597
1777
|
if (entry.header.mode !== 384 || repositoryBundle) throw new Error("candidate workspace archive repository bundle is invalid");
|
|
1598
1778
|
assertRetainedArchiveSize(bytes.byteLength, retainedEntryBytes, entry.header.size, limits);
|
|
1599
1779
|
repositoryBundle = await readTarEntry(entry, limits.maxRepositoryBundleBytes, "candidate Git bundle");
|
|
1600
1780
|
retainedEntryBytes += repositoryBundle.byteLength;
|
|
1781
|
+
} else if (name === repositoryIndexEntry) {
|
|
1782
|
+
if (entry.header.mode !== 384 || repositoryIndex) throw new Error("candidate workspace archive repository index is invalid");
|
|
1783
|
+
assertRetainedArchiveSize(bytes.byteLength, retainedEntryBytes, entry.header.size, limits);
|
|
1784
|
+
repositoryIndex = await readTarEntry(entry, limits.maxArchiveBytes, "candidate Git index manifest");
|
|
1785
|
+
retainedEntryBytes += repositoryIndex.byteLength;
|
|
1786
|
+
} else if (name.startsWith(repositoryIndexPrefix)) {
|
|
1787
|
+
if (!repositoryMetadata?.workingTree || !repositoryIndex || indexFiles.length >= limits.maxFiles) throw new Error("candidate Git index evidence is incomplete or exceeds maxFiles");
|
|
1788
|
+
const path = safeArchivePath(name.slice(6), limits.maxPathBytes);
|
|
1789
|
+
if (entry.header.mode !== 420 && entry.header.mode !== 493) throw new Error("candidate Git index contains an unsupported mode");
|
|
1790
|
+
assertWorkspacePathOrder(path, previousIndexPath, indexPaths, "candidate Git index paths must be unique and sorted");
|
|
1791
|
+
previousIndexPath = path;
|
|
1792
|
+
assertRetainedArchiveSize(bytes.byteLength, retainedEntryBytes, entry.header.size, limits);
|
|
1793
|
+
if (entry.header.size === void 0 || entry.header.size > limits.maxTotalFileBytes - indexBytes) throw new Error("candidate Git index exceeds maxTotalFileBytes");
|
|
1794
|
+
if (entry.header.size > limits.maxFileBytes) throw new Error("candidate Git index exceeds maxFileBytes");
|
|
1795
|
+
const fileBytes = await readTarEntry(entry, limits.maxFileBytes, `Git index file ${path}`);
|
|
1796
|
+
retainedEntryBytes += fileBytes.byteLength;
|
|
1797
|
+
indexBytes += fileBytes.byteLength;
|
|
1798
|
+
indexFiles.push({
|
|
1799
|
+
path,
|
|
1800
|
+
mode: entry.header.mode,
|
|
1801
|
+
bytes: fileBytes
|
|
1802
|
+
});
|
|
1601
1803
|
} else throw new Error(`candidate workspace tar contains an unsupported entry: ${name}`);
|
|
1602
1804
|
}
|
|
1603
1805
|
if (Boolean(repositoryMetadata) !== Boolean(repositoryBundle)) throw new Error("candidate workspace archive repository evidence is incomplete");
|
|
1604
|
-
|
|
1806
|
+
if (Boolean(repositoryMetadata?.workingTree) !== Boolean(repositoryIndex)) throw new Error("candidate workspace archive repository index evidence is incomplete");
|
|
1807
|
+
const repository = repositoryMetadata && repositoryBundle ? repositoryFromTar(repositoryMetadata, repositoryBundle, repositoryIndex, indexFiles) : void 0;
|
|
1605
1808
|
return {
|
|
1606
1809
|
files,
|
|
1607
1810
|
...repository ? { repository } : {}
|
|
@@ -1615,18 +1818,27 @@ async function parseWorkspaceArchive(bytes, limits) {
|
|
|
1615
1818
|
function assertRetainedArchiveSize(archiveBytes, retainedEntryBytes, entryBytes, limits) {
|
|
1616
1819
|
if (!Number.isSafeInteger(entryBytes) || entryBytes === void 0 || entryBytes < 0 || entryBytes > limits.maxArchiveBytes - archiveBytes - retainedEntryBytes) throw new Error("candidate workspace archive exceeds maxArchiveBytes while decoding");
|
|
1617
1820
|
}
|
|
1618
|
-
function parseRepositoryMetadata(bytes,
|
|
1821
|
+
function parseRepositoryMetadata(bytes, limits) {
|
|
1619
1822
|
let value;
|
|
1620
1823
|
try {
|
|
1621
1824
|
value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
1622
1825
|
} catch (error) {
|
|
1623
1826
|
throw new Error("candidate workspace archive repository metadata is invalid", { cause: error });
|
|
1624
1827
|
}
|
|
1625
|
-
if (!isRecord(value) || Object.keys(value).sort().join(",")
|
|
1828
|
+
if (!isRecord(value) || !["bundle,headCommit,headTree,kind", "bundle,headCommit,headTree,kind,workingTree"].includes(Object.keys(value).sort().join(",")) || value.kind !== archiveKind || typeof value.headCommit !== "string" || typeof value.headTree !== "string" || !isRecord(value.bundle) || Object.keys(value.bundle).sort().join(",") !== "byteLength,sha256" || typeof value.bundle.sha256 !== "string" || !/^sha256:[a-f0-9]{64}$/.test(value.bundle.sha256) || !Number.isSafeInteger(value.bundle.byteLength) || value.bundle.byteLength <= 0 || value.bundle.byteLength > limits.maxRepositoryBundleBytes) throw new Error("candidate workspace archive repository is invalid");
|
|
1626
1829
|
if (!Buffer.from(canonicalCandidateBytes$1(value)).equals(Buffer.from(bytes))) throw new Error("candidate workspace archive repository metadata is not canonical");
|
|
1627
1830
|
assertGitObjectId(value.headCommit, "repository HEAD");
|
|
1628
1831
|
assertGitObjectId(value.headTree, "repository HEAD tree");
|
|
1629
1832
|
if (value.headCommit.length !== value.headTree.length) throw new Error("candidate repository HEAD and tree use different object formats");
|
|
1833
|
+
let workingTree;
|
|
1834
|
+
if ("workingTree" in value) {
|
|
1835
|
+
const working = value.workingTree;
|
|
1836
|
+
if (!isRecord(working) || Object.keys(working).join(",") !== "indexManifest" || !isRecord(working.indexManifest) || Object.keys(working.indexManifest).sort().join(",") !== "byteLength,sha256" || typeof working.indexManifest.sha256 !== "string" || !/^sha256:[a-f0-9]{64}$/.test(working.indexManifest.sha256) || !Number.isSafeInteger(working.indexManifest.byteLength) || working.indexManifest.byteLength < 0 || working.indexManifest.byteLength > limits.maxArchiveBytes) throw new Error("candidate workspace archive repository index is invalid");
|
|
1837
|
+
workingTree = { indexManifest: {
|
|
1838
|
+
sha256: working.indexManifest.sha256,
|
|
1839
|
+
byteLength: working.indexManifest.byteLength
|
|
1840
|
+
} };
|
|
1841
|
+
}
|
|
1630
1842
|
return {
|
|
1631
1843
|
kind: archiveKind,
|
|
1632
1844
|
headCommit: value.headCommit,
|
|
@@ -1634,18 +1846,24 @@ function parseRepositoryMetadata(bytes, maxBundleBytes) {
|
|
|
1634
1846
|
bundle: {
|
|
1635
1847
|
sha256: value.bundle.sha256,
|
|
1636
1848
|
byteLength: value.bundle.byteLength
|
|
1637
|
-
}
|
|
1849
|
+
},
|
|
1850
|
+
...workingTree ? { workingTree } : {}
|
|
1638
1851
|
};
|
|
1639
1852
|
}
|
|
1640
|
-
function repositoryFromTar(metadata, bundle) {
|
|
1853
|
+
function repositoryFromTar(metadata, bundle, indexManifest, indexFiles) {
|
|
1641
1854
|
verifyBytes(bundle, metadata.bundle.sha256, metadata.bundle.byteLength, "candidate Git bundle");
|
|
1855
|
+
if (metadata.workingTree && indexManifest) {
|
|
1856
|
+
verifyBytes(indexManifest, metadata.workingTree.indexManifest.sha256, metadata.workingTree.indexManifest.byteLength, "candidate Git index manifest");
|
|
1857
|
+
if (!Buffer.from(indexManifest).equals(Buffer.from(canonicalCandidateBytes$1(candidateWorkspaceManifest(indexFiles))))) throw new Error("candidate Git index files do not match the captured manifest");
|
|
1858
|
+
}
|
|
1642
1859
|
return {
|
|
1643
1860
|
headCommit: metadata.headCommit,
|
|
1644
1861
|
headTree: metadata.headTree,
|
|
1645
1862
|
bundle: {
|
|
1646
1863
|
...metadata.bundle,
|
|
1647
1864
|
bytes: bundle
|
|
1648
|
-
}
|
|
1865
|
+
},
|
|
1866
|
+
...metadata.workingTree && indexManifest ? { workingTree: { files: indexFiles } } : {}
|
|
1649
1867
|
};
|
|
1650
1868
|
}
|
|
1651
1869
|
async function writeTarEntry(archive, name, mode, bytes) {
|
|
@@ -1693,19 +1911,26 @@ async function streamEqualsBytes(stream, expected, maxBytes, label) {
|
|
|
1693
1911
|
}
|
|
1694
1912
|
return equal && offset === expectedBuffer.byteLength;
|
|
1695
1913
|
}
|
|
1696
|
-
async function prepareEmptyDestination(destination) {
|
|
1697
|
-
await mkdir(destination, {
|
|
1914
|
+
async function prepareEmptyDestination(destination, options = {}) {
|
|
1915
|
+
await mkdir(options.createDestination === false ? dirname(destination) : destination, {
|
|
1698
1916
|
recursive: true,
|
|
1699
1917
|
mode: 448
|
|
1700
1918
|
});
|
|
1701
|
-
|
|
1919
|
+
let stats;
|
|
1920
|
+
try {
|
|
1921
|
+
stats = await lstat(destination);
|
|
1922
|
+
} catch (error) {
|
|
1923
|
+
if (options.createDestination === false && error.code === "ENOENT") return;
|
|
1924
|
+
throw error;
|
|
1925
|
+
}
|
|
1702
1926
|
if (!stats.isDirectory() || stats.isSymbolicLink()) throw new Error("candidate workspace destination must be a real directory");
|
|
1703
1927
|
const resolvedStats = await lstat(await realpath(destination));
|
|
1704
1928
|
if (!resolvedStats.isDirectory() || resolvedStats.isSymbolicLink()) throw new Error("candidate workspace destination must resolve to a real directory");
|
|
1705
1929
|
if ((await readdir(destination)).length > 0) throw new Error("candidate workspace destination must be empty");
|
|
1706
1930
|
}
|
|
1707
|
-
async function writeWorkspaceFiles(destination, files) {
|
|
1931
|
+
async function writeWorkspaceFiles(destination, files, signal) {
|
|
1708
1932
|
for (const file of files) {
|
|
1933
|
+
signal?.throwIfAborted();
|
|
1709
1934
|
const path = workspacePath(destination, file.path);
|
|
1710
1935
|
await mkdir(dirname(path), {
|
|
1711
1936
|
recursive: true,
|
|
@@ -1713,53 +1938,86 @@ async function writeWorkspaceFiles(destination, files) {
|
|
|
1713
1938
|
});
|
|
1714
1939
|
const descriptor = await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0), 384);
|
|
1715
1940
|
try {
|
|
1716
|
-
|
|
1941
|
+
signal?.throwIfAborted();
|
|
1942
|
+
await descriptor.writeFile(file.bytes, { signal });
|
|
1717
1943
|
const stats = await descriptor.stat();
|
|
1718
1944
|
if (!stats.isFile() || stats.nlink !== 1) throw new Error(`candidate workspace file identity changed while writing: ${file.path}`);
|
|
1719
1945
|
await descriptor.chmod(file.mode);
|
|
1946
|
+
signal?.throwIfAborted();
|
|
1720
1947
|
} finally {
|
|
1721
1948
|
await descriptor.close();
|
|
1722
1949
|
}
|
|
1723
1950
|
}
|
|
1724
1951
|
}
|
|
1725
|
-
async function materializeRepository(repository, destination) {
|
|
1952
|
+
async function materializeRepository(repository, destination, limits, signal) {
|
|
1953
|
+
signal?.throwIfAborted();
|
|
1954
|
+
const git = async (args, bytes, options = {}) => {
|
|
1955
|
+
signal?.throwIfAborted();
|
|
1956
|
+
const result = await runCandidateGit(destination, args, bytes, {}, options);
|
|
1957
|
+
signal?.throwIfAborted();
|
|
1958
|
+
return result;
|
|
1959
|
+
};
|
|
1726
1960
|
const temporary = await mkdtemp(join(tmpdir(), "agent-candidate-workspace-bundle-"));
|
|
1727
1961
|
const bundlePath = join(temporary, `${randomUUID()}.bundle`);
|
|
1728
1962
|
try {
|
|
1963
|
+
signal?.throwIfAborted();
|
|
1729
1964
|
await writeFile(bundlePath, repository.bundle.bytes, {
|
|
1730
1965
|
flag: "wx",
|
|
1731
|
-
mode: 384
|
|
1966
|
+
mode: 384,
|
|
1967
|
+
signal
|
|
1732
1968
|
});
|
|
1733
|
-
await
|
|
1969
|
+
await git([
|
|
1734
1970
|
"init",
|
|
1735
1971
|
"--quiet",
|
|
1736
1972
|
"--initial-branch=candidate",
|
|
1737
1973
|
`--object-format=${repository.headCommit.length === 64 ? "sha256" : "sha1"}`
|
|
1738
1974
|
]);
|
|
1739
|
-
await
|
|
1975
|
+
await git([
|
|
1740
1976
|
"bundle",
|
|
1741
1977
|
"verify",
|
|
1742
1978
|
bundlePath
|
|
1743
1979
|
]);
|
|
1744
|
-
await
|
|
1980
|
+
await git([
|
|
1745
1981
|
"bundle",
|
|
1746
1982
|
"unbundle",
|
|
1747
1983
|
bundlePath
|
|
1748
1984
|
]);
|
|
1749
|
-
if ((await
|
|
1985
|
+
if ((await git([
|
|
1750
1986
|
"cat-file",
|
|
1751
1987
|
"-t",
|
|
1752
1988
|
repository.headCommit
|
|
1753
1989
|
])).stdout.toString("utf8").trim() !== "commit") throw new Error("candidate repository HEAD is not a commit");
|
|
1754
|
-
if ((await
|
|
1755
|
-
await
|
|
1990
|
+
if ((await git(["rev-parse", `${repository.headCommit}^{tree}`])).stdout.toString("utf8").trim() !== repository.headTree) throw new Error("candidate repository bundle HEAD tree changed");
|
|
1991
|
+
await git([
|
|
1756
1992
|
"update-ref",
|
|
1757
1993
|
"--no-deref",
|
|
1758
1994
|
"HEAD",
|
|
1759
1995
|
repository.headCommit
|
|
1760
1996
|
]);
|
|
1761
|
-
await
|
|
1762
|
-
if (
|
|
1997
|
+
await git(["read-tree", repository.headTree]);
|
|
1998
|
+
if (repository.workingTree) {
|
|
1999
|
+
await git(["read-tree", "--empty"]);
|
|
2000
|
+
const entries = [];
|
|
2001
|
+
for (const file of repository.workingTree.files) {
|
|
2002
|
+
const object = (await git([
|
|
2003
|
+
"hash-object",
|
|
2004
|
+
"-w",
|
|
2005
|
+
"--stdin"
|
|
2006
|
+
], file.bytes, { maxOutputBytes: 256 })).stdout.toString("utf8").trim();
|
|
2007
|
+
assertGitObjectId(object, "staged blob");
|
|
2008
|
+
entries.push(`${file.mode === 493 ? "100755" : "100644"} ${object}\t${file.path}\0`);
|
|
2009
|
+
}
|
|
2010
|
+
if (entries.length) await git([
|
|
2011
|
+
"update-index",
|
|
2012
|
+
"-z",
|
|
2013
|
+
"--index-info"
|
|
2014
|
+
], Buffer.from(entries.join("")));
|
|
2015
|
+
const observed = await readCandidateGitTreeFiles(destination, (await git(["write-tree"])).stdout.toString("utf8").trim(), {}, limits);
|
|
2016
|
+
signal?.throwIfAborted();
|
|
2017
|
+
if (!Buffer.from(canonicalCandidateBytes$1(candidateWorkspaceManifest(observed))).equals(Buffer.from(canonicalCandidateBytes$1(candidateWorkspaceManifest(repository.workingTree.files))))) throw new Error("candidate repository staged files do not match the captured index");
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
if ((await git([
|
|
1763
2021
|
"status",
|
|
1764
2022
|
"--porcelain=v1",
|
|
1765
2023
|
"--untracked-files=all"
|
|
@@ -2231,6 +2489,6 @@ function asError(error) {
|
|
|
2231
2489
|
return error instanceof Error ? error : new Error(String(error));
|
|
2232
2490
|
}
|
|
2233
2491
|
//#endregion
|
|
2234
|
-
export {
|
|
2492
|
+
export { promptCacheTokenClasses as $, markPutStreamVerified as A, verifyCanonicalCandidateDocument as B, readMaterializedWorkspaceFiles as C, checkInIdleMs as Ct, verifyMaterializedProfileWorkspace as D, teardownSurfaces as Dt, verifyBytes as E, teardownExecutor as Et, deepFreezeCandidate as F, cloneTokenUsage as G, addTokenUsage as H, embeddedCandidateArtifact as I, fnv1a32Hex as J, deleteBoxSafe as K, immutableCandidateValue as L, canonicalCandidateBytes$1 as M, canonicalCandidateDigest$1 as N, verifyMaterializedWorkspace as O, canonicalCandidateDocument as P, mapWithConcurrency as Q, omitTopLevelDigest as R, captureMaterializedWorkspace as S, boundedChildDeadlineAt as St, scanMaterializedWorkspaceManifest as T, singleFlightTeardown as Tt, chargedTokens as U, addSpend as V, cloneSpend as W, isAbortError as X, hasCompleteCacheBreakdown as Y, isAsyncIterable as Z, assertExactObjectKeys as _, DEADLINE_CHECK_IN_MESSAGE as _t, verifyAgentCandidateWorkspaceArtifacts as a, throwAbort as at, artifactCacheKey as b, ROOT_DEADLINE_REASON as bt, captureAgentCandidateWorkspaceFiles as c, withTimeout as ct, workspaceLimits as d, addResourceSpend as dt, randomSuffix as et, persistCandidateOutputArtifact as f, assertResources as ft, verifyTaskOutcomePatch as g, CHILD_DEADLINE_REASON as gt, verifyTaskCheckout as h, ACCEPTED_RESULT_GRACE_MS as ht, readAgentCandidateWorkspaceArtifactFiles as i, stringifySafe as it, verifiedArtifactChunks as j, verifyWorkspaceSnapshotArtifacts as k, createAgentCandidateWorkspacePort as l, zeroSpend as lt, verifyCandidateCode as m, withBudgetResources as mt, captureAgentCandidateWorkspaceTreeToArtifacts as n, roundBoxMinutes as nt, verifyAgentCandidateWorkspaceTree as o, throwIfAborted as ot, readCandidateGitHubResource as p, resourceTelemetry as pt, errorMessage as q, materializeAgentCandidateWorkspaceFromArtifacts as r, sleep as rt, captureAgentCandidateWorkspace as s, unmeteredSpend as st, captureAgentCandidateWorkspaceToArtifacts as t, randomUuid as tt, verifyAgentCandidateWorkspaceArchive as u, zeroTokenUsage as ut, isWellFormedUnicode as v, DEFAULT_CHECK_IN_IDLE_MS as vt, readVerifiedArtifact as w, isDeadlineAbortReason as wt, candidateWorkspaceManifest as x, armDeadlineTimer as xt, WorkspaceScanLimitError as y, DEFAULT_SUCCESSFUL_SHUTDOWN_MS as yt, sha256Bytes$1 as z };
|
|
2235
2493
|
|
|
2236
|
-
//# sourceMappingURL=workspace-streams-
|
|
2494
|
+
//# sourceMappingURL=workspace-streams-DFAhW7hF.js.map
|