mason-context 0.21.0 → 0.23.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.
@@ -31,14 +31,14 @@ var init_types = __esm({
31
31
  });
32
32
 
33
33
  // src/review/cli.ts
34
- import path13 from "path";
34
+ import path12 from "path";
35
35
  import { stripVTControlCharacters } from "util";
36
36
 
37
37
  // src/review/review.ts
38
38
  import fs7 from "fs/promises";
39
- import path12 from "path";
40
- import { execFile as execFile3 } from "child_process";
41
- import { promisify as promisify3 } from "util";
39
+ import path11 from "path";
40
+ import { execFile as execFile4 } from "child_process";
41
+ import { promisify as promisify4 } from "util";
42
42
 
43
43
  // src/utils/git-read.ts
44
44
  import { execFile } from "child_process";
@@ -91,10 +91,7 @@ function execGit(args, options) {
91
91
 
92
92
  // src/drift/drift.ts
93
93
  import fs4 from "fs/promises";
94
- import path6 from "path";
95
-
96
- // src/snapshot/snapshot.ts
97
- import path5 from "path";
94
+ import path4 from "path";
98
95
 
99
96
  // src/utils/validation.ts
100
97
  function isRecord(value) {
@@ -394,11 +391,13 @@ async function storePath(root, relative, createParents = false) {
394
391
  }
395
392
  return current;
396
393
  }
397
- async function readStoreJson(root, relative) {
394
+ var STORE_MAX_BYTES = 10 * 1024 * 1024;
395
+ async function readStoreJson(root, relative, maxBytes = STORE_MAX_BYTES) {
398
396
  try {
399
397
  const file = await storePath(root, relative);
400
- const raw = await readBoundedFile(file, 10 * 1024 * 1024);
401
- if (raw === null) throw new Error("file is not regular or exceeds 10 MiB");
398
+ const raw = await readBoundedFile(file, maxBytes);
399
+ if (raw === null)
400
+ throw new Error(`file is not regular or exceeds ${maxBytes / 1024 / 1024} MiB`);
402
401
  const parsed = JSON.parse(raw);
403
402
  if (parsed === null) throw new Error("expected a JSON object, received null");
404
403
  return parsed;
@@ -420,76 +419,6 @@ import fs3 from "fs/promises";
420
419
  import os from "os";
421
420
  var lockOwnerSchema = z.object({ host: z.string(), pid: z.number().int().positive() });
422
421
 
423
- // src/test-map.ts
424
- import path4 from "path";
425
- async function buildTestMap(dir) {
426
- const rootDir = path4.resolve(dir);
427
- const access = await createFileAccess(rootDir);
428
- const testPatterns = [
429
- "**/*.test.*",
430
- "**/*.spec.*",
431
- "**/*Test.kt",
432
- "**/*Test.java",
433
- "**/*Tests.kt",
434
- "**/*Tests.java",
435
- "**/test_*.py",
436
- "**/*_test.py",
437
- "**/*_test.go",
438
- "**/*Tests.swift",
439
- "**/*Test.swift",
440
- "**/*_test.rs"
441
- ];
442
- const testFiles = await access.list(testPatterns);
443
- const sourceFiles = await access.list();
444
- const sourceByBaseName = /* @__PURE__ */ new Map();
445
- for (const file of sourceFiles) {
446
- if (testFiles.includes(file)) continue;
447
- const baseName = path4.basename(file).replace(/\.[^.]+$/, "");
448
- const existing = sourceByBaseName.get(baseName) ?? [];
449
- existing.push(file);
450
- sourceByBaseName.set(baseName, existing);
451
- }
452
- const paired = [];
453
- const unmatched = [];
454
- for (const testFile of testFiles) {
455
- const testBaseName = path4.basename(testFile).replace(/\.[^.]+$/, "");
456
- const sourceName = testBaseName.replace(/Test$|Tests$|Spec$|\.test$|\.spec$/, "").replace(/^test_|_test$/, "");
457
- if (!sourceName) {
458
- unmatched.push(testFile);
459
- continue;
460
- }
461
- const candidates = sourceByBaseName.get(sourceName);
462
- if (candidates && candidates.length > 0) {
463
- const testDir = path4.dirname(testFile);
464
- const bestMatch = candidates.reduce((best, candidate) => {
465
- const candidateDir = path4.dirname(candidate);
466
- const bestDir = path4.dirname(best);
467
- const candidateOverlap = commonSegments(testDir, candidateDir);
468
- const bestOverlap = commonSegments(testDir, bestDir);
469
- return candidateOverlap > bestOverlap ? candidate : best;
470
- });
471
- paired.push({
472
- test: testFile,
473
- source: bestMatch,
474
- confidence: candidates.length === 1 ? "exact" : "best-guess"
475
- });
476
- } else {
477
- unmatched.push(testFile);
478
- }
479
- }
480
- return { totalTestFiles: testFiles.length, paired, unmatched };
481
- }
482
- function commonSegments(pathA, pathB) {
483
- const segsA = pathA.split("/");
484
- const segsB = pathB.split("/");
485
- let count2 = 0;
486
- for (let i = 0; i < Math.min(segsA.length, segsB.length); i++) {
487
- if (segsA[i] === segsB[i]) count2++;
488
- else break;
489
- }
490
- return count2;
491
- }
492
-
493
422
  // src/snapshot/snapshot.ts
494
423
  var repoPath = z2.string().refine((value) => normalizeRepoPath(value) !== null, "Expected a relative repository path");
495
424
  var verificationFields = {
@@ -600,11 +529,11 @@ import fg3 from "fast-glob";
600
529
  // src/audit/inspection.ts
601
530
  import fg2 from "fast-glob";
602
531
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
603
- import path7 from "path";
532
+ import path5 from "path";
604
533
  var inspections = new AsyncLocalStorage2();
605
534
  function inspectionRead(root, key, read) {
606
535
  const inspection = inspections.getStore();
607
- if (!inspection || inspection.root !== path7.resolve(root)) return read();
536
+ if (!inspection || inspection.root !== path5.resolve(root)) return read();
608
537
  if (!inspection.reads.has(key)) {
609
538
  const pending = read();
610
539
  inspection.reads.set(key, pending);
@@ -645,7 +574,12 @@ async function captureAnchorScopes(root, scopes) {
645
574
  );
646
575
  const inventory = access.inventory();
647
576
  if (!inventory) throw new Error("Git anchor inventory unavailable");
648
- const ignored = await inspectionGit(
577
+ const visible = indexMatchingPaths(
578
+ union.map((anchor) => [anchor]),
579
+ inventory
580
+ );
581
+ const hidden = new Set(union.filter((_, index2) => !visible[index2].length));
582
+ const ignored = hidden.size ? (await inspectionGit(
649
583
  [
650
584
  "ls-files",
651
585
  "-z",
@@ -653,13 +587,11 @@ async function captureAnchorScopes(root, scopes) {
653
587
  "--ignored",
654
588
  "--exclude-standard",
655
589
  "--",
656
- ...union.map((anchor) => `:(literal)${anchor}`)
590
+ ...[...hidden].map((anchor) => `:(literal)${anchor}`)
657
591
  ],
658
592
  { cwd: root, maxBuffer: 8 * 1024 * 1024 }
659
- );
660
- const files = [
661
- .../* @__PURE__ */ new Set([...inventory, ...ignored.stdout.split("\0").filter(Boolean)])
662
- ].sort();
593
+ )).stdout.split("\0").filter(Boolean) : [];
594
+ const files = [.../* @__PURE__ */ new Set([...inventory, ...ignored])].sort();
663
595
  const patterns = await Promise.all(
664
596
  union.map(async (anchor) => {
665
597
  const literal = fg3.escapePath(anchor);
@@ -675,7 +607,7 @@ async function captureAnchorScopes(root, scopes) {
675
607
  const filesByScope = new Map(
676
608
  scopes.map((scope, index2) => [JSON.stringify([...new Set(scope)].sort()), indexed[index2]])
677
609
  );
678
- return { filesByScope, eligible };
610
+ return { filesByScope, eligible, hidden, ignored: new Set(ignored) };
679
611
  };
680
612
  return Promise.all(
681
613
  scopes.map((scope) => {
@@ -687,8 +619,10 @@ async function captureAnchorScopes(root, scopes) {
687
619
  const capture = { anchors, files: {}, complete: true };
688
620
  if (!anchors.length) return capture;
689
621
  try {
690
- const { eligible, filesByScope } = await (context ??= prepareContext());
691
- const files = filesByScope.get(JSON.stringify(anchors));
622
+ const { eligible, filesByScope, hidden, ignored } = await (context ??= prepareContext());
623
+ const files = filesByScope.get(JSON.stringify(anchors)).filter(
624
+ (file) => !ignored.has(file) || anchors.some((anchor) => hidden.has(anchor) && anchorMatches(anchor, file))
625
+ );
692
626
  if (files.length > 2e3) return { ...capture, complete: false };
693
627
  for (const file of files) {
694
628
  const evidence = await inspectionRead(
@@ -847,6 +781,7 @@ var currentSchema = legacySchema.extend({
847
781
  inspector: text(200),
848
782
  note: text(1500),
849
783
  outcome: z4.literal("no_contradiction_found"),
784
+ scope: z4.literal("operative").optional(),
850
785
  decisionDigest: z4.string().regex(/^[a-f0-9]{64}$/),
851
786
  headHash: z4.string(),
852
787
  capture: anchorCaptureSchema
@@ -957,8 +892,19 @@ function decisionTrust(record, freshness) {
957
892
  freshness
958
893
  );
959
894
  }
960
- function decisionInspectionDigest(record) {
895
+ function decisionInspectionDigest(record, scope = "all") {
961
896
  const effective = effectiveDecision(record);
897
+ if (scope === "operative")
898
+ return createHash2("sha256").update(
899
+ JSON.stringify([
900
+ "operative",
901
+ record.status,
902
+ decisionApproval(effective),
903
+ effective.version === 2 ? effective.revision : 0,
904
+ decisionContent(effective),
905
+ effective.refreshedHash
906
+ ])
907
+ ).digest("hex");
962
908
  return createHash2("sha256").update(
963
909
  JSON.stringify([
964
910
  record.status,
@@ -970,8 +916,10 @@ function decisionInspectionDigest(record) {
970
916
  ])
971
917
  ).digest("hex");
972
918
  }
973
- function latestDecisionInspection(record) {
974
- return record.version === 2 ? record.inspections?.filter((i) => i.decisionDigest === decisionInspectionDigest(record)).at(-1) : void 0;
919
+ function latestDecisionInspection(record, scope = "all") {
920
+ return record.version === 2 ? record.inspections?.filter(
921
+ (i) => (scope === "operative" || i.scope !== "operative") && i.decisionDigest === decisionInspectionDigest(record, i.scope ?? "all")
922
+ ).at(-1) : void 0;
975
923
  }
976
924
  function revisionKnowledge(record, freshness) {
977
925
  return {
@@ -982,7 +930,10 @@ function revisionKnowledge(record, freshness) {
982
930
  }
983
931
  function decisionKnowledge(record, freshness = "unknown", proposalFreshness = "unknown") {
984
932
  const effective = effectiveDecision(record);
985
- const inspection = latestDecisionInspection(record);
933
+ const inspection = latestDecisionInspection(
934
+ record,
935
+ decisionApproval(effective) === "accepted" ? "operative" : "all"
936
+ );
986
937
  return {
987
938
  ...revisionKnowledge(effective, freshness),
988
939
  ...inspection ? {
@@ -992,21 +943,27 @@ function decisionKnowledge(record, freshness = "unknown", proposalFreshness = "u
992
943
  inspector: inspection.inspector,
993
944
  note: inspection.note,
994
945
  outcome: inspection.outcome,
946
+ scope: inspection.scope ?? "all",
995
947
  headHash: inspection.headHash
996
948
  }
997
949
  } : {},
998
- ...effective !== record ? { pendingProposal: revisionKnowledge(record, proposalFreshness) } : {}
950
+ ...effective !== record ? {
951
+ pendingProposal: {
952
+ ...revisionKnowledge(record, proposalFreshness),
953
+ assessment: latestDecisionInspection(record) ? "no_contradiction_found" : "not_assessed"
954
+ }
955
+ } : {}
999
956
  };
1000
957
  }
1001
958
 
1002
959
  // src/decisions/decisions.ts
1003
960
  import fs6 from "fs/promises";
1004
- import path9 from "path";
961
+ import path7 from "path";
1005
962
  import { createHash as createHash3 } from "crypto";
1006
963
  import { z as z5 } from "zod";
1007
964
 
1008
965
  // src/context/lexical.ts
1009
- import path8 from "path";
966
+ import path6 from "path";
1010
967
 
1011
968
  // src/decisions/decisions.ts
1012
969
  var TITLE_MAX_CHARS = 80;
@@ -1085,9 +1042,31 @@ async function loadDecisionStore(rootDir) {
1085
1042
  }
1086
1043
 
1087
1044
  // src/decisions/drift.ts
1088
- import path10 from "path";
1045
+ import path8 from "path";
1046
+
1047
+ // src/decisions/excerpts.ts
1048
+ import { createHash as createHash4 } from "crypto";
1049
+ import { execFile as execFile2 } from "child_process";
1050
+ import { promisify as promisify2 } from "util";
1051
+ var exec = promisify2(execFile2);
1052
+ function driftBaseline(record) {
1053
+ const effective = effectiveDecision(record);
1054
+ const inspection = latestDecisionInspection(
1055
+ record,
1056
+ decisionApproval(effective) === "accepted" ? "operative" : "all"
1057
+ );
1058
+ return {
1059
+ record: effective,
1060
+ capture: inspection?.capture ?? (effective.version === 2 ? effective.capture : void 0),
1061
+ commits: [inspection?.headHash, effective.refreshedHash].filter(
1062
+ (hash) => !!hash && /^[a-f0-9]{40,64}$/.test(hash)
1063
+ )
1064
+ };
1065
+ }
1066
+
1067
+ // src/decisions/drift.ts
1089
1068
  async function computeDecisionDrift(rootDir, decisions) {
1090
- const resolvedRoot = path10.resolve(rootDir);
1069
+ const resolvedRoot = path8.resolve(rootDir);
1091
1070
  const store = decisions ? { records: decisions, diagnostics: [] } : await loadDecisionStore(resolvedRoot);
1092
1071
  const report = {
1093
1072
  historyAvailable: true,
@@ -1102,11 +1081,15 @@ async function computeDecisionDrift(rootDir, decisions) {
1102
1081
  ]);
1103
1082
  const changesByHash = /* @__PURE__ */ new Map();
1104
1083
  const baselines = store.records.filter((record) => record.status === "active").flatMap((record) => {
1105
- const inspection = latestDecisionInspection(record);
1106
- if (inspection) return [inspection.capture];
1107
- return [.../* @__PURE__ */ new Set([effectiveDecision(record), record])].flatMap(
1108
- (candidate) => candidate.version === 2 && candidate.capture ? [candidate.capture] : []
1109
- );
1084
+ const effective = effectiveDecision(record);
1085
+ return [.../* @__PURE__ */ new Set([effective, record])].flatMap((candidate) => {
1086
+ const inspection = latestDecisionInspection(
1087
+ record,
1088
+ candidate === effective && decisionApproval(effective) === "accepted" ? "operative" : "all"
1089
+ );
1090
+ const capture = inspection?.capture ?? (candidate.version === 2 ? candidate.capture : void 0);
1091
+ return capture ? [capture] : [];
1092
+ });
1110
1093
  });
1111
1094
  const captures = await captureAnchorScopes(
1112
1095
  resolvedRoot,
@@ -1144,21 +1127,23 @@ async function computeDecisionDrift(rootDir, decisions) {
1144
1127
  };
1145
1128
  for (const record of store.records) {
1146
1129
  if (record.status !== "active") continue;
1147
- const effective = effectiveDecision(record);
1148
- const inspection = latestDecisionInspection(record);
1149
- const state = await inspect(effective, inspection?.capture);
1130
+ const baseline = driftBaseline(record);
1131
+ const state = await inspect(baseline.record, baseline.capture);
1150
1132
  report.freshness[record.id] = state.freshness;
1151
1133
  if (state.changedFiles.length) report.staleDecisions[record.id] = state.changedFiles;
1152
- if (effective !== record)
1153
- (report.pendingProposals ??= {})[record.id] = await inspect(record, inspection?.capture);
1134
+ if (baseline.record !== record)
1135
+ (report.pendingProposals ??= {})[record.id] = await inspect(
1136
+ record,
1137
+ latestDecisionInspection(record)?.capture
1138
+ );
1154
1139
  }
1155
1140
  return report;
1156
1141
  }
1157
1142
 
1158
1143
  // src/review/cochange.ts
1159
- import { execFile as execFile2 } from "child_process";
1160
- import { promisify as promisify2 } from "util";
1161
- var exec = promisify2(execFile2);
1144
+ import { execFile as execFile3 } from "child_process";
1145
+ import { promisify as promisify3 } from "util";
1146
+ var exec2 = promisify3(execFile3);
1162
1147
  var HISTORY_COMMITS = 1500;
1163
1148
  var MIN_FILE_COMMITS = 5;
1164
1149
  var MIN_SHARED_COMMITS = 4;
@@ -1166,11 +1151,11 @@ var MIN_COCHANGE_RATE = 0.6;
1166
1151
  var MAX_COMMIT_FILES = 30;
1167
1152
  async function buildMatrix(resolvedRoot) {
1168
1153
  try {
1169
- const { stdout: shallow } = await exec("git", ["rev-parse", "--is-shallow-repository"], {
1154
+ const { stdout: shallow } = await exec2("git", ["rev-parse", "--is-shallow-repository"], {
1170
1155
  cwd: resolvedRoot
1171
1156
  });
1172
1157
  if (shallow.trim() === "true") return null;
1173
- const { stdout } = await exec(
1158
+ const { stdout } = await exec2(
1174
1159
  "git",
1175
1160
  ["log", `-n${HISTORY_COMMITS}`, "--format=%x01", "--name-only", "-M"],
1176
1161
  { cwd: resolvedRoot, maxBuffer: 100 * 1024 * 1024 }
@@ -1228,9 +1213,79 @@ async function findMissingPartners(resolvedRoot, changedFiles, existsOnDisk, all
1228
1213
  }
1229
1214
 
1230
1215
  // src/review/evidence.ts
1231
- import path11 from "path";
1216
+ import path10 from "path";
1232
1217
  import { z as z9 } from "zod";
1233
1218
 
1219
+ // src/test-map.ts
1220
+ import path9 from "path";
1221
+ async function buildTestMap(dir) {
1222
+ const rootDir = path9.resolve(dir);
1223
+ const access = await createFileAccess(rootDir);
1224
+ const testPatterns = [
1225
+ "**/*.test.*",
1226
+ "**/*.spec.*",
1227
+ "**/*Test.kt",
1228
+ "**/*Test.java",
1229
+ "**/*Tests.kt",
1230
+ "**/*Tests.java",
1231
+ "**/test_*.py",
1232
+ "**/*_test.py",
1233
+ "**/*_test.go",
1234
+ "**/*Tests.swift",
1235
+ "**/*Test.swift",
1236
+ "**/*_test.rs"
1237
+ ];
1238
+ const testFiles = await access.list(testPatterns);
1239
+ const sourceFiles = await access.list();
1240
+ const sourceByBaseName = /* @__PURE__ */ new Map();
1241
+ for (const file of sourceFiles) {
1242
+ if (testFiles.includes(file)) continue;
1243
+ const baseName = path9.basename(file).replace(/\.[^.]+$/, "");
1244
+ const existing = sourceByBaseName.get(baseName) ?? [];
1245
+ existing.push(file);
1246
+ sourceByBaseName.set(baseName, existing);
1247
+ }
1248
+ const paired = [];
1249
+ const unmatched = [];
1250
+ for (const testFile of testFiles) {
1251
+ const testBaseName = path9.basename(testFile).replace(/\.[^.]+$/, "");
1252
+ const sourceName = testBaseName.replace(/Test$|Tests$|Spec$|\.test$|\.spec$/, "").replace(/^test_|_test$/, "");
1253
+ if (!sourceName) {
1254
+ unmatched.push(testFile);
1255
+ continue;
1256
+ }
1257
+ const candidates = sourceByBaseName.get(sourceName);
1258
+ if (candidates && candidates.length > 0) {
1259
+ const testDir = path9.dirname(testFile);
1260
+ const bestMatch = candidates.reduce((best, candidate) => {
1261
+ const candidateDir = path9.dirname(candidate);
1262
+ const bestDir = path9.dirname(best);
1263
+ const candidateOverlap = commonSegments(testDir, candidateDir);
1264
+ const bestOverlap = commonSegments(testDir, bestDir);
1265
+ return candidateOverlap > bestOverlap ? candidate : best;
1266
+ });
1267
+ paired.push({
1268
+ test: testFile,
1269
+ source: bestMatch,
1270
+ confidence: candidates.length === 1 ? "exact" : "best-guess"
1271
+ });
1272
+ } else {
1273
+ unmatched.push(testFile);
1274
+ }
1275
+ }
1276
+ return { totalTestFiles: testFiles.length, paired, unmatched };
1277
+ }
1278
+ function commonSegments(pathA, pathB) {
1279
+ const segsA = pathA.split("/");
1280
+ const segsB = pathB.split("/");
1281
+ let count2 = 0;
1282
+ for (let i = 0; i < Math.min(segsA.length, segsB.length); i++) {
1283
+ if (segsA[i] === segsB[i]) count2++;
1284
+ else break;
1285
+ }
1286
+ return count2;
1287
+ }
1288
+
1234
1289
  // src/review/evidence/vitest.ts
1235
1290
  import { z as z6 } from "zod";
1236
1291
 
@@ -1622,7 +1677,7 @@ var checkSchema = z9.object({
1622
1677
  }).optional()
1623
1678
  });
1624
1679
  function relativeArtifact(root, file) {
1625
- const relative = path11.isAbsolute(file) ? path11.relative(root, file) : file;
1680
+ const relative = path10.isAbsolute(file) ? path10.relative(root, file) : file;
1626
1681
  const normalized = normalizeRepoPath(relative);
1627
1682
  if (!normalized) throw new Error(`Evidence artifact must be inside the repository: ${file}`);
1628
1683
  return normalized;
@@ -1751,7 +1806,7 @@ async function collectReviewEvidence(root, manifests, changedFiles, decisions, d
1751
1806
  const report = await readStoreJson(root, file);
1752
1807
  if (report === null) throw new Error(`Report artifact is missing: ${file}`);
1753
1808
  const sourceRoot = check.sourceRoot ?? root;
1754
- if (!path11.posix.isAbsolute(sourceRoot) && !/^[A-Za-z]:[\\/]/.test(sourceRoot))
1809
+ if (!path10.posix.isAbsolute(sourceRoot) && !/^[A-Za-z]:[\\/]/.test(sourceRoot))
1755
1810
  throw new Error(
1756
1811
  "sourceRoot must identify the absolute checkout root on the check runner."
1757
1812
  );
@@ -1828,11 +1883,11 @@ async function collectReviewEvidence(root, manifests, changedFiles, decisions, d
1828
1883
  }
1829
1884
 
1830
1885
  // src/review/review.ts
1831
- var exec2 = promisify3(execFile3);
1886
+ var exec3 = promisify4(execFile4);
1832
1887
  var MAX_ANALYZED_FILES = 50;
1833
1888
  async function resolveMergeBase(resolvedRoot, base, head) {
1834
1889
  try {
1835
- const { stdout } = await exec2("git", ["merge-base", base, head], {
1890
+ const { stdout } = await exec3("git", ["merge-base", base, head], {
1836
1891
  cwd: resolvedRoot
1837
1892
  });
1838
1893
  return stdout.trim() || null;
@@ -1843,7 +1898,7 @@ async function resolveMergeBase(resolvedRoot, base, head) {
1843
1898
  async function defaultBase(resolvedRoot) {
1844
1899
  for (const ref of ["origin/HEAD", "origin/main", "origin/master", "main"]) {
1845
1900
  try {
1846
- await exec2("git", ["rev-parse", "--verify", "--quiet", ref], {
1901
+ await exec3("git", ["rev-parse", "--verify", "--quiet", ref], {
1847
1902
  cwd: resolvedRoot
1848
1903
  });
1849
1904
  return ref;
@@ -1856,7 +1911,7 @@ function anchorsTouched(record, changedFiles) {
1856
1911
  return matchingPaths(record.files, changedFiles);
1857
1912
  }
1858
1913
  async function computeReview(rootDir, base, options = {}) {
1859
- const resolvedRoot = path12.resolve(rootDir);
1914
+ const resolvedRoot = path11.resolve(rootDir);
1860
1915
  const head = await getCurrentGitHash(resolvedRoot);
1861
1916
  if (head === "unknown") return null;
1862
1917
  const mergeBase = await resolveMergeBase(resolvedRoot, base, head);
@@ -1917,7 +1972,7 @@ async function computeReview(rootDir, base, options = {}) {
1917
1972
  analyzed,
1918
1973
  async (relPath) => {
1919
1974
  try {
1920
- await fs7.access(path12.join(resolvedRoot, relPath));
1975
+ await fs7.access(path11.join(resolvedRoot, relPath));
1921
1976
  return true;
1922
1977
  } catch {
1923
1978
  return false;
@@ -2152,7 +2207,7 @@ async function runReviewCli(argv, io = {
2152
2207
  io.out(USAGE);
2153
2208
  return 0;
2154
2209
  }
2155
- const rootDir = path13.resolve(args.dir);
2210
+ const rootDir = path12.resolve(args.dir);
2156
2211
  const base = args.base ?? await defaultBase(rootDir);
2157
2212
  if (!base) {
2158
2213
  io.err(