@tangle-network/agent-eval 0.112.0 → 0.114.0

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 (60) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/belief-state/index.js +1 -1
  3. package/dist/benchmarks/index.d.ts +2 -2
  4. package/dist/benchmarks/index.js +6 -6
  5. package/dist/builder-eval/index.js +1 -1
  6. package/dist/campaign/index.d.ts +55 -22
  7. package/dist/campaign/index.js +13 -7
  8. package/dist/{chunk-VLNGPUJJ.js → chunk-3LXTCTWL.js} +2 -2
  9. package/dist/{chunk-7QPK6W7R.js → chunk-ARU2PZFM.js} +2 -2
  10. package/dist/{chunk-EMKORATZ.js → chunk-DPZAEKA6.js} +2 -2
  11. package/dist/{chunk-XNCF3JU3.js → chunk-FAOEFFRT.js} +2 -2
  12. package/dist/{chunk-WZOIFFG2.js → chunk-LOBMT6SB.js} +2 -2
  13. package/dist/{chunk-RT2AFUXM.js → chunk-MOXWMGPC.js} +2 -2
  14. package/dist/{chunk-RCXMWGRY.js → chunk-N6MTC3GK.js} +69 -25
  15. package/dist/chunk-N6MTC3GK.js.map +1 -0
  16. package/dist/{chunk-YWGKQARF.js → chunk-NYFUT3B3.js} +2 -2
  17. package/dist/{chunk-VC43KQCK.js → chunk-PJQFMIOX.js} +62 -9
  18. package/dist/chunk-PJQFMIOX.js.map +1 -0
  19. package/dist/{chunk-QQVYMBCZ.js → chunk-VHPD6AXX.js} +512 -21
  20. package/dist/{chunk-QQVYMBCZ.js.map → chunk-VHPD6AXX.js.map} +1 -1
  21. package/dist/{chunk-BOLYPSAE.js → chunk-WBOGKYM4.js} +4 -4
  22. package/dist/{chunk-3LDPUYAC.js → chunk-X4UCIOTZ.js} +2 -2
  23. package/dist/contract/index.d.ts +7 -7
  24. package/dist/contract/index.js +9 -8
  25. package/dist/contract/index.js.map +1 -1
  26. package/dist/{gepa-T8T215nw.d.ts → gepa-DolL_Fko.d.ts} +2 -6
  27. package/dist/hosted/index.d.ts +1 -1
  28. package/dist/{index-Dc3VLGhp.d.ts → index-CWr5SIG-.d.ts} +1 -1
  29. package/dist/index.d.ts +8 -8
  30. package/dist/index.js +13 -11
  31. package/dist/index.js.map +1 -1
  32. package/dist/meta-eval/index.d.ts +1 -1
  33. package/dist/meta-eval/index.js +2 -2
  34. package/dist/multishot/index.d.ts +1 -1
  35. package/dist/openapi.json +1 -1
  36. package/dist/pipelines/index.js +2 -2
  37. package/dist/{pre-registration-BepVVa6P.d.ts → pre-registration-CTQbZbpX.d.ts} +1 -1
  38. package/dist/{provenance-KhY8ESVM.d.ts → provenance-BZmpWmn4.d.ts} +5 -11
  39. package/dist/reporting.d.ts +1 -1
  40. package/dist/reporting.js +4 -4
  41. package/dist/rl.d.ts +1 -1
  42. package/dist/rl.js +5 -5
  43. package/dist/{run-campaign-HJQEDCJQ.js → run-campaign-UADIM77S.js} +3 -3
  44. package/dist/{statistics-CDfpwIdX.d.ts → statistics-oUbOJe-S.d.ts} +34 -1
  45. package/dist/{types-v--ctu-b.d.ts → types-CgSlO6wT.d.ts} +26 -11
  46. package/docs/design/loop-taxonomy.md +7 -1
  47. package/docs/improvement-glossary.md +1 -1
  48. package/package.json +1 -1
  49. package/dist/chunk-RCXMWGRY.js.map +0 -1
  50. package/dist/chunk-VC43KQCK.js.map +0 -1
  51. /package/dist/{chunk-VLNGPUJJ.js.map → chunk-3LXTCTWL.js.map} +0 -0
  52. /package/dist/{chunk-7QPK6W7R.js.map → chunk-ARU2PZFM.js.map} +0 -0
  53. /package/dist/{chunk-EMKORATZ.js.map → chunk-DPZAEKA6.js.map} +0 -0
  54. /package/dist/{chunk-XNCF3JU3.js.map → chunk-FAOEFFRT.js.map} +0 -0
  55. /package/dist/{chunk-WZOIFFG2.js.map → chunk-LOBMT6SB.js.map} +0 -0
  56. /package/dist/{chunk-RT2AFUXM.js.map → chunk-MOXWMGPC.js.map} +0 -0
  57. /package/dist/{chunk-YWGKQARF.js.map → chunk-NYFUT3B3.js.map} +0 -0
  58. /package/dist/{chunk-BOLYPSAE.js.map → chunk-WBOGKYM4.js.map} +0 -0
  59. /package/dist/{chunk-3LDPUYAC.js.map → chunk-X4UCIOTZ.js.map} +0 -0
  60. /package/dist/{run-campaign-HJQEDCJQ.js.map → run-campaign-UADIM77S.js.map} +0 -0
@@ -1,4 +1,5 @@
1
1
  import {
2
+ assertCodeSurfaceIdentity,
2
3
  campaignBreakdown,
3
4
  campaignMeanComposite,
4
5
  defaultProductionGate,
@@ -9,8 +10,9 @@ import {
9
10
  recoverTruncatedJson,
10
11
  renderAnalystEvidence,
11
12
  runImprovementLoop,
13
+ surfaceContentHash,
12
14
  surfaceHash
13
- } from "./chunk-RCXMWGRY.js";
15
+ } from "./chunk-N6MTC3GK.js";
14
16
  import {
15
17
  estimateCost,
16
18
  isModelPriced
@@ -21,7 +23,7 @@ import {
21
23
  planCampaignRun,
22
24
  runCampaign,
23
25
  summarizeBackendIntegrity
24
- } from "./chunk-XNCF3JU3.js";
26
+ } from "./chunk-FAOEFFRT.js";
25
27
  import {
26
28
  admitPolicyEdit,
27
29
  applyPolicyEditToSurface,
@@ -39,7 +41,7 @@ import {
39
41
  mulberry32,
40
42
  pairedBootstrap,
41
43
  weightedComposite
42
- } from "./chunk-VC43KQCK.js";
44
+ } from "./chunk-PJQFMIOX.js";
43
45
  import {
44
46
  analyzeTraces
45
47
  } from "./chunk-RPDDVKI7.js";
@@ -3906,7 +3908,7 @@ function compositeProposer(opts) {
3906
3908
  const surface = isCandidate ? proposal.surface : proposal;
3907
3909
  const label = isCandidate ? proposal.label : "candidate";
3908
3910
  const rationale = isCandidate ? proposal.rationale : "";
3909
- const key = typeof surface === "string" ? surface : JSON.stringify(surface);
3911
+ const key = surfaceContentHash(surface);
3910
3912
  if (seen.has(key)) continue;
3911
3913
  seen.add(key);
3912
3914
  pool.push({ surface, label: `${member.kind}:${label}`, rationale });
@@ -4172,6 +4174,7 @@ function coerceCandidateSurface(surface) {
4172
4174
  if (surface && typeof surface === "object") {
4173
4175
  const obj = surface;
4174
4176
  if (obj.kind === "code" && typeof obj.worktreeRef === "string") {
4177
+ assertCodeSurfaceIdentity(surface);
4175
4178
  return surface;
4176
4179
  }
4177
4180
  return JSON.stringify(surface, null, 2);
@@ -4179,7 +4182,7 @@ function coerceCandidateSurface(surface) {
4179
4182
  throw new Error("policyEditProposer: policy edit produced an unsupported surface");
4180
4183
  }
4181
4184
  function sameSurface(a, b) {
4182
- return JSON.stringify(a) === JSON.stringify(b);
4185
+ return surfaceContentHash(a) === surfaceContentHash(b);
4183
4186
  }
4184
4187
 
4185
4188
  // src/campaign/proposers/trace-analyst.ts
@@ -4338,8 +4341,36 @@ function isTransientTransportFailure(message, opts = {}) {
4338
4341
 
4339
4342
  // src/campaign/worktree/index.ts
4340
4343
  import { execFileSync } from "child_process";
4341
- import { existsSync as existsSync4 } from "fs";
4342
- import { basename, isAbsolute as isAbsolute2, join as join5 } from "path";
4344
+ import { createHash as createHash7 } from "crypto";
4345
+ import {
4346
+ closeSync,
4347
+ existsSync as existsSync4,
4348
+ constants as fsConstants,
4349
+ fstatSync,
4350
+ lstatSync,
4351
+ mkdirSync as mkdirSync2,
4352
+ mkdtempSync as mkdtempSync2,
4353
+ openSync,
4354
+ readlinkSync,
4355
+ readSync,
4356
+ realpathSync,
4357
+ rmSync
4358
+ } from "fs";
4359
+ import { devNull, tmpdir as tmpdir2 } from "os";
4360
+ import { basename, dirname as dirname2, isAbsolute as isAbsolute2, join as join5, relative as relative2, resolve as resolve2, sep } from "path";
4361
+ var MAX_GIT_OUTPUT_BYTES = 256 * 1024 * 1024;
4362
+ var FILE_HASH_CHUNK_BYTES = 1024 * 1024;
4363
+ var GIT_REPOSITORY_ENV = /* @__PURE__ */ new Set([
4364
+ "GIT_ALTERNATE_OBJECT_DIRECTORIES",
4365
+ "GIT_COMMON_DIR",
4366
+ "GIT_DIR",
4367
+ "GIT_INDEX_FILE",
4368
+ "GIT_NAMESPACE",
4369
+ "GIT_OBJECT_DIRECTORY",
4370
+ "GIT_PREFIX",
4371
+ "GIT_QUARANTINE_PATH",
4372
+ "GIT_WORK_TREE"
4373
+ ]);
4343
4374
  var WorktreeAdapterError = class extends Error {
4344
4375
  constructor(message, cause) {
4345
4376
  super(message);
@@ -4348,14 +4379,443 @@ var WorktreeAdapterError = class extends Error {
4348
4379
  }
4349
4380
  cause;
4350
4381
  };
4351
- function defaultGit(args, cwd) {
4382
+ function defaultGit(args, cwd, overrides) {
4352
4383
  try {
4353
- return execFileSync("git", args, { cwd, encoding: "utf8" }).trim();
4384
+ const env = { ...process.env };
4385
+ for (const key of Object.keys(env)) {
4386
+ if (GIT_REPOSITORY_ENV.has(key) || key === "GIT_CONFIG" || key.startsWith("GIT_CONFIG_") || key.startsWith("GIT_ATTR_") || key === "GIT_DIFF_OPTS" || key === "GIT_EXTERNAL_DIFF") {
4387
+ delete env[key];
4388
+ }
4389
+ }
4390
+ Object.assign(env, overrides);
4391
+ env.GIT_NO_REPLACE_OBJECTS = "1";
4392
+ env.LC_ALL = "C";
4393
+ env.LANG = "C";
4394
+ return execFileSync("git", args, { cwd, env, maxBuffer: MAX_GIT_OUTPUT_BYTES });
4354
4395
  } catch (err) {
4355
4396
  const stderr = err && typeof err === "object" && "stderr" in err ? String(err.stderr) : "";
4356
4397
  throw new WorktreeAdapterError(`git ${args.join(" ")} failed: ${stderr || String(err)}`, err);
4357
4398
  }
4358
4399
  }
4400
+ function gitBytes(git, args, cwd, env) {
4401
+ try {
4402
+ const output = git(args, cwd, env);
4403
+ return typeof output === "string" ? Buffer.from(output, "utf8") : Buffer.from(output);
4404
+ } catch (err) {
4405
+ if (err instanceof WorktreeAdapterError) throw err;
4406
+ throw new WorktreeAdapterError(`git ${args.join(" ")} failed: ${String(err)}`, err);
4407
+ }
4408
+ }
4409
+ function gitText(git, args, cwd, env) {
4410
+ return gitBytes(git, args, cwd, env).toString("utf8").trim();
4411
+ }
4412
+ function sha2562(bytes) {
4413
+ return `sha256:${createHash7("sha256").update(bytes).digest("hex")}`;
4414
+ }
4415
+ var PATCH_ARGS = [
4416
+ // Git binary patches embed a zlib stream. Pin no-compression at command
4417
+ // scope so repository/global config and compressor heuristics cannot change
4418
+ // the candidate identity for the same base and final tree.
4419
+ "-c",
4420
+ "core.compression=0",
4421
+ "-c",
4422
+ `core.attributesFile=${devNull}`,
4423
+ "-c",
4424
+ "core.quotePath=true",
4425
+ "-c",
4426
+ "diff.suppressBlankEmpty=false",
4427
+ "diff",
4428
+ "--unified=3",
4429
+ "--inter-hunk-context=0",
4430
+ `-O${devNull}`,
4431
+ "--binary",
4432
+ "--full-index",
4433
+ "--no-color",
4434
+ "--no-ext-diff",
4435
+ "--no-textconv",
4436
+ "--no-renames",
4437
+ "--diff-algorithm=myers",
4438
+ "--no-indent-heuristic",
4439
+ "--src-prefix=a/",
4440
+ "--dst-prefix=b/"
4441
+ ];
4442
+ var CANONICAL_GIT_ENV = {
4443
+ GIT_ATTR_GLOBAL: devNull,
4444
+ GIT_ATTR_NOSYSTEM: "1",
4445
+ GIT_CONFIG_GLOBAL: devNull,
4446
+ GIT_CONFIG_NOSYSTEM: "1",
4447
+ GIT_CONFIG_SYSTEM: devNull
4448
+ };
4449
+ function patchBytes(git, cwd, baseCommit, candidateCommit) {
4450
+ const scratch = mkdtempSync2(join5(tmpdir2(), "agent-eval-patch-"));
4451
+ const bareRepo = join5(scratch, "repo.git");
4452
+ const emptyTemplate = join5(scratch, "empty-template");
4453
+ mkdirSync2(emptyTemplate);
4454
+ try {
4455
+ const objectFormat = gitObjectHashAlgorithm(candidateCommit);
4456
+ const sourceObjects = realpathSync(gitText(git, ["rev-parse", "--git-path", "objects"], cwd));
4457
+ gitText(
4458
+ git,
4459
+ [
4460
+ "init",
4461
+ "--bare",
4462
+ "--quiet",
4463
+ ...objectFormat === "sha256" ? ["--object-format=sha256"] : [],
4464
+ `--template=${emptyTemplate}`,
4465
+ bareRepo
4466
+ ],
4467
+ scratch,
4468
+ CANONICAL_GIT_ENV
4469
+ );
4470
+ return gitBytes(
4471
+ git,
4472
+ [`--git-dir=${bareRepo}`, ...PATCH_ARGS, baseCommit, candidateCommit, "--"],
4473
+ scratch,
4474
+ {
4475
+ ...CANONICAL_GIT_ENV,
4476
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: sourceObjects
4477
+ }
4478
+ );
4479
+ } finally {
4480
+ rmSync(scratch, { recursive: true, force: true });
4481
+ }
4482
+ }
4483
+ function resolveCommit(git, cwd, ref) {
4484
+ return gitText(git, ["rev-parse", "--verify", `${ref}^{commit}`], cwd);
4485
+ }
4486
+ function unresolvedWorktreePath(surface, worktreeDir) {
4487
+ if (isAbsolute2(surface.worktreeRef)) return surface.worktreeRef;
4488
+ if (worktreeDir) return join5(worktreeDir, basename(surface.worktreeRef));
4489
+ return surface.worktreeRef;
4490
+ }
4491
+ function displayGitPath(path) {
4492
+ return JSON.stringify(path);
4493
+ }
4494
+ function parseGitTreeEntries(bytes) {
4495
+ const input = Buffer.from(bytes);
4496
+ const entries = [];
4497
+ let start = 0;
4498
+ while (start < input.length) {
4499
+ const end = input.indexOf(0, start);
4500
+ if (end < 0) throw new WorktreeAdapterError("Git tree output was not NUL-terminated");
4501
+ const record = input.subarray(start, end);
4502
+ start = end + 1;
4503
+ if (record.length === 0) continue;
4504
+ const tab = record.indexOf(9);
4505
+ if (tab < 0) throw new WorktreeAdapterError("Git tree entry did not contain a path");
4506
+ const metadata = record.subarray(0, tab).toString("ascii").split(" ");
4507
+ if (metadata.length !== 3) throw new WorktreeAdapterError("Git tree entry was malformed");
4508
+ const mode = metadata[0];
4509
+ const type = metadata[1];
4510
+ const objectId = metadata[2];
4511
+ if (!mode || !type || !objectId) {
4512
+ throw new WorktreeAdapterError("Git tree entry was malformed");
4513
+ }
4514
+ const pathBytes = record.subarray(tab + 1);
4515
+ const path = pathBytes.toString("utf8");
4516
+ if (!Buffer.from(path, "utf8").equals(pathBytes)) {
4517
+ throw new WorktreeAdapterError("CodeSurface paths must be valid UTF-8");
4518
+ }
4519
+ if (type !== "blob" && type !== "commit") {
4520
+ throw new WorktreeAdapterError(
4521
+ `CodeSurface contains unsupported Git object type ${type} at ${displayGitPath(path)}`
4522
+ );
4523
+ }
4524
+ entries.push({ mode, objectId, path });
4525
+ }
4526
+ return entries;
4527
+ }
4528
+ function parseGitPathList(bytes) {
4529
+ const input = Buffer.from(bytes);
4530
+ const paths = [];
4531
+ let start = 0;
4532
+ while (start < input.length) {
4533
+ const end = input.indexOf(0, start);
4534
+ if (end < 0) throw new WorktreeAdapterError("Git path output was not NUL-terminated");
4535
+ const pathBytes = input.subarray(start, end);
4536
+ start = end + 1;
4537
+ if (pathBytes.length === 0) continue;
4538
+ const path = pathBytes.toString("utf8");
4539
+ if (!Buffer.from(path, "utf8").equals(pathBytes)) {
4540
+ throw new WorktreeAdapterError("CodeSurface paths must be valid UTF-8");
4541
+ }
4542
+ paths.push(path);
4543
+ }
4544
+ return paths;
4545
+ }
4546
+ function isWithinRoot(root, candidate) {
4547
+ const rel = relative2(root, candidate);
4548
+ return rel === "" || !isAbsolute2(rel) && rel !== ".." && !rel.startsWith(`..${sep}`);
4549
+ }
4550
+ function assertSafeRelativePath(root, path) {
4551
+ if (path.length === 0 || isAbsolute2(path)) {
4552
+ throw new WorktreeAdapterError(`CodeSurface contains unsafe path ${displayGitPath(path)}`);
4553
+ }
4554
+ const absolutePath = resolve2(root, path);
4555
+ if (!isWithinRoot(root, absolutePath) || absolutePath === root) {
4556
+ throw new WorktreeAdapterError(`CodeSurface path escapes its worktree: ${displayGitPath(path)}`);
4557
+ }
4558
+ const segments = path.split(/[\\/]/u);
4559
+ let parent = root;
4560
+ for (const segment of segments.slice(0, -1)) {
4561
+ if (segment.length === 0 || segment === "." || segment === "..") {
4562
+ throw new WorktreeAdapterError(`CodeSurface contains unsafe path ${displayGitPath(path)}`);
4563
+ }
4564
+ parent = join5(parent, segment);
4565
+ const stat = lstatSync(parent);
4566
+ if (!stat.isDirectory() || stat.isSymbolicLink()) {
4567
+ throw new WorktreeAdapterError(
4568
+ `CodeSurface path traverses a non-directory or symbolic link: ${displayGitPath(path)}`
4569
+ );
4570
+ }
4571
+ }
4572
+ return absolutePath;
4573
+ }
4574
+ function gitObjectHashAlgorithm(objectId) {
4575
+ if (/^[a-f0-9]{40}$/.test(objectId)) return "sha1";
4576
+ if (/^[a-f0-9]{64}$/.test(objectId)) return "sha256";
4577
+ throw new WorktreeAdapterError(`Unsupported Git object id: ${objectId}`);
4578
+ }
4579
+ function hashGitBlobBytes(bytes, objectId) {
4580
+ const hash = createHash7(gitObjectHashAlgorithm(objectId));
4581
+ hash.update(`blob ${bytes.byteLength}\0`);
4582
+ hash.update(bytes);
4583
+ return hash.digest("hex");
4584
+ }
4585
+ function hashGitBlobFile(path, objectId) {
4586
+ const before = lstatSync(path);
4587
+ if (!before.isFile() || before.isSymbolicLink()) {
4588
+ throw new WorktreeAdapterError(`CodeSurface expected a regular file at ${displayGitPath(path)}`);
4589
+ }
4590
+ const noFollow = process.platform === "win32" ? 0 : fsConstants.O_NOFOLLOW;
4591
+ const fd = openSync(path, fsConstants.O_RDONLY | noFollow);
4592
+ try {
4593
+ const opened = fstatSync(fd);
4594
+ if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino || opened.size !== before.size) {
4595
+ throw new WorktreeAdapterError(
4596
+ `CodeSurface file changed while it was being verified: ${displayGitPath(path)}`
4597
+ );
4598
+ }
4599
+ const hash = createHash7(gitObjectHashAlgorithm(objectId));
4600
+ hash.update(`blob ${opened.size}\0`);
4601
+ const chunk = Buffer.allocUnsafe(FILE_HASH_CHUNK_BYTES);
4602
+ let total = 0;
4603
+ while (true) {
4604
+ const count = readSync(fd, chunk, 0, chunk.length, null);
4605
+ if (count === 0) break;
4606
+ total += count;
4607
+ hash.update(chunk.subarray(0, count));
4608
+ }
4609
+ if (total !== opened.size) {
4610
+ throw new WorktreeAdapterError(
4611
+ `CodeSurface file changed while it was being verified: ${displayGitPath(path)}`
4612
+ );
4613
+ }
4614
+ return { hash: hash.digest("hex"), executable: (opened.mode & 73) !== 0 };
4615
+ } finally {
4616
+ closeSync(fd);
4617
+ }
4618
+ }
4619
+ function assertSymlinkTargetIsBound(root, linkPath, trackedPaths) {
4620
+ const targetBytes = readlinkSync(linkPath, { encoding: "buffer" });
4621
+ const target = targetBytes.toString("utf8");
4622
+ if (!Buffer.from(target, "utf8").equals(targetBytes)) {
4623
+ throw new WorktreeAdapterError(
4624
+ `CodeSurface symbolic link has an unsafe target at ${displayGitPath(linkPath)}`
4625
+ );
4626
+ }
4627
+ if (isAbsolute2(target)) {
4628
+ throw new WorktreeAdapterError(
4629
+ `CodeSurface symbolic link escapes its worktree at ${displayGitPath(linkPath)}`
4630
+ );
4631
+ }
4632
+ const lexicalTarget = resolve2(dirname2(linkPath), target);
4633
+ if (!isWithinRoot(root, lexicalTarget)) {
4634
+ throw new WorktreeAdapterError(
4635
+ `CodeSurface symbolic link escapes its worktree at ${displayGitPath(linkPath)}`
4636
+ );
4637
+ }
4638
+ let resolvedTarget;
4639
+ try {
4640
+ resolvedTarget = realpathSync(linkPath);
4641
+ } catch (err) {
4642
+ throw new WorktreeAdapterError(
4643
+ `CodeSurface symbolic link target is missing or cyclic at ${displayGitPath(linkPath)}`,
4644
+ err
4645
+ );
4646
+ }
4647
+ if (!isWithinRoot(root, resolvedTarget)) {
4648
+ throw new WorktreeAdapterError(
4649
+ `CodeSurface symbolic link escapes its worktree at ${displayGitPath(linkPath)}`
4650
+ );
4651
+ }
4652
+ const targetRelative = relative2(root, resolvedTarget).split(sep).join("/");
4653
+ const targetIsTracked = trackedPaths.has(targetRelative) || [...trackedPaths].some((trackedPath) => trackedPath.startsWith(`${targetRelative}/`));
4654
+ if (!targetIsTracked) {
4655
+ throw new WorktreeAdapterError(
4656
+ `CodeSurface symbolic link resolves to untracked content at ${displayGitPath(linkPath)}`
4657
+ );
4658
+ }
4659
+ }
4660
+ function assertRawTreeMatchesWorktree(git, root, candidateCommit) {
4661
+ const entries = parseGitTreeEntries(
4662
+ gitBytes(git, ["ls-tree", "-r", "-z", "--full-tree", candidateCommit], root)
4663
+ );
4664
+ const trackedPaths = new Set(entries.map((entry) => entry.path));
4665
+ for (const entry of entries) {
4666
+ const absolutePath = assertSafeRelativePath(root, entry.path);
4667
+ if (entry.mode === "160000" || entry.mode === "040000") {
4668
+ throw new WorktreeAdapterError(
4669
+ `CodeSurface contains a Git submodule whose executable bytes are not bound: ${displayGitPath(entry.path)}`
4670
+ );
4671
+ }
4672
+ if (entry.mode === "120000") {
4673
+ const stat = lstatSync(absolutePath);
4674
+ if (!stat.isSymbolicLink()) {
4675
+ throw new WorktreeAdapterError(
4676
+ `CodeSurface expected a symbolic link at ${displayGitPath(entry.path)}`
4677
+ );
4678
+ }
4679
+ const targetBytes = readlinkSync(absolutePath, { encoding: "buffer" });
4680
+ const actualObjectId = hashGitBlobBytes(targetBytes, entry.objectId);
4681
+ if (actualObjectId !== entry.objectId) {
4682
+ throw new WorktreeAdapterError(
4683
+ `CodeSurface raw symbolic-link bytes differ from the candidate tree at ${displayGitPath(entry.path)}`
4684
+ );
4685
+ }
4686
+ assertSymlinkTargetIsBound(root, absolutePath, trackedPaths);
4687
+ continue;
4688
+ }
4689
+ if (entry.mode !== "100644" && entry.mode !== "100755") {
4690
+ throw new WorktreeAdapterError(
4691
+ `CodeSurface contains unsupported Git mode ${entry.mode} at ${displayGitPath(entry.path)}`
4692
+ );
4693
+ }
4694
+ const actual = hashGitBlobFile(absolutePath, entry.objectId);
4695
+ if (actual.hash !== entry.objectId) {
4696
+ throw new WorktreeAdapterError(
4697
+ `CodeSurface raw tracked bytes differ from the candidate tree because the worktree changed after finalization at ${displayGitPath(entry.path)}`
4698
+ );
4699
+ }
4700
+ if (process.platform !== "win32" && actual.executable !== (entry.mode === "100755")) {
4701
+ throw new WorktreeAdapterError(
4702
+ `CodeSurface executable mode differs from the candidate tree at ${displayGitPath(entry.path)}`
4703
+ );
4704
+ }
4705
+ }
4706
+ }
4707
+ function verifyCodeSurfaceWithGit(surface, path, git) {
4708
+ assertCodeSurfaceIdentity(surface);
4709
+ if (!existsSync4(path)) {
4710
+ throw new WorktreeAdapterError(`CodeSurface worktree does not exist: ${path}`);
4711
+ }
4712
+ const lexicalRoot = resolve2(path);
4713
+ const canonicalRoot = realpathSync(path);
4714
+ if (lstatSync(lexicalRoot).isSymbolicLink() || process.platform !== "win32" && lexicalRoot !== canonicalRoot) {
4715
+ throw new WorktreeAdapterError(
4716
+ `CodeSurface worktree locator must not contain a symbolic link: ${path}`
4717
+ );
4718
+ }
4719
+ const repoRoot = gitText(git, ["rev-parse", "--show-toplevel"], path);
4720
+ const canonicalRepoRoot = realpathSync(repoRoot);
4721
+ if (canonicalRepoRoot !== canonicalRoot) {
4722
+ throw new WorktreeAdapterError(
4723
+ `CodeSurface worktree locator is not the repository root: expected ${repoRoot}, got ${path}`
4724
+ );
4725
+ }
4726
+ const indexFlags = gitText(git, ["ls-files", "-v"], path).split("\n").filter((line) => line.length > 0 && (line.startsWith("S ") || /^[a-z]/.test(line)));
4727
+ if (indexFlags.length > 0) {
4728
+ throw new WorktreeAdapterError(
4729
+ `CodeSurface worktree uses hidden index entries that cannot be verified: ${path}
4730
+ ${indexFlags.join("\n")}`
4731
+ );
4732
+ }
4733
+ const extraPaths = [
4734
+ ...parseGitPathList(gitBytes(git, ["ls-files", "--others", "--exclude-standard", "-z"], path)),
4735
+ ...parseGitPathList(
4736
+ gitBytes(git, ["ls-files", "--others", "--ignored", "--exclude-standard", "-z"], path)
4737
+ )
4738
+ ];
4739
+ if (extraPaths.length > 0) {
4740
+ throw new WorktreeAdapterError(
4741
+ `CodeSurface worktree changed after finalization: ${path}
4742
+ ${extraPaths.join("\n")}`
4743
+ );
4744
+ }
4745
+ const candidateCommit = resolveCommit(git, path, "HEAD");
4746
+ if (candidateCommit !== surface.candidateCommit) {
4747
+ throw new WorktreeAdapterError(
4748
+ `CodeSurface candidate commit mismatch: expected ${surface.candidateCommit}, got ${candidateCommit}`
4749
+ );
4750
+ }
4751
+ const baseCommit = resolveCommit(git, path, surface.baseCommit);
4752
+ if (baseCommit !== surface.baseCommit) {
4753
+ throw new WorktreeAdapterError(
4754
+ `CodeSurface base commit mismatch: expected ${surface.baseCommit}, got ${baseCommit}`
4755
+ );
4756
+ }
4757
+ const baseTree = gitText(git, ["rev-parse", "--verify", `${surface.baseCommit}^{tree}`], path);
4758
+ if (baseTree !== surface.baseTree) {
4759
+ throw new WorktreeAdapterError(
4760
+ `CodeSurface base tree mismatch: expected ${surface.baseTree}, got ${baseTree}`
4761
+ );
4762
+ }
4763
+ const candidateTree = gitText(
4764
+ git,
4765
+ ["rev-parse", "--verify", `${surface.candidateCommit}^{tree}`],
4766
+ path
4767
+ );
4768
+ if (candidateTree !== surface.candidateTree) {
4769
+ throw new WorktreeAdapterError(
4770
+ `CodeSurface tree mismatch: expected ${surface.candidateTree}, got ${candidateTree}`
4771
+ );
4772
+ }
4773
+ try {
4774
+ gitText(
4775
+ git,
4776
+ [
4777
+ "diff-index",
4778
+ "--cached",
4779
+ "--quiet",
4780
+ "--no-ext-diff",
4781
+ "--no-textconv",
4782
+ surface.candidateCommit,
4783
+ "--"
4784
+ ],
4785
+ path
4786
+ );
4787
+ } catch (err) {
4788
+ throw new WorktreeAdapterError(
4789
+ `CodeSurface index differs from finalized candidate: ${path}`,
4790
+ err
4791
+ );
4792
+ }
4793
+ try {
4794
+ assertRawTreeMatchesWorktree(git, canonicalRepoRoot, surface.candidateCommit);
4795
+ } catch (err) {
4796
+ if (err instanceof WorktreeAdapterError) throw err;
4797
+ throw new WorktreeAdapterError(`CodeSurface raw tree verification failed: ${path}`, err);
4798
+ }
4799
+ const mergeBase = gitText(git, ["merge-base", surface.baseCommit, surface.candidateCommit], path);
4800
+ if (mergeBase !== surface.baseCommit) {
4801
+ throw new WorktreeAdapterError(
4802
+ `CodeSurface candidate ${surface.candidateCommit} does not descend from base ${surface.baseCommit}`
4803
+ );
4804
+ }
4805
+ const patch = patchBytes(git, path, surface.baseCommit, surface.candidateCommit);
4806
+ const actualPatchHash = sha2562(patch);
4807
+ if (actualPatchHash !== surface.patch.sha256 || patch.byteLength !== surface.patch.byteLength) {
4808
+ throw new WorktreeAdapterError(
4809
+ `CodeSurface patch mismatch: expected ${surface.patch.sha256}/${surface.patch.byteLength} bytes, got ${actualPatchHash}/${patch.byteLength} bytes`
4810
+ );
4811
+ }
4812
+ return {
4813
+ path,
4814
+ repoRoot: canonicalRepoRoot,
4815
+ contentHash: surfaceContentHash(surface),
4816
+ patchBytes: new Uint8Array(patch)
4817
+ };
4818
+ }
4359
4819
  function slug2(label) {
4360
4820
  return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "candidate";
4361
4821
  }
@@ -4368,32 +4828,62 @@ function gitWorktreeAdapter(opts) {
4368
4828
  const id = `${slug2(label)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
4369
4829
  const branch = `${branchPrefix}/${id}`;
4370
4830
  const path = join5(worktreeDir, id);
4371
- git(["worktree", "add", "-b", branch, path, baseRef], opts.repoRoot);
4372
- return { path, branch, baseRef };
4831
+ const baseCommit = resolveCommit(git, opts.repoRoot, baseRef);
4832
+ const baseTree = gitText(
4833
+ git,
4834
+ ["rev-parse", "--verify", `${baseCommit}^{tree}`],
4835
+ opts.repoRoot
4836
+ );
4837
+ gitText(git, ["worktree", "add", "-b", branch, path, baseCommit], opts.repoRoot);
4838
+ return { path, branch, baseRef, baseCommit, baseTree };
4373
4839
  },
4374
4840
  async finalize(worktree, summary) {
4375
- const status = git(["status", "--porcelain"], worktree.path);
4841
+ const status = gitText(
4842
+ git,
4843
+ ["status", "--porcelain=v1", "--untracked-files=all"],
4844
+ worktree.path
4845
+ );
4376
4846
  if (status.length > 0) {
4377
- git(["add", "-A"], worktree.path);
4378
- git(["commit", "-m", summary], worktree.path);
4847
+ gitText(git, ["add", "-A"], worktree.path);
4848
+ gitText(git, ["commit", "-m", summary], worktree.path);
4379
4849
  }
4380
- return {
4850
+ const candidateCommit = resolveCommit(git, worktree.path, "HEAD");
4851
+ const candidateTree = gitText(
4852
+ git,
4853
+ ["rev-parse", "--verify", `${candidateCommit}^{tree}`],
4854
+ worktree.path
4855
+ );
4856
+ const patch = patchBytes(git, worktree.path, worktree.baseCommit, candidateCommit);
4857
+ const surface = {
4381
4858
  kind: "code",
4382
4859
  worktreeRef: worktree.path,
4383
4860
  baseRef: worktree.baseRef,
4861
+ baseCommit: worktree.baseCommit,
4862
+ baseTree: worktree.baseTree,
4863
+ candidateCommit,
4864
+ candidateTree,
4865
+ patch: {
4866
+ format: "git-diff-binary",
4867
+ sha256: sha2562(patch),
4868
+ byteLength: patch.byteLength
4869
+ },
4384
4870
  summary
4385
4871
  };
4872
+ verifyCodeSurfaceWithGit(surface, worktree.path, git);
4873
+ return surface;
4386
4874
  },
4387
4875
  async discard(worktree) {
4388
- git(["worktree", "remove", "--force", worktree.path], opts.repoRoot);
4389
- git(["branch", "-D", worktree.branch], opts.repoRoot);
4876
+ gitText(git, ["worktree", "remove", "--force", worktree.path], opts.repoRoot);
4877
+ gitText(git, ["branch", "-D", worktree.branch], opts.repoRoot);
4390
4878
  }
4391
4879
  };
4392
4880
  }
4881
+ function verifyCodeSurface(surface, worktreeDir) {
4882
+ const path = unresolvedWorktreePath(surface, worktreeDir);
4883
+ return verifyCodeSurfaceWithGit(surface, path, defaultGit);
4884
+ }
4393
4885
  function resolveWorktreePath(surface, worktreeDir) {
4394
- if (isAbsolute2(surface.worktreeRef) && existsSync4(surface.worktreeRef)) return surface.worktreeRef;
4395
- if (worktreeDir) return join5(worktreeDir, basename(surface.worktreeRef));
4396
- return surface.worktreeRef;
4886
+ return verifyCodeSurface(surface, worktreeDir).path;
4397
4887
  }
4398
4888
 
4399
4889
  export {
@@ -4473,6 +4963,7 @@ export {
4473
4963
  isTransientTransportFailure,
4474
4964
  WorktreeAdapterError,
4475
4965
  gitWorktreeAdapter,
4966
+ verifyCodeSurface,
4476
4967
  resolveWorktreePath
4477
4968
  };
4478
- //# sourceMappingURL=chunk-QQVYMBCZ.js.map
4969
+ //# sourceMappingURL=chunk-VHPD6AXX.js.map