@tangle-network/agent-runtime 0.94.5 → 0.94.7

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.
Files changed (72) hide show
  1. package/dist/agent.d.ts +1 -1
  2. package/dist/agent.js +4 -4
  3. package/dist/{agentic-generator-CL1q0H91.d.ts → agentic-generator-1g7GDba7.d.ts} +73 -6
  4. package/dist/analyst-loop.d.ts +1 -1
  5. package/dist/analyst-loop.js +2 -2
  6. package/dist/candidate-execution/index.d.ts +39 -4
  7. package/dist/candidate-execution/index.js +8 -2
  8. package/dist/{chunk-MZH4HORF.js → chunk-5BT2NMML.js} +689 -3
  9. package/dist/chunk-5BT2NMML.js.map +1 -0
  10. package/dist/{chunk-GKZ6DFDN.js → chunk-7HH22XN4.js} +105 -27
  11. package/dist/chunk-7HH22XN4.js.map +1 -0
  12. package/dist/{chunk-JMT5VYY3.js → chunk-7NCP74SL.js} +174 -48
  13. package/dist/chunk-7NCP74SL.js.map +1 -0
  14. package/dist/{chunk-WQA5Y6PD.js → chunk-EP6RVHMX.js} +3 -3
  15. package/dist/chunk-EP6RVHMX.js.map +1 -0
  16. package/dist/{chunk-LWNMCOEA.js → chunk-FRXDOBFP.js} +3 -3
  17. package/dist/chunk-GHXW56PO.js +526 -0
  18. package/dist/chunk-GHXW56PO.js.map +1 -0
  19. package/dist/{chunk-KHLE3C5G.js → chunk-HKMKUESZ.js} +169 -50
  20. package/dist/chunk-HKMKUESZ.js.map +1 -0
  21. package/dist/{chunk-63TIZHMI.js → chunk-KYPVUEJ4.js} +4 -4
  22. package/dist/{chunk-FVJ7M3DA.js → chunk-M22PL4GH.js} +1 -1
  23. package/dist/chunk-M22PL4GH.js.map +1 -0
  24. package/dist/{chunk-4VMRCEI6.js → chunk-MSUWXCHD.js} +2 -2
  25. package/dist/{chunk-ZQZX77MM.js → chunk-QDSOD7RC.js} +2 -2
  26. package/dist/{chunk-RNWDH5Z3.js → chunk-TNUBPPZA.js} +2 -2
  27. package/dist/{completion-gate-CfX2thvL.d.ts → completion-gate-tzwyyD-E.d.ts} +2 -2
  28. package/dist/{coordination-pOGZuYS7.d.ts → coordination-o0TzS7Ms.d.ts} +5 -5
  29. package/dist/environment-provider.d.ts +2 -2
  30. package/dist/{improve-Ciuvu2jh.d.ts → improve-DZeatcs7.d.ts} +19 -8
  31. package/dist/index.d.ts +22 -19
  32. package/dist/index.js +45 -22
  33. package/dist/index.js.map +1 -1
  34. package/dist/intelligence.d.ts +7 -7
  35. package/dist/intelligence.js +42 -18
  36. package/dist/intelligence.js.map +1 -1
  37. package/dist/knowledge.d.ts +7 -7
  38. package/dist/knowledge.js +4 -4
  39. package/dist/lifecycle.d.ts +3 -3
  40. package/dist/lifecycle.js +2 -2
  41. package/dist/{local-harness-CePtFrwu.d.ts → local-harness-ZLMkKdZc.d.ts} +1 -1
  42. package/dist/{loop-runner-bin-B4PwjVaF.d.ts → loop-runner-bin-iTSxSmpv.d.ts} +2 -2
  43. package/dist/loop-runner-bin.d.ts +6 -6
  44. package/dist/loop-runner-bin.js +6 -6
  45. package/dist/loops.d.ts +36 -23
  46. package/dist/loops.js +4 -4
  47. package/dist/mcp/bin.js +3 -3
  48. package/dist/mcp/index.d.ts +10 -10
  49. package/dist/mcp/index.js +5 -5
  50. package/dist/{mcp-serve-verifier-D7hCZIkT.d.ts → mcp-serve-verifier-BO4MEsR3.d.ts} +1 -1
  51. package/dist/{openai-tools-BMOu1t3A.d.ts → openai-tools-0wACz8f8.d.ts} +1 -1
  52. package/dist/{prepare-BKxAiUcH.d.ts → prepare-DIeVgQG3.d.ts} +1 -1
  53. package/dist/profiles.d.ts +1 -1
  54. package/dist/{sanitize-Dr3SliRC.d.ts → sanitize-Dcbjp0tU.d.ts} +1 -1
  55. package/dist/{supervise-Y3w878fN.d.ts → supervise-CRwaJIkd.d.ts} +4 -4
  56. package/dist/{types-Kjr5W6OF.d.ts → types-CKmyZ9TP.d.ts} +4 -7
  57. package/dist/{types-DHLXdLVN.d.ts → types-CogNCaw7.d.ts} +1 -1
  58. package/dist/{worktree-fanout-DmBvR-_O.d.ts → worktree-fanout-BJy24LYe.d.ts} +4 -4
  59. package/package.json +6 -4
  60. package/dist/chunk-4WWSICFY.js +0 -210
  61. package/dist/chunk-4WWSICFY.js.map +0 -1
  62. package/dist/chunk-FVJ7M3DA.js.map +0 -1
  63. package/dist/chunk-GKZ6DFDN.js.map +0 -1
  64. package/dist/chunk-JMT5VYY3.js.map +0 -1
  65. package/dist/chunk-KHLE3C5G.js.map +0 -1
  66. package/dist/chunk-MZH4HORF.js.map +0 -1
  67. package/dist/chunk-WQA5Y6PD.js.map +0 -1
  68. /package/dist/{chunk-LWNMCOEA.js.map → chunk-FRXDOBFP.js.map} +0 -0
  69. /package/dist/{chunk-63TIZHMI.js.map → chunk-KYPVUEJ4.js.map} +0 -0
  70. /package/dist/{chunk-4VMRCEI6.js.map → chunk-MSUWXCHD.js.map} +0 -0
  71. /package/dist/{chunk-ZQZX77MM.js.map → chunk-QDSOD7RC.js.map} +0 -0
  72. /package/dist/{chunk-RNWDH5Z3.js.map → chunk-TNUBPPZA.js.map} +0 -0
@@ -1442,8 +1442,23 @@ async function verifyMaterializedWorkspace(root, expected, options = {}) {
1442
1442
  const observed = await scanWorkspace(root, new Set(options.ignoredProtectedRootEntries ?? []));
1443
1443
  assertWorkspaceManifest(observed.manifest, expected);
1444
1444
  }
1445
+ async function captureMaterializedWorkspace(root, options = {}) {
1446
+ const observed = await scanWorkspace(
1447
+ root,
1448
+ new Set(options.ignoredProtectedRootEntries ?? []),
1449
+ options.limits
1450
+ );
1451
+ return {
1452
+ manifest: observed.manifest,
1453
+ files: observed.files.map((file) => ({
1454
+ path: file.path,
1455
+ mode: file.mode,
1456
+ bytes: Uint8Array.from(file.bytes)
1457
+ }))
1458
+ };
1459
+ }
1445
1460
  async function readMaterializedWorkspaceFiles(root, expected, options = {}) {
1446
- const observed = await scanWorkspace(root, new Set(options.ignoredProtectedRootEntries ?? []));
1461
+ const observed = await captureMaterializedWorkspace(root, options);
1447
1462
  assertWorkspaceManifest(observed.manifest, expected);
1448
1463
  return observed.files.map(
1449
1464
  (file) => Object.freeze({ path: file.path, mode: file.mode, bytes: Uint8Array.from(file.bytes) })
@@ -1469,7 +1484,7 @@ async function verifyMaterializedProfileWorkspace(root, expected) {
1469
1484
  throw new Error("profile staging files, modes, or bytes do not match the signed profile plan");
1470
1485
  }
1471
1486
  }
1472
- async function scanWorkspace(root, ignoredProtectedRootEntries) {
1487
+ async function scanWorkspace(root, ignoredProtectedRootEntries, limits) {
1473
1488
  const absoluteRoot = resolve(root);
1474
1489
  const rootStats = await lstat(absoluteRoot);
1475
1490
  if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) {
@@ -1480,6 +1495,7 @@ async function scanWorkspace(root, ignoredProtectedRootEntries) {
1480
1495
  }
1481
1496
  const files = [];
1482
1497
  const capturedFiles = [];
1498
+ let totalBytes = 0;
1483
1499
  async function visit(directory) {
1484
1500
  const entries = await readdir(directory, { withFileTypes: true });
1485
1501
  entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
@@ -1503,6 +1519,9 @@ async function scanWorkspace(root, ignoredProtectedRootEntries) {
1503
1519
  if (!stats.isFile()) {
1504
1520
  throw new Error(`workspace contains a non-regular entry: ${relPath}`);
1505
1521
  }
1522
+ if (limits && files.length >= limits.maxFiles) {
1523
+ throw new Error("workspace exceeds maxFiles");
1524
+ }
1506
1525
  const descriptor = await open(
1507
1526
  absolute,
1508
1527
  fsConstants.O_RDONLY | (typeof fsConstants.O_NOFOLLOW === "number" ? fsConstants.O_NOFOLLOW : 0)
@@ -1519,7 +1538,19 @@ async function scanWorkspace(root, ignoredProtectedRootEntries) {
1519
1538
  if (mode !== 420 && mode !== 493) {
1520
1539
  throw new Error(`workspace file has unsupported mode ${mode.toString(8)}: ${relPath}`);
1521
1540
  }
1522
- const bytes = await descriptor.readFile();
1541
+ if (limits && openedStats.size > limits.maxFileBytes) {
1542
+ throw new Error(`workspace file exceeds maxFileBytes: ${relPath}`);
1543
+ }
1544
+ const remainingBytes = limits ? limits.maxTotalFileBytes - totalBytes : void 0;
1545
+ if (remainingBytes !== void 0 && openedStats.size > remainingBytes) {
1546
+ throw new Error("workspace exceeds maxTotalFileBytes");
1547
+ }
1548
+ const bytes = await readBoundedFile(
1549
+ descriptor,
1550
+ limits ? Math.min(limits.maxFileBytes, remainingBytes ?? limits.maxFileBytes) : void 0,
1551
+ relPath
1552
+ );
1553
+ totalBytes += bytes.byteLength;
1523
1554
  const supportedMode = mode;
1524
1555
  files.push({
1525
1556
  path: relPath,
@@ -1545,6 +1576,21 @@ async function scanWorkspace(root, ignoredProtectedRootEntries) {
1545
1576
  files: capturedFiles
1546
1577
  };
1547
1578
  }
1579
+ async function readBoundedFile(descriptor, maxBytes, path) {
1580
+ if (maxBytes === void 0) return await descriptor.readFile();
1581
+ const chunks = [];
1582
+ let total = 0;
1583
+ while (true) {
1584
+ const remaining = maxBytes - total;
1585
+ const chunk = Buffer.allocUnsafe(Math.min(64 * 1024, remaining + 1));
1586
+ const { bytesRead } = await descriptor.read(chunk, 0, chunk.byteLength, null);
1587
+ if (bytesRead === 0) break;
1588
+ total += bytesRead;
1589
+ if (total > maxBytes) throw new Error(`workspace file exceeds its capture limit: ${path}`);
1590
+ chunks.push(chunk.subarray(0, bytesRead));
1591
+ }
1592
+ return Buffer.concat(chunks, total);
1593
+ }
1548
1594
 
1549
1595
  // src/candidate-execution/git-materialize.ts
1550
1596
  import { spawn } from "child_process";
@@ -1563,16 +1609,18 @@ async function verifyCandidateCode(code, repositories, patchBytes) {
1563
1609
  const temporary = await mkdtemp(join(tmpdir(), "agent-candidate-git-"));
1564
1610
  try {
1565
1611
  const indexFile = join(temporary, "index");
1566
- await git(repositoryRoot, ["read-tree", code.baseTree], void 0, {
1612
+ await runCandidateGit(repositoryRoot, ["read-tree", code.baseTree], void 0, {
1567
1613
  GIT_INDEX_FILE: indexFile
1568
1614
  });
1569
- await git(
1615
+ await runCandidateGit(
1570
1616
  repositoryRoot,
1571
1617
  ["apply", "--cached", "--binary", "--whitespace=nowarn", "-"],
1572
1618
  patchBytes,
1573
1619
  { GIT_INDEX_FILE: indexFile }
1574
1620
  );
1575
- const candidateTree = (await git(repositoryRoot, ["write-tree"], void 0, { GIT_INDEX_FILE: indexFile })).stdout.toString("utf8").trim();
1621
+ const candidateTree = (await runCandidateGit(repositoryRoot, ["write-tree"], void 0, {
1622
+ GIT_INDEX_FILE: indexFile
1623
+ })).stdout.toString("utf8").trim();
1576
1624
  if (candidateTree !== code.candidateTree) {
1577
1625
  throw new Error(
1578
1626
  `git patch materialized tree ${candidateTree} does not match ${code.candidateTree}`
@@ -1586,11 +1634,11 @@ async function verifyCandidateCode(code, repositories, patchBytes) {
1586
1634
  }
1587
1635
  async function readCandidateGitHubResource(resource, repositories) {
1588
1636
  const repositoryRoot = await verifiedRepositoryRoot(resource.repository, repositories);
1589
- const commitType = (await git(repositoryRoot, ["cat-file", "-t", resource.commit])).stdout.toString("utf8").trim();
1637
+ const commitType = (await runCandidateGit(repositoryRoot, ["cat-file", "-t", resource.commit])).stdout.toString("utf8").trim();
1590
1638
  if (commitType !== "commit") {
1591
1639
  throw new Error(`GitHub resource commit is not a commit object: ${resource.commit}`);
1592
1640
  }
1593
- const listing = (await git(repositoryRoot, ["ls-tree", "-z", resource.commit, "--", resource.path])).stdout;
1641
+ const listing = (await runCandidateGit(repositoryRoot, ["ls-tree", "-z", resource.commit, "--", resource.path])).stdout;
1594
1642
  const entries = parseTreeEntries(listing);
1595
1643
  if (entries.length !== 1 || entries[0]?.path !== resource.path) {
1596
1644
  throw new Error(`GitHub resource path is not one exact file: ${resource.path}`);
@@ -1599,17 +1647,17 @@ async function readCandidateGitHubResource(resource, repositories) {
1599
1647
  if (!entry || entry.type !== "blob" || entry.mode !== "100644" && entry.mode !== "100755") {
1600
1648
  throw new Error(`GitHub resource path is not a regular Git blob: ${resource.path}`);
1601
1649
  }
1602
- const bytes = (await git(repositoryRoot, ["cat-file", "blob", entry.object])).stdout;
1650
+ const bytes = (await runCandidateGit(repositoryRoot, ["cat-file", "blob", entry.object])).stdout;
1603
1651
  verifyBytes(bytes, resource.sha256, resource.byteLength, `GitHub resource ${resource.path}`);
1604
1652
  return Uint8Array.from(bytes);
1605
1653
  }
1606
1654
  async function verifyTaskCheckout(taskRoot, expected) {
1607
1655
  const root = resolve2(taskRoot);
1608
- const head = (await git(root, ["rev-parse", "HEAD"])).stdout.toString("utf8").trim();
1656
+ const head = (await runCandidateGit(root, ["rev-parse", "HEAD"])).stdout.toString("utf8").trim();
1609
1657
  if (head !== expected.baseCommit) {
1610
1658
  throw new Error(`task checkout HEAD ${head} does not match ${expected.baseCommit}`);
1611
1659
  }
1612
- const tree = (await git(root, ["rev-parse", "HEAD^{tree}"])).stdout.toString("utf8").trim();
1660
+ const tree = (await runCandidateGit(root, ["rev-parse", "HEAD^{tree}"])).stdout.toString("utf8").trim();
1613
1661
  if (tree !== expected.baseTree) {
1614
1662
  throw new Error(`task checkout base tree ${tree} does not match ${expected.baseTree}`);
1615
1663
  }
@@ -1618,7 +1666,7 @@ async function verifyTaskOutcomePatch(input) {
1618
1666
  const repositoryRoot = resolve2(input.repositoryRoot);
1619
1667
  await verifyTaskCheckout(repositoryRoot, input);
1620
1668
  const gitDir = resolve2(
1621
- (await git(repositoryRoot, ["rev-parse", "--absolute-git-dir"])).stdout.toString("utf8").trim()
1669
+ (await runCandidateGit(repositoryRoot, ["rev-parse", "--absolute-git-dir"])).stdout.toString("utf8").trim()
1622
1670
  );
1623
1671
  if (await realpath2(gitDir) !== gitDir || gitDir.includes(":")) {
1624
1672
  throw new Error("task Git object store has an unsupported path");
@@ -1634,16 +1682,16 @@ async function verifyTaskOutcomePatch(input) {
1634
1682
  GIT_OBJECT_DIRECTORY: objectDirectory,
1635
1683
  GIT_ALTERNATE_OBJECT_DIRECTORIES: join(gitDir, "objects")
1636
1684
  };
1637
- await git(repositoryRoot, ["read-tree", input.baseTree], void 0, gitEnvironment);
1685
+ await runCandidateGit(repositoryRoot, ["read-tree", input.baseTree], void 0, gitEnvironment);
1638
1686
  if (input.patch.byteLength > 0) {
1639
- await git(
1687
+ await runCandidateGit(
1640
1688
  repositoryRoot,
1641
1689
  ["apply", "--cached", "--binary", "--whitespace=nowarn", "-"],
1642
1690
  input.patch,
1643
1691
  gitEnvironment
1644
1692
  );
1645
1693
  }
1646
- const resultTree = (await git(repositoryRoot, ["write-tree"], void 0, gitEnvironment)).stdout.toString("utf8").trim();
1694
+ const resultTree = (await runCandidateGit(repositoryRoot, ["write-tree"], void 0, gitEnvironment)).stdout.toString("utf8").trim();
1647
1695
  if (resultTree !== input.resultTree) {
1648
1696
  throw new Error(
1649
1697
  `task outcome patch materialized tree ${resultTree} does not match ${input.resultTree}`
@@ -1656,7 +1704,7 @@ async function verifyTaskOutcomePatch(input) {
1656
1704
  )) {
1657
1705
  throw new Error("task outcome after-state does not match the materialized result tree");
1658
1706
  }
1659
- const resultCommit = (await git(
1707
+ const resultCommit = (await runCandidateGit(
1660
1708
  repositoryRoot,
1661
1709
  ["commit-tree", resultTree, "-p", input.baseCommit],
1662
1710
  Buffer.from("candidate task outcome\n", "utf8"),
@@ -1670,7 +1718,12 @@ async function verifyTaskOutcomePatch(input) {
1670
1718
  GIT_COMMITTER_DATE: "2000-01-01T00:00:00Z"
1671
1719
  }
1672
1720
  )).stdout.toString("utf8").trim();
1673
- const committedTree = (await git(repositoryRoot, ["rev-parse", `${resultCommit}^{tree}`], void 0, gitEnvironment)).stdout.toString("utf8").trim();
1721
+ const committedTree = (await runCandidateGit(
1722
+ repositoryRoot,
1723
+ ["rev-parse", `${resultCommit}^{tree}`],
1724
+ void 0,
1725
+ gitEnvironment
1726
+ )).stdout.toString("utf8").trim();
1674
1727
  if (committedTree !== resultTree) {
1675
1728
  throw new Error("task outcome evaluator commit does not bind the verified result tree");
1676
1729
  }
@@ -1683,41 +1736,55 @@ async function verifiedRepositoryRoot(repository, repositories) {
1683
1736
  const repositoryRoot = resolve2(await repositories.resolve(repository));
1684
1737
  const rootStats = await stat(repositoryRoot);
1685
1738
  if (!rootStats.isDirectory()) throw new Error("candidate repository path is not a directory");
1686
- const origin = (await git(repositoryRoot, ["remote", "get-url", "origin"])).stdout.toString("utf8").trim();
1739
+ const origin = (await runCandidateGit(repositoryRoot, ["remote", "get-url", "origin"])).stdout.toString("utf8").trim();
1687
1740
  const actual = parseGitHubRemote(origin);
1688
1741
  if (!actual || actual.owner !== repository.owner || actual.repo !== repository.repo) {
1689
1742
  throw new Error(
1690
1743
  `local repository origin ${origin || "<missing>"} does not match github.com/${repository.owner}/${repository.repo}`
1691
1744
  );
1692
1745
  }
1693
- const gitDirText = (await git(repositoryRoot, ["rev-parse", "--absolute-git-dir"])).stdout.toString("utf8").trim();
1746
+ const gitDirText = (await runCandidateGit(repositoryRoot, ["rev-parse", "--absolute-git-dir"])).stdout.toString("utf8").trim();
1694
1747
  const gitDir = resolve2(gitDirText);
1695
1748
  await assertNoGitIndirection(repositoryRoot, gitDir, "candidate repository");
1696
1749
  return repositoryRoot;
1697
1750
  }
1698
1751
  async function assertNoGitIndirection(repositoryRoot, gitDir, label) {
1699
- const replacements = (await git(repositoryRoot, ["for-each-ref", "--format=%(refname)", "refs/replace"])).stdout.toString("utf8").trim();
1752
+ const replacements = (await runCandidateGit(repositoryRoot, ["for-each-ref", "--format=%(refname)", "refs/replace"])).stdout.toString("utf8").trim();
1700
1753
  if (replacements) throw new Error(`${label} contains Git replace refs`);
1701
- for (const name of ["alternates", "http-alternates"]) {
1702
- const path = join(gitDir, "objects", "info", name);
1703
- try {
1704
- const contents = await readFile2(path, "utf8");
1705
- if (contents.trim()) throw new Error(`${label} uses forbidden Git ${name}`);
1706
- } catch (error) {
1707
- if (!isNoEntry(error)) throw error;
1754
+ const commonDir = resolve2(
1755
+ repositoryRoot,
1756
+ (await runCandidateGit(repositoryRoot, ["rev-parse", "--git-common-dir"])).stdout.toString("utf8").trim()
1757
+ );
1758
+ if (await realpath2(commonDir) !== commonDir || commonDir.includes(":")) {
1759
+ throw new Error(`${label} Git common directory has an unsupported path`);
1760
+ }
1761
+ for (const objectRoot of /* @__PURE__ */ new Set([gitDir, commonDir])) {
1762
+ for (const name of ["alternates", "http-alternates"]) {
1763
+ const path = join(objectRoot, "objects", "info", name);
1764
+ try {
1765
+ const contents = await readFile2(path, "utf8");
1766
+ if (contents.trim()) throw new Error(`${label} uses forbidden Git ${name}`);
1767
+ } catch (error) {
1768
+ if (!isNoEntry(error)) throw error;
1769
+ }
1708
1770
  }
1709
1771
  }
1710
1772
  }
1711
1773
  async function assertCommitAndBaseTree(repositoryRoot, commit, expectedTree) {
1712
- const type = (await git(repositoryRoot, ["cat-file", "-t", commit])).stdout.toString("utf8").trim();
1774
+ const type = (await runCandidateGit(repositoryRoot, ["cat-file", "-t", commit])).stdout.toString("utf8").trim();
1713
1775
  if (type !== "commit") throw new Error(`candidate base object is not a commit: ${commit}`);
1714
- const actualTree = (await git(repositoryRoot, ["rev-parse", `${commit}^{tree}`])).stdout.toString("utf8").trim();
1776
+ const actualTree = (await runCandidateGit(repositoryRoot, ["rev-parse", `${commit}^{tree}`])).stdout.toString("utf8").trim();
1715
1777
  if (actualTree !== expectedTree) {
1716
1778
  throw new Error(`candidate base commit tree ${actualTree} does not match ${expectedTree}`);
1717
1779
  }
1718
1780
  }
1719
1781
  async function assertSafeTree(repositoryRoot, tree, environment = {}) {
1720
- const listing = (await git(repositoryRoot, ["ls-tree", "-rz", "--full-tree", tree], void 0, environment)).stdout;
1782
+ const listing = (await runCandidateGit(
1783
+ repositoryRoot,
1784
+ ["ls-tree", "-rz", "--full-tree", tree],
1785
+ void 0,
1786
+ environment
1787
+ )).stdout;
1721
1788
  const entries = parseTreeEntries(listing);
1722
1789
  if (entries.length === 0) throw new Error("candidate Git tree cannot be empty");
1723
1790
  for (const entry of entries) {
@@ -1730,29 +1797,65 @@ async function assertSafeTree(repositoryRoot, tree, environment = {}) {
1730
1797
  }
1731
1798
  }
1732
1799
  async function workspaceManifestFromGitTree(repositoryRoot, tree, environment) {
1733
- const listing = (await git(repositoryRoot, ["ls-tree", "-rz", "--full-tree", tree], void 0, environment)).stdout;
1734
- const entries = parseTreeEntries(listing);
1735
- const files = await Promise.all(
1736
- entries.map(async (entry) => {
1737
- if (entry.type !== "blob" || entry.mode !== "100644" && entry.mode !== "100755") {
1738
- throw new Error(`task outcome tree contains a non-regular file: ${entry.path}`);
1739
- }
1740
- const bytes = (await git(repositoryRoot, ["cat-file", "blob", entry.object], void 0, environment)).stdout;
1741
- return {
1742
- path: entry.path,
1743
- mode: entry.mode === "100755" ? 493 : 420,
1744
- sha256: sha256Bytes(bytes),
1745
- byteLength: bytes.byteLength
1746
- };
1800
+ const files = (await readCandidateGitTreeFiles(repositoryRoot, tree, environment)).map(
1801
+ ({ path, mode, bytes }) => ({
1802
+ path,
1803
+ mode,
1804
+ sha256: sha256Bytes(bytes),
1805
+ byteLength: bytes.byteLength
1747
1806
  })
1748
1807
  );
1749
- files.sort((left, right) => left.path.localeCompare(right.path));
1750
1808
  return {
1751
1809
  schemaVersion: 1,
1752
1810
  kind: "agent-candidate-workspace-manifest",
1753
1811
  files
1754
1812
  };
1755
1813
  }
1814
+ async function readCandidateGitTreeFiles(repositoryRoot, tree, environment = {}, limits) {
1815
+ const listing = (await runCandidateGit(
1816
+ repositoryRoot,
1817
+ ["ls-tree", "-rzl", "--full-tree", tree],
1818
+ void 0,
1819
+ environment
1820
+ )).stdout;
1821
+ const files = [];
1822
+ const entries = parseTreeEntries(listing);
1823
+ if (limits && entries.length > limits.maxFiles) {
1824
+ throw new Error("candidate Git tree exceeds maxFiles");
1825
+ }
1826
+ let totalBytes = 0;
1827
+ for (const entry of entries) {
1828
+ if (entry.type !== "blob" || entry.mode !== "100644" && entry.mode !== "100755") {
1829
+ throw new Error(`candidate Git tree contains a non-regular file: ${entry.path}`);
1830
+ }
1831
+ assertSafeGitPath(entry.path);
1832
+ if (entry.size === void 0) {
1833
+ throw new Error(`candidate Git tree is missing blob size: ${entry.path}`);
1834
+ }
1835
+ if (limits && entry.size > limits.maxFileBytes) {
1836
+ throw new Error(`candidate Git tree file exceeds maxFileBytes: ${entry.path}`);
1837
+ }
1838
+ totalBytes += entry.size;
1839
+ if (limits && totalBytes > limits.maxTotalFileBytes) {
1840
+ throw new Error("candidate Git tree exceeds maxTotalFileBytes");
1841
+ }
1842
+ const bytes = (await runCandidateGit(
1843
+ repositoryRoot,
1844
+ ["cat-file", "blob", entry.object],
1845
+ void 0,
1846
+ environment
1847
+ )).stdout;
1848
+ if (bytes.byteLength !== entry.size) {
1849
+ throw new Error(`candidate Git blob size changed: ${entry.path}`);
1850
+ }
1851
+ files.push({
1852
+ path: entry.path,
1853
+ mode: entry.mode === "100755" ? 493 : 420,
1854
+ bytes: Uint8Array.from(bytes)
1855
+ });
1856
+ }
1857
+ return files.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
1858
+ }
1756
1859
  function parseTreeEntries(bytes) {
1757
1860
  const raw = Buffer.from(bytes);
1758
1861
  const decoded = raw.toString("utf8");
@@ -1762,13 +1865,17 @@ function parseTreeEntries(bytes) {
1762
1865
  const rows = decoded.split("\0").filter(Boolean);
1763
1866
  return rows.map((row) => {
1764
1867
  const tab = row.indexOf(" ");
1765
- const header = row.slice(0, tab).split(" ");
1868
+ const header = row.slice(0, tab).split(" ").filter(Boolean);
1766
1869
  const path = row.slice(tab + 1);
1767
- const [mode, type, object] = header;
1870
+ const [mode, type, object, sizeText] = header;
1768
1871
  if (tab < 1 || !mode || !type || !object || !path) {
1769
1872
  throw new Error("malformed Git tree entry");
1770
1873
  }
1771
- return { mode, type, object, path };
1874
+ const size = sizeText && /^\d+$/.test(sizeText) ? Number(sizeText) : void 0;
1875
+ if (size !== void 0 && !Number.isSafeInteger(size)) {
1876
+ throw new Error("candidate Git tree entry size exceeds the safe integer range");
1877
+ }
1878
+ return { mode, type, object, ...size === void 0 ? {} : { size }, path };
1772
1879
  });
1773
1880
  }
1774
1881
  function assertSafeGitPath(path) {
@@ -1790,7 +1897,7 @@ function parseGitHubRemote(value) {
1790
1897
  if (!match?.[1] || !match[2]) return void 0;
1791
1898
  return { owner: match[1], repo: match[2] };
1792
1899
  }
1793
- async function git(repositoryRoot, args, input, extraEnv = {}) {
1900
+ async function runCandidateGit(repositoryRoot, args, input, extraEnv = {}) {
1794
1901
  const env = Object.fromEntries(
1795
1902
  Object.entries(process.env).filter(([name]) => !name.startsWith("GIT_"))
1796
1903
  );
@@ -1807,6 +1914,10 @@ async function git(repositoryRoot, args, input, extraEnv = {}) {
1807
1914
  "-c",
1808
1915
  "core.hooksPath=/dev/null",
1809
1916
  "-c",
1917
+ "core.fsmonitor=false",
1918
+ "-c",
1919
+ "core.untrackedCache=false",
1920
+ "-c",
1810
1921
  "protocol.file.allow=never",
1811
1922
  "-C",
1812
1923
  repositoryRoot,
@@ -5032,12 +5143,14 @@ function errorMessage2(error) {
5032
5143
  }
5033
5144
 
5034
5145
  export {
5146
+ sha256Bytes,
5035
5147
  canonicalCandidateBytes,
5036
5148
  canonicalCandidateDigest,
5037
5149
  immutableCandidateValue,
5038
5150
  canonicalCandidateDocument,
5039
5151
  embeddedCandidateArtifact,
5040
5152
  omitTopLevelDigest,
5153
+ deepFreezeCandidate,
5041
5154
  sealAgentCandidateBundle,
5042
5155
  freezeGenericAgentCandidateProfile,
5043
5156
  assertCandidateProfileBinding,
@@ -5063,6 +5176,12 @@ export {
5063
5176
  candidateCleanupTimeout,
5064
5177
  candidateCleanupDeadline,
5065
5178
  withinCandidateCleanupDeadline,
5179
+ verifyBytes,
5180
+ verifyMaterializedWorkspace,
5181
+ captureMaterializedWorkspace,
5182
+ assertNoGitIndirection,
5183
+ readCandidateGitTreeFiles,
5184
+ runCandidateGit,
5066
5185
  CANDIDATE_TRACE_TAGS,
5067
5186
  CANDIDATE_TRACE_ENV,
5068
5187
  assertPreparedCandidateIntegrity,
@@ -5081,4 +5200,4 @@ export {
5081
5200
  verifyAgentCandidateBundle,
5082
5201
  prepareAgentCandidateExecution
5083
5202
  };
5084
- //# sourceMappingURL=chunk-KHLE3C5G.js.map
5203
+ //# sourceMappingURL=chunk-HKMKUESZ.js.map