@tangle-network/agent-runtime 0.105.0 → 0.106.1

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 (218) hide show
  1. package/README.md +2 -2
  2. package/dist/activation-CRjVfOiy.js +203 -0
  3. package/dist/activation-CRjVfOiy.js.map +1 -0
  4. package/dist/activation-DyWB0K6E.d.ts +98 -0
  5. package/dist/agent.d.ts +216 -234
  6. package/dist/agent.js +615 -547
  7. package/dist/agent.js.map +1 -1
  8. package/dist/analyst-loop-DGdtVENg.js +517 -0
  9. package/dist/analyst-loop-DGdtVENg.js.map +1 -0
  10. package/dist/analyst-loop.d.ts +10 -43
  11. package/dist/analyst-loop.js +2 -11
  12. package/dist/backends-CiOCyRHb.js +743 -0
  13. package/dist/backends-CiOCyRHb.js.map +1 -0
  14. package/dist/candidate-execution/index.d.ts +4 -192
  15. package/dist/candidate-execution/index.js +5 -66
  16. package/dist/candidate-execution-DqMbv1rU.js +488 -0
  17. package/dist/candidate-execution-DqMbv1rU.js.map +1 -0
  18. package/dist/coder-yhVWbdWc.js +40 -0
  19. package/dist/coder-yhVWbdWc.js.map +1 -0
  20. package/dist/conversation-BpLQZGPH.js +1265 -0
  21. package/dist/conversation-BpLQZGPH.js.map +1 -0
  22. package/dist/conversation.d.ts +2 -804
  23. package/dist/conversation.js +2 -55
  24. package/dist/environment-provider-CfLUmKmf.js +1168 -0
  25. package/dist/environment-provider-CfLUmKmf.js.map +1 -0
  26. package/dist/environment-provider-IUGU3epE.d.ts +964 -0
  27. package/dist/environment-provider.d.ts +2 -78
  28. package/dist/environment-provider.js +2 -18
  29. package/dist/errors-DEAvWQPy.js +111 -0
  30. package/dist/errors-DEAvWQPy.js.map +1 -0
  31. package/dist/improvement-adapter-Cr5TBSji.d.ts +166 -0
  32. package/dist/improvement-cycle-C095kS_g.js +2624 -0
  33. package/dist/improvement-cycle-C095kS_g.js.map +1 -0
  34. package/dist/index-BGdxAwfO.d.ts +838 -0
  35. package/dist/index-C-FYUuFG.d.ts +193 -0
  36. package/dist/index-CbNM40xG.d.ts +140 -0
  37. package/dist/index-DruSKs3Z.d.ts +7224 -0
  38. package/dist/index-Efjb3nrQ.d.ts +671 -0
  39. package/dist/index.d.ts +14 -1058
  40. package/dist/index.js +2106 -2082
  41. package/dist/index.js.map +1 -1
  42. package/dist/intelligence.d.ts +768 -889
  43. package/dist/intelligence.js +1466 -1367
  44. package/dist/intelligence.js.map +1 -1
  45. package/dist/{kb-gate-CwHO0vz6.d.ts → kb-gate-C8z2juK8.d.ts} +33 -31
  46. package/dist/kb-gate-DpaSwXVx.js +80 -0
  47. package/dist/kb-gate-DpaSwXVx.js.map +1 -0
  48. package/dist/knowledge-Ku-mPP4f.js +433 -0
  49. package/dist/knowledge-Ku-mPP4f.js.map +1 -0
  50. package/dist/knowledge.d.ts +2 -150
  51. package/dist/knowledge.js +2 -40
  52. package/dist/local-harness-Dh8PJ0ot.d.ts +455 -0
  53. package/dist/loop-runner-bin-BXsFEUcf.d.ts +162 -0
  54. package/dist/loop-runner-bin-CRagyuNb.js +268 -0
  55. package/dist/loop-runner-bin-CRagyuNb.js.map +1 -0
  56. package/dist/loop-runner-bin.d.ts +2 -15
  57. package/dist/loop-runner-bin.js +2 -24
  58. package/dist/loops.d.ts +5 -4164
  59. package/dist/loops.js +8 -419
  60. package/dist/mcp/bin.d.ts +1 -1
  61. package/dist/mcp/bin.js +116 -146
  62. package/dist/mcp/bin.js.map +1 -1
  63. package/dist/mcp/index.d.ts +295 -436
  64. package/dist/mcp/index.js +1242 -1177
  65. package/dist/mcp/index.js.map +1 -1
  66. package/dist/mcp/memory-bin.d.ts +1 -1
  67. package/dist/mcp/memory-bin.js +37 -16
  68. package/dist/mcp/memory-bin.js.map +1 -1
  69. package/dist/memory-server-DL6cE2Ag.js +234 -0
  70. package/dist/memory-server-DL6cE2Ag.js.map +1 -0
  71. package/dist/model-resolution-Btd9iIKV.js +98 -0
  72. package/dist/model-resolution-Btd9iIKV.js.map +1 -0
  73. package/dist/openai-tools-B68JaOCx.d.ts +24 -0
  74. package/dist/openai-tools-CKLy1C7M.js +44 -0
  75. package/dist/openai-tools-CKLy1C7M.js.map +1 -0
  76. package/dist/otel-export-D34IQW1C.js +843 -0
  77. package/dist/otel-export-D34IQW1C.js.map +1 -0
  78. package/dist/platform.d.ts +188 -185
  79. package/dist/platform.js +185 -218
  80. package/dist/platform.js.map +1 -1
  81. package/dist/prepare-B53sPV7M.js +4292 -0
  82. package/dist/prepare-B53sPV7M.js.map +1 -0
  83. package/dist/primeintellect/index.d.ts +149 -145
  84. package/dist/primeintellect/index.js +626 -1003
  85. package/dist/primeintellect/index.js.map +1 -1
  86. package/dist/profiles.d.ts +296 -490
  87. package/dist/profiles.js +722 -749
  88. package/dist/profiles.js.map +1 -1
  89. package/dist/protected-model-port-BLPH5VVv.js +722 -0
  90. package/dist/protected-model-port-BLPH5VVv.js.map +1 -0
  91. package/dist/protected-model-port-BP6Z4eau.d.ts +283 -0
  92. package/dist/protected-redaction--F3v1oo8.js +200 -0
  93. package/dist/protected-redaction--F3v1oo8.js.map +1 -0
  94. package/dist/redact-D-u-rrcn.js +82 -0
  95. package/dist/redact-D-u-rrcn.js.map +1 -0
  96. package/dist/redact-kbIOjfjM.d.ts +452 -0
  97. package/dist/researcher-CoVqNhfI.js +433 -0
  98. package/dist/researcher-CoVqNhfI.js.map +1 -0
  99. package/dist/runtime-5zM5XxLr.js +5408 -0
  100. package/dist/runtime-5zM5XxLr.js.map +1 -0
  101. package/dist/sandbox-events-DeI5xX8P.js +316 -0
  102. package/dist/sandbox-events-DeI5xX8P.js.map +1 -0
  103. package/dist/spawn-journal-CwPvKUTa.js +456 -0
  104. package/dist/spawn-journal-CwPvKUTa.js.map +1 -0
  105. package/dist/structural-rollout-IXUEplky.js +1445 -0
  106. package/dist/structural-rollout-IXUEplky.js.map +1 -0
  107. package/dist/substrate-B0TYNrXn.js +27 -0
  108. package/dist/substrate-B0TYNrXn.js.map +1 -0
  109. package/dist/{substrate-Dyiqmd3o.d.ts → substrate-BcnuSHXm.d.ts} +57 -54
  110. package/dist/supervise-BiRutHS9.js +7321 -0
  111. package/dist/supervise-BiRutHS9.js.map +1 -0
  112. package/dist/supervisor-DTKhF-RV.js +3826 -0
  113. package/dist/supervisor-DTKhF-RV.js.map +1 -0
  114. package/dist/testing.d.ts +4 -3
  115. package/dist/testing.js +2478 -2637
  116. package/dist/testing.js.map +1 -1
  117. package/dist/tool-server-RcWgLIsL.js +141 -0
  118. package/dist/tool-server-RcWgLIsL.js.map +1 -0
  119. package/dist/trace-propagation-CJJC7SVB.js +57 -0
  120. package/dist/trace-propagation-CJJC7SVB.js.map +1 -0
  121. package/dist/types-BaIpb0XT.d.ts +492 -0
  122. package/dist/types-BevOjfTY.d.ts +765 -0
  123. package/dist/types-C9j4qg6l.d.ts +500 -0
  124. package/dist/types-Cja5OTGh.d.ts +190 -0
  125. package/dist/util-MVgdwuIS.js +145 -0
  126. package/dist/util-MVgdwuIS.js.map +1 -0
  127. package/dist/workspace-archive-BosQiotA.js +575 -0
  128. package/dist/workspace-archive-BosQiotA.js.map +1 -0
  129. package/package.json +44 -56
  130. package/skills/build-with-agent-runtime/SKILL.md +1 -0
  131. package/dist/activation-Cm-9MMX1.d.ts +0 -69
  132. package/dist/analyst-loop.js.map +0 -1
  133. package/dist/backends-BO4Jqoe2.d.ts +0 -134
  134. package/dist/candidate-execution/index.js.map +0 -1
  135. package/dist/chunk-2KGAN2HM.js +0 -1256
  136. package/dist/chunk-2KGAN2HM.js.map +0 -1
  137. package/dist/chunk-2VZYRB55.js +0 -834
  138. package/dist/chunk-2VZYRB55.js.map +0 -1
  139. package/dist/chunk-3MDZX7YU.js +0 -125
  140. package/dist/chunk-3MDZX7YU.js.map +0 -1
  141. package/dist/chunk-5IBQAPVB.js +0 -29
  142. package/dist/chunk-5IBQAPVB.js.map +0 -1
  143. package/dist/chunk-5QOB7H74.js +0 -387
  144. package/dist/chunk-5QOB7H74.js.map +0 -1
  145. package/dist/chunk-C5RTIBNZ.js +0 -48
  146. package/dist/chunk-C5RTIBNZ.js.map +0 -1
  147. package/dist/chunk-CTRA64LY.js +0 -680
  148. package/dist/chunk-CTRA64LY.js.map +0 -1
  149. package/dist/chunk-DPEUKJRO.js +0 -27
  150. package/dist/chunk-DPEUKJRO.js.map +0 -1
  151. package/dist/chunk-FD2MBMOH.js +0 -494
  152. package/dist/chunk-FD2MBMOH.js.map +0 -1
  153. package/dist/chunk-H5QPIZNX.js +0 -907
  154. package/dist/chunk-H5QPIZNX.js.map +0 -1
  155. package/dist/chunk-HLKC4UYB.js +0 -3514
  156. package/dist/chunk-HLKC4UYB.js.map +0 -1
  157. package/dist/chunk-HNP72PNU.js +0 -192
  158. package/dist/chunk-HNP72PNU.js.map +0 -1
  159. package/dist/chunk-ISPWRSEC.js +0 -408
  160. package/dist/chunk-ISPWRSEC.js.map +0 -1
  161. package/dist/chunk-KRBFHMV6.js +0 -1228
  162. package/dist/chunk-KRBFHMV6.js.map +0 -1
  163. package/dist/chunk-M22PL4GH.js +0 -171
  164. package/dist/chunk-M22PL4GH.js.map +0 -1
  165. package/dist/chunk-NURIQBJQ.js +0 -72
  166. package/dist/chunk-NURIQBJQ.js.map +0 -1
  167. package/dist/chunk-OPVWXJ2H.js +0 -75
  168. package/dist/chunk-OPVWXJ2H.js.map +0 -1
  169. package/dist/chunk-PZZKQVQV.js +0 -52
  170. package/dist/chunk-PZZKQVQV.js.map +0 -1
  171. package/dist/chunk-Q2JSAVQ3.js +0 -671
  172. package/dist/chunk-Q2JSAVQ3.js.map +0 -1
  173. package/dist/chunk-RDOAVVHY.js +0 -699
  174. package/dist/chunk-RDOAVVHY.js.map +0 -1
  175. package/dist/chunk-SGKPNBXE.js +0 -60
  176. package/dist/chunk-SGKPNBXE.js.map +0 -1
  177. package/dist/chunk-SMQXZGLZ.js +0 -351
  178. package/dist/chunk-SMQXZGLZ.js.map +0 -1
  179. package/dist/chunk-UHEZW5BU.js +0 -2918
  180. package/dist/chunk-UHEZW5BU.js.map +0 -1
  181. package/dist/chunk-UPWGXKXB.js +0 -254
  182. package/dist/chunk-UPWGXKXB.js.map +0 -1
  183. package/dist/chunk-VISA6CI3.js +0 -200
  184. package/dist/chunk-VISA6CI3.js.map +0 -1
  185. package/dist/chunk-WMTCUOQL.js +0 -474
  186. package/dist/chunk-WMTCUOQL.js.map +0 -1
  187. package/dist/chunk-WRTOVNN4.js +0 -4728
  188. package/dist/chunk-WRTOVNN4.js.map +0 -1
  189. package/dist/chunk-WSTRQZYQ.js +0 -5576
  190. package/dist/chunk-WSTRQZYQ.js.map +0 -1
  191. package/dist/chunk-XBG2W2VW.js +0 -6434
  192. package/dist/chunk-XBG2W2VW.js.map +0 -1
  193. package/dist/chunk-YEJR7IXO.js +0 -68
  194. package/dist/chunk-YEJR7IXO.js.map +0 -1
  195. package/dist/chunk-YJZA2BIK.js +0 -1338
  196. package/dist/chunk-YJZA2BIK.js.map +0 -1
  197. package/dist/completion-gate-BMy5LGoP.d.ts +0 -256
  198. package/dist/conversation.js.map +0 -1
  199. package/dist/coordination-BZZSVYpZ.d.ts +0 -2570
  200. package/dist/environment-provider.js.map +0 -1
  201. package/dist/improvement-adapter-HAZz-7vK.d.ts +0 -203
  202. package/dist/knowledge.js.map +0 -1
  203. package/dist/local-harness-BDNcl6jI.d.ts +0 -175
  204. package/dist/loop-runner-bin-68aoM9-7.d.ts +0 -199
  205. package/dist/loop-runner-bin.js.map +0 -1
  206. package/dist/loops.js.map +0 -1
  207. package/dist/openai-tools-fnj6SRVg.d.ts +0 -46
  208. package/dist/protected-model-port-B4t-OQjL.d.ts +0 -271
  209. package/dist/redact-BuFjxBUJ.d.ts +0 -481
  210. package/dist/sanitize-DEbPNtyI.d.ts +0 -328
  211. package/dist/structural-rollout-DEh6CEsa.d.ts +0 -446
  212. package/dist/supervise-4_48wwvy.d.ts +0 -379
  213. package/dist/types-BCoemcXU.d.ts +0 -802
  214. package/dist/types-BwoZWq-i.d.ts +0 -510
  215. package/dist/types-Cbp72qyu.d.ts +0 -491
  216. package/dist/types-CmYCMbFT.d.ts +0 -203
  217. package/dist/types-CvNwMzQt.d.ts +0 -957
  218. package/dist/worktree-fanout-DxhAWr5Z.d.ts +0 -999
@@ -0,0 +1,575 @@
1
+ import { A as verifyMaterializedWorkspace, C as assertNoGitIndirection, D as captureMaterializedWorkspace, E as candidateWorkspaceManifest, T as runCandidateGit, a as persistCandidateOutputArtifact, at as deepFreezeCandidate, ct as omitTopLevelDigest, k as verifyBytes, lt as sha256Bytes, nt as canonicalCandidateBytes, ot as embeddedCandidateArtifact, rt as canonicalCandidateDigest$1, st as immutableCandidateValue, w as readCandidateGitTreeFiles } from "./prepare-B53sPV7M.js";
2
+ import { agentCandidateBundleSchema } from "@tangle-network/agent-interface";
3
+ import { randomUUID } from "node:crypto";
4
+ import { lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
5
+ import { constants } from "node:fs";
6
+ import { dirname, isAbsolute, join, resolve, sep, win32 } from "node:path";
7
+ import { tmpdir } from "node:os";
8
+ import { isAnyArrayBuffer, isSharedArrayBuffer } from "node:util/types";
9
+ import { extract, pack } from "tar-stream";
10
+ //#region src/candidate-execution/bundle.ts
11
+ /** Validate and content-address a candidate bundle before it crosses an approval boundary. */
12
+ function sealAgentCandidateBundle(input) {
13
+ const digest = canonicalCandidateDigest$1(input);
14
+ const parsed = agentCandidateBundleSchema.parse({
15
+ ...input,
16
+ digest
17
+ });
18
+ if (canonicalCandidateDigest$1(omitTopLevelDigest(parsed)) !== digest) throw new Error("candidate bundle changed while validating its canonical wire shape");
19
+ return immutableCandidateValue(parsed);
20
+ }
21
+ //#endregion
22
+ //#region src/candidate-execution/workspace-archive.ts
23
+ const archiveKind = "agent-candidate-workspace-archive";
24
+ const workspaceEntryPrefix = "workspace/";
25
+ const repositoryMetadataEntry = "metadata/repository.json";
26
+ const repositoryBundleEntry = "metadata/repository.bundle";
27
+ const fixedTarTime = /* @__PURE__ */ new Date(0);
28
+ const defaultLimits = Object.freeze({
29
+ maxArchiveBytes: 512 * 1024 * 1024,
30
+ maxEmbeddedArtifactBytes: 1024 * 1024,
31
+ maxFiles: 5e4,
32
+ maxFileBytes: 128 * 1024 * 1024,
33
+ maxTotalFileBytes: 256 * 1024 * 1024,
34
+ maxPathBytes: 4096,
35
+ maxRepositoryBundleBytes: 128 * 1024 * 1024
36
+ });
37
+ /** Capture one exact regular-file workspace for immutable candidate execution. */
38
+ async function captureAgentCandidateWorkspace(rootInput, options = {}) {
39
+ const root = resolve(rootInput);
40
+ const limits = workspaceLimits(options.limits);
41
+ const captured = options.includeRepository ? await captureRepository(root, limits) : await captureMaterializedWorkspace(root, { limits: {
42
+ maxFiles: limits.maxFiles,
43
+ maxFileBytes: limits.maxFileBytes,
44
+ maxTotalFileBytes: limits.maxTotalFileBytes
45
+ } });
46
+ assertWorkspaceFilesWithinLimits(captured.files, limits);
47
+ const repository = "repository" in captured ? captured.repository : void 0;
48
+ return captureWorkspaceFiles(captured.files, repository, limits, options.artifactPersistence);
49
+ }
50
+ /** Capture detached files returned by a remote executor into the standard archive. */
51
+ async function captureAgentCandidateWorkspaceFiles(input, options = {}) {
52
+ const limits = workspaceLimits(options.limits);
53
+ return captureWorkspaceFiles(normalizeWorkspaceFiles(input, limits), void 0, limits, options.artifactPersistence);
54
+ }
55
+ async function captureWorkspaceFiles(files, repository, limits, artifactPersistence) {
56
+ const material = candidateWorkspaceManifest(files);
57
+ const manifest = canonicalCandidateBytes(material);
58
+ const archive = await encodeWorkspaceArchive(files, repository, limits.maxArchiveBytes);
59
+ if (!artifactPersistence && (manifest.byteLength > limits.maxEmbeddedArtifactBytes || archive.byteLength > limits.maxEmbeddedArtifactBytes)) throw new Error("candidate workspace artifacts exceed maxEmbeddedArtifactBytes; artifactPersistence is required");
60
+ const manifestArtifact = await captureWorkspaceArtifact("manifest", manifest, artifactPersistence);
61
+ const archiveArtifact = await captureWorkspaceArtifact("archive", archive, artifactPersistence);
62
+ const snapshot = deepFreezeCandidate({
63
+ kind: "agent-candidate-workspace-snapshot",
64
+ digest: canonicalCandidateDigest$1(material),
65
+ material,
66
+ manifest: manifestArtifact,
67
+ archive: archiveArtifact
68
+ });
69
+ return Object.freeze({
70
+ snapshot,
71
+ archive
72
+ });
73
+ }
74
+ async function captureWorkspaceArtifact(kind, bytes, persistence) {
75
+ if (!persistence) return embeddedCandidateArtifact(bytes);
76
+ if (!persistence.executionId.trim()) throw new Error("candidate workspace artifact persistence requires an executionId");
77
+ return persistCandidateOutputArtifact(persistence.outputArtifacts, {
78
+ executionId: persistence.executionId,
79
+ purpose: kind === "manifest" ? "candidate-workspace-manifest" : "candidate-workspace-archive",
80
+ bytes,
81
+ ...persistence.signal ? { signal: persistence.signal } : {}
82
+ });
83
+ }
84
+ /** Create the standard bounded materializer for candidate execution ports. */
85
+ function createAgentCandidateWorkspacePort(options = {}) {
86
+ const limits = workspaceLimits(options.limits);
87
+ return Object.freeze({ materialize: async ({ role, snapshot, archive, destination }) => {
88
+ await materializeAgentCandidateWorkspace({
89
+ role,
90
+ snapshot,
91
+ archive,
92
+ destination,
93
+ limits
94
+ });
95
+ } });
96
+ }
97
+ async function materializeAgentCandidateWorkspace(input) {
98
+ verifyBytes(input.archive, input.snapshot.archive.sha256, input.snapshot.archive.byteLength, "candidate workspace archive");
99
+ const decoded = await parseWorkspaceArchive(input.archive, input.limits);
100
+ if (decoded.repository && input.role !== "task") throw new Error("only task workspaces may carry a Git repository");
101
+ assertArchiveMatchesSnapshot(decoded.files, input.snapshot);
102
+ const destination = resolve(input.destination);
103
+ await prepareEmptyDestination(destination);
104
+ const staging = await mkdtemp(`${destination}.materializing-`);
105
+ try {
106
+ await writeWorkspaceFiles(staging, decoded.files);
107
+ if (decoded.repository) await materializeRepository(decoded.repository, staging);
108
+ await verifyMaterializedWorkspace(staging, input.snapshot.material, { ignoredProtectedRootEntries: decoded.repository ? [".git"] : [] });
109
+ await rename(staging, destination);
110
+ } catch (error) {
111
+ await rm(staging, {
112
+ recursive: true,
113
+ force: true
114
+ });
115
+ await rm(destination, {
116
+ recursive: true,
117
+ force: true
118
+ });
119
+ throw error;
120
+ }
121
+ }
122
+ async function captureRepository(root, limits) {
123
+ const stats = await lstat(root);
124
+ if (!stats.isDirectory() || stats.isSymbolicLink() || await realpath(root) !== root) throw new Error("candidate repository root must be a real directory");
125
+ if (resolve((await runCandidateGit(root, ["rev-parse", "--show-toplevel"])).stdout.toString("utf8").trim()) !== root) throw new Error("candidate repository capture must start at the Git worktree root");
126
+ const gitDir = resolve((await runCandidateGit(root, ["rev-parse", "--absolute-git-dir"])).stdout.toString("utf8").trim());
127
+ if (await realpath(gitDir) !== gitDir || gitDir.includes(":")) throw new Error("candidate repository Git object store has an unsupported path");
128
+ await assertNoGitIndirection(root, gitDir, "candidate repository");
129
+ const headCommit = (await runCandidateGit(root, ["rev-parse", "HEAD"])).stdout.toString("utf8").trim();
130
+ const headTree = (await runCandidateGit(root, ["rev-parse", "HEAD^{tree}"])).stdout.toString("utf8").trim();
131
+ assertGitObjectId(headCommit, "HEAD");
132
+ assertGitObjectId(headTree, "HEAD tree");
133
+ if (headCommit.length !== headTree.length) throw new Error("candidate repository HEAD and tree use different object formats");
134
+ const files = await readCandidateGitTreeFiles(root, headTree, {}, limits);
135
+ assertWorkspaceFilesWithinLimits(files, limits);
136
+ const reachableBytesText = (await runCandidateGit(root, [
137
+ "rev-list",
138
+ "--disk-usage",
139
+ "--objects",
140
+ "HEAD"
141
+ ])).stdout.toString("utf8").trim();
142
+ const reachableBytes = Number(reachableBytesText);
143
+ if (!Number.isSafeInteger(reachableBytes) || reachableBytes < 0) throw new Error("candidate repository reachable size is invalid");
144
+ if (reachableBytes > limits.maxRepositoryBundleBytes) throw new Error("candidate repository exceeds maxRepositoryBundleBytes");
145
+ const temporary = await mkdtemp(join(tmpdir(), "agent-candidate-workspace-bundle-"));
146
+ const bundlePath = join(temporary, `${randomUUID()}.bundle`);
147
+ try {
148
+ await runCandidateGit(root, [
149
+ "bundle",
150
+ "create",
151
+ bundlePath,
152
+ "HEAD"
153
+ ]);
154
+ const bundle = Uint8Array.from(await readFile(bundlePath));
155
+ if (bundle.byteLength > limits.maxRepositoryBundleBytes) throw new Error("candidate repository bundle exceeds maxRepositoryBundleBytes");
156
+ return {
157
+ files,
158
+ repository: {
159
+ headCommit,
160
+ headTree,
161
+ bundle: {
162
+ sha256: sha256Bytes(bundle),
163
+ byteLength: bundle.byteLength,
164
+ bytes: bundle
165
+ }
166
+ }
167
+ };
168
+ } finally {
169
+ await rm(temporary, {
170
+ recursive: true,
171
+ force: true
172
+ });
173
+ }
174
+ }
175
+ async function encodeWorkspaceArchive(files, repository, maxArchiveBytes) {
176
+ const archive = pack();
177
+ const output = collectStream(archive, maxArchiveBytes, "candidate workspace archive");
178
+ try {
179
+ await writeWorkspaceArchiveEntries(archive, files, repository);
180
+ archive.finalize();
181
+ return await output;
182
+ } catch (error) {
183
+ archive.destroy(error instanceof Error ? error : new Error(String(error)));
184
+ await output.catch(() => void 0);
185
+ throw error;
186
+ }
187
+ }
188
+ async function verifyCanonicalWorkspaceArchive(files, repository, expected, maxArchiveBytes) {
189
+ const archive = pack();
190
+ const comparison = streamEqualsBytes(archive, expected, maxArchiveBytes, "candidate workspace archive");
191
+ try {
192
+ await writeWorkspaceArchiveEntries(archive, files, repository);
193
+ archive.finalize();
194
+ if (!await comparison) throw new Error("candidate workspace tar is not canonical");
195
+ } catch (error) {
196
+ archive.destroy(error instanceof Error ? error : new Error(String(error)));
197
+ await comparison.catch(() => void 0);
198
+ throw error;
199
+ }
200
+ }
201
+ async function writeWorkspaceArchiveEntries(archive, files, repository) {
202
+ for (const file of files) await writeTarEntry(archive, `${workspaceEntryPrefix}${file.path}`, file.mode, file.bytes);
203
+ if (!repository) return;
204
+ const metadata = canonicalCandidateBytes({
205
+ kind: archiveKind,
206
+ headCommit: repository.headCommit,
207
+ headTree: repository.headTree,
208
+ bundle: {
209
+ sha256: repository.bundle.sha256,
210
+ byteLength: repository.bundle.byteLength
211
+ }
212
+ });
213
+ await writeTarEntry(archive, repositoryMetadataEntry, 384, metadata);
214
+ await writeTarEntry(archive, repositoryBundleEntry, 384, repository.bundle.bytes);
215
+ }
216
+ async function parseWorkspaceArchive(bytes, limits) {
217
+ if (bytes.byteLength > limits.maxArchiveBytes) throw new Error("candidate workspace archive exceeds maxArchiveBytes");
218
+ const parser = extract();
219
+ const files = [];
220
+ const observedEntryNames = /* @__PURE__ */ new Set();
221
+ const observedPaths = /* @__PURE__ */ new Set();
222
+ let totalBytes = 0;
223
+ let retainedEntryBytes = 0;
224
+ let previousPath;
225
+ let repositoryMetadata;
226
+ let repositoryBundle;
227
+ const decoded = (async () => {
228
+ for await (const entry of parser) {
229
+ const name = entry.header.name;
230
+ if (entry.header.type !== "file" || typeof name !== "string" || observedEntryNames.has(name)) throw new Error("candidate workspace tar contains an invalid entry");
231
+ observedEntryNames.add(name);
232
+ if (name.startsWith(workspaceEntryPrefix)) {
233
+ if (files.length >= limits.maxFiles) throw new Error("candidate workspace archive has an invalid file count");
234
+ const path = safeArchivePath(name.slice(10), limits.maxPathBytes);
235
+ if (!isWorkspaceFileMode(entry.header.mode)) throw new Error(`candidate workspace archive has an unsupported mode: ${path}`);
236
+ assertRetainedArchiveSize(bytes.byteLength, retainedEntryBytes, entry.header.size, limits);
237
+ const fileBytes = await readTarEntry(entry, limits.maxFileBytes, `workspace file ${path}`);
238
+ retainedEntryBytes += fileBytes.byteLength;
239
+ assertWorkspacePathOrder(path, previousPath, observedPaths, "candidate workspace archive paths must be unique and sorted");
240
+ previousPath = path;
241
+ if (fileBytes.byteLength > limits.maxTotalFileBytes - totalBytes) throw new Error("candidate workspace archive exceeds maxTotalFileBytes");
242
+ totalBytes += fileBytes.byteLength;
243
+ files.push({
244
+ path,
245
+ mode: entry.header.mode,
246
+ bytes: fileBytes
247
+ });
248
+ } else if (name === repositoryMetadataEntry) {
249
+ if (entry.header.mode !== 384 || repositoryMetadata) throw new Error("candidate workspace archive repository metadata is invalid");
250
+ assertRetainedArchiveSize(bytes.byteLength, retainedEntryBytes, entry.header.size, limits);
251
+ const metadataBytes = await readTarEntry(entry, limits.maxPathBytes, "candidate repository metadata");
252
+ retainedEntryBytes += metadataBytes.byteLength;
253
+ repositoryMetadata = parseRepositoryMetadata(metadataBytes, limits.maxRepositoryBundleBytes);
254
+ } else if (name === repositoryBundleEntry) {
255
+ if (entry.header.mode !== 384 || repositoryBundle) throw new Error("candidate workspace archive repository bundle is invalid");
256
+ assertRetainedArchiveSize(bytes.byteLength, retainedEntryBytes, entry.header.size, limits);
257
+ repositoryBundle = await readTarEntry(entry, limits.maxRepositoryBundleBytes, "candidate Git bundle");
258
+ retainedEntryBytes += repositoryBundle.byteLength;
259
+ } else throw new Error(`candidate workspace tar contains an unsupported entry: ${name}`);
260
+ }
261
+ if (Boolean(repositoryMetadata) !== Boolean(repositoryBundle)) throw new Error("candidate workspace archive repository evidence is incomplete");
262
+ const repository = repositoryMetadata && repositoryBundle ? repositoryFromTar(repositoryMetadata, repositoryBundle) : void 0;
263
+ return {
264
+ files,
265
+ ...repository ? { repository } : {}
266
+ };
267
+ })();
268
+ parser.end(Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength));
269
+ const result = await decoded;
270
+ await verifyCanonicalWorkspaceArchive(result.files, result.repository, bytes, limits.maxArchiveBytes);
271
+ return result;
272
+ }
273
+ function assertRetainedArchiveSize(archiveBytes, retainedEntryBytes, entryBytes, limits) {
274
+ if (!Number.isSafeInteger(entryBytes) || entryBytes === void 0 || entryBytes < 0 || entryBytes > limits.maxArchiveBytes - archiveBytes - retainedEntryBytes) throw new Error("candidate workspace archive exceeds maxArchiveBytes while decoding");
275
+ }
276
+ function parseRepositoryMetadata(bytes, maxBundleBytes) {
277
+ let value;
278
+ try {
279
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
280
+ } catch (error) {
281
+ throw new Error("candidate workspace archive repository metadata is invalid", { cause: error });
282
+ }
283
+ if (!isRecord(value) || Object.keys(value).sort().join(",") !== "bundle,headCommit,headTree,kind" || 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 > maxBundleBytes) throw new Error("candidate workspace archive repository is invalid");
284
+ if (!Buffer.from(canonicalCandidateBytes(value)).equals(Buffer.from(bytes))) throw new Error("candidate workspace archive repository metadata is not canonical");
285
+ assertGitObjectId(value.headCommit, "repository HEAD");
286
+ assertGitObjectId(value.headTree, "repository HEAD tree");
287
+ if (value.headCommit.length !== value.headTree.length) throw new Error("candidate repository HEAD and tree use different object formats");
288
+ return {
289
+ kind: archiveKind,
290
+ headCommit: value.headCommit,
291
+ headTree: value.headTree,
292
+ bundle: {
293
+ sha256: value.bundle.sha256,
294
+ byteLength: value.bundle.byteLength
295
+ }
296
+ };
297
+ }
298
+ function repositoryFromTar(metadata, bundle) {
299
+ verifyBytes(bundle, metadata.bundle.sha256, metadata.bundle.byteLength, "candidate Git bundle");
300
+ return {
301
+ headCommit: metadata.headCommit,
302
+ headTree: metadata.headTree,
303
+ bundle: {
304
+ ...metadata.bundle,
305
+ bytes: bundle
306
+ }
307
+ };
308
+ }
309
+ async function writeTarEntry(archive, name, mode, bytes) {
310
+ await new Promise((resolveEntry, rejectEntry) => {
311
+ archive.entry({
312
+ name,
313
+ mode,
314
+ uid: 0,
315
+ gid: 0,
316
+ size: bytes.byteLength,
317
+ mtime: fixedTarTime,
318
+ type: "file",
319
+ uname: "",
320
+ gname: ""
321
+ }, Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength), (error) => error ? rejectEntry(error) : resolveEntry());
322
+ });
323
+ }
324
+ async function readTarEntry(entry, maxBytes, label) {
325
+ const size = entry.header.size;
326
+ if (!Number.isSafeInteger(size) || size === void 0 || size < 0 || size > maxBytes) throw new Error(`${label} has an invalid tar size`);
327
+ const bytes = await collectStream(entry, maxBytes, label);
328
+ if (bytes.byteLength !== size) throw new Error(`${label} differs from its tar size`);
329
+ return bytes;
330
+ }
331
+ async function collectStream(stream, maxBytes, label) {
332
+ const chunks = [];
333
+ let totalBytes = 0;
334
+ for await (const chunk of stream) {
335
+ if (chunk.byteLength > maxBytes - totalBytes) {
336
+ const error = /* @__PURE__ */ new Error(`${label} exceeds its size limit`);
337
+ if ("destroy" in stream && typeof stream.destroy === "function") stream.destroy(error);
338
+ throw error;
339
+ }
340
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
341
+ chunks.push(bytes);
342
+ totalBytes += bytes.byteLength;
343
+ }
344
+ return Buffer.concat(chunks, totalBytes);
345
+ }
346
+ async function streamEqualsBytes(stream, expected, maxBytes, label) {
347
+ const expectedBuffer = Buffer.from(expected.buffer, expected.byteOffset, expected.byteLength);
348
+ let equal = true;
349
+ let offset = 0;
350
+ for await (const chunk of stream) {
351
+ if (chunk.byteLength > maxBytes - offset) {
352
+ const error = /* @__PURE__ */ new Error(`${label} exceeds its size limit`);
353
+ if ("destroy" in stream && typeof stream.destroy === "function") stream.destroy(error);
354
+ throw error;
355
+ }
356
+ const observed = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
357
+ if (offset + observed.byteLength > expectedBuffer.byteLength || !observed.equals(expectedBuffer.subarray(offset, offset + observed.byteLength))) equal = false;
358
+ offset += observed.byteLength;
359
+ }
360
+ return equal && offset === expectedBuffer.byteLength;
361
+ }
362
+ async function prepareEmptyDestination(destination) {
363
+ await mkdir(destination, {
364
+ recursive: true,
365
+ mode: 448
366
+ });
367
+ const stats = await lstat(destination);
368
+ if (!stats.isDirectory() || stats.isSymbolicLink() || await realpath(destination) !== destination) throw new Error("candidate workspace destination must be a real directory");
369
+ if ((await readdir(destination)).length > 0) throw new Error("candidate workspace destination must be empty");
370
+ }
371
+ async function writeWorkspaceFiles(destination, files) {
372
+ for (const file of files) {
373
+ const path = workspacePath(destination, file.path);
374
+ await mkdir(dirname(path), {
375
+ recursive: true,
376
+ mode: 448
377
+ });
378
+ const descriptor = await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0), 384);
379
+ try {
380
+ await descriptor.writeFile(file.bytes);
381
+ const stats = await descriptor.stat();
382
+ if (!stats.isFile() || stats.nlink !== 1) throw new Error(`candidate workspace file identity changed while writing: ${file.path}`);
383
+ await descriptor.chmod(file.mode);
384
+ } finally {
385
+ await descriptor.close();
386
+ }
387
+ }
388
+ }
389
+ async function materializeRepository(repository, destination) {
390
+ const temporary = await mkdtemp(join(tmpdir(), "agent-candidate-workspace-bundle-"));
391
+ const bundlePath = join(temporary, `${randomUUID()}.bundle`);
392
+ try {
393
+ await writeFile(bundlePath, repository.bundle.bytes, {
394
+ flag: "wx",
395
+ mode: 384
396
+ });
397
+ await runCandidateGit(destination, [
398
+ "init",
399
+ "--quiet",
400
+ "--initial-branch=candidate",
401
+ `--object-format=${repository.headCommit.length === 64 ? "sha256" : "sha1"}`
402
+ ]);
403
+ await runCandidateGit(destination, [
404
+ "bundle",
405
+ "verify",
406
+ bundlePath
407
+ ]);
408
+ await runCandidateGit(destination, [
409
+ "bundle",
410
+ "unbundle",
411
+ bundlePath
412
+ ]);
413
+ if ((await runCandidateGit(destination, [
414
+ "cat-file",
415
+ "-t",
416
+ repository.headCommit
417
+ ])).stdout.toString("utf8").trim() !== "commit") throw new Error("candidate repository HEAD is not a commit");
418
+ if ((await runCandidateGit(destination, ["rev-parse", `${repository.headCommit}^{tree}`])).stdout.toString("utf8").trim() !== repository.headTree) throw new Error("candidate repository bundle HEAD tree changed");
419
+ await runCandidateGit(destination, [
420
+ "update-ref",
421
+ "--no-deref",
422
+ "HEAD",
423
+ repository.headCommit
424
+ ]);
425
+ await runCandidateGit(destination, ["read-tree", repository.headTree]);
426
+ if ((await runCandidateGit(destination, [
427
+ "status",
428
+ "--porcelain=v1",
429
+ "--untracked-files=all"
430
+ ])).stdout.toString("utf8").trim()) throw new Error("candidate repository files do not exactly match HEAD");
431
+ } finally {
432
+ await rm(temporary, {
433
+ recursive: true,
434
+ force: true
435
+ });
436
+ }
437
+ }
438
+ function assertArchiveMatchesSnapshot(files, snapshot) {
439
+ const material = candidateWorkspaceManifest(files);
440
+ const materialBytes = canonicalCandidateBytes(material);
441
+ verifyBytes(materialBytes, snapshot.manifest.sha256, snapshot.manifest.byteLength, "candidate workspace manifest");
442
+ if (canonicalCandidateDigest$1(material) !== snapshot.digest || !Buffer.from(materialBytes).equals(Buffer.from(canonicalCandidateBytes(snapshot.material)))) throw new Error("candidate workspace archive does not match its snapshot manifest");
443
+ }
444
+ function assertWorkspaceFilesWithinLimits(files, limits) {
445
+ if (files.length > limits.maxFiles) throw new Error("candidate workspace exceeds maxFiles");
446
+ let totalBytes = 0;
447
+ let previousPath;
448
+ const observedPaths = /* @__PURE__ */ new Set();
449
+ for (const file of files) {
450
+ const path = safeArchivePath(file.path, limits.maxPathBytes);
451
+ assertWorkspacePathOrder(path, previousPath, observedPaths, "candidate workspace paths must be unique and sorted");
452
+ previousPath = path;
453
+ if (!isWorkspaceFileMode(file.mode)) throw new Error(`candidate workspace file has unsupported mode: ${path}`);
454
+ if (file.bytes.byteLength > limits.maxFileBytes) throw new Error(`candidate workspace file exceeds maxFileBytes: ${path}`);
455
+ totalBytes += file.bytes.byteLength;
456
+ if (totalBytes > limits.maxTotalFileBytes) throw new Error("candidate workspace exceeds maxTotalFileBytes");
457
+ }
458
+ }
459
+ function normalizeWorkspaceFiles(input, limits) {
460
+ if (!Array.isArray(input)) throw new Error("candidate workspace files must be an array");
461
+ const fileCount = input.length;
462
+ if (fileCount > limits.maxFiles) throw new Error("candidate workspace exceeds maxFiles");
463
+ let totalBytes = 0;
464
+ const files = [];
465
+ for (let index = 0; index < fileCount; index++) {
466
+ const inputFile = input[index];
467
+ if (!isRecord(inputFile) || Object.keys(inputFile).sort().join(",") !== "bytes,mode,path") throw new Error(`candidate workspace file ${index} is invalid`);
468
+ const descriptors = Object.getOwnPropertyDescriptors(inputFile);
469
+ if (!("value" in (descriptors.path ?? {})) || !("value" in (descriptors.mode ?? {})) || !("value" in (descriptors.bytes ?? {}))) throw new Error(`candidate workspace file ${index} must use fixed values`);
470
+ const path = safeArchivePath(descriptors.path?.value, limits.maxPathBytes);
471
+ const mode = descriptors.mode?.value;
472
+ const inputBytes = descriptors.bytes?.value;
473
+ if (!isWorkspaceFileMode(mode)) throw new Error(`candidate workspace file has unsupported mode: ${path}`);
474
+ const view = inspectWorkspaceBytes(inputBytes, path);
475
+ if (view.byteLength > limits.maxFileBytes) throw new Error(`candidate workspace file exceeds maxFileBytes: ${path}`);
476
+ if (view.byteLength > limits.maxTotalFileBytes - totalBytes) throw new Error("candidate workspace exceeds maxTotalFileBytes");
477
+ if (view.byteLength > Math.max(0, limits.maxArchiveBytes - 1024)) throw new Error("candidate workspace archive exceeds maxArchiveBytes");
478
+ totalBytes += view.byteLength;
479
+ files.push({
480
+ path,
481
+ mode,
482
+ bytes: detachWorkspaceBytes(view)
483
+ });
484
+ }
485
+ files.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
486
+ assertWorkspaceFilesWithinLimits(files, limits);
487
+ return files;
488
+ }
489
+ function isWorkspaceFileMode(value) {
490
+ return Number.isSafeInteger(value) && value >= 0 && value <= 511;
491
+ }
492
+ function workspaceLimits(overrides) {
493
+ const limits = {
494
+ ...defaultLimits,
495
+ ...overrides
496
+ };
497
+ for (const [name, value] of Object.entries(limits)) if (!Number.isSafeInteger(value) || value <= 0) throw new Error(`candidate workspace ${name} must be a positive safe integer`);
498
+ return Object.freeze(limits);
499
+ }
500
+ function safeArchivePath(value, maxPathBytes) {
501
+ if (typeof value !== "string" || !value || !isWellFormedUnicode(value) || Buffer.byteLength(value, "utf8") > maxPathBytes || isAbsolute(value) || win32.isAbsolute(value) || value.includes("\\") || value.includes("\0") || hasControlCharacter(value) || value.split("/").some((part) => !part || part === "." || part === "..") || [".git", ".sidecar"].includes(value.split("/")[0]?.toLowerCase() ?? "")) throw new Error(`candidate workspace archive contains an unsafe path: ${String(value)}`);
502
+ return value;
503
+ }
504
+ function assertWorkspacePathOrder(path, previousPath, observedPaths, errorMessage) {
505
+ if (previousPath !== void 0 && previousPath >= path) throw new Error(errorMessage);
506
+ for (let slash = path.indexOf("/"); slash !== -1; slash = path.indexOf("/", slash + 1)) if (observedPaths.has(path.slice(0, slash))) throw new Error(errorMessage);
507
+ observedPaths.add(path);
508
+ }
509
+ function inspectWorkspaceBytes(input, path) {
510
+ let buffer;
511
+ let byteOffset;
512
+ let byteLength;
513
+ try {
514
+ buffer = typedArrayBufferGetter.call(input);
515
+ byteOffset = typedArrayByteOffsetGetter.call(input);
516
+ byteLength = typedArrayByteLengthGetter.call(input);
517
+ } catch {
518
+ throw new Error(`candidate workspace file bytes are invalid: ${path}`);
519
+ }
520
+ if (isSharedArrayBuffer(buffer)) throw new Error(`candidate workspace file uses shared bytes: ${path}`);
521
+ if (!isAnyArrayBuffer(buffer)) throw new Error(`candidate workspace file bytes are invalid: ${path}`);
522
+ return {
523
+ buffer,
524
+ byteOffset,
525
+ byteLength
526
+ };
527
+ }
528
+ function detachWorkspaceBytes(input) {
529
+ const { buffer, byteOffset, byteLength } = input;
530
+ const copy = new Uint8Array(byteLength);
531
+ Uint8Array.prototype.set.call(copy, new Uint8Array(buffer, byteOffset, byteLength));
532
+ return copy;
533
+ }
534
+ function isWellFormedUnicode(value) {
535
+ for (let index = 0; index < value.length; index++) {
536
+ const code = value.charCodeAt(index);
537
+ if (code >= 55296 && code <= 56319) {
538
+ const next = value.charCodeAt(index + 1);
539
+ if (!(next >= 56320 && next <= 57343)) return false;
540
+ index++;
541
+ } else if (code >= 56320 && code <= 57343) return false;
542
+ }
543
+ return true;
544
+ }
545
+ function workspacePath(root, relativePath) {
546
+ const path = resolve(root, relativePath);
547
+ if (!path.startsWith(`${root}${sep}`)) throw new Error(`candidate workspace archive path escapes its destination: ${relativePath}`);
548
+ return path;
549
+ }
550
+ function assertGitObjectId(value, label) {
551
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(value)) throw new Error(`candidate repository ${label} is not a Git object id`);
552
+ }
553
+ function hasControlCharacter(value) {
554
+ for (let index = 0; index < value.length; index++) {
555
+ const code = value.charCodeAt(index);
556
+ if (code < 32 || code === 127) return true;
557
+ }
558
+ return false;
559
+ }
560
+ function isRecord(value) {
561
+ return typeof value === "object" && value !== null && !Array.isArray(value);
562
+ }
563
+ function requireTypedArrayGetter(name) {
564
+ const typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
565
+ const getter = Object.getOwnPropertyDescriptor(typedArrayPrototype, name)?.get;
566
+ if (!getter) throw new Error(`typed array intrinsic ${name} accessor is unavailable`);
567
+ return getter;
568
+ }
569
+ const typedArrayBufferGetter = requireTypedArrayGetter("buffer");
570
+ const typedArrayByteOffsetGetter = requireTypedArrayGetter("byteOffset");
571
+ const typedArrayByteLengthGetter = requireTypedArrayGetter("byteLength");
572
+ //#endregion
573
+ export { sealAgentCandidateBundle as i, captureAgentCandidateWorkspaceFiles as n, createAgentCandidateWorkspacePort as r, captureAgentCandidateWorkspace as t };
574
+
575
+ //# sourceMappingURL=workspace-archive-BosQiotA.js.map