truecourse 0.7.0-next.7 → 0.7.0-next.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.mjs CHANGED
@@ -972,8 +972,8 @@ var require_command = __commonJS({
972
972
  "node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
973
973
  var EventEmitter2 = __require("node:events").EventEmitter;
974
974
  var childProcess = __require("node:child_process");
975
- var path80 = __require("node:path");
976
- var fs71 = __require("node:fs");
975
+ var path81 = __require("node:path");
976
+ var fs72 = __require("node:fs");
977
977
  var process2 = __require("node:process");
978
978
  var { Argument: Argument2, humanReadableArgName } = require_argument();
979
979
  var { CommanderError: CommanderError2 } = require_error();
@@ -1905,11 +1905,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1905
1905
  let launchWithNode = false;
1906
1906
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1907
1907
  function findFile(baseDir, baseName) {
1908
- const localBin = path80.resolve(baseDir, baseName);
1909
- if (fs71.existsSync(localBin)) return localBin;
1910
- if (sourceExt.includes(path80.extname(baseName))) return void 0;
1908
+ const localBin = path81.resolve(baseDir, baseName);
1909
+ if (fs72.existsSync(localBin)) return localBin;
1910
+ if (sourceExt.includes(path81.extname(baseName))) return void 0;
1911
1911
  const foundExt = sourceExt.find(
1912
- (ext2) => fs71.existsSync(`${localBin}${ext2}`)
1912
+ (ext2) => fs72.existsSync(`${localBin}${ext2}`)
1913
1913
  );
1914
1914
  if (foundExt) return `${localBin}${foundExt}`;
1915
1915
  return void 0;
@@ -1921,21 +1921,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
1921
1921
  if (this._scriptPath) {
1922
1922
  let resolvedScriptPath;
1923
1923
  try {
1924
- resolvedScriptPath = fs71.realpathSync(this._scriptPath);
1924
+ resolvedScriptPath = fs72.realpathSync(this._scriptPath);
1925
1925
  } catch (err) {
1926
1926
  resolvedScriptPath = this._scriptPath;
1927
1927
  }
1928
- executableDir = path80.resolve(
1929
- path80.dirname(resolvedScriptPath),
1928
+ executableDir = path81.resolve(
1929
+ path81.dirname(resolvedScriptPath),
1930
1930
  executableDir
1931
1931
  );
1932
1932
  }
1933
1933
  if (executableDir) {
1934
1934
  let localFile = findFile(executableDir, executableFile);
1935
1935
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1936
- const legacyName = path80.basename(
1936
+ const legacyName = path81.basename(
1937
1937
  this._scriptPath,
1938
- path80.extname(this._scriptPath)
1938
+ path81.extname(this._scriptPath)
1939
1939
  );
1940
1940
  if (legacyName !== this._name) {
1941
1941
  localFile = findFile(
@@ -1946,7 +1946,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1946
1946
  }
1947
1947
  executableFile = localFile || executableFile;
1948
1948
  }
1949
- launchWithNode = sourceExt.includes(path80.extname(executableFile));
1949
+ launchWithNode = sourceExt.includes(path81.extname(executableFile));
1950
1950
  let proc;
1951
1951
  if (process2.platform !== "win32") {
1952
1952
  if (launchWithNode) {
@@ -2786,7 +2786,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2786
2786
  * @return {Command}
2787
2787
  */
2788
2788
  nameFromFilename(filename) {
2789
- this._name = path80.basename(filename, path80.extname(filename));
2789
+ this._name = path81.basename(filename, path81.extname(filename));
2790
2790
  return this;
2791
2791
  }
2792
2792
  /**
@@ -2800,9 +2800,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2800
2800
  * @param {string} [path]
2801
2801
  * @return {(string|null|Command)}
2802
2802
  */
2803
- executableDir(path81) {
2804
- if (path81 === void 0) return this._executableDir;
2805
- this._executableDir = path81;
2803
+ executableDir(path82) {
2804
+ if (path82 === void 0) return this._executableDir;
2805
+ this._executableDir = path82;
2806
2806
  return this;
2807
2807
  }
2808
2808
  /**
@@ -5206,8 +5206,8 @@ var init_parseUtil = __esm({
5206
5206
  init_errors();
5207
5207
  init_en();
5208
5208
  makeIssue = (params) => {
5209
- const { data, path: path80, errorMaps, issueData } = params;
5210
- const fullPath = [...path80, ...issueData.path || []];
5209
+ const { data, path: path81, errorMaps, issueData } = params;
5210
+ const fullPath = [...path81, ...issueData.path || []];
5211
5211
  const fullIssue = {
5212
5212
  ...issueData,
5213
5213
  path: fullPath
@@ -5515,11 +5515,11 @@ var init_types = __esm({
5515
5515
  init_parseUtil();
5516
5516
  init_util();
5517
5517
  ParseInputLazyPath = class {
5518
- constructor(parent, value, path80, key4) {
5518
+ constructor(parent, value, path81, key4) {
5519
5519
  this._cachedPath = [];
5520
5520
  this.parent = parent;
5521
5521
  this.data = value;
5522
- this._path = path80;
5522
+ this._path = path81;
5523
5523
  this._key = key4;
5524
5524
  }
5525
5525
  get path() {
@@ -11976,10 +11976,10 @@ var require_src3 = __commonJS({
11976
11976
  var fs_1 = __require("fs");
11977
11977
  var debug_1 = __importDefault(require_src2());
11978
11978
  var log2 = debug_1.default("@kwsites/file-exists");
11979
- function check(path80, isFile, isDirectory) {
11980
- log2(`checking %s`, path80);
11979
+ function check(path81, isFile, isDirectory) {
11980
+ log2(`checking %s`, path81);
11981
11981
  try {
11982
- const stat = fs_1.statSync(path80);
11982
+ const stat = fs_1.statSync(path81);
11983
11983
  if (stat.isFile() && isFile) {
11984
11984
  log2(`[OK] path represents a file`);
11985
11985
  return true;
@@ -11999,8 +11999,8 @@ var require_src3 = __commonJS({
11999
11999
  throw e;
12000
12000
  }
12001
12001
  }
12002
- function exists2(path80, type2 = exports.READABLE) {
12003
- return check(path80, (type2 & exports.FILE) > 0, (type2 & exports.FOLDER) > 0);
12002
+ function exists2(path81, type2 = exports.READABLE) {
12003
+ return check(path81, (type2 & exports.FILE) > 0, (type2 & exports.FOLDER) > 0);
12004
12004
  }
12005
12005
  exports.exists = exists2;
12006
12006
  exports.FILE = 1;
@@ -12073,8 +12073,8 @@ function pathspec(...paths) {
12073
12073
  cache.set(key4, paths);
12074
12074
  return key4;
12075
12075
  }
12076
- function isPathSpec(path80) {
12077
- return path80 instanceof String && cache.has(path80);
12076
+ function isPathSpec(path81) {
12077
+ return path81 instanceof String && cache.has(path81);
12078
12078
  }
12079
12079
  function toPaths(pathSpec) {
12080
12080
  return cache.get(pathSpec) || [];
@@ -12118,8 +12118,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
12118
12118
  function forEachLineWithContent(input, callback) {
12119
12119
  return toLinesWithContent(input, true).map((line) => callback(line));
12120
12120
  }
12121
- function folderExists(path80) {
12122
- return (0, import_file_exists.exists)(path80, import_file_exists.FOLDER);
12121
+ function folderExists(path81) {
12122
+ return (0, import_file_exists.exists)(path81, import_file_exists.FOLDER);
12123
12123
  }
12124
12124
  function append(target, item) {
12125
12125
  if (Array.isArray(target)) {
@@ -12310,8 +12310,8 @@ function checkIsRepoRootTask() {
12310
12310
  commands,
12311
12311
  format: "utf-8",
12312
12312
  onError,
12313
- parser(path80) {
12314
- return /^\.(git)?$/.test(path80.trim());
12313
+ parser(path81) {
12314
+ return /^\.(git)?$/.test(path81.trim());
12315
12315
  }
12316
12316
  };
12317
12317
  }
@@ -12567,11 +12567,11 @@ function parseGrep(grep) {
12567
12567
  const paths = /* @__PURE__ */ new Set();
12568
12568
  const results = {};
12569
12569
  forEachLineWithContent(grep, (input) => {
12570
- const [path80, line, preview] = input.split(NULL);
12571
- paths.add(path80);
12572
- (results[path80] = results[path80] || []).push({
12570
+ const [path81, line, preview] = input.split(NULL);
12571
+ paths.add(path81);
12572
+ (results[path81] = results[path81] || []).push({
12573
12573
  line: asNumber(line),
12574
- path: path80,
12574
+ path: path81,
12575
12575
  preview
12576
12576
  });
12577
12577
  });
@@ -12868,14 +12868,14 @@ function hashObjectTask(filePath, write) {
12868
12868
  }
12869
12869
  return straightThroughStringTask(commands, true);
12870
12870
  }
12871
- function parseInit(bare, path80, text4) {
12871
+ function parseInit(bare, path81, text4) {
12872
12872
  const response = String(text4).trim();
12873
12873
  let result;
12874
12874
  if (result = initResponseRegex.exec(response)) {
12875
- return new InitSummary(bare, path80, false, result[1]);
12875
+ return new InitSummary(bare, path81, false, result[1]);
12876
12876
  }
12877
12877
  if (result = reInitResponseRegex.exec(response)) {
12878
- return new InitSummary(bare, path80, true, result[1]);
12878
+ return new InitSummary(bare, path81, true, result[1]);
12879
12879
  }
12880
12880
  let gitDir = "";
12881
12881
  const tokens = response.split(" ");
@@ -12886,12 +12886,12 @@ function parseInit(bare, path80, text4) {
12886
12886
  break;
12887
12887
  }
12888
12888
  }
12889
- return new InitSummary(bare, path80, /^re/i.test(response), gitDir);
12889
+ return new InitSummary(bare, path81, /^re/i.test(response), gitDir);
12890
12890
  }
12891
12891
  function hasBareCommand(command) {
12892
12892
  return command.includes(bareCommand);
12893
12893
  }
12894
- function initTask(bare = false, path80, customArgs) {
12894
+ function initTask(bare = false, path81, customArgs) {
12895
12895
  const commands = ["init", ...customArgs];
12896
12896
  if (bare && !hasBareCommand(commands)) {
12897
12897
  commands.splice(1, 0, bareCommand);
@@ -12900,7 +12900,7 @@ function initTask(bare = false, path80, customArgs) {
12900
12900
  commands,
12901
12901
  format: "utf-8",
12902
12902
  parser(text4) {
12903
- return parseInit(commands.includes("--bare"), path80, text4);
12903
+ return parseInit(commands.includes("--bare"), path81, text4);
12904
12904
  }
12905
12905
  };
12906
12906
  }
@@ -13179,14 +13179,14 @@ function splitLine(result, lineStr) {
13179
13179
  default:
13180
13180
  return;
13181
13181
  }
13182
- function data(index, workingDir, path80) {
13182
+ function data(index, workingDir, path81) {
13183
13183
  const raw = `${index}${workingDir}`;
13184
13184
  const handler = parsers6.get(raw);
13185
13185
  if (handler) {
13186
- handler(result, path80);
13186
+ handler(result, path81);
13187
13187
  }
13188
13188
  if (raw !== "##" && raw !== "!!") {
13189
- result.files.push(new FileStatusSummary(path80, index, workingDir));
13189
+ result.files.push(new FileStatusSummary(path81, index, workingDir));
13190
13190
  }
13191
13191
  }
13192
13192
  }
@@ -13373,8 +13373,8 @@ function deleteBranchTask(branch, forceDelete = false) {
13373
13373
  return task;
13374
13374
  }
13375
13375
  function toPath(input) {
13376
- const path80 = input.trim().replace(/^["']|["']$/g, "");
13377
- return path80 && normalize(path80);
13376
+ const path81 = input.trim().replace(/^["']|["']$/g, "");
13377
+ return path81 && normalize(path81);
13378
13378
  }
13379
13379
  function checkIgnoreTask(paths) {
13380
13380
  return {
@@ -13513,8 +13513,8 @@ function stashListTask(opt = {}, customArgs) {
13513
13513
  parser: parser4
13514
13514
  };
13515
13515
  }
13516
- function addSubModuleTask(repo, path80) {
13517
- return subModuleTask(["add", repo, path80]);
13516
+ function addSubModuleTask(repo, path81) {
13517
+ return subModuleTask(["add", repo, path81]);
13518
13518
  }
13519
13519
  function initSubModuleTask(customArgs) {
13520
13520
  return subModuleTask(["init", ...customArgs]);
@@ -14826,9 +14826,9 @@ var init_esm2 = __esm({
14826
14826
  "src/lib/responses/InitSummary.ts"() {
14827
14827
  "use strict";
14828
14828
  InitSummary = class {
14829
- constructor(bare, path80, existing, gitDir) {
14829
+ constructor(bare, path81, existing, gitDir) {
14830
14830
  this.bare = bare;
14831
- this.path = path80;
14831
+ this.path = path81;
14832
14832
  this.existing = existing;
14833
14833
  this.gitDir = gitDir;
14834
14834
  }
@@ -15362,12 +15362,12 @@ var init_esm2 = __esm({
15362
15362
  "use strict";
15363
15363
  fromPathRegex = /^(.+)\0(.+)$/;
15364
15364
  FileStatusSummary = class {
15365
- constructor(path80, index, working_dir) {
15366
- this.path = path80;
15365
+ constructor(path81, index, working_dir) {
15366
+ this.path = path81;
15367
15367
  this.index = index;
15368
15368
  this.working_dir = working_dir;
15369
15369
  if (index === "R" || working_dir === "R") {
15370
- const detail = fromPathRegex.exec(path80) || [null, path80, path80];
15370
+ const detail = fromPathRegex.exec(path81) || [null, path81, path81];
15371
15371
  this.from = detail[2] || "";
15372
15372
  this.path = detail[1] || "";
15373
15373
  }
@@ -15630,9 +15630,9 @@ var init_esm2 = __esm({
15630
15630
  next
15631
15631
  );
15632
15632
  }
15633
- hashObject(path80, write) {
15633
+ hashObject(path81, write) {
15634
15634
  return this._runTask(
15635
- hashObjectTask(path80, write === true),
15635
+ hashObjectTask(path81, write === true),
15636
15636
  trailingFunctionArgument(arguments)
15637
15637
  );
15638
15638
  }
@@ -16269,8 +16269,8 @@ var init_esm2 = __esm({
16269
16269
  }
16270
16270
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
16271
16271
  };
16272
- Git2.prototype.submoduleAdd = function(repo, path80, then) {
16273
- return this._runTask(addSubModuleTask2(repo, path80), trailingFunctionArgument2(arguments));
16272
+ Git2.prototype.submoduleAdd = function(repo, path81, then) {
16273
+ return this._runTask(addSubModuleTask2(repo, path81), trailingFunctionArgument2(arguments));
16274
16274
  };
16275
16275
  Git2.prototype.submoduleUpdate = function(args, then) {
16276
16276
  return this._runTask(
@@ -16896,7 +16896,7 @@ var require_ignore = __commonJS({
16896
16896
  // path matching.
16897
16897
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
16898
16898
  // @returns {TestResult} true if a file is ignored
16899
- test(path80, checkUnignored, mode) {
16899
+ test(path81, checkUnignored, mode) {
16900
16900
  let ignored = false;
16901
16901
  let unignored = false;
16902
16902
  let matchedRule;
@@ -16905,7 +16905,7 @@ var require_ignore = __commonJS({
16905
16905
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
16906
16906
  return;
16907
16907
  }
16908
- const matched = rule[mode].test(path80);
16908
+ const matched = rule[mode].test(path81);
16909
16909
  if (!matched) {
16910
16910
  return;
16911
16911
  }
@@ -16926,17 +16926,17 @@ var require_ignore = __commonJS({
16926
16926
  var throwError2 = (message, Ctor) => {
16927
16927
  throw new Ctor(message);
16928
16928
  };
16929
- var checkPath = (path80, originalPath, doThrow) => {
16930
- if (!isString(path80)) {
16929
+ var checkPath = (path81, originalPath, doThrow) => {
16930
+ if (!isString(path81)) {
16931
16931
  return doThrow(
16932
16932
  `path must be a string, but got \`${originalPath}\``,
16933
16933
  TypeError
16934
16934
  );
16935
16935
  }
16936
- if (!path80) {
16936
+ if (!path81) {
16937
16937
  return doThrow(`path must not be empty`, TypeError);
16938
16938
  }
16939
- if (checkPath.isNotRelative(path80)) {
16939
+ if (checkPath.isNotRelative(path81)) {
16940
16940
  const r = "`path.relative()`d";
16941
16941
  return doThrow(
16942
16942
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -16945,7 +16945,7 @@ var require_ignore = __commonJS({
16945
16945
  }
16946
16946
  return true;
16947
16947
  };
16948
- var isNotRelative = (path80) => REGEX_TEST_INVALID_PATH.test(path80);
16948
+ var isNotRelative = (path81) => REGEX_TEST_INVALID_PATH.test(path81);
16949
16949
  checkPath.isNotRelative = isNotRelative;
16950
16950
  checkPath.convert = (p2) => p2;
16951
16951
  var Ignore = class {
@@ -16975,19 +16975,19 @@ var require_ignore = __commonJS({
16975
16975
  }
16976
16976
  // @returns {TestResult}
16977
16977
  _test(originalPath, cache3, checkUnignored, slices) {
16978
- const path80 = originalPath && checkPath.convert(originalPath);
16978
+ const path81 = originalPath && checkPath.convert(originalPath);
16979
16979
  checkPath(
16980
- path80,
16980
+ path81,
16981
16981
  originalPath,
16982
16982
  this._strictPathCheck ? throwError2 : RETURN_FALSE
16983
16983
  );
16984
- return this._t(path80, cache3, checkUnignored, slices);
16984
+ return this._t(path81, cache3, checkUnignored, slices);
16985
16985
  }
16986
- checkIgnore(path80) {
16987
- if (!REGEX_TEST_TRAILING_SLASH.test(path80)) {
16988
- return this.test(path80);
16986
+ checkIgnore(path81) {
16987
+ if (!REGEX_TEST_TRAILING_SLASH.test(path81)) {
16988
+ return this.test(path81);
16989
16989
  }
16990
- const slices = path80.split(SLASH).filter(Boolean);
16990
+ const slices = path81.split(SLASH).filter(Boolean);
16991
16991
  slices.pop();
16992
16992
  if (slices.length) {
16993
16993
  const parent = this._t(
@@ -17000,18 +17000,18 @@ var require_ignore = __commonJS({
17000
17000
  return parent;
17001
17001
  }
17002
17002
  }
17003
- return this._rules.test(path80, false, MODE_CHECK_IGNORE);
17003
+ return this._rules.test(path81, false, MODE_CHECK_IGNORE);
17004
17004
  }
17005
- _t(path80, cache3, checkUnignored, slices) {
17006
- if (path80 in cache3) {
17007
- return cache3[path80];
17005
+ _t(path81, cache3, checkUnignored, slices) {
17006
+ if (path81 in cache3) {
17007
+ return cache3[path81];
17008
17008
  }
17009
17009
  if (!slices) {
17010
- slices = path80.split(SLASH).filter(Boolean);
17010
+ slices = path81.split(SLASH).filter(Boolean);
17011
17011
  }
17012
17012
  slices.pop();
17013
17013
  if (!slices.length) {
17014
- return cache3[path80] = this._rules.test(path80, checkUnignored, MODE_IGNORE);
17014
+ return cache3[path81] = this._rules.test(path81, checkUnignored, MODE_IGNORE);
17015
17015
  }
17016
17016
  const parent = this._t(
17017
17017
  slices.join(SLASH) + SLASH,
@@ -17019,29 +17019,29 @@ var require_ignore = __commonJS({
17019
17019
  checkUnignored,
17020
17020
  slices
17021
17021
  );
17022
- return cache3[path80] = parent.ignored ? parent : this._rules.test(path80, checkUnignored, MODE_IGNORE);
17022
+ return cache3[path81] = parent.ignored ? parent : this._rules.test(path81, checkUnignored, MODE_IGNORE);
17023
17023
  }
17024
- ignores(path80) {
17025
- return this._test(path80, this._ignoreCache, false).ignored;
17024
+ ignores(path81) {
17025
+ return this._test(path81, this._ignoreCache, false).ignored;
17026
17026
  }
17027
17027
  createFilter() {
17028
- return (path80) => !this.ignores(path80);
17028
+ return (path81) => !this.ignores(path81);
17029
17029
  }
17030
17030
  filter(paths) {
17031
17031
  return makeArray(paths).filter(this.createFilter());
17032
17032
  }
17033
17033
  // @returns {TestResult}
17034
- test(path80) {
17035
- return this._test(path80, this._testCache, true);
17034
+ test(path81) {
17035
+ return this._test(path81, this._testCache, true);
17036
17036
  }
17037
17037
  };
17038
17038
  var factory = (options) => new Ignore(options);
17039
- var isPathValid = (path80) => checkPath(path80 && checkPath.convert(path80), path80, RETURN_FALSE);
17039
+ var isPathValid = (path81) => checkPath(path81 && checkPath.convert(path81), path81, RETURN_FALSE);
17040
17040
  var setupWindows = () => {
17041
17041
  const makePosix = (str2) => /^\\\\\?\\/.test(str2) || /["<>|\u0000-\u001F]+/u.test(str2) ? str2 : str2.replace(/\\/g, "/");
17042
17042
  checkPath.convert = makePosix;
17043
17043
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
17044
- checkPath.isNotRelative = (path80) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path80) || isNotRelative(path80);
17044
+ checkPath.isNotRelative = (path81) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path81) || isNotRelative(path81);
17045
17045
  };
17046
17046
  if (
17047
17047
  // Detect `process` so that it can run in browsers.
@@ -18782,18 +18782,18 @@ function extractRouterMount(callNode, filePath) {
18782
18782
  const routerName = args[0]?.type === "identifier" ? args[0].text : null;
18783
18783
  if (!routerName)
18784
18784
  return null;
18785
- let path80 = "/";
18785
+ let path81 = "/";
18786
18786
  for (const arg of args) {
18787
18787
  if (arg.type === "keyword_argument") {
18788
18788
  const key4 = arg.childForFieldName("name")?.text;
18789
18789
  const value = arg.childForFieldName("value");
18790
18790
  if ((key4 === "url_prefix" || key4 === "prefix") && value) {
18791
- path80 = value.text.replace(/^["']|["']$/g, "");
18791
+ path81 = value.text.replace(/^["']|["']$/g, "");
18792
18792
  }
18793
18793
  }
18794
18794
  }
18795
18795
  return {
18796
- path: path80,
18796
+ path: path81,
18797
18797
  routerName,
18798
18798
  location: {
18799
18799
  filePath,
@@ -18817,11 +18817,11 @@ function extractChainedRoute(outerCall, filePath) {
18817
18817
  const innerArgs = innerCall.childForFieldName("arguments");
18818
18818
  if (!innerArgs)
18819
18819
  return null;
18820
- let path80 = null;
18820
+ let path81 = null;
18821
18821
  let httpMethod = methodName3 === "route" ? "GET" : methodName3.toUpperCase();
18822
18822
  for (const arg of innerArgs.namedChildren) {
18823
- if (!path80 && arg.type === "string") {
18824
- path80 = arg.text.replace(/^["']|["']$/g, "");
18823
+ if (!path81 && arg.type === "string") {
18824
+ path81 = arg.text.replace(/^["']|["']$/g, "");
18825
18825
  }
18826
18826
  if (arg.type === "keyword_argument") {
18827
18827
  const key4 = arg.childForFieldName("name")?.text;
@@ -18833,14 +18833,14 @@ function extractChainedRoute(outerCall, filePath) {
18833
18833
  }
18834
18834
  }
18835
18835
  }
18836
- if (!path80)
18836
+ if (!path81)
18837
18837
  return null;
18838
18838
  const outerArgs = outerCall.childForFieldName("arguments");
18839
18839
  const handlerArg = outerArgs?.namedChildren[0];
18840
18840
  const handlerName = handlerArg?.type === "identifier" ? handlerArg.text : "anonymous";
18841
18841
  return {
18842
18842
  httpMethod,
18843
- path: path80,
18843
+ path: path81,
18844
18844
  handlerName,
18845
18845
  location: {
18846
18846
  filePath,
@@ -18902,11 +18902,11 @@ function collectGroupPrefixes(root2) {
18902
18902
  const fn = child.childForFieldName("function");
18903
18903
  if (fn?.type === "member_access_expression" && fn.childForFieldName("name")?.text === "MapGroup") {
18904
18904
  const args = child.childForFieldName("arguments");
18905
- const path80 = args ? extractFirstStringArg(args) : null;
18906
- if (name && path80) {
18905
+ const path81 = args ? extractFirstStringArg(args) : null;
18906
+ if (name && path81) {
18907
18907
  const receiver = fn.childForFieldName("expression")?.text ?? "";
18908
18908
  const parentPrefix = prefixes.get(receiver) ?? "";
18909
- prefixes.set(name, joinRoute(parentPrefix, path80));
18909
+ prefixes.set(name, joinRoute(parentPrefix, path81));
18910
18910
  }
18911
18911
  }
18912
18912
  }
@@ -18930,9 +18930,9 @@ function extractClassRoutePrefix(classNode) {
18930
18930
  continue;
18931
18931
  const args = childOfType(attr, "attribute_argument_list");
18932
18932
  if (args) {
18933
- const path80 = extractFirstStringArg(args);
18934
- if (path80)
18935
- return path80;
18933
+ const path81 = extractFirstStringArg(args);
18934
+ if (path81)
18935
+ return path81;
18936
18936
  }
18937
18937
  }
18938
18938
  }
@@ -18955,16 +18955,16 @@ function extractAttributeRoute(methodNode, filePath, classContext) {
18955
18955
  httpMethod = method;
18956
18956
  const args = childOfType(attr, "attribute_argument_list");
18957
18957
  if (args) {
18958
- const path80 = extractFirstStringArg(args);
18959
- if (path80)
18960
- routePath = path80;
18958
+ const path81 = extractFirstStringArg(args);
18959
+ if (path81)
18960
+ routePath = path81;
18961
18961
  }
18962
18962
  } else if (name === "Route" && !routePath) {
18963
18963
  const args = childOfType(attr, "attribute_argument_list");
18964
18964
  if (args) {
18965
- const path80 = extractFirstStringArg(args);
18966
- if (path80)
18967
- routePath = path80;
18965
+ const path81 = extractFirstStringArg(args);
18966
+ if (path81)
18967
+ routePath = path81;
18968
18968
  }
18969
18969
  }
18970
18970
  }
@@ -18998,12 +18998,12 @@ function extractMinimalApiRoute(callNode, filePath, groupPrefixes) {
18998
18998
  const argsNode = callNode.childForFieldName("arguments");
18999
18999
  if (!argsNode)
19000
19000
  return null;
19001
- const path80 = extractFirstStringArg(argsNode);
19002
- if (path80 === null)
19001
+ const path81 = extractFirstStringArg(argsNode);
19002
+ if (path81 === null)
19003
19003
  return null;
19004
19004
  const receiver = funcNode.childForFieldName("expression")?.text ?? "";
19005
19005
  const prefix = groupPrefixes.get(receiver) ?? "";
19006
- let fullPath = joinRoute(prefix, path80);
19006
+ let fullPath = joinRoute(prefix, path81);
19007
19007
  if (!fullPath.startsWith("/"))
19008
19008
  fullPath = "/" + fullPath;
19009
19009
  let handlerName = "anonymous";
@@ -19030,11 +19030,11 @@ function childOfType(node2, type2) {
19030
19030
  }
19031
19031
  return null;
19032
19032
  }
19033
- function joinRoute(prefix, path80) {
19033
+ function joinRoute(prefix, path81) {
19034
19034
  const p2 = prefix.replace(/\/$/, "");
19035
- const s = path80.replace(/^\//, "");
19035
+ const s = path81.replace(/^\//, "");
19036
19036
  if (!p2)
19037
- return path80;
19037
+ return path81;
19038
19038
  if (!s)
19039
19039
  return p2;
19040
19040
  return `${p2}/${s}`;
@@ -19143,8 +19143,8 @@ function extractRoute(methodName3, argsNode, filePath, callNode) {
19143
19143
  const firstArg = argsNode.namedChild(0);
19144
19144
  if (!firstArg)
19145
19145
  return null;
19146
- const path80 = extractStringLiteral(firstArg);
19147
- if (!path80)
19146
+ const path81 = extractStringLiteral(firstArg);
19147
+ if (!path81)
19148
19148
  return null;
19149
19149
  const argCount = argsNode.namedChildCount;
19150
19150
  if (argCount < 2)
@@ -19157,7 +19157,7 @@ function extractRoute(methodName3, argsNode, filePath, callNode) {
19157
19157
  return null;
19158
19158
  return {
19159
19159
  httpMethod: methodName3.toUpperCase(),
19160
- path: path80,
19160
+ path: path81,
19161
19161
  handlerName,
19162
19162
  location: {
19163
19163
  filePath,
@@ -19174,8 +19174,8 @@ function extractMount(argsNode, filePath, callNode) {
19174
19174
  const firstArg = argsNode.namedChild(0);
19175
19175
  if (!firstArg)
19176
19176
  return null;
19177
- const path80 = extractStringLiteral(firstArg);
19178
- if (!path80)
19177
+ const path81 = extractStringLiteral(firstArg);
19178
+ if (!path81)
19179
19179
  return null;
19180
19180
  const secondArg = argsNode.namedChild(1);
19181
19181
  if (!secondArg)
@@ -19184,7 +19184,7 @@ function extractMount(argsNode, filePath, callNode) {
19184
19184
  if (!routerName)
19185
19185
  return null;
19186
19186
  return {
19187
- path: path80,
19187
+ path: path81,
19188
19188
  routerName,
19189
19189
  location: {
19190
19190
  filePath,
@@ -21715,11 +21715,11 @@ function buildCSharpSymbolIndex(files, rootPath) {
21715
21715
  byFullName.get(full).push(decl);
21716
21716
  }
21717
21717
  const stats = { resolvedRefs: 0, ambiguousRefs: 0 };
21718
- function resolveQualified(path80) {
21719
- const exact = byFullName.get(path80);
21718
+ function resolveQualified(path81) {
21719
+ const exact = byFullName.get(path81);
21720
21720
  if (exact)
21721
21721
  return exact;
21722
- const parts = path80.split(".");
21722
+ const parts = path81.split(".");
21723
21723
  for (let i = parts.length - 1; i > 0; i--) {
21724
21724
  const prefix = parts.slice(0, i).join(".");
21725
21725
  const found = byFullName.get(prefix);
@@ -21733,8 +21733,8 @@ function buildCSharpSymbolIndex(files, rootPath) {
21733
21733
  const firstDot = ref.name.indexOf(".");
21734
21734
  const head = ref.name.slice(0, firstDot);
21735
21735
  const aliasTarget2 = aliases.get(head);
21736
- const path80 = aliasTarget2 ? `${aliasTarget2}${ref.name.slice(firstDot)}` : ref.name;
21737
- return resolveQualified(path80).filter((d3) => isDeclVisibleFrom(d3, ctx.project, fileProjects.get(d3.filePath)));
21736
+ const path81 = aliasTarget2 ? `${aliasTarget2}${ref.name.slice(firstDot)}` : ref.name;
21737
+ return resolveQualified(path81).filter((d3) => isDeclVisibleFrom(d3, ctx.project, fileProjects.get(d3.filePath)));
21738
21738
  }
21739
21739
  const aliasTarget = aliases.get(ref.name);
21740
21740
  if (aliasTarget) {
@@ -24855,9 +24855,9 @@ function detectDockerComposeServices(rootPath, allFiles) {
24855
24855
  ];
24856
24856
  let composePath2 = null;
24857
24857
  for (const file of composeFiles) {
24858
- const path80 = join8(rootPath, file);
24859
- if (existsSync7(path80)) {
24860
- composePath2 = path80;
24858
+ const path81 = join8(rootPath, file);
24859
+ if (existsSync7(path81)) {
24860
+ composePath2 = path81;
24861
24861
  break;
24862
24862
  }
24863
24863
  }
@@ -28077,9 +28077,9 @@ function findSimpleCycles(component, componentSet, adjacency) {
28077
28077
  for (const next of successors) {
28078
28078
  if (!componentSet.has(next))
28079
28079
  continue;
28080
- if (next === start && path80.length >= 2) {
28081
- const chain = [...path80, start];
28082
- const minNode = path80.reduce((a, b) => a < b ? a : b);
28080
+ if (next === start && path81.length >= 2) {
28081
+ const chain = [...path81, start];
28082
+ const minNode = path81.reduce((a, b) => a < b ? a : b);
28083
28083
  if (minNode === start) {
28084
28084
  cycles.push(chain);
28085
28085
  }
@@ -28087,15 +28087,15 @@ function findSimpleCycles(component, componentSet, adjacency) {
28087
28087
  }
28088
28088
  if (!visited.has(next) && !seen.has(next)) {
28089
28089
  visited.add(next);
28090
- path80.push(next);
28090
+ path81.push(next);
28091
28091
  dfs2(next);
28092
- path80.pop();
28092
+ path81.pop();
28093
28093
  visited.delete(next);
28094
28094
  }
28095
28095
  }
28096
28096
  };
28097
28097
  var dfs = dfs2;
28098
- const path80 = [start];
28098
+ const path81 = [start];
28099
28099
  const visited = /* @__PURE__ */ new Set([start]);
28100
28100
  dfs2(start);
28101
28101
  seen.add(start);
@@ -28117,7 +28117,7 @@ function findShortestCycle(start, componentSet, adjacency) {
28117
28117
  visited.add(next);
28118
28118
  }
28119
28119
  while (queue.length > 0) {
28120
- const { node: node2, path: path80 } = queue.shift();
28120
+ const { node: node2, path: path81 } = queue.shift();
28121
28121
  const nexts = adjacency.get(node2);
28122
28122
  if (!nexts)
28123
28123
  continue;
@@ -28125,11 +28125,11 @@ function findShortestCycle(start, componentSet, adjacency) {
28125
28125
  if (!componentSet.has(next))
28126
28126
  continue;
28127
28127
  if (next === start) {
28128
- return [...path80, start];
28128
+ return [...path81, start];
28129
28129
  }
28130
28130
  if (!visited.has(next)) {
28131
28131
  visited.add(next);
28132
- queue.push({ node: next, path: [...path80, next] });
28132
+ queue.push({ node: next, path: [...path81, next] });
28133
28133
  }
28134
28134
  }
28135
28135
  }
@@ -105838,11 +105838,8 @@ var init_guard = __esm({
105838
105838
  });
105839
105839
 
105840
105840
  // packages/shared/dist/spec/overlap-resolution.js
105841
- function coveringRelationInAreas(relations, a, b, areas) {
105842
- return relations.find((r) => {
105843
- const samePair = r.older === a && r.newer === b || r.older === b && r.newer === a;
105844
- return samePair && (r.scope === void 0 || areas.includes(r.scope));
105845
- });
105841
+ function normalizeQuote(text4) {
105842
+ return text4.replace(/[`*_~]/g, "").toLowerCase().replace(/\s+/g, " ").trim();
105846
105843
  }
105847
105844
  function dedupeCrossAreaOverlaps(entries) {
105848
105845
  const byPair = /* @__PURE__ */ new Map();
@@ -105916,9 +105913,23 @@ function dedupeCrossAreaOverlaps(entries) {
105916
105913
  });
105917
105914
  return merged;
105918
105915
  }
105916
+ function resolutionMatchesConflict(r, a, b, sections) {
105917
+ if (!samePair(r.docA, r.docB, a, b))
105918
+ return false;
105919
+ const rSide = (doc) => doc === r.docA ? { anchor: r.anchorA, quote: r.quoteA } : { anchor: r.anchorB, quote: r.quoteB };
105920
+ const cSide = (doc) => (sections ?? []).find((s) => s.doc === doc);
105921
+ const bothHaveQuotes = !!r.quoteA && !!r.quoteB && !!cSide(a)?.quote && !!cSide(b)?.quote;
105922
+ if (bothHaveQuotes) {
105923
+ const quoteMatch = (doc) => normalizeQuote(rSide(doc).quote ?? "") === normalizeQuote(cSide(doc)?.quote ?? "");
105924
+ return quoteMatch(a) && quoteMatch(b);
105925
+ }
105926
+ const anchorMatch = (doc) => anchorKey(rSide(doc).anchor) === anchorKey(cSide(doc)?.heading);
105927
+ return anchorMatch(a) && anchorMatch(b);
105928
+ }
105929
+ function matchResolution(decisions, a, b, sections) {
105930
+ return (decisions.conflictResolutions ?? []).find((r) => resolutionMatchesConflict(r, a, b, sections));
105931
+ }
105919
105932
  function buildCorpusConflicts(corpus, decisions) {
105920
- const userRelations = decisions.relations ?? [];
105921
- const effectiveRels = [...corpus.relations, ...userRelations];
105922
105933
  const excludes = new Set(decisions.manualExcludes ?? []);
105923
105934
  const entries = [];
105924
105935
  for (const area of corpus.areas)
@@ -105928,43 +105939,46 @@ function buildCorpusConflicts(corpus, decisions) {
105928
105939
  const flagged = [];
105929
105940
  for (const m of mergedOverlaps) {
105930
105941
  const [a, b] = m.overlap.docs;
105931
- const relation = coveringRelationInAreas(effectiveRels, a, b, m.areas);
105932
- const userRelation = coveringRelationInAreas(userRelations, a, b, m.areas);
105942
+ const sections = m.overlap.sections ? [...m.overlap.sections] : void 0;
105933
105943
  const excludedRef = excludes.has(a) ? a : excludes.has(b) ? b : void 0;
105944
+ const resolution = matchResolution(decisions, a, b, sections);
105934
105945
  flagged.push({
105935
105946
  area: m.area,
105936
105947
  areas: m.areas,
105937
105948
  a,
105938
105949
  b,
105939
105950
  note: m.overlap.note ?? "",
105940
- resolved: relation !== void 0 || excludedRef !== void 0,
105941
- synthesized: false,
105942
- ...relation ? { relation } : {},
105943
- ...userRelation ? { userRelation } : {},
105944
- ...excludedRef ? { excludedRef } : {}
105951
+ ...sections ? { sections } : {},
105952
+ resolved: excludedRef !== void 0 || resolution !== void 0,
105953
+ ...excludedRef ? { excludedRef } : {},
105954
+ ...resolution ? { resolution } : {}
105945
105955
  });
105946
105956
  }
105947
- const coversFlagged = (r) => flagged.some((o) => {
105948
- const samePair = o.a === r.older && o.b === r.newer || o.a === r.newer && o.b === r.older;
105949
- return samePair && (r.scope === void 0 || o.areas.includes(r.scope));
105950
- });
105951
- const synthesized = userRelations.filter((r) => !coversFlagged(r)).map((r) => ({
105952
- area: r.scope ?? "",
105953
- areas: r.scope ? [r.scope] : [],
105954
- a: r.older,
105955
- b: r.newer,
105956
- note: r.note ?? "",
105957
- resolved: true,
105958
- synthesized: true,
105959
- relation: r,
105960
- userRelation: r
105961
- }));
105962
- return [...flagged, ...synthesized];
105957
+ return flagged;
105963
105958
  }
105964
105959
  function openConflicts(corpus, decisions) {
105965
105960
  return buildCorpusConflicts(corpus, decisions).filter((c2) => !c2.resolved);
105966
105961
  }
105967
- var PREAMBLE_PTR, NUL, unorderedPairKey, sectionPointerKeys, preambleCount;
105962
+ function orphanedConflictResolutions(corpus, decisions) {
105963
+ const resolutions = decisions.conflictResolutions ?? [];
105964
+ if (resolutions.length === 0)
105965
+ return [];
105966
+ const conflicts2 = buildCorpusConflicts(corpus, decisions);
105967
+ return resolutions.filter((r) => !conflicts2.some((c2) => resolutionMatchesConflict(r, c2.a, c2.b, c2.sections)));
105968
+ }
105969
+ function suppressedClaims(corpus, decisions) {
105970
+ const out = [];
105971
+ for (const c2 of buildCorpusConflicts(corpus, decisions)) {
105972
+ const r = c2.resolution;
105973
+ if (!r || r.verdict === "dismissed")
105974
+ continue;
105975
+ const loser = r.verdict === "a" ? { doc: r.docB, anchor: r.anchorB, quote: r.quoteB } : { doc: r.docA, anchor: r.anchorA, quote: r.quoteA };
105976
+ if (loser.quote && loser.quote.trim())
105977
+ out.push({ doc: loser.doc, anchor: loser.anchor, quote: loser.quote });
105978
+ }
105979
+ return out;
105980
+ }
105981
+ var PREAMBLE_PTR, NUL, unorderedPairKey, sectionPointerKeys, preambleCount, samePair, anchorKey;
105968
105982
  var init_overlap_resolution = __esm({
105969
105983
  "packages/shared/dist/spec/overlap-resolution.js"() {
105970
105984
  "use strict";
@@ -105973,6 +105987,8 @@ var init_overlap_resolution = __esm({
105973
105987
  unorderedPairKey = (a, b) => a < b ? `${a}${NUL}${b}` : `${b}${NUL}${a}`;
105974
105988
  sectionPointerKeys = (ov) => (ov.sections ?? []).map((s) => `${s.doc}${NUL}${s.heading ?? PREAMBLE_PTR}`);
105975
105989
  preambleCount = (ov) => (ov.sections ?? []).filter((s) => s.heading === null || s.heading === void 0).length;
105990
+ samePair = (a1, b1, a2, b2) => a1 === a2 && b1 === b2 || a1 === b2 && b1 === a2;
105991
+ anchorKey = (h) => h === null || h === void 0 ? null : h.replace(/[`*_~]/g, "").trim().toLowerCase();
105976
105992
  }
105977
105993
  });
105978
105994
 
@@ -112402,14 +112418,14 @@ var init_missing_error_status_code = __esm({
112402
112418
  });
112403
112419
 
112404
112420
  // packages/analyzer/dist/rules/architecture/visitors/javascript/route-without-auth-middleware.js
112405
- function isPublicPath(path80) {
112406
- return PUBLIC_PATH_PATTERNS.some((re2) => re2.test(path80));
112421
+ function isPublicPath(path81) {
112422
+ return PUBLIC_PATH_PATTERNS.some((re2) => re2.test(path81));
112407
112423
  }
112408
- function isUrlCredentialAuthedPath(path80) {
112409
- return URL_CREDENTIAL_PARAMS.test(path80);
112424
+ function isUrlCredentialAuthedPath(path81) {
112425
+ return URL_CREDENTIAL_PARAMS.test(path81);
112410
112426
  }
112411
- function isApiDocsPath(path80) {
112412
- return API_DOCS_PATH.test(path80);
112427
+ function isApiDocsPath(path81) {
112428
+ return API_DOCS_PATH.test(path81);
112413
112429
  }
112414
112430
  function isFrameworkRequestHandler(arg) {
112415
112431
  if (!arg)
@@ -112558,14 +112574,14 @@ var init_route_without_auth_middleware = __esm({
112558
112574
  return null;
112559
112575
  const firstArg = args.namedChildren[0];
112560
112576
  if (firstArg?.type === "string" || firstArg?.type === "template_string") {
112561
- const path80 = firstArg.text.replace(/^['"`]|['"`]$/g, "");
112562
- if (isPublicPath(path80))
112577
+ const path81 = firstArg.text.replace(/^['"`]|['"`]$/g, "");
112578
+ if (isPublicPath(path81))
112563
112579
  return null;
112564
- if (isUrlCredentialAuthedPath(path80))
112580
+ if (isUrlCredentialAuthedPath(path81))
112565
112581
  return null;
112566
- if (isApiDocsPath(path80))
112582
+ if (isApiDocsPath(path81))
112567
112583
  return null;
112568
- if (path80 === "*" || path80 === "(.*)" || path80 === "/*") {
112584
+ if (path81 === "*" || path81 === "(.*)" || path81 === "/*") {
112569
112585
  if (isFrameworkRequestHandler(args.namedChildren[args.namedChildren.length - 1])) {
112570
112586
  return null;
112571
112587
  }
@@ -147471,8 +147487,8 @@ var require_windows = __commonJS({
147471
147487
  "node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js"(exports, module) {
147472
147488
  module.exports = isexe;
147473
147489
  isexe.sync = sync;
147474
- var fs71 = __require("fs");
147475
- function checkPathExt(path80, options) {
147490
+ var fs72 = __require("fs");
147491
+ function checkPathExt(path81, options) {
147476
147492
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
147477
147493
  if (!pathext) {
147478
147494
  return true;
@@ -147483,25 +147499,25 @@ var require_windows = __commonJS({
147483
147499
  }
147484
147500
  for (var i = 0; i < pathext.length; i++) {
147485
147501
  var p2 = pathext[i].toLowerCase();
147486
- if (p2 && path80.substr(-p2.length).toLowerCase() === p2) {
147502
+ if (p2 && path81.substr(-p2.length).toLowerCase() === p2) {
147487
147503
  return true;
147488
147504
  }
147489
147505
  }
147490
147506
  return false;
147491
147507
  }
147492
- function checkStat(stat, path80, options) {
147508
+ function checkStat(stat, path81, options) {
147493
147509
  if (!stat.isSymbolicLink() && !stat.isFile()) {
147494
147510
  return false;
147495
147511
  }
147496
- return checkPathExt(path80, options);
147512
+ return checkPathExt(path81, options);
147497
147513
  }
147498
- function isexe(path80, options, cb) {
147499
- fs71.stat(path80, function(er, stat) {
147500
- cb(er, er ? false : checkStat(stat, path80, options));
147514
+ function isexe(path81, options, cb) {
147515
+ fs72.stat(path81, function(er, stat) {
147516
+ cb(er, er ? false : checkStat(stat, path81, options));
147501
147517
  });
147502
147518
  }
147503
- function sync(path80, options) {
147504
- return checkStat(fs71.statSync(path80), path80, options);
147519
+ function sync(path81, options) {
147520
+ return checkStat(fs72.statSync(path81), path81, options);
147505
147521
  }
147506
147522
  }
147507
147523
  });
@@ -147511,14 +147527,14 @@ var require_mode = __commonJS({
147511
147527
  "node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js"(exports, module) {
147512
147528
  module.exports = isexe;
147513
147529
  isexe.sync = sync;
147514
- var fs71 = __require("fs");
147515
- function isexe(path80, options, cb) {
147516
- fs71.stat(path80, function(er, stat) {
147530
+ var fs72 = __require("fs");
147531
+ function isexe(path81, options, cb) {
147532
+ fs72.stat(path81, function(er, stat) {
147517
147533
  cb(er, er ? false : checkStat(stat, options));
147518
147534
  });
147519
147535
  }
147520
- function sync(path80, options) {
147521
- return checkStat(fs71.statSync(path80), options);
147536
+ function sync(path81, options) {
147537
+ return checkStat(fs72.statSync(path81), options);
147522
147538
  }
147523
147539
  function checkStat(stat, options) {
147524
147540
  return stat.isFile() && checkMode(stat, options);
@@ -147542,7 +147558,7 @@ var require_mode = __commonJS({
147542
147558
  // node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js
147543
147559
  var require_isexe = __commonJS({
147544
147560
  "node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports, module) {
147545
- var fs71 = __require("fs");
147561
+ var fs72 = __require("fs");
147546
147562
  var core2;
147547
147563
  if (process.platform === "win32" || global.TESTING_WINDOWS) {
147548
147564
  core2 = require_windows();
@@ -147551,7 +147567,7 @@ var require_isexe = __commonJS({
147551
147567
  }
147552
147568
  module.exports = isexe;
147553
147569
  isexe.sync = sync;
147554
- function isexe(path80, options, cb) {
147570
+ function isexe(path81, options, cb) {
147555
147571
  if (typeof options === "function") {
147556
147572
  cb = options;
147557
147573
  options = {};
@@ -147561,7 +147577,7 @@ var require_isexe = __commonJS({
147561
147577
  throw new TypeError("callback not provided");
147562
147578
  }
147563
147579
  return new Promise(function(resolve12, reject) {
147564
- isexe(path80, options || {}, function(er, is) {
147580
+ isexe(path81, options || {}, function(er, is) {
147565
147581
  if (er) {
147566
147582
  reject(er);
147567
147583
  } else {
@@ -147570,7 +147586,7 @@ var require_isexe = __commonJS({
147570
147586
  });
147571
147587
  });
147572
147588
  }
147573
- core2(path80, options || {}, function(er, is) {
147589
+ core2(path81, options || {}, function(er, is) {
147574
147590
  if (er) {
147575
147591
  if (er.code === "EACCES" || options && options.ignoreErrors) {
147576
147592
  er = null;
@@ -147580,9 +147596,9 @@ var require_isexe = __commonJS({
147580
147596
  cb(er, is);
147581
147597
  });
147582
147598
  }
147583
- function sync(path80, options) {
147599
+ function sync(path81, options) {
147584
147600
  try {
147585
- return core2.sync(path80, options || {});
147601
+ return core2.sync(path81, options || {});
147586
147602
  } catch (er) {
147587
147603
  if (options && options.ignoreErrors || er.code === "EACCES") {
147588
147604
  return false;
@@ -147598,7 +147614,7 @@ var require_isexe = __commonJS({
147598
147614
  var require_which = __commonJS({
147599
147615
  "node_modules/.pnpm/which@2.0.2/node_modules/which/which.js"(exports, module) {
147600
147616
  var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
147601
- var path80 = __require("path");
147617
+ var path81 = __require("path");
147602
147618
  var COLON = isWindows ? ";" : ":";
147603
147619
  var isexe = require_isexe();
147604
147620
  var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -147636,7 +147652,7 @@ var require_which = __commonJS({
147636
147652
  return opt.all && found.length ? resolve12(found) : reject(getNotFoundError(cmd));
147637
147653
  const ppRaw = pathEnv[i];
147638
147654
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
147639
- const pCmd = path80.join(pathPart, cmd);
147655
+ const pCmd = path81.join(pathPart, cmd);
147640
147656
  const p2 = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
147641
147657
  resolve12(subStep(p2, i, 0));
147642
147658
  });
@@ -147663,7 +147679,7 @@ var require_which = __commonJS({
147663
147679
  for (let i = 0; i < pathEnv.length; i++) {
147664
147680
  const ppRaw = pathEnv[i];
147665
147681
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
147666
- const pCmd = path80.join(pathPart, cmd);
147682
+ const pCmd = path81.join(pathPart, cmd);
147667
147683
  const p2 = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
147668
147684
  for (let j2 = 0; j2 < pathExt.length; j2++) {
147669
147685
  const cur = p2 + pathExt[j2];
@@ -147711,7 +147727,7 @@ var require_path_key = __commonJS({
147711
147727
  var require_resolveCommand = __commonJS({
147712
147728
  "node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module) {
147713
147729
  "use strict";
147714
- var path80 = __require("path");
147730
+ var path81 = __require("path");
147715
147731
  var which = require_which();
147716
147732
  var getPathKey = require_path_key();
147717
147733
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -147729,7 +147745,7 @@ var require_resolveCommand = __commonJS({
147729
147745
  try {
147730
147746
  resolved = which.sync(parsed.command, {
147731
147747
  path: env[getPathKey({ env })],
147732
- pathExt: withoutPathExt ? path80.delimiter : void 0
147748
+ pathExt: withoutPathExt ? path81.delimiter : void 0
147733
147749
  });
147734
147750
  } catch (e) {
147735
147751
  } finally {
@@ -147738,7 +147754,7 @@ var require_resolveCommand = __commonJS({
147738
147754
  }
147739
147755
  }
147740
147756
  if (resolved) {
147741
- resolved = path80.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
147757
+ resolved = path81.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
147742
147758
  }
147743
147759
  return resolved;
147744
147760
  }
@@ -147792,8 +147808,8 @@ var require_shebang_command = __commonJS({
147792
147808
  if (!match4) {
147793
147809
  return null;
147794
147810
  }
147795
- const [path80, argument] = match4[0].replace(/#! ?/, "").split(" ");
147796
- const binary2 = path80.split("/").pop();
147811
+ const [path81, argument] = match4[0].replace(/#! ?/, "").split(" ");
147812
+ const binary2 = path81.split("/").pop();
147797
147813
  if (binary2 === "env") {
147798
147814
  return argument;
147799
147815
  }
@@ -147806,16 +147822,16 @@ var require_shebang_command = __commonJS({
147806
147822
  var require_readShebang = __commonJS({
147807
147823
  "node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js"(exports, module) {
147808
147824
  "use strict";
147809
- var fs71 = __require("fs");
147825
+ var fs72 = __require("fs");
147810
147826
  var shebangCommand = require_shebang_command();
147811
147827
  function readShebang(command) {
147812
147828
  const size = 150;
147813
147829
  const buffer = Buffer.alloc(size);
147814
147830
  let fd;
147815
147831
  try {
147816
- fd = fs71.openSync(command, "r");
147817
- fs71.readSync(fd, buffer, 0, size, 0);
147818
- fs71.closeSync(fd);
147832
+ fd = fs72.openSync(command, "r");
147833
+ fs72.readSync(fd, buffer, 0, size, 0);
147834
+ fs72.closeSync(fd);
147819
147835
  } catch (e) {
147820
147836
  }
147821
147837
  return shebangCommand(buffer.toString());
@@ -147828,7 +147844,7 @@ var require_readShebang = __commonJS({
147828
147844
  var require_parse = __commonJS({
147829
147845
  "node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js"(exports, module) {
147830
147846
  "use strict";
147831
- var path80 = __require("path");
147847
+ var path81 = __require("path");
147832
147848
  var resolveCommand = require_resolveCommand();
147833
147849
  var escape2 = require_escape();
147834
147850
  var readShebang = require_readShebang();
@@ -147853,7 +147869,7 @@ var require_parse = __commonJS({
147853
147869
  const needsShell = !isExecutableRegExp.test(commandFile);
147854
147870
  if (parsed.options.forceShell || needsShell) {
147855
147871
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
147856
- parsed.command = path80.normalize(parsed.command);
147872
+ parsed.command = path81.normalize(parsed.command);
147857
147873
  parsed.command = escape2.command(parsed.command);
147858
147874
  parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
147859
147875
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
@@ -148219,8 +148235,8 @@ var require_package = __commonJS({
148219
148235
  // node_modules/.pnpm/dotenv@16.6.1/node_modules/dotenv/lib/main.js
148220
148236
  var require_main = __commonJS({
148221
148237
  "node_modules/.pnpm/dotenv@16.6.1/node_modules/dotenv/lib/main.js"(exports, module) {
148222
- var fs71 = __require("fs");
148223
- var path80 = __require("path");
148238
+ var fs72 = __require("fs");
148239
+ var path81 = __require("path");
148224
148240
  var os15 = __require("os");
148225
148241
  var crypto6 = __require("crypto");
148226
148242
  var packageJson = require_package();
@@ -148328,7 +148344,7 @@ var require_main = __commonJS({
148328
148344
  if (options && options.path && options.path.length > 0) {
148329
148345
  if (Array.isArray(options.path)) {
148330
148346
  for (const filepath of options.path) {
148331
- if (fs71.existsSync(filepath)) {
148347
+ if (fs72.existsSync(filepath)) {
148332
148348
  possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
148333
148349
  }
148334
148350
  }
@@ -148336,15 +148352,15 @@ var require_main = __commonJS({
148336
148352
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
148337
148353
  }
148338
148354
  } else {
148339
- possibleVaultPath = path80.resolve(process.cwd(), ".env.vault");
148355
+ possibleVaultPath = path81.resolve(process.cwd(), ".env.vault");
148340
148356
  }
148341
- if (fs71.existsSync(possibleVaultPath)) {
148357
+ if (fs72.existsSync(possibleVaultPath)) {
148342
148358
  return possibleVaultPath;
148343
148359
  }
148344
148360
  return null;
148345
148361
  }
148346
148362
  function _resolveHome(envPath) {
148347
- return envPath[0] === "~" ? path80.join(os15.homedir(), envPath.slice(1)) : envPath;
148363
+ return envPath[0] === "~" ? path81.join(os15.homedir(), envPath.slice(1)) : envPath;
148348
148364
  }
148349
148365
  function _configVault(options) {
148350
148366
  const debug2 = Boolean(options && options.debug);
@@ -148361,7 +148377,7 @@ var require_main = __commonJS({
148361
148377
  return { parsed };
148362
148378
  }
148363
148379
  function configDotenv(options) {
148364
- const dotenvPath = path80.resolve(process.cwd(), ".env");
148380
+ const dotenvPath = path81.resolve(process.cwd(), ".env");
148365
148381
  let encoding = "utf8";
148366
148382
  const debug2 = Boolean(options && options.debug);
148367
148383
  const quiet = options && "quiet" in options ? options.quiet : true;
@@ -148385,13 +148401,13 @@ var require_main = __commonJS({
148385
148401
  }
148386
148402
  let lastError;
148387
148403
  const parsedAll = {};
148388
- for (const path81 of optionPaths) {
148404
+ for (const path82 of optionPaths) {
148389
148405
  try {
148390
- const parsed = DotenvModule.parse(fs71.readFileSync(path81, { encoding }));
148406
+ const parsed = DotenvModule.parse(fs72.readFileSync(path82, { encoding }));
148391
148407
  DotenvModule.populate(parsedAll, parsed, options);
148392
148408
  } catch (e) {
148393
148409
  if (debug2) {
148394
- _debug(`Failed to load ${path81} ${e.message}`);
148410
+ _debug(`Failed to load ${path82} ${e.message}`);
148395
148411
  }
148396
148412
  lastError = e;
148397
148413
  }
@@ -148406,7 +148422,7 @@ var require_main = __commonJS({
148406
148422
  const shortPaths = [];
148407
148423
  for (const filePath of optionPaths) {
148408
148424
  try {
148409
- const relative2 = path80.relative(process.cwd(), filePath);
148425
+ const relative2 = path81.relative(process.cwd(), filePath);
148410
148426
  shortPaths.push(relative2);
148411
148427
  } catch (e) {
148412
148428
  if (debug2) {
@@ -149265,8 +149281,8 @@ var init_cli_provider = __esm({
149265
149281
  this._repoId = repoId;
149266
149282
  }
149267
149283
  /** Set target repo path — used as cwd when spawning CLI so Read tool accesses the right files. */
149268
- setRepoPath(path80) {
149269
- this._repoPath = path80;
149284
+ setRepoPath(path81) {
149285
+ this._repoPath = path81;
149270
149286
  }
149271
149287
  flushUsage() {
149272
149288
  if (this._usageRecords.length === 0)
@@ -161397,11 +161413,11 @@ var require_mime_types = __commonJS({
161397
161413
  }
161398
161414
  return exts[0];
161399
161415
  }
161400
- function lookup(path80) {
161401
- if (!path80 || typeof path80 !== "string") {
161416
+ function lookup(path81) {
161417
+ if (!path81 || typeof path81 !== "string") {
161402
161418
  return false;
161403
161419
  }
161404
- var extension2 = extname("x." + path80).toLowerCase().substr(1);
161420
+ var extension2 = extname("x." + path81).toLowerCase().substr(1);
161405
161421
  if (!extension2) {
161406
161422
  return false;
161407
161423
  }
@@ -162506,11 +162522,11 @@ var require_form_data = __commonJS({
162506
162522
  "use strict";
162507
162523
  var CombinedStream = require_combined_stream();
162508
162524
  var util2 = __require("util");
162509
- var path80 = __require("path");
162525
+ var path81 = __require("path");
162510
162526
  var http = __require("http");
162511
162527
  var https = __require("https");
162512
162528
  var parseUrl = __require("url").parse;
162513
- var fs71 = __require("fs");
162529
+ var fs72 = __require("fs");
162514
162530
  var Stream = __require("stream").Stream;
162515
162531
  var crypto6 = __require("crypto");
162516
162532
  var mime = require_mime_types();
@@ -162577,7 +162593,7 @@ var require_form_data = __commonJS({
162577
162593
  if (value.end != void 0 && value.end != Infinity && value.start != void 0) {
162578
162594
  callback(null, value.end + 1 - (value.start ? value.start : 0));
162579
162595
  } else {
162580
- fs71.stat(value.path, function(err, stat) {
162596
+ fs72.stat(value.path, function(err, stat) {
162581
162597
  if (err) {
162582
162598
  callback(err);
162583
162599
  return;
@@ -162634,11 +162650,11 @@ var require_form_data = __commonJS({
162634
162650
  FormData2.prototype._getContentDisposition = function(value, options) {
162635
162651
  var filename;
162636
162652
  if (typeof options.filepath === "string") {
162637
- filename = path80.normalize(options.filepath).replace(/\\/g, "/");
162653
+ filename = path81.normalize(options.filepath).replace(/\\/g, "/");
162638
162654
  } else if (options.filename || value && (value.name || value.path)) {
162639
- filename = path80.basename(options.filename || value && (value.name || value.path));
162655
+ filename = path81.basename(options.filename || value && (value.name || value.path));
162640
162656
  } else if (value && value.readable && hasOwn(value, "httpVersion")) {
162641
- filename = path80.basename(value.client._httpMessage.path || "");
162657
+ filename = path81.basename(value.client._httpMessage.path || "");
162642
162658
  }
162643
162659
  if (filename) {
162644
162660
  return 'filename="' + filename + '"';
@@ -163195,8 +163211,8 @@ var require_node2 = __commonJS({
163195
163211
  }
163196
163212
  break;
163197
163213
  case "FILE":
163198
- var fs71 = __require("fs");
163199
- stream2 = new fs71.SyncWriteStream(fd2, { autoClose: false });
163214
+ var fs72 = __require("fs");
163215
+ stream2 = new fs72.SyncWriteStream(fd2, { autoClose: false });
163200
163216
  stream2._type = "fs";
163201
163217
  break;
163202
163218
  case "PIPE":
@@ -164292,9 +164308,9 @@ var require_axios = __commonJS({
164292
164308
  function removeBrackets(key4) {
164293
164309
  return utils$1.endsWith(key4, "[]") ? key4.slice(0, -2) : key4;
164294
164310
  }
164295
- function renderKey(path80, key4, dots) {
164296
- if (!path80) return key4;
164297
- return path80.concat(key4).map(function each(token, i) {
164311
+ function renderKey(path81, key4, dots) {
164312
+ if (!path81) return key4;
164313
+ return path81.concat(key4).map(function each(token, i) {
164298
164314
  token = removeBrackets(token);
164299
164315
  return !dots && i ? "[" + token + "]" : token;
164300
164316
  }).join(dots ? "." : "");
@@ -164342,13 +164358,13 @@ var require_axios = __commonJS({
164342
164358
  }
164343
164359
  return value;
164344
164360
  }
164345
- function defaultVisitor(value, key4, path80) {
164361
+ function defaultVisitor(value, key4, path81) {
164346
164362
  let arr = value;
164347
164363
  if (utils$1.isReactNative(formData) && utils$1.isReactNativeBlob(value)) {
164348
- formData.append(renderKey(path80, key4, dots), convertValue(value));
164364
+ formData.append(renderKey(path81, key4, dots), convertValue(value));
164349
164365
  return false;
164350
164366
  }
164351
- if (value && !path80 && typeof value === "object") {
164367
+ if (value && !path81 && typeof value === "object") {
164352
164368
  if (utils$1.endsWith(key4, "{}")) {
164353
164369
  key4 = metaTokens ? key4 : key4.slice(0, -2);
164354
164370
  value = JSON.stringify(value);
@@ -164367,7 +164383,7 @@ var require_axios = __commonJS({
164367
164383
  if (isVisitable(value)) {
164368
164384
  return true;
164369
164385
  }
164370
- formData.append(renderKey(path80, key4, dots), convertValue(value));
164386
+ formData.append(renderKey(path81, key4, dots), convertValue(value));
164371
164387
  return false;
164372
164388
  }
164373
164389
  const stack2 = [];
@@ -164376,16 +164392,16 @@ var require_axios = __commonJS({
164376
164392
  convertValue,
164377
164393
  isVisitable
164378
164394
  });
164379
- function build8(value, path80) {
164395
+ function build8(value, path81) {
164380
164396
  if (utils$1.isUndefined(value)) return;
164381
164397
  if (stack2.indexOf(value) !== -1) {
164382
- throw Error("Circular reference detected in " + path80.join("."));
164398
+ throw Error("Circular reference detected in " + path81.join("."));
164383
164399
  }
164384
164400
  stack2.push(value);
164385
164401
  utils$1.forEach(value, function each(el, key4) {
164386
- const result = !(utils$1.isUndefined(el) || el === null) && visitor.call(formData, el, utils$1.isString(key4) ? key4.trim() : key4, path80, exposedHelpers);
164402
+ const result = !(utils$1.isUndefined(el) || el === null) && visitor.call(formData, el, utils$1.isString(key4) ? key4.trim() : key4, path81, exposedHelpers);
164387
164403
  if (result === true) {
164388
- build8(el, path80 ? path80.concat(key4) : [key4]);
164404
+ build8(el, path81 ? path81.concat(key4) : [key4]);
164389
164405
  }
164390
164406
  });
164391
164407
  stack2.pop();
@@ -164574,7 +164590,7 @@ var require_axios = __commonJS({
164574
164590
  };
164575
164591
  function toURLEncodedForm(data, options) {
164576
164592
  return toFormData(data, new platform.classes.URLSearchParams(), {
164577
- visitor: function(value, key4, path80, helpers) {
164593
+ visitor: function(value, key4, path81, helpers) {
164578
164594
  if (platform.isNode && utils$1.isBuffer(value)) {
164579
164595
  this.append(key4, value.toString("base64"));
164580
164596
  return false;
@@ -164602,11 +164618,11 @@ var require_axios = __commonJS({
164602
164618
  return obj;
164603
164619
  }
164604
164620
  function formDataToJSON(formData) {
164605
- function buildPath(path80, value, target, index) {
164606
- let name = path80[index++];
164621
+ function buildPath(path81, value, target, index) {
164622
+ let name = path81[index++];
164607
164623
  if (name === "__proto__") return true;
164608
164624
  const isNumericKey = Number.isFinite(+name);
164609
- const isLast = index >= path80.length;
164625
+ const isLast = index >= path81.length;
164610
164626
  name = !name && utils$1.isArray(target) ? target.length : name;
164611
164627
  if (isLast) {
164612
164628
  if (utils$1.hasOwnProp(target, name)) {
@@ -164619,7 +164635,7 @@ var require_axios = __commonJS({
164619
164635
  if (!target[name] || !utils$1.isObject(target[name])) {
164620
164636
  target[name] = [];
164621
164637
  }
164622
- const result = buildPath(path80, value, target[name], index);
164638
+ const result = buildPath(path81, value, target[name], index);
164623
164639
  if (result && utils$1.isArray(target[name])) {
164624
164640
  target[name] = arrayToObject(target[name]);
164625
164641
  }
@@ -165937,9 +165953,9 @@ var require_axios = __commonJS({
165937
165953
  auth = urlUsername + ":" + urlPassword;
165938
165954
  }
165939
165955
  auth && headers.delete("authorization");
165940
- let path80;
165956
+ let path81;
165941
165957
  try {
165942
- path80 = buildURL(parsed.pathname + parsed.search, config2.params, config2.paramsSerializer).replace(/^\?/, "");
165958
+ path81 = buildURL(parsed.pathname + parsed.search, config2.params, config2.paramsSerializer).replace(/^\?/, "");
165943
165959
  } catch (err) {
165944
165960
  const customErr = new Error(err.message);
165945
165961
  customErr.config = config2;
@@ -165949,7 +165965,7 @@ var require_axios = __commonJS({
165949
165965
  }
165950
165966
  headers.set("Accept-Encoding", "gzip, compress, deflate" + (isBrotliSupported ? ", br" : ""), false);
165951
165967
  const options = {
165952
- path: path80,
165968
+ path: path81,
165953
165969
  method,
165954
165970
  headers: headers.toJSON(),
165955
165971
  agents: {
@@ -166155,14 +166171,14 @@ var require_axios = __commonJS({
166155
166171
  var cookies = platform.hasStandardBrowserEnv ? (
166156
166172
  // Standard browser envs support document.cookie
166157
166173
  {
166158
- write(name, value, expires, path80, domain, secure, sameSite) {
166174
+ write(name, value, expires, path81, domain, secure, sameSite) {
166159
166175
  if (typeof document === "undefined") return;
166160
166176
  const cookie = [`${name}=${encodeURIComponent(value)}`];
166161
166177
  if (utils$1.isNumber(expires)) {
166162
166178
  cookie.push(`expires=${new Date(expires).toUTCString()}`);
166163
166179
  }
166164
- if (utils$1.isString(path80)) {
166165
- cookie.push(`path=${path80}`);
166180
+ if (utils$1.isString(path81)) {
166181
+ cookie.push(`path=${path81}`);
166166
166182
  }
166167
166183
  if (utils$1.isString(domain)) {
166168
166184
  cookie.push(`domain=${domain}`);
@@ -167683,8 +167699,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname10(proc
167683
167699
  return decodedFile;
167684
167700
  };
167685
167701
  }
167686
- function normalizeWindowsPath(path80) {
167687
- return path80.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
167702
+ function normalizeWindowsPath(path81) {
167703
+ return path81.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
167688
167704
  }
167689
167705
  async function addSourceContext(frames) {
167690
167706
  const filesToLines = {};
@@ -167729,9 +167745,9 @@ async function addSourceContext(frames) {
167729
167745
  LRU_FILE_CONTENTS_CACHE.reduce();
167730
167746
  return frames;
167731
167747
  }
167732
- function getContextLinesFromFile(path80, ranges, output) {
167748
+ function getContextLinesFromFile(path81, ranges, output) {
167733
167749
  return new Promise((resolve12) => {
167734
- const stream = createReadStream(path80);
167750
+ const stream = createReadStream(path81);
167735
167751
  const lineReaded = createInterface2({
167736
167752
  input: stream
167737
167753
  });
@@ -167749,7 +167765,7 @@ function getContextLinesFromFile(path80, ranges, output) {
167749
167765
  let rangeStart = range2[0];
167750
167766
  let rangeEnd = range2[1];
167751
167767
  function onStreamError() {
167752
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path80, 1);
167768
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path81, 1);
167753
167769
  lineReaded.close();
167754
167770
  lineReaded.removeAllListeners();
167755
167771
  destroyStreamAndResolve();
@@ -167826,8 +167842,8 @@ function clearLineContext(frame) {
167826
167842
  delete frame.context_line;
167827
167843
  delete frame.post_context;
167828
167844
  }
167829
- function shouldSkipContextLinesForFile(path80) {
167830
- return path80.startsWith("node:") || path80.endsWith(".min.js") || path80.endsWith(".min.cjs") || path80.endsWith(".min.mjs") || path80.startsWith("data:");
167845
+ function shouldSkipContextLinesForFile(path81) {
167846
+ return path81.startsWith("node:") || path81.endsWith(".min.js") || path81.endsWith(".min.cjs") || path81.endsWith(".min.mjs") || path81.startsWith("data:");
167831
167847
  }
167832
167848
  function shouldSkipContextLinesForFrame(frame) {
167833
167849
  if (frame.lineno !== void 0 && frame.lineno > MAX_CONTEXTLINES_LINENO) {
@@ -171176,7 +171192,7 @@ function readToolVersion() {
171176
171192
  if (cachedVersion)
171177
171193
  return cachedVersion;
171178
171194
  if (true) {
171179
- cachedVersion = "0.7.0-next.7";
171195
+ cachedVersion = "0.7.0-next.9";
171180
171196
  return cachedVersion;
171181
171197
  }
171182
171198
  try {
@@ -173582,13 +173598,13 @@ var init_pexprs_toFailure = __esm({
173582
173598
  return new Failure(this, "a Unicode [" + this.categoryOrProp + "] character", "description");
173583
173599
  };
173584
173600
  Alt.prototype.toFailure = function(grammar2) {
173585
- const fs71 = this.terms.map((t2) => t2.toFailure(grammar2));
173586
- const description = "(" + fs71.join(" or ") + ")";
173601
+ const fs72 = this.terms.map((t2) => t2.toFailure(grammar2));
173602
+ const description = "(" + fs72.join(" or ") + ")";
173587
173603
  return new Failure(this, description, "description");
173588
173604
  };
173589
173605
  Seq.prototype.toFailure = function(grammar2) {
173590
- const fs71 = this.factors.map((f2) => f2.toFailure(grammar2));
173591
- const description = "(" + fs71.join(" ") + ")";
173606
+ const fs72 = this.factors.map((f2) => f2.toFailure(grammar2));
173607
+ const description = "(" + fs72.join(" ") + ")";
173592
173608
  return new Failure(this, description, "description");
173593
173609
  };
173594
173610
  Iter.prototype.toFailure = function(grammar2) {
@@ -175425,9 +175441,9 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
175425
175441
  decl.withSuperGrammar(namespace[superGrammarName]);
175426
175442
  }
175427
175443
  },
175428
- Rule_define(n, fs71, d3, _2, b) {
175444
+ Rule_define(n, fs72, d3, _2, b) {
175429
175445
  currentRuleName = n.visit();
175430
- currentRuleFormals = fs71.children.map((c2) => c2.visit())[0] || [];
175446
+ currentRuleFormals = fs72.children.map((c2) => c2.visit())[0] || [];
175431
175447
  if (!decl.defaultStartRule && decl.ensureSuperGrammar() !== Grammar.ProtoBuiltInRules) {
175432
175448
  decl.withDefaultStartRule(currentRuleName);
175433
175449
  }
@@ -175436,9 +175452,9 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
175436
175452
  const source = this.source.trimmed();
175437
175453
  return decl.define(currentRuleName, currentRuleFormals, body, description, source);
175438
175454
  },
175439
- Rule_override(n, fs71, _2, b) {
175455
+ Rule_override(n, fs72, _2, b) {
175440
175456
  currentRuleName = n.visit();
175441
- currentRuleFormals = fs71.children.map((c2) => c2.visit())[0] || [];
175457
+ currentRuleFormals = fs72.children.map((c2) => c2.visit())[0] || [];
175442
175458
  const source = this.source.trimmed();
175443
175459
  decl.ensureSuperGrammarRuleForOverriding(currentRuleName, source);
175444
175460
  overriding = true;
@@ -175446,9 +175462,9 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
175446
175462
  overriding = false;
175447
175463
  return decl.override(currentRuleName, currentRuleFormals, body, null, source);
175448
175464
  },
175449
- Rule_extend(n, fs71, _2, b) {
175465
+ Rule_extend(n, fs72, _2, b) {
175450
175466
  currentRuleName = n.visit();
175451
- currentRuleFormals = fs71.children.map((c2) => c2.visit())[0] || [];
175467
+ currentRuleFormals = fs72.children.map((c2) => c2.visit())[0] || [];
175452
175468
  const body = b.visit();
175453
175469
  const source = this.source.trimmed();
175454
175470
  return decl.extend(currentRuleName, currentRuleFormals, body, null, source);
@@ -175475,8 +175491,8 @@ function buildGrammar2(match4, namespace, optOhmGrammarForTesting, options) {
175475
175491
  return builder.alt(...args).withSource(this.source);
175476
175492
  }
175477
175493
  },
175478
- Formals(opointy, fs71, cpointy) {
175479
- return fs71.visit();
175494
+ Formals(opointy, fs72, cpointy) {
175495
+ return fs72.visit();
175480
175496
  },
175481
175497
  Params(opointy, ps, cpointy) {
175482
175498
  return ps.visit();
@@ -175638,8 +175654,8 @@ function initPrototypeParser(grammar2) {
175638
175654
  formals: optFormals.children.map((c2) => c2.parse())[0] || []
175639
175655
  };
175640
175656
  },
175641
- Formals(oparen, fs71, cparen) {
175642
- return fs71.asIteration().children.map((c2) => c2.parse());
175657
+ Formals(oparen, fs72, cparen) {
175658
+ return fs72.asIteration().children.map((c2) => c2.parse());
175643
175659
  },
175644
175660
  name(first2, rest) {
175645
175661
  return this.sourceString;
@@ -178960,8 +178976,8 @@ function parseAndResolve(files) {
178960
178976
  const parsed = files.map((f2) => parseOne(f2.path, f2.source));
178961
178977
  return resolve10(parsed);
178962
178978
  }
178963
- function parseTcFile(path80, source) {
178964
- return parseOne(path80, source);
178979
+ function parseTcFile(path81, source) {
178980
+ return parseOne(path81, source);
178965
178981
  }
178966
178982
  var LineMap, OP_VALUES;
178967
178983
  var init_parser_ohm = __esm({
@@ -180350,13 +180366,13 @@ function extractStarletteRoutesFromFile(filePath, source, tree) {
180350
180366
  const identities = starletteIdentitiesForPath(rawPath);
180351
180367
  const line = node2.startPosition.row + 1;
180352
180368
  for (const method of methods) {
180353
- for (const path80 of identities) {
180369
+ for (const path81 of identities) {
180354
180370
  out.push({
180355
- identity: `${method} ${path80}`,
180371
+ identity: `${method} ${path81}`,
180356
180372
  contract: {
180357
180373
  protocol: "http",
180358
180374
  method,
180359
- path: path80,
180375
+ path: path81,
180360
180376
  responses: [],
180361
180377
  tags: []
180362
180378
  },
@@ -180533,14 +180549,14 @@ function parseRouteDecorator(dec, source, stringVars) {
180533
180549
  const args = call.childForFieldName("arguments");
180534
180550
  if (!args)
180535
180551
  return null;
180536
- let path80 = null;
180552
+ let path81 = null;
180537
180553
  let successStatus = "200";
180538
180554
  for (let i = 0; i < args.namedChildCount; i++) {
180539
180555
  const a = args.namedChild(i);
180540
180556
  if (!a)
180541
180557
  continue;
180542
- if (path80 === null && a.type === "string")
180543
- path80 = pyStr(a, source);
180558
+ if (path81 === null && a.type === "string")
180559
+ path81 = pyStr(a, source);
180544
180560
  else if (a.type === "keyword_argument") {
180545
180561
  const name = a.childForFieldName("name");
180546
180562
  const value = a.childForFieldName("value");
@@ -180549,17 +180565,17 @@ function parseRouteDecorator(dec, source, stringVars) {
180549
180565
  }
180550
180566
  }
180551
180567
  }
180552
- if (path80 === null) {
180568
+ if (path81 === null) {
180553
180569
  const firstArg = args.namedChild(0);
180554
180570
  if (firstArg?.type === "identifier") {
180555
180571
  const resolved = stringVars.get(source.slice(firstArg.startIndex, firstArg.endIndex));
180556
180572
  if (resolved !== void 0)
180557
- path80 = resolved;
180573
+ path81 = resolved;
180558
180574
  }
180559
180575
  }
180560
- if (path80 === null)
180576
+ if (path81 === null)
180561
180577
  return null;
180562
- return { method, path: path80, routerVar, successStatus };
180578
+ return { method, path: path81, routerVar, successStatus };
180563
180579
  }
180564
180580
  function extractResponses2(body, source, successStatus) {
180565
180581
  const byStatus = /* @__PURE__ */ new Map();
@@ -180692,9 +180708,9 @@ function looksLikeModel(p2, source) {
180692
180708
  const text4 = source.slice(type2.startIndex, type2.endIndex);
180693
180709
  return /^[A-Z]/.test(text4);
180694
180710
  }
180695
- function joinPath(prefix, path80) {
180711
+ function joinPath(prefix, path81) {
180696
180712
  const a = prefix.replace(/\/$/, "");
180697
- const b = path80.startsWith("/") ? path80 : `/${path80}`;
180713
+ const b = path81.startsWith("/") ? path81 : `/${path81}`;
180698
180714
  return a + b || "/";
180699
180715
  }
180700
180716
  function callName(call, source) {
@@ -197012,8 +197028,8 @@ async function runRulesReset({ ruleKey }) {
197012
197028
 
197013
197029
  // tools/cli/src/commands/contracts.ts
197014
197030
  init_dist4();
197015
- import fs68 from "node:fs";
197016
- import path73 from "node:path";
197031
+ import fs69 from "node:fs";
197032
+ import path74 from "node:path";
197017
197033
 
197018
197034
  // packages/spec-consolidator/dist/types.js
197019
197035
  init_zod();
@@ -197051,6 +197067,26 @@ var RelationSchema = external_exports.object({
197051
197067
  /** Optional human-readable rationale. */
197052
197068
  note: external_exports.string().optional()
197053
197069
  });
197070
+ var ConflictResolutionSchema = external_exports.object({
197071
+ /** Repo-relative path / DocRef of the first doc in the dispute. */
197072
+ docA: external_exports.string(),
197073
+ /** docA's conflicting section heading, or `null` for its preamble/lead. */
197074
+ anchorA: external_exports.string().nullable(),
197075
+ /** docA's verbatim disputed sentence, when the detector captured one. */
197076
+ quoteA: external_exports.string().optional(),
197077
+ /** Repo-relative path / DocRef of the second doc in the dispute. */
197078
+ docB: external_exports.string(),
197079
+ /** docB's conflicting section heading, or `null` for its preamble/lead. */
197080
+ anchorB: external_exports.string().nullable(),
197081
+ /** docB's verbatim disputed sentence, when the detector captured one. */
197082
+ quoteB: external_exports.string().optional(),
197083
+ /** Which side wins, or `dismissed` (not a real conflict). */
197084
+ verdict: external_exports.enum(["a", "b", "dismissed"]),
197085
+ /** ISO timestamp the resolution was recorded. */
197086
+ resolvedAt: external_exports.string(),
197087
+ /** Optional human-readable rationale. */
197088
+ note: external_exports.string().optional()
197089
+ });
197054
197090
  var ManualAreaSchema = external_exports.object({
197055
197091
  /** Repo-relative path / DocRef of the doc. */
197056
197092
  doc: external_exports.string(),
@@ -197075,7 +197111,13 @@ var DecisionsFileSchema = external_exports.object({
197075
197111
  /** User-authored doc→doc relations (replace/precedence/keep-both). */
197076
197112
  relations: external_exports.array(RelationSchema).default([]),
197077
197113
  /** User overrides of a doc's auto-assigned area tags. */
197078
- manualAreas: external_exports.array(ManualAreaSchema).default([])
197114
+ manualAreas: external_exports.array(ManualAreaSchema).default([]),
197115
+ /**
197116
+ * SECTION-scoped conflict verdicts (plan item 31) — pick-a-side / dismissal on
197117
+ * one flagged disagreement, keyed by dispute identity. Optional with a `[]`
197118
+ * default so a decisions.json written before item 31 still parses.
197119
+ */
197120
+ conflictResolutions: external_exports.array(ConflictResolutionSchema).default([])
197079
197121
  });
197080
197122
 
197081
197123
  // packages/spec-consolidator/dist/corpus-types.js
@@ -197210,7 +197252,17 @@ var OverlapSectionSchema = external_exports.object({
197210
197252
  * from older corpora still parses; `null` is the preamble marker the viewer
197211
197253
  * bands as the pre-first-heading block.
197212
197254
  */
197213
- heading: external_exports.string().nullable()
197255
+ heading: external_exports.string().nullable(),
197256
+ /**
197257
+ * A short verbatim excerpt (≤ ~25 words) of the disputed sentence, copied from
197258
+ * the doc — the model's evidence for the heading it picked. Persisted (optional,
197259
+ * so older corpora without it still parse) for verification transparency and so
197260
+ * the viewer can later highlight the exact disputed sentence, not just band the
197261
+ * section. Consumed at assembly by `verifyOverlapSections` to anchor the pointer
197262
+ * by exact location; NOT part of the cross-area dedup identity (that stays
197263
+ * doc + heading).
197264
+ */
197265
+ quote: external_exports.string().optional()
197214
197266
  });
197215
197267
  var OverlapSchema = external_exports.object({
197216
197268
  /** The two docs that overlap, by ref. */
@@ -198003,13 +198055,241 @@ import { createHash as createHash7 } from "node:crypto";
198003
198055
  import fs26 from "node:fs";
198004
198056
  init_transport();
198005
198057
  init_dist5();
198058
+
198059
+ // packages/spec-consolidator/dist/pointer-verifier.js
198060
+ init_dist5();
198061
+ var MIN_MEANINGFUL_SCORE = 1.5;
198062
+ var NEGLIGIBLE_RATIO = 0.25;
198063
+ var STOPWORDS2 = /* @__PURE__ */ new Set([
198064
+ "the",
198065
+ "a",
198066
+ "an",
198067
+ "and",
198068
+ "or",
198069
+ "but",
198070
+ "if",
198071
+ "then",
198072
+ "else",
198073
+ "of",
198074
+ "to",
198075
+ "in",
198076
+ "on",
198077
+ "at",
198078
+ "by",
198079
+ "for",
198080
+ "with",
198081
+ "as",
198082
+ "is",
198083
+ "are",
198084
+ "was",
198085
+ "were",
198086
+ "be",
198087
+ "been",
198088
+ "being",
198089
+ "it",
198090
+ "its",
198091
+ "this",
198092
+ "that",
198093
+ "these",
198094
+ "those",
198095
+ "they",
198096
+ "them",
198097
+ "their",
198098
+ "there",
198099
+ "here",
198100
+ "no",
198101
+ "not",
198102
+ "yes",
198103
+ "so",
198104
+ "than",
198105
+ "too",
198106
+ "very",
198107
+ "can",
198108
+ "could",
198109
+ "will",
198110
+ "would",
198111
+ "shall",
198112
+ "should",
198113
+ "may",
198114
+ "might",
198115
+ "must",
198116
+ "do",
198117
+ "does",
198118
+ "did",
198119
+ "done",
198120
+ "has",
198121
+ "have",
198122
+ "had",
198123
+ "from",
198124
+ "up",
198125
+ "out",
198126
+ "down",
198127
+ "over",
198128
+ "under",
198129
+ "again",
198130
+ "we",
198131
+ "you",
198132
+ "your",
198133
+ "our",
198134
+ "us",
198135
+ "i",
198136
+ "he",
198137
+ "she",
198138
+ "his",
198139
+ "her",
198140
+ "each",
198141
+ "any",
198142
+ "all",
198143
+ "both",
198144
+ "some",
198145
+ "such",
198146
+ "only",
198147
+ "own",
198148
+ "same",
198149
+ "more",
198150
+ "most",
198151
+ "other",
198152
+ "into",
198153
+ "about",
198154
+ "when",
198155
+ "where",
198156
+ "which",
198157
+ "who",
198158
+ "whom",
198159
+ "what",
198160
+ "how",
198161
+ "why",
198162
+ "per",
198163
+ "via",
198164
+ "also"
198165
+ ]);
198166
+ function tokenize(text4, drop) {
198167
+ const lowered = text4.toLowerCase().replace(/[`*_~#>]/g, " ");
198168
+ const out = [];
198169
+ for (const raw of lowered.split(/[^a-z0-9]+/)) {
198170
+ if (raw.length < 2)
198171
+ continue;
198172
+ if (STOPWORDS2.has(raw))
198173
+ continue;
198174
+ if (drop.has(raw))
198175
+ continue;
198176
+ out.push(raw);
198177
+ }
198178
+ return out;
198179
+ }
198180
+ function pathWords(p2) {
198181
+ return p2.toLowerCase().split(/[^a-z0-9]+/).filter((t2) => t2.length >= 2);
198182
+ }
198183
+ var HEADING_RE = /^ {0,3}#{1,6}\s+(.*)$/;
198184
+ function splitDocSections(body, drop) {
198185
+ const raws = [];
198186
+ let cur = { heading: "", text: "" };
198187
+ for (const line of body.split(/\r?\n/)) {
198188
+ const m = HEADING_RE.exec(line);
198189
+ if (m) {
198190
+ if (cur.text.trim() || cur.heading)
198191
+ raws.push(cur);
198192
+ cur = { heading: m[1].trim(), text: `${line}
198193
+ ` };
198194
+ } else {
198195
+ cur.text += `${line}
198196
+ `;
198197
+ }
198198
+ }
198199
+ if (cur.text.trim() || cur.heading)
198200
+ raws.push(cur);
198201
+ return raws.map((r) => ({
198202
+ realHeading: r.heading === "" ? null : r.heading,
198203
+ tokens: new Set(tokenize(r.text, drop)),
198204
+ text: r.text
198205
+ }));
198206
+ }
198207
+ function headingKey(h) {
198208
+ return h.replace(/[`*_~]/g, "").trim().toLowerCase();
198209
+ }
198210
+ function locateQuote(sections, quote) {
198211
+ const needle = normalizeQuote(quote);
198212
+ if (!needle)
198213
+ return [];
198214
+ const hits = [];
198215
+ for (let i = 0; i < sections.length; i++) {
198216
+ if (normalizeQuote(sections[i].text).includes(needle))
198217
+ hits.push(i);
198218
+ }
198219
+ return hits;
198220
+ }
198221
+ function scoreSections(sections, noteTokens) {
198222
+ const N = sections.length;
198223
+ const df = /* @__PURE__ */ new Map();
198224
+ for (const s of sections)
198225
+ for (const t2 of s.tokens)
198226
+ df.set(t2, (df.get(t2) ?? 0) + 1);
198227
+ const idf = (t2) => {
198228
+ const d3 = df.get(t2) ?? 0;
198229
+ if (d3 === 0)
198230
+ return 0;
198231
+ return Math.max(0, Math.log2((N + 1) / (d3 + 1)));
198232
+ };
198233
+ return sections.map((s) => {
198234
+ let score = 0;
198235
+ for (const t2 of noteTokens)
198236
+ if (s.tokens.has(t2))
198237
+ score += idf(t2);
198238
+ return score;
198239
+ });
198240
+ }
198241
+ function verifyOverlapSections(input) {
198242
+ const { docs, note, sections, bodyOf } = input;
198243
+ if (sections.length === 0)
198244
+ return [...sections];
198245
+ const drop = /* @__PURE__ */ new Set([...pathWords(docs[0]), ...pathWords(docs[1])]);
198246
+ const noteTokens = new Set(tokenize(note, drop));
198247
+ return sections.map((ptr) => {
198248
+ const body = bodyOf(ptr.doc);
198249
+ if (body === void 0)
198250
+ return { ...ptr };
198251
+ const candidates = splitDocSections(body, drop);
198252
+ if (candidates.length === 0)
198253
+ return { ...ptr };
198254
+ let pointedIdx;
198255
+ if (ptr.heading === null) {
198256
+ pointedIdx = 0;
198257
+ } else {
198258
+ const key4 = headingKey(ptr.heading);
198259
+ pointedIdx = candidates.findIndex((c2) => c2.realHeading !== null && headingKey(c2.realHeading) === key4);
198260
+ }
198261
+ if (ptr.quote !== void 0) {
198262
+ const hits = locateQuote(candidates, ptr.quote);
198263
+ if (hits.length > 0) {
198264
+ if (pointedIdx >= 0 && hits.includes(pointedIdx))
198265
+ return { ...ptr };
198266
+ const target = hits[0];
198267
+ return { ...ptr, heading: target === 0 ? null : candidates[target].realHeading };
198268
+ }
198269
+ }
198270
+ if (noteTokens.size === 0)
198271
+ return { ...ptr };
198272
+ const scores = scoreSections(candidates, noteTokens);
198273
+ let bestIdx = 0;
198274
+ for (let i = 1; i < scores.length; i++)
198275
+ if (scores[i] > scores[bestIdx])
198276
+ bestIdx = i;
198277
+ const bestScore = scores[bestIdx];
198278
+ const pointedScore = pointedIdx >= 0 ? scores[pointedIdx] : 0;
198279
+ const reanchor = bestIdx !== pointedIdx && bestScore >= MIN_MEANINGFUL_SCORE && pointedScore < MIN_MEANINGFUL_SCORE && pointedScore <= NEGLIGIBLE_RATIO * bestScore;
198280
+ if (!reanchor)
198281
+ return { ...ptr };
198282
+ return { ...ptr, heading: bestIdx === 0 ? null : candidates[bestIdx].realHeading };
198283
+ });
198284
+ }
198285
+
198286
+ // packages/spec-consolidator/dist/overlap-detector.js
198006
198287
  var DEFAULT_MAX_PAIRS_PER_AREA = 60;
198007
198288
  async function flagOverlaps(repoRoot5, areas, docs, opts = {}) {
198008
198289
  const result = /* @__PURE__ */ new Map();
198009
198290
  if (opts.enabled === false)
198010
198291
  return result;
198011
198292
  const byPath = new Map(docs.map((d3) => [d3.path, d3]));
198012
- const resolved = resolvedPairKeys(opts.relations ?? []);
198013
198293
  const maxPairs = opts.maxPairsPerArea ?? DEFAULT_MAX_PAIRS_PER_AREA;
198014
198294
  const vocab = opts.vocab;
198015
198295
  const pairs2 = [];
@@ -198024,8 +198304,6 @@ async function flagOverlaps(repoRoot5, areas, docs, opts = {}) {
198024
198304
  const b = byPath.get(y);
198025
198305
  if (!a || !b)
198026
198306
  return;
198027
- if (isResolved(resolved, area.id, x, y))
198028
- return;
198029
198307
  const key4 = x < y ? `${x}\0${y}` : `${y}\0${x}`;
198030
198308
  if (seen.has(key4))
198031
198309
  return;
@@ -198092,6 +198370,19 @@ async function flagOverlaps(repoRoot5, areas, docs, opts = {}) {
198092
198370
  };
198093
198371
  launch();
198094
198372
  });
198373
+ for (const list of result.values()) {
198374
+ for (const overlap of list) {
198375
+ overlap.sections = verifyOverlapSections({
198376
+ docs: overlap.docs,
198377
+ note: overlap.note,
198378
+ sections: overlap.sections,
198379
+ bodyOf: (ref) => {
198380
+ const d3 = byPath.get(ref);
198381
+ return d3 ? docBody2(d3) : void 0;
198382
+ }
198383
+ });
198384
+ }
198385
+ }
198095
198386
  const entries = [...result].flatMap(([area, list]) => list.map((overlap) => ({ area, overlap })));
198096
198387
  const merged = dedupeCrossAreaOverlaps(entries);
198097
198388
  result.clear();
@@ -198115,22 +198406,6 @@ async function examineOne(repoRoot5, areaId, a, b, runner) {
198115
198406
  await writeCache3(repoRoot5, cacheKey, verdict);
198116
198407
  return verdict;
198117
198408
  }
198118
- function resolvedPairKeys(relations) {
198119
- const set2 = /* @__PURE__ */ new Set();
198120
- for (const r of relations) {
198121
- if (r.scope)
198122
- set2.add(scopedKey2(r.scope, r.older, r.newer));
198123
- else
198124
- set2.add(globalKey(r.older, r.newer));
198125
- }
198126
- return set2;
198127
- }
198128
- var sortedPair = (x, y) => [x, y].sort().join(" ");
198129
- var globalKey = (x, y) => `* ${sortedPair(x, y)}`;
198130
- var scopedKey2 = (scope, x, y) => `${scope} ${sortedPair(x, y)}`;
198131
- function isResolved(set2, areaId, x, y) {
198132
- return set2.has(globalKey(x, y)) || set2.has(scopedKey2(areaId, x, y));
198133
- }
198134
198409
  var OVERLAP_DETECTOR_SYSTEM_PROMPT = `You compare TWO documentation files that both cover the same AREA of a software system and decide whether they may DISAGREE.
198135
198410
 
198136
198411
  ${OUTPUT_ONLY_GUARDRAIL}
@@ -198146,9 +198421,12 @@ NOT a disagreement (do NOT flag):
198146
198421
 
198147
198422
  Bias: when there is a PLAUSIBLE contradiction a human should check, flag it. When the docs are clearly complementary or agree, do not.
198148
198423
 
198149
- When you flag an overlap, also identify the SECTIONS that conflict: the nearest markdown heading (the \`#\`/\`##\`/\`###\` title, verbatim, WITHOUT the leading #s) above the conflicting text in EACH doc. List one entry per side; omit a side only when it genuinely has no conflicting passage.
198424
+ When you flag an overlap, point at WHERE each side's disputed claim lives. Below each doc you are given a CLOSED list of that doc's section options \u2014 its headings, plus a "lead" option. Do NOT recall or guess a heading; SELECT from the list. For EACH side output a pointer with two fields:
198425
+ - \`heading\`: EXACTLY one of that doc's listed section headings, copied verbatim \u2014 OR the JSON literal \`null\` (not the string "null", not "") for the LEAD, the text ABOVE its first heading (or, when the doc opens straight with a title, that opening title block). Never emit a heading that is not one of the listed options.
198426
+ - \`quote\`: a SHORT verbatim excerpt (\u2264 25 words) of the disputed sentence, copied EXACTLY from that doc \u2014 the words that state the claim in dispute. This is your evidence for the heading you picked; copy it, do not paraphrase.
198427
+ List one entry per side; omit a side only when it genuinely has no conflicting passage.
198150
198428
 
198151
- PREAMBLE: when a doc's conflicting passage sits ABOVE its first \`#\` heading \u2014 the preamble block (a README's badges, tagline, or the intro line before any heading) \u2014 there is no heading to name. Set that side's \`heading\` to the JSON literal \`null\` (not the string "null", not ""). Use \`null\` ONLY for that pre-first-heading block; whenever the passage is under a heading, name the heading verbatim.
198429
+ PREAMBLE: use \`heading\`: \`null\` ONLY for that lead/preamble block; whenever the disputed passage is under a listed heading, select that heading verbatim.
198152
198430
 
198153
198431
  In the NOTE, refer to each doc by its FILENAME (the basename shown in the header, e.g. \`users.md\`) \u2014 NEVER "doc A" / "doc B", which mean nothing to the reader.
198154
198432
 
@@ -198156,13 +198434,19 @@ Output ONLY a JSON object, no prose, no code fences:
198156
198434
 
198157
198435
  { "overlap": true,
198158
198436
  "note": "users.md uses auth0_id; identity.md uses auth0_sub for the same user column",
198159
- "sections": [ { "side": "A", "heading": "User model" }, { "side": "B", "heading": "Identity" } ] }
198437
+ "sections": [
198438
+ { "side": "A", "heading": "User model", "quote": "the auth0_id column stores the Auth0 subject" },
198439
+ { "side": "B", "heading": "Identity", "quote": "we persist the Auth0 subject in auth0_sub" }
198440
+ ] }
198160
198441
 
198161
- Preamble example \u2014 doc A's claim is a README badge/tagline above any heading, so its side uses null:
198442
+ Preamble example \u2014 doc A's disputed claim is a README tagline ABOVE its first heading, so its side uses \`heading\`: null and quotes that tagline verbatim:
198162
198443
 
198163
198444
  { "overlap": true,
198164
198445
  "note": "README.md lists C# as a supported language in the preamble; plan.md's Tech Stack omits it",
198165
- "sections": [ { "side": "A", "heading": null }, { "side": "B", "heading": "Tech Stack" } ] }
198446
+ "sections": [
198447
+ { "side": "A", "heading": null, "quote": "Supports TypeScript, Python, and C# out of the box" },
198448
+ { "side": "B", "heading": "Tech Stack", "quote": "The stack is TypeScript and Python" }
198449
+ ] }
198166
198450
 
198167
198451
  Use { "overlap": false, "note": "", "sections": [] } when they are complementary or agree. The note is shown to the user \u2014 name the specific thing that differs.`;
198168
198452
  var OVERLAP_PREVIEW_LINES = 120;
@@ -198196,31 +198480,59 @@ function hasConcernHeading(doc, concern, vocab) {
198196
198480
  }
198197
198481
  return false;
198198
198482
  }
198483
+ function sectionHeadings(body) {
198484
+ const out = [];
198485
+ for (const line of body.split(/\r?\n/)) {
198486
+ const m = /^ {0,3}#{1,6}\s+(.*)$/.exec(line);
198487
+ if (!m)
198488
+ continue;
198489
+ const text4 = m[1].replace(/\s*#*\s*$/, "").trim();
198490
+ if (text4)
198491
+ out.push(text4);
198492
+ }
198493
+ return out;
198494
+ }
198495
+ function sectionOptions(slice5) {
198496
+ const lines = [" - the lead (text above the first heading, or the opening title block) \u2192 use heading: null"];
198497
+ for (const h of sectionHeadings(slice5))
198498
+ lines.push(` - ${h}`);
198499
+ return lines;
198500
+ }
198199
198501
  function buildOverlapUserPrompt(areaId, a, b) {
198200
198502
  const slice5 = (d3) => docBody2(d3).split(/\r?\n/).slice(0, OVERLAP_PREVIEW_LINES).join("\n");
198503
+ const sliceA = slice5(a);
198504
+ const sliceB = slice5(b);
198201
198505
  return [
198202
198506
  `Area: ${areaId}`,
198203
198507
  "",
198204
198508
  `--- doc A: ${a.path} ---`,
198205
- slice5(a),
198509
+ sliceA,
198206
198510
  `--- end doc A ---`,
198207
198511
  "",
198208
198512
  `--- doc B: ${b.path} ---`,
198209
- slice5(b),
198513
+ sliceB,
198210
198514
  `--- end doc B ---`,
198211
198515
  "",
198516
+ "SECTION OPTIONS \u2014 each side pointer MUST be one of these (verbatim), or the lead (heading: null):",
198517
+ "",
198518
+ `doc A (${a.path}):`,
198519
+ ...sectionOptions(sliceA),
198520
+ "",
198521
+ `doc B (${b.path}):`,
198522
+ ...sectionOptions(sliceB),
198523
+ "",
198212
198524
  "Return the JSON object as specified."
198213
198525
  ].join("\n");
198214
198526
  }
198215
198527
  var LlmOverlapSchema = external_exports.object({
198216
198528
  overlap: external_exports.boolean(),
198217
198529
  note: external_exports.string().default(""),
198218
- sections: external_exports.array(external_exports.object({ side: external_exports.enum(["A", "B"]), heading: external_exports.string().nullable() })).default([])
198530
+ sections: external_exports.array(external_exports.object({ side: external_exports.enum(["A", "B"]), heading: external_exports.string().nullable(), quote: external_exports.string().optional() })).default([])
198219
198531
  });
198220
198532
  var OverlapVerdictSchema = external_exports.object({
198221
198533
  overlap: external_exports.boolean(),
198222
198534
  note: external_exports.string().default(""),
198223
- sections: external_exports.array(external_exports.object({ doc: external_exports.string(), heading: external_exports.string().nullable() })).default([])
198535
+ sections: external_exports.array(external_exports.object({ doc: external_exports.string(), heading: external_exports.string().nullable(), quote: external_exports.string().optional() })).default([])
198224
198536
  });
198225
198537
  function spawnOverlapRunner(opts = {}) {
198226
198538
  const transport = opts.transport ?? cliTransport({ bin: opts.bin });
@@ -198240,7 +198552,11 @@ function spawnOverlapRunner(opts = {}) {
198240
198552
  return {
198241
198553
  overlap: inner.overlap,
198242
198554
  note: inner.note,
198243
- sections: inner.sections.map((s) => ({ doc: s.side === "A" ? a.path : b.path, heading: s.heading }))
198555
+ sections: inner.sections.map((s) => ({
198556
+ doc: s.side === "A" ? a.path : b.path,
198557
+ heading: s.heading,
198558
+ ...s.quote !== void 0 ? { quote: s.quote } : {}
198559
+ }))
198244
198560
  };
198245
198561
  };
198246
198562
  }
@@ -198402,12 +198718,12 @@ function prefilterDocs(docs, manualIncludes = []) {
198402
198718
  if (reason)
198403
198719
  reasons.set(doc.path, reason);
198404
198720
  }
198405
- for (const { path: path80, reason } of dedupeNearDuplicates(docs.filter((d3) => !manualSet.has(d3.path) && !reasons.has(d3.path)))) {
198406
- reasons.set(path80, reason);
198721
+ for (const { path: path81, reason } of dedupeNearDuplicates(docs.filter((d3) => !manualSet.has(d3.path) && !reasons.has(d3.path)))) {
198722
+ reasons.set(path81, reason);
198407
198723
  }
198408
198724
  return {
198409
198725
  toClassify: docs.filter((d3) => !reasons.has(d3.path)),
198410
- skipped: [...reasons].map(([path80, reason]) => ({ path: path80, reason }))
198726
+ skipped: [...reasons].map(([path81, reason]) => ({ path: path81, reason }))
198411
198727
  };
198412
198728
  }
198413
198729
  async function planRelevanceWork(repoRoot5, docs, manualIncludes = []) {
@@ -198725,7 +199041,6 @@ async function curate(repoRoot5, opts = {}) {
198725
199041
  const overlapsByArea = await flagOverlaps(repoRoot5, grouped.areas, docs, {
198726
199042
  runner: opts.overlapRunner,
198727
199043
  enabled: opts.disableOverlapDetection !== true,
198728
- relations,
198729
199044
  vocab,
198730
199045
  transport: opts.transport,
198731
199046
  model: models.overlap,
@@ -198771,7 +199086,8 @@ var EMPTY_DECISIONS = {
198771
199086
  manualIncludes: [],
198772
199087
  manualExcludes: [],
198773
199088
  relations: [],
198774
- manualAreas: []
199089
+ manualAreas: [],
199090
+ conflictResolutions: []
198775
199091
  };
198776
199092
  function readCorpusDecisions(repoRoot5) {
198777
199093
  const file = path31.join(repoRoot5, ".truecourse", "specs", "decisions.json");
@@ -198793,7 +199109,8 @@ var EMPTY_DECISIONS2 = {
198793
199109
  manualIncludes: [],
198794
199110
  manualExcludes: [],
198795
199111
  relations: [],
198796
- manualAreas: []
199112
+ manualAreas: [],
199113
+ conflictResolutions: []
198797
199114
  };
198798
199115
  function decisionsPath(repoRoot5) {
198799
199116
  return path32.join(repoRoot5, ".truecourse", "specs", "decisions.json");
@@ -198973,8 +199290,8 @@ function canonicalIdentity(_kind, identity) {
198973
199290
  let id = identity.trim().replace(/\s+/g, " ");
198974
199291
  const op = HTTP_METHOD.exec(id);
198975
199292
  if (op) {
198976
- const path80 = op[2].replace(/\/+$/, "").replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, "{$1}");
198977
- id = `${op[1].toUpperCase()} ${path80}`;
199293
+ const path81 = op[2].replace(/\/+$/, "").replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, "{$1}");
199294
+ id = `${op[1].toUpperCase()} ${path81}`;
198978
199295
  }
198979
199296
  return id;
198980
199297
  }
@@ -202871,6 +203188,7 @@ function describeStageResolutions(repoDir = resolveRepoDir(process.cwd())) {
202871
203188
  }
202872
203189
 
202873
203190
  // packages/core/dist/commands/spec-in-process.js
203191
+ init_dist5();
202874
203192
  init_transport();
202875
203193
 
202876
203194
  // packages/core/dist/lib/llm-call-log.js
@@ -207137,8 +207455,8 @@ init_dist5();
207137
207455
 
207138
207456
  // packages/guard-generator/dist/section-plan.js
207139
207457
  init_zod();
207140
- import fs59 from "node:fs";
207141
- import path63 from "node:path";
207458
+ import fs60 from "node:fs";
207459
+ import path64 from "node:path";
207142
207460
  import { createHash as createHash15 } from "node:crypto";
207143
207461
  init_dist5();
207144
207462
 
@@ -207280,6 +207598,11 @@ function buildExtractUserPrompt(ctx) {
207280
207598
  ctx.viewText,
207281
207599
  '"""'
207282
207600
  ];
207601
+ if (ctx.suppressed && ctx.suppressed.length > 0) {
207602
+ lines.push("", "RESOLVED \u2014 STALE, DO NOT EXTRACT. A conflict resolution judged the following", "sentence(s) in this document stale (another document is authoritative here).", "Extract NO claim that asserts what any of them says \u2014 treat them as if absent:");
207603
+ for (const q2 of ctx.suppressed)
207604
+ lines.push(`- "${q2}"`);
207605
+ }
207283
207606
  if (ctx.correction) {
207284
207607
  lines.push("", "CORRECTION \u2014 your previous response was NOT valid. You returned:", ctx.correction.invalidOutput, 'Return exactly ONE JSON object with "claims" and "untestable" arrays matching', 'the schema above, and NOTHING else. Every "driver" is one of cli|api|web|tui;', 'every "sectionAnchor" is an anchor copied verbatim from the outline.');
207285
207608
  }
@@ -207448,17 +207771,127 @@ function buildRecipeUserPrompt(input) {
207448
207771
  return lines.join("\n");
207449
207772
  }
207450
207773
 
207451
- // packages/guard-generator/dist/section-plan.js
207774
+ // packages/guard-generator/dist/suppression.js
207775
+ init_zod();
207776
+ init_dist5();
207777
+ import fs59 from "node:fs";
207778
+ import path63 from "node:path";
207779
+ var OverlapSectionShape = external_exports.object({ doc: external_exports.string(), heading: external_exports.string().nullable().optional(), quote: external_exports.string().optional() }).passthrough();
207780
+ var OverlapShape = external_exports.object({
207781
+ docs: external_exports.tuple([external_exports.string(), external_exports.string()]),
207782
+ note: external_exports.string().optional(),
207783
+ sections: external_exports.array(OverlapSectionShape).optional(),
207784
+ areas: external_exports.array(external_exports.string()).optional()
207785
+ }).passthrough();
207786
+ var RelationShape = external_exports.object({ older: external_exports.string(), newer: external_exports.string(), scope: external_exports.string().optional() }).passthrough();
207452
207787
  var CorpusShape2 = external_exports.object({
207788
+ areas: external_exports.array(external_exports.object({ id: external_exports.string(), overlaps: external_exports.array(OverlapShape).optional() }).passthrough()).optional(),
207789
+ relations: external_exports.array(RelationShape).optional()
207790
+ }).passthrough();
207791
+ var ConflictResolutionShape = external_exports.object({
207792
+ docA: external_exports.string(),
207793
+ anchorA: external_exports.string().nullable().optional(),
207794
+ quoteA: external_exports.string().optional(),
207795
+ docB: external_exports.string(),
207796
+ anchorB: external_exports.string().nullable().optional(),
207797
+ quoteB: external_exports.string().optional(),
207798
+ verdict: external_exports.enum(["a", "b", "dismissed"]),
207799
+ resolvedAt: external_exports.string().optional(),
207800
+ note: external_exports.string().optional()
207801
+ }).passthrough();
207802
+ var DecisionsShape = external_exports.object({
207803
+ relations: external_exports.array(RelationShape).optional(),
207804
+ manualExcludes: external_exports.array(external_exports.string()).optional(),
207805
+ conflictResolutions: external_exports.array(ConflictResolutionShape).optional()
207806
+ }).passthrough();
207807
+ function readJsonTolerant(file, schema2) {
207808
+ if (!fs59.existsSync(file))
207809
+ return void 0;
207810
+ try {
207811
+ const parsed = schema2.safeParse(JSON.parse(fs59.readFileSync(file, "utf-8")));
207812
+ return parsed.success ? parsed.data : void 0;
207813
+ } catch {
207814
+ return void 0;
207815
+ }
207816
+ }
207817
+ function readSuppressedClaims(repoRoot5) {
207818
+ const specDir = path63.join(repoRoot5, ".truecourse", "specs");
207819
+ const corpus = readJsonTolerant(path63.join(specDir, "corpus.json"), CorpusShape2);
207820
+ if (!corpus)
207821
+ return [];
207822
+ const decisions = readJsonTolerant(path63.join(specDir, "decisions.json"), DecisionsShape);
207823
+ const corpusLike = {
207824
+ areas: (corpus.areas ?? []).map((a) => ({
207825
+ id: a.id,
207826
+ overlaps: (a.overlaps ?? []).map((o) => ({
207827
+ docs: o.docs,
207828
+ note: o.note,
207829
+ sections: (o.sections ?? []).map((s) => ({ doc: s.doc, heading: s.heading ?? null, quote: s.quote })),
207830
+ areas: o.areas
207831
+ }))
207832
+ })),
207833
+ relations: corpus.relations ?? []
207834
+ };
207835
+ const decisionsLike = {
207836
+ relations: decisions?.relations ?? [],
207837
+ manualExcludes: decisions?.manualExcludes ?? [],
207838
+ conflictResolutions: (decisions?.conflictResolutions ?? []).map((r) => ({
207839
+ docA: r.docA,
207840
+ anchorA: r.anchorA ?? null,
207841
+ quoteA: r.quoteA,
207842
+ docB: r.docB,
207843
+ anchorB: r.anchorB ?? null,
207844
+ quoteB: r.quoteB,
207845
+ verdict: r.verdict,
207846
+ resolvedAt: r.resolvedAt,
207847
+ note: r.note
207848
+ }))
207849
+ };
207850
+ return suppressedClaims(corpusLike, decisionsLike);
207851
+ }
207852
+ function readSuppressionIndex(repoRoot5) {
207853
+ const map2 = /* @__PURE__ */ new Map();
207854
+ for (const claim of readSuppressedClaims(repoRoot5)) {
207855
+ const list = map2.get(claim.doc);
207856
+ if (list)
207857
+ list.push(claim.quote);
207858
+ else
207859
+ map2.set(claim.doc, [claim.quote]);
207860
+ }
207861
+ return map2;
207862
+ }
207863
+ function suppressedQuotesIn(text4, docQuotes) {
207864
+ if (docQuotes.length === 0)
207865
+ return [];
207866
+ const haystack = normalizeQuote(text4);
207867
+ const seen = /* @__PURE__ */ new Set();
207868
+ const hits = [];
207869
+ for (const q2 of docQuotes) {
207870
+ const needle = normalizeQuote(q2);
207871
+ if (!needle || seen.has(needle) || !haystack.includes(needle))
207872
+ continue;
207873
+ seen.add(needle);
207874
+ hits.push(q2);
207875
+ }
207876
+ return hits.sort((a, b) => normalizeQuote(a) < normalizeQuote(b) ? -1 : 1);
207877
+ }
207878
+ function suppressionKey(quotes) {
207879
+ if (quotes.length === 0)
207880
+ return "";
207881
+ return [...quotes].map(normalizeQuote).sort().join("\0");
207882
+ }
207883
+
207884
+ // packages/guard-generator/dist/section-plan.js
207885
+ var CorpusShape3 = external_exports.object({
207453
207886
  docs: external_exports.array(external_exports.object({ ref: external_exports.string(), areaTags: external_exports.array(external_exports.string()).optional() }).passthrough()).optional()
207454
207887
  }).passthrough();
207455
207888
  function readCorpusAreaTags(repoRoot5) {
207456
- const file = path63.join(repoRoot5, ".truecourse", "specs", "corpus.json");
207889
+ const file = path64.join(repoRoot5, ".truecourse", "specs", "corpus.json");
207457
207890
  const map2 = /* @__PURE__ */ new Map();
207458
- if (!fs59.existsSync(file))
207891
+ if (!fs60.existsSync(file))
207459
207892
  return map2;
207460
207893
  try {
207461
- const parsed = CorpusShape2.safeParse(JSON.parse(fs59.readFileSync(file, "utf-8")));
207894
+ const parsed = CorpusShape3.safeParse(JSON.parse(fs60.readFileSync(file, "utf-8")));
207462
207895
  if (!parsed.success)
207463
207896
  return map2;
207464
207897
  for (const d3 of parsed.data.docs ?? [])
@@ -207467,29 +207900,35 @@ function readCorpusAreaTags(repoRoot5) {
207467
207900
  }
207468
207901
  return map2;
207469
207902
  }
207470
- function generationInputsHash(fingerprint2, recipeFingerprint) {
207471
- return "sha256:" + createHash15("sha256").update([
207903
+ function generationInputsHash(fingerprint2, recipeFingerprint, suppressionFingerprint = "") {
207904
+ const parts = [
207472
207905
  fingerprint2,
207473
207906
  recipeFingerprint,
207474
207907
  String(GUARD_FORMAT_VERSION),
207475
207908
  EXTRACT_PROMPT_FINGERPRINT2,
207476
207909
  GENERATE_PROMPT_FINGERPRINT
207477
- ].join("\0")).digest("hex");
207910
+ ];
207911
+ if (suppressionFingerprint)
207912
+ parts.push(suppressionFingerprint);
207913
+ return "sha256:" + createHash15("sha256").update(parts.join("\0")).digest("hex");
207478
207914
  }
207479
207915
  function hasGuardUniverse(repoRoot5) {
207480
- return fs59.existsSync(path63.join(repoRoot5, ".truecourse", "specs", "corpus.json"));
207916
+ return fs60.existsSync(path64.join(repoRoot5, ".truecourse", "specs", "corpus.json"));
207481
207917
  }
207482
207918
  function planGuardWork(repoRoot5, recipeFingerprint) {
207483
207919
  const recipeFp = recipeFingerprint ?? computeRecipeFingerprint(repoRoot5);
207484
- const recipeMissing = !fs59.existsSync(recipePath(repoRoot5));
207920
+ const recipeMissing = !fs60.existsSync(recipePath(repoRoot5));
207485
207921
  const hasUniverse = hasGuardUniverse(repoRoot5);
207486
207922
  const { indexes } = indexRepoDocs(repoRoot5, []);
207487
207923
  const areaTags = readCorpusAreaTags(repoRoot5);
207924
+ const suppressionIndex = readSuppressionIndex(repoRoot5);
207488
207925
  const sections = [];
207489
207926
  for (const [doc, index] of indexes) {
207490
- const texts = extractSectionTexts(doc, fs59.readFileSync(path63.resolve(repoRoot5, doc), "utf-8"));
207927
+ const texts = extractSectionTexts(doc, fs60.readFileSync(path64.resolve(repoRoot5, doc), "utf-8"));
207928
+ const docQuotes = suppressionIndex.get(doc) ?? [];
207491
207929
  for (const s of index.sections) {
207492
207930
  const t2 = texts.get(s.anchor);
207931
+ const fullText = t2?.fullText ?? "";
207493
207932
  sections.push({
207494
207933
  doc,
207495
207934
  anchor: s.anchor,
@@ -207497,8 +207936,9 @@ function planGuardWork(repoRoot5, recipeFingerprint) {
207497
207936
  headingText: s.headingText,
207498
207937
  level: s.level,
207499
207938
  ownText: t2?.ownText ?? "",
207500
- fullText: t2?.fullText ?? "",
207501
- areaTags: areaTags.get(doc) ?? []
207939
+ fullText,
207940
+ areaTags: areaTags.get(doc) ?? [],
207941
+ suppressionFingerprint: suppressionKey(suppressedQuotesIn(fullText, docQuotes))
207502
207942
  });
207503
207943
  }
207504
207944
  }
@@ -207511,12 +207951,12 @@ function planGuardWork(repoRoot5, recipeFingerprint) {
207511
207951
  const key4 = `${s.doc}\0${s.anchor}`;
207512
207952
  seen.add(key4);
207513
207953
  const prior = byKey.get(key4);
207514
- const inputsHash = generationInputsHash(s.fingerprint, recipeFp);
207954
+ const inputsHash = generationInputsHash(s.fingerprint, recipeFp, s.suppressionFingerprint);
207515
207955
  if (!prior || prior.generationInputsHash !== inputsHash)
207516
207956
  work.push(s);
207517
207957
  }
207518
207958
  const orphaned = (manifest?.sections ?? []).filter((e) => !seen.has(`${e.doc}\0${e.anchor}`));
207519
- return { hasUniverse, sections, work, orphaned, recipeFingerprint: recipeFp, recipeMissing };
207959
+ return { hasUniverse, sections, work, orphaned, recipeFingerprint: recipeFp, recipeMissing, suppressionIndex };
207520
207960
  }
207521
207961
  function collectWorkDocs(repoRoot5, plan) {
207522
207962
  const workDocs = new Set(plan.work.map((s) => s.doc));
@@ -207532,8 +207972,9 @@ function collectWorkDocs(repoRoot5, plan) {
207532
207972
  }
207533
207973
  return [...byDoc].map(([doc, sections]) => ({
207534
207974
  doc,
207535
- content: fs59.readFileSync(path63.resolve(repoRoot5, doc), "utf-8"),
207536
- sections
207975
+ content: fs60.readFileSync(path64.resolve(repoRoot5, doc), "utf-8"),
207976
+ sections,
207977
+ suppressedQuotes: plan.suppressionIndex.get(doc) ?? []
207537
207978
  }));
207538
207979
  }
207539
207980
 
@@ -207616,8 +208057,13 @@ function flattenZodError(error) {
207616
208057
  // packages/guard-generator/dist/extract.js
207617
208058
  var EXTRACT_CACHE_NAME2 = "guard/extract";
207618
208059
  var EXTRACT_VIEW_BUDGET = 16e3;
207619
- function viewCacheKey(viewText) {
207620
- return createHash16("sha256").update(`${EXTRACT_PROMPT_FINGERPRINT2}::${sha(viewText)}`).digest("hex");
208060
+ function viewCacheKey(viewText, suppressed = []) {
208061
+ const base2 = `${EXTRACT_PROMPT_FINGERPRINT2}::${sha(viewText)}`;
208062
+ const suppression = suppressionKey(suppressed);
208063
+ return createHash16("sha256").update(suppression ? `${base2}::${suppression}` : base2).digest("hex");
208064
+ }
208065
+ function suppressedForView(doc, viewText) {
208066
+ return suppressedQuotesIn(viewText, doc.suppressedQuotes);
207621
208067
  }
207622
208068
  function sha(text4) {
207623
208069
  return createHash16("sha256").update(text4).digest("hex");
@@ -207663,7 +208109,7 @@ function countExtractViews(doc) {
207663
208109
  async function countUncachedExtractViews(repoRoot5, doc) {
207664
208110
  let n = 0;
207665
208111
  for (const v of planViews(doc)) {
207666
- if (!await getCacheEntry(repoRoot5, EXTRACT_CACHE_NAME2, viewCacheKey(v.text)))
208112
+ if (!await getCacheEntry(repoRoot5, EXTRACT_CACHE_NAME2, viewCacheKey(v.text, suppressedForView(doc, v.text))))
207667
208113
  n++;
207668
208114
  }
207669
208115
  return n;
@@ -207672,7 +208118,7 @@ async function extractDocClaims(repoRoot5, doc, runner, limit, onView) {
207672
208118
  const outline = outlineOf(doc.sections);
207673
208119
  const views = planViews(doc);
207674
208120
  const run = limit ?? ((fn) => fn());
207675
- const attempts = await Promise.all(views.map((v) => run(() => extractView(repoRoot5, doc.doc, outline, v, runner)).then((got) => {
208121
+ const attempts = await Promise.all(views.map((v) => run(() => extractView(repoRoot5, doc.doc, outline, v, suppressedForView(doc, v.text), runner)).then((got) => {
207676
208122
  onView?.();
207677
208123
  return got;
207678
208124
  })));
@@ -207693,15 +208139,21 @@ async function extractDocClaims(repoRoot5, doc, runner, limit, onView) {
207693
208139
  return { ok: false, reason: firstError || "all extraction views failed" };
207694
208140
  return { ok: true, data: snap(merged, doc.sections), complete: failedViews === 0, failedViews };
207695
208141
  }
207696
- async function extractView(repoRoot5, docPath, outline, view, runner) {
207697
- const cacheKey = viewCacheKey(view.text);
208142
+ async function extractView(repoRoot5, docPath, outline, view, suppressed, runner) {
208143
+ const cacheKey = viewCacheKey(view.text, suppressed);
207698
208144
  const cached = await getCacheEntry(repoRoot5, EXTRACT_CACHE_NAME2, cacheKey);
207699
208145
  if (cached) {
207700
208146
  const parsed = DocExtractionSchema.safeParse(cached);
207701
208147
  if (parsed.success)
207702
208148
  return { data: parsed.data };
207703
208149
  }
207704
- const ctx = { doc: docPath, outline, viewText: view.text, view: view.view };
208150
+ const ctx = {
208151
+ doc: docPath,
208152
+ outline,
208153
+ viewText: view.text,
208154
+ view: view.view,
208155
+ ...suppressed.length > 0 ? { suppressed } : {}
208156
+ };
207705
208157
  const attempt = await callExtractWithReask(ctx, runner);
207706
208158
  if ("data" in attempt)
207707
208159
  await setCacheEntry(repoRoot5, EXTRACT_CACHE_NAME2, cacheKey, attempt.data);
@@ -207780,7 +208232,7 @@ function snap(raw, sections) {
207780
208232
 
207781
208233
  // packages/guard-generator/dist/ground.js
207782
208234
  init_zod();
207783
- import path64 from "node:path";
208235
+ import path65 from "node:path";
207784
208236
  import { createHash as createHash17 } from "node:crypto";
207785
208237
  var GROUND_CACHE_NAME = "guard/ground";
207786
208238
  var PROBE_TIMEOUT_MS = 2e4;
@@ -207836,7 +208288,7 @@ function toProbeArgv(fragment, programNames) {
207836
208288
  const tokens = fragment.trim().split(/\s+/).filter(Boolean);
207837
208289
  if (tokens.length === 0)
207838
208290
  return null;
207839
- if (programNames.has(tokens[0]) || programNames.has(path64.basename(tokens[0])))
208291
+ if (programNames.has(tokens[0]) || programNames.has(path65.basename(tokens[0])))
207840
208292
  tokens.shift();
207841
208293
  if (tokens.length === 0)
207842
208294
  return [];
@@ -207857,7 +208309,7 @@ function programNamesOf(entry) {
207857
208309
  return names;
207858
208310
  }
207859
208311
  function addName(set2, arg) {
207860
- const base2 = path64.basename(arg);
208312
+ const base2 = path65.basename(arg);
207861
208313
  if (base2)
207862
208314
  set2.add(base2);
207863
208315
  const stem = base2.replace(/\.[^.]+$/, "");
@@ -207919,9 +208371,9 @@ function truncate3(text4) {
207919
208371
  }
207920
208372
 
207921
208373
  // packages/guard-generator/dist/recipe-discovery.js
207922
- import fs60 from "node:fs";
208374
+ import fs61 from "node:fs";
207923
208375
  import os13 from "node:os";
207924
- import path65 from "node:path";
208376
+ import path66 from "node:path";
207925
208377
  import { createHash as createHash18 } from "node:crypto";
207926
208378
  var RECIPE_CACHE_NAME = "guard/recipe";
207927
208379
  var DISCOVERY_INPUTS = ["package.json", "pnpm-lock.yaml", "package-lock.json", "yarn.lock", "turbo.json"];
@@ -207975,13 +208427,13 @@ async function discoverRecipe(repoRoot5, runner) {
207975
208427
  ...proposal.env ? { env: proposal.env } : {}
207976
208428
  };
207977
208429
  const target = recipePath(repoRoot5);
207978
- fs60.mkdirSync(path65.dirname(target), { recursive: true });
207979
- fs60.writeFileSync(target, JSON.stringify(recipe, null, 2) + "\n");
208430
+ fs61.mkdirSync(path66.dirname(target), { recursive: true });
208431
+ fs61.writeFileSync(target, JSON.stringify(recipe, null, 2) + "\n");
207980
208432
  return {
207981
208433
  status: "discovered",
207982
208434
  recipe,
207983
208435
  fingerprint: computeRecipeFingerprint(repoRoot5),
207984
- wrotePath: path65.relative(repoRoot5, target)
208436
+ wrotePath: path66.relative(repoRoot5, target)
207985
208437
  };
207986
208438
  }
207987
208439
  async function proposeRecipeWithReask(input, runner) {
@@ -208006,14 +208458,14 @@ async function proposeRecipeWithReask(input, runner) {
208006
208458
  return { error: `recipe proposal invalid after re-ask: ${flattenZodError(reParsed.error)}` };
208007
208459
  }
208008
208460
  function readDiscoveryInputs(repoRoot5) {
208009
- const pkgPath = path65.join(repoRoot5, "package.json");
208010
- const packageJson = fs60.existsSync(pkgPath) ? fs60.readFileSync(pkgPath, "utf-8") : "(no package.json)";
208011
- const presentInputs = DISCOVERY_INPUTS.filter((f2) => fs60.existsSync(path65.join(repoRoot5, f2)));
208461
+ const pkgPath = path66.join(repoRoot5, "package.json");
208462
+ const packageJson = fs61.existsSync(pkgPath) ? fs61.readFileSync(pkgPath, "utf-8") : "(no package.json)";
208463
+ const presentInputs = DISCOVERY_INPUTS.filter((f2) => fs61.existsSync(path66.join(repoRoot5, f2)));
208012
208464
  return { packageJson, presentInputs };
208013
208465
  }
208014
208466
  async function probeEntry(repoRoot5, entry) {
208015
208467
  const resolved = resolveEntry(repoRoot5, entry);
208016
- const cwd = fs60.mkdtempSync(path65.join(os13.tmpdir(), "tc-guard-probe-"));
208468
+ const cwd = fs61.mkdtempSync(path66.join(os13.tmpdir(), "tc-guard-probe-"));
208017
208469
  try {
208018
208470
  for (const args of [["--help"], []]) {
208019
208471
  const capture = await executeStep({
@@ -208030,7 +208482,7 @@ async function probeEntry(repoRoot5, entry) {
208030
208482
  reason: `entrypoint ${JSON.stringify(entry)} did not answer to \`--help\` or a bare invocation`
208031
208483
  };
208032
208484
  } finally {
208033
- fs60.rmSync(cwd, { recursive: true, force: true });
208485
+ fs61.rmSync(cwd, { recursive: true, force: true });
208034
208486
  }
208035
208487
  }
208036
208488
 
@@ -208077,8 +208529,8 @@ async function birthValidate(repoRoot5, candidates, opts = {}) {
208077
208529
  }
208078
208530
 
208079
208531
  // packages/guard-generator/dist/serialize.js
208080
- import fs61 from "node:fs";
208081
- import path66 from "node:path";
208532
+ import fs62 from "node:fs";
208533
+ import path67 from "node:path";
208082
208534
  init_dist5();
208083
208535
  function anchorLeaf(anchor) {
208084
208536
  const segs = anchor.split("/").filter(Boolean);
@@ -208097,7 +208549,7 @@ function assignScenarioId(anchor, used) {
208097
208549
  function areaOrDocSlug(section) {
208098
208550
  if (section.areaTags.length > 0)
208099
208551
  return slugifyHeading(section.areaTags[0]) || "area";
208100
- const base2 = path66.basename(section.doc).replace(/\.[^.]+$/, "");
208552
+ const base2 = path67.basename(section.doc).replace(/\.[^.]+$/, "");
208101
208553
  return slugifyHeading(base2) || "doc";
208102
208554
  }
208103
208555
  function buildScenario(section, raw, id) {
@@ -208120,15 +208572,15 @@ function scenarioFileIndex(repoRoot5) {
208120
208572
  const root2 = scenariosDir(repoRoot5);
208121
208573
  const map2 = /* @__PURE__ */ new Map();
208122
208574
  const walk20 = (dir) => {
208123
- if (!fs61.existsSync(dir))
208575
+ if (!fs62.existsSync(dir))
208124
208576
  return;
208125
- for (const entry of fs61.readdirSync(dir, { withFileTypes: true })) {
208126
- const full = path66.join(dir, entry.name);
208577
+ for (const entry of fs62.readdirSync(dir, { withFileTypes: true })) {
208578
+ const full = path67.join(dir, entry.name);
208127
208579
  if (entry.isDirectory())
208128
208580
  walk20(full);
208129
208581
  else if (entry.isFile() && /\.ya?ml$/i.test(entry.name)) {
208130
208582
  try {
208131
- const doc = jsYaml.load(fs61.readFileSync(full, "utf-8"));
208583
+ const doc = jsYaml.load(fs62.readFileSync(full, "utf-8"));
208132
208584
  if (doc && typeof doc.id === "string")
208133
208585
  map2.set(doc.id, full);
208134
208586
  } catch {
@@ -208146,18 +208598,18 @@ function serializeScenarioYaml(scenario) {
208146
208598
  return jsYaml.dump(scenario, { lineWidth: -1, noRefs: true });
208147
208599
  }
208148
208600
  function writeScenarioFile(repoRoot5, slug2, scenario) {
208149
- const dir = path66.join(scenariosDir(repoRoot5), slug2);
208150
- fs61.mkdirSync(dir, { recursive: true });
208151
- const file = path66.join(dir, `${scenario.id}.yaml`);
208152
- fs61.writeFileSync(file, serializeScenarioYaml(scenario));
208153
- return path66.relative(repoRoot5, file);
208601
+ const dir = path67.join(scenariosDir(repoRoot5), slug2);
208602
+ fs62.mkdirSync(dir, { recursive: true });
208603
+ const file = path67.join(dir, `${scenario.id}.yaml`);
208604
+ fs62.writeFileSync(file, serializeScenarioYaml(scenario));
208605
+ return path67.relative(repoRoot5, file);
208154
208606
  }
208155
208607
  function deleteScenarioFiles(repoRoot5, ids) {
208156
208608
  const index = scenarioFileIndex(repoRoot5);
208157
208609
  for (const id of ids) {
208158
208610
  const file = index.get(id);
208159
- if (file && fs61.existsSync(file))
208160
- fs61.rmSync(file);
208611
+ if (file && fs62.existsSync(file))
208612
+ fs62.rmSync(file);
208161
208613
  }
208162
208614
  }
208163
208615
 
@@ -208377,7 +208829,7 @@ async function generateGuards(options) {
208377
208829
  anchor: section.anchor,
208378
208830
  fingerprint: section.fingerprint,
208379
208831
  scenarioIds: scenarioIds.slice().sort(),
208380
- generationInputsHash: generationInputsHash(section.fingerprint, recipeFingerprint),
208832
+ generationInputsHash: generationInputsHash(section.fingerprint, recipeFingerprint, section.suppressionFingerprint),
208381
208833
  ...classification ? { classification } : {}
208382
208834
  });
208383
208835
  settledKeys.add(k);
@@ -208862,8 +209314,8 @@ init_context_router();
208862
209314
 
208863
209315
  // packages/core/dist/services/llm/model-prices.js
208864
209316
  init_paths();
208865
- import fs62 from "node:fs";
208866
- import path67 from "node:path";
209317
+ import fs63 from "node:fs";
209318
+ import path68 from "node:path";
208867
209319
  var OPENROUTER_URL = "https://openrouter.ai/api/v1/models";
208868
209320
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
208869
209321
  var FETCH_TIMEOUT_MS = 8e3;
@@ -208879,11 +209331,11 @@ function tierOf(id) {
208879
209331
  return s.includes("opus") ? "opus" : s.includes("sonnet") ? "sonnet" : s.includes("haiku") ? "haiku" : null;
208880
209332
  }
208881
209333
  function cacheFilePath() {
208882
- return path67.join(getGlobalDir(), "cache", CACHE_FILE);
209334
+ return path68.join(getGlobalDir(), "cache", CACHE_FILE);
208883
209335
  }
208884
209336
  function readCache7() {
208885
209337
  try {
208886
- const t2 = JSON.parse(fs62.readFileSync(cacheFilePath(), "utf-8"));
209338
+ const t2 = JSON.parse(fs63.readFileSync(cacheFilePath(), "utf-8"));
208887
209339
  if (t2 && t2.tiers && t2.byId && typeof t2.fetchedAt === "number")
208888
209340
  return t2;
208889
209341
  } catch {
@@ -208892,8 +209344,8 @@ function readCache7() {
208892
209344
  }
208893
209345
  function writeCache7(t2) {
208894
209346
  try {
208895
- fs62.mkdirSync(path67.dirname(cacheFilePath()), { recursive: true });
208896
- fs62.writeFileSync(cacheFilePath(), JSON.stringify(t2));
209347
+ fs63.mkdirSync(path68.dirname(cacheFilePath()), { recursive: true });
209348
+ fs63.writeFileSync(cacheFilePath(), JSON.stringify(t2));
208897
209349
  } catch {
208898
209350
  }
208899
209351
  }
@@ -209272,16 +209724,16 @@ function changedSubject(total, changed, noun) {
209272
209724
 
209273
209725
  // packages/core/dist/commands/spec-in-process.js
209274
209726
  init_dist8();
209275
- import fs67 from "node:fs";
209276
- import path72 from "node:path";
209727
+ import fs68 from "node:fs";
209728
+ import path73 from "node:path";
209277
209729
  init_git();
209278
209730
  import { createHash as createHash20, randomUUID as randomUUID27 } from "node:crypto";
209279
209731
 
209280
209732
  // packages/core/dist/lib/verify-store.js
209281
209733
  init_atomic_write();
209282
209734
  init_analysis_store();
209283
- import fs63 from "node:fs";
209284
- import path68 from "node:path";
209735
+ import fs64 from "node:fs";
209736
+ import path69 from "node:path";
209285
209737
 
209286
209738
  // packages/core/dist/types/verify-snapshot.js
209287
209739
  function driftKey(d3) {
@@ -209329,23 +209781,23 @@ var LATEST_FILE3 = "LATEST.json";
209329
209781
  var HISTORY_FILE3 = "history.json";
209330
209782
  var DIFF_FILE2 = "diff.json";
209331
209783
  function verifierDir(repoPath) {
209332
- return path68.join(repoPath, TRUECOURSE_DIR4, VERIFIER_DIR);
209784
+ return path69.join(repoPath, TRUECOURSE_DIR4, VERIFIER_DIR);
209333
209785
  }
209334
209786
  function runsDir(repoPath) {
209335
- return path68.join(verifierDir(repoPath), RUNS_DIR2);
209787
+ return path69.join(verifierDir(repoPath), RUNS_DIR2);
209336
209788
  }
209337
209789
  function verifyRunPath(repoPath, filename) {
209338
- return path68.join(runsDir(repoPath), filename);
209790
+ return path69.join(runsDir(repoPath), filename);
209339
209791
  }
209340
209792
  function verifyLatestPath(repoPath) {
209341
- return path68.join(verifierDir(repoPath), LATEST_FILE3);
209793
+ return path69.join(verifierDir(repoPath), LATEST_FILE3);
209342
209794
  }
209343
209795
  function verifyHistoryPath(repoPath) {
209344
- return path68.join(verifierDir(repoPath), HISTORY_FILE3);
209796
+ return path69.join(verifierDir(repoPath), HISTORY_FILE3);
209345
209797
  }
209346
209798
  function verifyDiffPath(repoPath, scope) {
209347
209799
  const file = scope ? `diff-${sanitizeScope(scope)}.json` : DIFF_FILE2;
209348
- return path68.join(verifierDir(repoPath), file);
209800
+ return path69.join(verifierDir(repoPath), file);
209349
209801
  }
209350
209802
  function sanitizeScope(scope) {
209351
209803
  return scope.replace(/[^a-zA-Z0-9._-]/g, "_");
@@ -209379,7 +209831,7 @@ var FileVerifyStore = class {
209379
209831
  const file = verifyLatestPath(repoPath);
209380
209832
  let mtime;
209381
209833
  try {
209382
- mtime = fs63.statSync(file).mtimeMs;
209834
+ mtime = fs64.statSync(file).mtimeMs;
209383
209835
  } catch (err) {
209384
209836
  if (err.code === "ENOENT") {
209385
209837
  latestCache2.delete(repoPath);
@@ -209390,7 +209842,7 @@ var FileVerifyStore = class {
209390
209842
  const cached = latestCache2.get(repoPath);
209391
209843
  if (cached && cached.mtime === mtime)
209392
209844
  return cached.data;
209393
- const data = JSON.parse(fs63.readFileSync(file, "utf-8"));
209845
+ const data = JSON.parse(fs64.readFileSync(file, "utf-8"));
209394
209846
  latestCache2.set(repoPath, { mtime, data });
209395
209847
  return data;
209396
209848
  }
@@ -209400,7 +209852,7 @@ var FileVerifyStore = class {
209400
209852
  }
209401
209853
  async deleteVerifyLatest(repoPath) {
209402
209854
  try {
209403
- fs63.unlinkSync(verifyLatestPath(repoPath));
209855
+ fs64.unlinkSync(verifyLatestPath(repoPath));
209404
209856
  } catch (err) {
209405
209857
  if (err.code !== "ENOENT")
209406
209858
  throw err;
@@ -209414,21 +209866,21 @@ var FileVerifyStore = class {
209414
209866
  }
209415
209867
  async readVerifyRun(repoPath, filename) {
209416
209868
  const file = verifyRunPath(repoPath, filename);
209417
- if (!fs63.existsSync(file))
209869
+ if (!fs64.existsSync(file))
209418
209870
  return null;
209419
- return JSON.parse(fs63.readFileSync(file, "utf-8"));
209871
+ return JSON.parse(fs64.readFileSync(file, "utf-8"));
209420
209872
  }
209421
209873
  async listVerifyRuns(repoPath) {
209422
209874
  const dir = runsDir(repoPath);
209423
- if (!fs63.existsSync(dir))
209875
+ if (!fs64.existsSync(dir))
209424
209876
  return [];
209425
- return fs63.readdirSync(dir).filter((n) => n.endsWith(".json")).sort();
209877
+ return fs64.readdirSync(dir).filter((n) => n.endsWith(".json")).sort();
209426
209878
  }
209427
209879
  async readVerifyHistory(repoPath) {
209428
209880
  const file = verifyHistoryPath(repoPath);
209429
- if (!fs63.existsSync(file))
209881
+ if (!fs64.existsSync(file))
209430
209882
  return { runs: [] };
209431
- return JSON.parse(fs63.readFileSync(file, "utf-8"));
209883
+ return JSON.parse(fs64.readFileSync(file, "utf-8"));
209432
209884
  }
209433
209885
  async appendVerifyHistory(repoPath, entry) {
209434
209886
  const history = await this.readVerifyHistory(repoPath);
@@ -209441,7 +209893,7 @@ var FileVerifyStore = class {
209441
209893
  if (!entry)
209442
209894
  return false;
209443
209895
  try {
209444
- fs63.unlinkSync(verifyRunPath(repoPath, entry.filename));
209896
+ fs64.unlinkSync(verifyRunPath(repoPath, entry.filename));
209445
209897
  } catch (err) {
209446
209898
  if (err.code !== "ENOENT")
209447
209899
  throw err;
@@ -209463,16 +209915,16 @@ var FileVerifyStore = class {
209463
209915
  }
209464
209916
  async readVerifyDiff(repoPath, scope) {
209465
209917
  const file = verifyDiffPath(repoPath, scope);
209466
- if (!fs63.existsSync(file))
209918
+ if (!fs64.existsSync(file))
209467
209919
  return null;
209468
- return JSON.parse(fs63.readFileSync(file, "utf-8"));
209920
+ return JSON.parse(fs64.readFileSync(file, "utf-8"));
209469
209921
  }
209470
209922
  async writeVerifyDiff(repoPath, diff, scope) {
209471
209923
  atomicWriteJson(verifyDiffPath(repoPath, scope), diff);
209472
209924
  }
209473
209925
  async deleteVerifyDiff(repoPath, scope) {
209474
209926
  try {
209475
- fs63.unlinkSync(verifyDiffPath(repoPath, scope));
209927
+ fs64.unlinkSync(verifyDiffPath(repoPath, scope));
209476
209928
  } catch (err) {
209477
209929
  if (err.code !== "ENOENT")
209478
209930
  throw err;
@@ -209506,8 +209958,8 @@ async function repoRef(repoRoot5, commitOverride) {
209506
209958
  }
209507
209959
 
209508
209960
  // packages/core/dist/lib/contract-store.js
209509
- import fs64 from "node:fs";
209510
- import path69 from "node:path";
209961
+ import fs65 from "node:fs";
209962
+ import path70 from "node:path";
209511
209963
  var KIND_REL = {
209512
209964
  contracts: [".truecourse", "contracts"],
209513
209965
  // The inferred tree lives at contracts/_inferred (matches `writeInferred`).
@@ -209517,13 +209969,13 @@ function countTcFiles(dir) {
209517
209969
  let n = 0;
209518
209970
  let entries;
209519
209971
  try {
209520
- entries = fs64.readdirSync(dir, { withFileTypes: true });
209972
+ entries = fs65.readdirSync(dir, { withFileTypes: true });
209521
209973
  } catch {
209522
209974
  return 0;
209523
209975
  }
209524
209976
  for (const e of entries) {
209525
209977
  if (e.isDirectory())
209526
- n += countTcFiles(path69.join(dir, e.name));
209978
+ n += countTcFiles(path70.join(dir, e.name));
209527
209979
  else if (e.isFile() && e.name.endsWith(".tc"))
209528
209980
  n += 1;
209529
209981
  }
@@ -209534,7 +209986,7 @@ function walkTcRel(dir, excludeInferred) {
209534
209986
  const walk20 = (rel) => {
209535
209987
  let entries;
209536
209988
  try {
209537
- entries = fs64.readdirSync(path69.join(dir, rel), { withFileTypes: true });
209989
+ entries = fs65.readdirSync(path70.join(dir, rel), { withFileTypes: true });
209538
209990
  } catch {
209539
209991
  return;
209540
209992
  }
@@ -209558,50 +210010,50 @@ function safeResolve(root2, rel) {
209558
210010
  return null;
209559
210011
  if (norm.split("/").some((s) => s === ".." || s === "." || s === ""))
209560
210012
  return null;
209561
- const base2 = path69.resolve(root2);
209562
- const dest = path69.resolve(base2, norm);
209563
- if (dest !== base2 && !dest.startsWith(base2 + path69.sep))
210013
+ const base2 = path70.resolve(root2);
210014
+ const dest = path70.resolve(base2, norm);
210015
+ if (dest !== base2 && !dest.startsWith(base2 + path70.sep))
209564
210016
  return null;
209565
210017
  return dest;
209566
210018
  }
209567
210019
  var FileContractStore = class {
209568
210020
  materializesInPlace = true;
209569
210021
  async saveContracts(ref, kind, _sourceDir) {
209570
- const dir = path69.join(ref.repoKey, ...KIND_REL[kind]);
210022
+ const dir = path70.join(ref.repoKey, ...KIND_REL[kind]);
209571
210023
  return { manifest: {}, fileCount: countTcFiles(dir), objectsWritten: 0, manifestHash: "" };
209572
210024
  }
209573
210025
  async loadContracts(ref, kind) {
209574
- const dir = path69.join(ref.repoKey, ...KIND_REL[kind]);
209575
- if (!fs64.existsSync(dir))
210026
+ const dir = path70.join(ref.repoKey, ...KIND_REL[kind]);
210027
+ if (!fs65.existsSync(dir))
209576
210028
  return null;
209577
210029
  return { dir, cleanup: async () => {
209578
210030
  } };
209579
210031
  }
209580
210032
  async hasContracts(ref, kind) {
209581
- return fs64.existsSync(path69.join(ref.repoKey, ...KIND_REL[kind]));
210033
+ return fs65.existsSync(path70.join(ref.repoKey, ...KIND_REL[kind]));
209582
210034
  }
209583
210035
  // The file impl reads the live repo tree, which is whatever is checked out —
209584
210036
  // there is no per-commit history, so `commitSha` is ignored (OSS is latest).
209585
210037
  async listContractFiles(repoKey, kind, _commitSha) {
209586
- return walkTcRel(path69.join(repoKey, ...KIND_REL[kind]), kind === "contracts");
210038
+ return walkTcRel(path70.join(repoKey, ...KIND_REL[kind]), kind === "contracts");
209587
210039
  }
209588
210040
  async readContractFile(repoKey, kind, relPath, _commitSha) {
209589
- const dest = safeResolve(path69.join(repoKey, ...KIND_REL[kind]), relPath);
209590
- if (!dest || !fs64.existsSync(dest) || !fs64.statSync(dest).isFile())
210041
+ const dest = safeResolve(path70.join(repoKey, ...KIND_REL[kind]), relPath);
210042
+ if (!dest || !fs65.existsSync(dest) || !fs65.statSync(dest).isFile())
209591
210043
  return null;
209592
- return fs64.readFileSync(dest, "utf-8");
210044
+ return fs65.readFileSync(dest, "utf-8");
209593
210045
  }
209594
210046
  async putContractFile(ref, kind, relPath, content) {
209595
- const dest = safeResolve(path69.join(ref.repoKey, ...KIND_REL[kind]), relPath);
210047
+ const dest = safeResolve(path70.join(ref.repoKey, ...KIND_REL[kind]), relPath);
209596
210048
  if (!dest)
209597
210049
  throw new Error(`[contract-store] unsafe contract path: ${relPath}`);
209598
- fs64.mkdirSync(path69.dirname(dest), { recursive: true });
209599
- fs64.writeFileSync(dest, content);
210050
+ fs65.mkdirSync(path70.dirname(dest), { recursive: true });
210051
+ fs65.writeFileSync(dest, content);
209600
210052
  }
209601
210053
  async deleteContractFile(ref, kind, relPath) {
209602
- const dest = safeResolve(path69.join(ref.repoKey, ...KIND_REL[kind]), relPath);
210054
+ const dest = safeResolve(path70.join(ref.repoKey, ...KIND_REL[kind]), relPath);
209603
210055
  if (dest)
209604
- fs64.rmSync(dest, { force: true });
210056
+ fs65.rmSync(dest, { force: true });
209605
210057
  }
209606
210058
  // OSS/local has no workspace concept (mirrors the spec store). Writing throws
209607
210059
  // (fail loud — a caller that reached here is mis-wired); reads are empty so an
@@ -209628,10 +210080,10 @@ var loadWorkspaceContracts = (ref, kind) => active8.loadWorkspaceContracts(ref,
209628
210080
  var contractsMaterializeInPlace = () => active8.materializesInPlace;
209629
210081
 
209630
210082
  // packages/core/dist/lib/spec-store.js
209631
- import fs65 from "node:fs";
209632
- import path70 from "node:path";
210083
+ import fs66 from "node:fs";
210084
+ import path71 from "node:path";
209633
210085
  function specPath(repoKey, artifact) {
209634
- return path70.join(repoKey, ".truecourse", "specs", `${artifact}.json`);
210086
+ return path71.join(repoKey, ".truecourse", "specs", `${artifact}.json`);
209635
210087
  }
209636
210088
  function isPrDecisionsRef(commitSha) {
209637
210089
  return /^_pr\/\d+$/.test(commitSha ?? "");
@@ -209644,18 +210096,18 @@ var FileSpecStore = class {
209644
210096
  throw new Error(PR_DECISIONS_FILE_ERROR);
209645
210097
  }
209646
210098
  const file = specPath(ref.repoKey, artifact);
209647
- fs65.mkdirSync(path70.dirname(file), { recursive: true });
209648
- fs65.writeFileSync(file, JSON.stringify(json2, null, 2) + "\n", "utf-8");
210099
+ fs66.mkdirSync(path71.dirname(file), { recursive: true });
210100
+ fs66.writeFileSync(file, JSON.stringify(json2, null, 2) + "\n", "utf-8");
209649
210101
  }
209650
210102
  async loadSpec(ref, artifact) {
209651
210103
  if (artifact === "decisions" && isPrDecisionsRef(ref.commitSha)) {
209652
210104
  throw new Error(PR_DECISIONS_FILE_ERROR);
209653
210105
  }
209654
210106
  const file = specPath(ref.repoKey, artifact);
209655
- if (!fs65.existsSync(file))
210107
+ if (!fs66.existsSync(file))
209656
210108
  return null;
209657
210109
  try {
209658
- return JSON.parse(fs65.readFileSync(file, "utf-8"));
210110
+ return JSON.parse(fs66.readFileSync(file, "utf-8"));
209659
210111
  } catch {
209660
210112
  return null;
209661
210113
  }
@@ -209665,8 +210117,8 @@ var FileSpecStore = class {
209665
210117
  throw new Error(PR_DECISIONS_FILE_ERROR);
209666
210118
  }
209667
210119
  const file = specPath(ref.repoKey, artifact);
209668
- if (fs65.existsSync(file))
209669
- fs65.rmSync(file);
210120
+ if (fs66.existsSync(file))
210121
+ fs66.rmSync(file);
209670
210122
  }
209671
210123
  // The file impl is single-document-per-repo, so "latest" === read the file.
209672
210124
  async loadLatest(repoKey, artifact) {
@@ -209693,23 +210145,23 @@ var loadLatestSpec = (repoKey, artifact) => active9.loadLatest(repoKey, artifact
209693
210145
  var specsMaterializeInPlace = () => active9.materializesInPlace;
209694
210146
 
209695
210147
  // packages/core/dist/lib/inferred-action-store.js
209696
- import fs66 from "node:fs";
209697
- import path71 from "node:path";
210148
+ import fs67 from "node:fs";
210149
+ import path72 from "node:path";
209698
210150
  function actionsFile(repoKey) {
209699
- return path71.join(repoKey, ".truecourse", "specs", "inferred-actions.json");
210151
+ return path72.join(repoKey, ".truecourse", "specs", "inferred-actions.json");
209700
210152
  }
209701
210153
  var FileInferredActionStore = class {
209702
210154
  read(repoKey) {
209703
210155
  try {
209704
- return JSON.parse(fs66.readFileSync(actionsFile(repoKey), "utf-8"));
210156
+ return JSON.parse(fs67.readFileSync(actionsFile(repoKey), "utf-8"));
209705
210157
  } catch {
209706
210158
  return [];
209707
210159
  }
209708
210160
  }
209709
210161
  write(repoKey, actions) {
209710
210162
  const file = actionsFile(repoKey);
209711
- fs66.mkdirSync(path71.dirname(file), { recursive: true });
209712
- fs66.writeFileSync(file, JSON.stringify(actions, null, 2) + "\n", "utf-8");
210163
+ fs67.mkdirSync(path72.dirname(file), { recursive: true });
210164
+ fs67.writeFileSync(file, JSON.stringify(actions, null, 2) + "\n", "utf-8");
209713
210165
  }
209714
210166
  async setAction(repoKey, action) {
209715
210167
  const next = this.read(repoKey).filter((a) => !(a.kind === action.kind && a.identity === action.identity));
@@ -209838,13 +210290,13 @@ function resolveTransport(options) {
209838
210290
  }
209839
210291
  return getDefaultTransport();
209840
210292
  }
209841
- var GENERATED_MARKER_REL = path72.join(".truecourse", "contracts", "result.json");
210293
+ var GENERATED_MARKER_REL = path73.join(".truecourse", "contracts", "result.json");
209842
210294
  function generatedMarkerPath(repoRoot5) {
209843
- return path72.join(repoRoot5, GENERATED_MARKER_REL);
210295
+ return path73.join(repoRoot5, GENERATED_MARKER_REL);
209844
210296
  }
209845
210297
  function stampGeneratedMarker(repoRoot5, summary) {
209846
210298
  const file = generatedMarkerPath(repoRoot5);
209847
- fs67.mkdirSync(path72.dirname(file), { recursive: true });
210299
+ fs68.mkdirSync(path73.dirname(file), { recursive: true });
209848
210300
  const body = {
209849
210301
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
209850
210302
  written: summary?.written ?? 0,
@@ -209852,7 +210304,7 @@ function stampGeneratedMarker(repoRoot5, summary) {
209852
210304
  validationIssues: summary?.validationIssues ?? [],
209853
210305
  enumerateFailures: summary?.enumerateFailures ?? []
209854
210306
  };
209855
- fs67.writeFileSync(file, JSON.stringify(body, null, 2) + "\n");
210307
+ fs68.writeFileSync(file, JSON.stringify(body, null, 2) + "\n");
209856
210308
  }
209857
210309
  function resolveCurateModels(repoRoot5) {
209858
210310
  return {
@@ -209976,22 +210428,22 @@ async function curateInProcess(repoRoot5, options = {}) {
209976
210428
  }
209977
210429
  }
209978
210430
  function buildPriorContracts(repoRoot5) {
209979
- const dir = path72.join(repoRoot5, ".truecourse", "contracts");
209980
- if (!fs67.existsSync(dir))
210431
+ const dir = path73.join(repoRoot5, ".truecourse", "contracts");
210432
+ if (!fs68.existsSync(dir))
209981
210433
  return void 0;
209982
210434
  const targets = [];
209983
210435
  const bodyByKey = /* @__PURE__ */ new Map();
209984
210436
  const walk20 = (d3) => {
209985
- for (const e of fs67.readdirSync(d3, { withFileTypes: true })) {
210437
+ for (const e of fs68.readdirSync(d3, { withFileTypes: true })) {
209986
210438
  if (e.isDirectory()) {
209987
210439
  if (e.name === "_inferred")
209988
210440
  continue;
209989
- walk20(path72.join(d3, e.name));
210441
+ walk20(path73.join(d3, e.name));
209990
210442
  } else if (e.name.endsWith(".tc")) {
209991
- const abs = path72.join(d3, e.name);
209992
- const src = fs67.readFileSync(abs, "utf-8");
210443
+ const abs = path73.join(d3, e.name);
210444
+ const src = fs68.readFileSync(abs, "utf-8");
209993
210445
  try {
209994
- const file = parser_ohm_exports.parseTcFile(path72.relative(dir, abs), src);
210446
+ const file = parser_ohm_exports.parseTcFile(path73.relative(dir, abs), src);
209995
210447
  for (const key4 of resolver_exports.resolve([file]).index.keys()) {
209996
210448
  const colon = key4.indexOf(":");
209997
210449
  if (colon < 0)
@@ -210151,18 +210603,18 @@ function resolverHardError(result) {
210151
210603
  const detail = reasons.length ? reasons.slice(0, 3).join("; ") : "duplicate or conflicting artifact identities";
210152
210604
  return new Error(`Contract corpus failed to resolve \u2014 ${detail}`);
210153
210605
  }
210154
- var LEGACY_VERIFY_STATE_REL = path72.join(".truecourse", ".cache", "verifier", "verify-state.json");
210606
+ var LEGACY_VERIFY_STATE_REL = path73.join(".truecourse", ".cache", "verifier", "verify-state.json");
210155
210607
  function legacyVerifyStatePath(repoRoot5) {
210156
- return path72.join(repoRoot5, LEGACY_VERIFY_STATE_REL);
210608
+ return path73.join(repoRoot5, LEGACY_VERIFY_STATE_REL);
210157
210609
  }
210158
210610
  async function withContracts(repoRoot5, options, tracker, fn) {
210159
- const fallbackPath = path72.join(repoRoot5, ".truecourse", "contracts");
210611
+ const fallbackPath = path73.join(repoRoot5, ".truecourse", "contracts");
210160
210612
  const wsMat = options.workspaceOrgId ? await loadWorkspaceContracts({ workspaceOrgId: options.workspaceOrgId }, "contracts") : null;
210161
210613
  let repoMat = null;
210162
210614
  try {
210163
210615
  let recorded;
210164
210616
  if (options.contractsDir) {
210165
- if (!fs67.existsSync(options.contractsDir)) {
210617
+ if (!fs68.existsSync(options.contractsDir)) {
210166
210618
  const err = new Error(`Contracts directory not found at ${options.contractsDir}. Run \`truecourse contracts generate\` first.`);
210167
210619
  tracker?.error("load", err.message);
210168
210620
  throw err;
@@ -210207,7 +210659,7 @@ async function verifyInProcess(repoRoot5, options = {}) {
210207
210659
  tracker?.start("compare");
210208
210660
  tracker?.done("compare", `${result.drifts.length} drift${result.drifts.length === 1 ? "" : "s"}`);
210209
210661
  if (options.ref) {
210210
- result.drifts = result.drifts.map((d3) => d3.filePath && path72.isAbsolute(d3.filePath) ? { ...d3, filePath: path72.relative(repoRoot5, d3.filePath).split(path72.sep).join("/") } : d3);
210662
+ result.drifts = result.drifts.map((d3) => d3.filePath && path73.isAbsolute(d3.filePath) ? { ...d3, filePath: path73.relative(repoRoot5, d3.filePath).split(path73.sep).join("/") } : d3);
210211
210663
  }
210212
210664
  const verifiedAt = (/* @__PURE__ */ new Date()).toISOString();
210213
210665
  const { branch, commitHash } = await gitMeta(repoRoot5);
@@ -210251,7 +210703,7 @@ async function verifyInProcess(repoRoot5, options = {}) {
210251
210703
  bySeverity: summary.bySeverity
210252
210704
  });
210253
210705
  await deleteVerifyDiff(storeKey);
210254
- fs67.rmSync(legacyVerifyStatePath(repoRoot5), { force: true });
210706
+ fs68.rmSync(legacyVerifyStatePath(repoRoot5), { force: true });
210255
210707
  }
210256
210708
  const state = {
210257
210709
  verifiedAt,
@@ -210299,7 +210751,7 @@ async function runWithStash(repoRoot5, skipStash, tracker, fn) {
210299
210751
  const status = await stashGit.status();
210300
210752
  if (!status.isClean()) {
210301
210753
  const gitRoot = (await stashGit.revparse(["--show-toplevel"])).trim();
210302
- if (path72.resolve(repoRoot5) === path72.resolve(gitRoot)) {
210754
+ if (path73.resolve(repoRoot5) === path73.resolve(gitRoot)) {
210303
210755
  tracker?.detail?.("load", "Stashing pending changes...");
210304
210756
  const res = await stashGit.stash(["push", "--include-untracked", "-m", "truecourse-verify-stash"]);
210305
210757
  didStash = !res.includes("No local changes");
@@ -210401,7 +210853,7 @@ async function verifyDiffInProcess(repoRoot5, options = {}) {
210401
210853
  async function inferInProcess(repoRoot5, options = {}) {
210402
210854
  const startedAt = Date.now();
210403
210855
  const codeDir = options.codeDir ?? autodetectCodeDir(repoRoot5);
210404
- let contractsDir = options.contractsDir ?? path72.join(repoRoot5, ".truecourse", "contracts");
210856
+ let contractsDir = options.contractsDir ?? path73.join(repoRoot5, ".truecourse", "contracts");
210405
210857
  let releaseContracts = async () => {
210406
210858
  };
210407
210859
  if (!options.contractsDir && options.ref) {
@@ -210445,7 +210897,7 @@ async function persistInferred(repoRoot5, options, contractsDir, codeDir, starte
210445
210897
  });
210446
210898
  }
210447
210899
  if (!options.dryRun && options.ref) {
210448
- await saveContracts(options.ref, "contracts_inferred", path72.join(contractsDir, "_inferred"));
210900
+ await saveContracts(options.ref, "contracts_inferred", path73.join(contractsDir, "_inferred"));
210449
210901
  }
210450
210902
  const rendered = result.decisions.map((d3) => renderDecision(d3));
210451
210903
  const decisionPaths = rendered.map((r) => r.relPath);
@@ -210468,8 +210920,8 @@ async function persistInferred(repoRoot5, options, contractsDir, codeDir, starte
210468
210920
  return { infer: result, written, proposed, decisionPaths, summaries };
210469
210921
  }
210470
210922
  function autodetectCodeDir(repoRoot5) {
210471
- const codeSubdir = path72.join(repoRoot5, "code");
210472
- if (fs67.existsSync(codeSubdir) && fs67.statSync(codeSubdir).isDirectory()) {
210923
+ const codeSubdir = path73.join(repoRoot5, "code");
210924
+ if (fs68.existsSync(codeSubdir) && fs68.statSync(codeSubdir).isDirectory()) {
210473
210925
  return codeSubdir;
210474
210926
  }
210475
210927
  return repoRoot5;
@@ -210479,7 +210931,8 @@ var EMPTY_DECISIONS3 = {
210479
210931
  manualIncludes: [],
210480
210932
  manualExcludes: [],
210481
210933
  relations: [],
210482
- manualAreas: []
210934
+ manualAreas: [],
210935
+ conflictResolutions: []
210483
210936
  };
210484
210937
  var DECISIONS_REF = "_repo";
210485
210938
  var prDecisionsRef = (pr) => `_pr/${pr}`;
@@ -210533,7 +210986,12 @@ function mergeDecisions(base2, overlay) {
210533
210986
  ...(base2.manualAreas ?? []).filter((a) => !overlayAreaDocs.has(a.doc)),
210534
210987
  ...overlay.manualAreas ?? []
210535
210988
  ];
210536
- return { version: 1, manualIncludes, manualExcludes, relations, manualAreas };
210989
+ const overlayResKeys = new Set((overlay.conflictResolutions ?? []).map(conflictResolutionKey));
210990
+ const conflictResolutions = [
210991
+ ...(base2.conflictResolutions ?? []).filter((r) => !overlayResKeys.has(conflictResolutionKey(r))),
210992
+ ...overlay.conflictResolutions ?? []
210993
+ ];
210994
+ return { version: 1, manualIncludes, manualExcludes, relations, manualAreas, conflictResolutions };
210537
210995
  }
210538
210996
  function uniqueStrings(items) {
210539
210997
  return [...new Set(items)];
@@ -210542,6 +211000,13 @@ function getCorpus(repoKey) {
210542
211000
  return loadLatestSpec(repoKey, "corpus");
210543
211001
  }
210544
211002
  var relationKey = (r) => `${[r.older, r.newer].sort().join(" ")} ${r.scope ?? ""}`;
211003
+ var conflictResolutionKey = (r) => {
211004
+ const sides = [
211005
+ `${r.docA}#${r.anchorA ?? ""}`,
211006
+ `${r.docB}#${r.anchorB ?? ""}`
211007
+ ].sort();
211008
+ return sides.join(" \0 ");
211009
+ };
210545
211010
  function applyAddRelation(existing, input) {
210546
211011
  if (input.older === input.newer) {
210547
211012
  throw new Error("addRelation: older and newer must be different docs");
@@ -210554,20 +211019,22 @@ function applyAddRelation(existing, input) {
210554
211019
  manualIncludes: existing.manualIncludes ?? [],
210555
211020
  manualExcludes: existing.manualExcludes ?? [],
210556
211021
  relations: [...dedup, relation],
210557
- manualAreas: existing.manualAreas ?? []
211022
+ manualAreas: existing.manualAreas ?? [],
211023
+ conflictResolutions: existing.conflictResolutions ?? []
210558
211024
  };
210559
211025
  }
210560
211026
  function applyRemoveRelation(existing, input) {
210561
211027
  const matches = (r) => {
210562
- const samePair = r.older === input.older && r.newer === input.newer || r.older === input.newer && r.newer === input.older;
210563
- return samePair && (input.scope === void 0 || r.scope === input.scope);
211028
+ const samePair2 = r.older === input.older && r.newer === input.newer || r.older === input.newer && r.newer === input.older;
211029
+ return samePair2 && (input.scope === void 0 || r.scope === input.scope);
210564
211030
  };
210565
211031
  return {
210566
211032
  version: 1,
210567
211033
  manualIncludes: existing.manualIncludes ?? [],
210568
211034
  manualExcludes: existing.manualExcludes ?? [],
210569
211035
  relations: (existing.relations ?? []).filter((r) => !matches(r)),
210570
- manualAreas: existing.manualAreas ?? []
211036
+ manualAreas: existing.manualAreas ?? [],
211037
+ conflictResolutions: existing.conflictResolutions ?? []
210571
211038
  };
210572
211039
  }
210573
211040
  function applyAddManualInclude(existing, docPath) {
@@ -210580,7 +211047,8 @@ function applyAddManualInclude(existing, docPath) {
210580
211047
  manualIncludes: includes.includes(docPath) ? includes : [...includes, docPath],
210581
211048
  manualExcludes: excludes.filter((p2) => p2 !== docPath),
210582
211049
  relations: existing.relations ?? [],
210583
- manualAreas: existing.manualAreas ?? []
211050
+ manualAreas: existing.manualAreas ?? [],
211051
+ conflictResolutions: existing.conflictResolutions ?? []
210584
211052
  };
210585
211053
  }
210586
211054
  function applyRemoveManualInclude(existing, docPath) {
@@ -210589,7 +211057,8 @@ function applyRemoveManualInclude(existing, docPath) {
210589
211057
  manualIncludes: (existing.manualIncludes ?? []).filter((p2) => p2 !== docPath),
210590
211058
  manualExcludes: existing.manualExcludes ?? [],
210591
211059
  relations: existing.relations ?? [],
210592
- manualAreas: existing.manualAreas ?? []
211060
+ manualAreas: existing.manualAreas ?? [],
211061
+ conflictResolutions: existing.conflictResolutions ?? []
210593
211062
  };
210594
211063
  }
210595
211064
  function applyAddManualExclude(existing, docPath) {
@@ -210602,7 +211071,8 @@ function applyAddManualExclude(existing, docPath) {
210602
211071
  manualIncludes: includes.filter((p2) => p2 !== docPath),
210603
211072
  manualExcludes: excludes.includes(docPath) ? excludes : [...excludes, docPath],
210604
211073
  relations: existing.relations ?? [],
210605
- manualAreas: existing.manualAreas ?? []
211074
+ manualAreas: existing.manualAreas ?? [],
211075
+ conflictResolutions: existing.conflictResolutions ?? []
210606
211076
  };
210607
211077
  }
210608
211078
  function applyRemoveManualExclude(existing, docPath) {
@@ -210611,7 +211081,23 @@ function applyRemoveManualExclude(existing, docPath) {
210611
211081
  manualIncludes: existing.manualIncludes ?? [],
210612
211082
  manualExcludes: (existing.manualExcludes ?? []).filter((p2) => p2 !== docPath),
210613
211083
  relations: existing.relations ?? [],
210614
- manualAreas: existing.manualAreas ?? []
211084
+ manualAreas: existing.manualAreas ?? [],
211085
+ conflictResolutions: existing.conflictResolutions ?? []
211086
+ };
211087
+ }
211088
+ function applyAddConflictResolution(existing, input) {
211089
+ if (input.docA === input.docB) {
211090
+ throw new Error("addConflictResolution: docA and docB must be different docs");
211091
+ }
211092
+ const key4 = conflictResolutionKey(input);
211093
+ const dedup = (existing.conflictResolutions ?? []).filter((r) => conflictResolutionKey(r) !== key4);
211094
+ return {
211095
+ version: 1,
211096
+ manualIncludes: existing.manualIncludes ?? [],
211097
+ manualExcludes: existing.manualExcludes ?? [],
211098
+ relations: existing.relations ?? [],
211099
+ manualAreas: existing.manualAreas ?? [],
211100
+ conflictResolutions: [...dedup, input]
210615
211101
  };
210616
211102
  }
210617
211103
  async function addRelation(repoRoot5, input, opts) {
@@ -210648,6 +211134,11 @@ async function removeManualExclude(repoRoot5, docPath, opts) {
210648
211134
  await storeDecisions(repoRoot5, next, opts);
210649
211135
  return next;
210650
211136
  }
211137
+ async function addConflictResolution(repoRoot5, input, opts) {
211138
+ const next = applyAddConflictResolution(await loadDecisions(repoRoot5, opts), input);
211139
+ await storeDecisions(repoRoot5, next, opts);
211140
+ return next;
211141
+ }
210651
211142
 
210652
211143
  // tools/cli/src/commands/contracts.ts
210653
211144
  init_progress();
@@ -210824,8 +211315,8 @@ async function runContractsGenerate(options = {}) {
210824
211315
  }
210825
211316
  async function runContractsList(options = {}) {
210826
211317
  const repoRoot5 = options.cwd ?? process.cwd();
210827
- const contractsDir = path73.join(repoRoot5, ".truecourse", "contracts");
210828
- if (!fs68.existsSync(contractsDir)) {
211318
+ const contractsDir = path74.join(repoRoot5, ".truecourse", "contracts");
211319
+ if (!fs69.existsSync(contractsDir)) {
210829
211320
  O2.info("No contracts found. Run `truecourse contracts generate` first.");
210830
211321
  return;
210831
211322
  }
@@ -210833,12 +211324,12 @@ async function runContractsList(options = {}) {
210833
211324
  const fileNodes = [];
210834
211325
  let parseErrors = 0;
210835
211326
  const visit = (dir) => {
210836
- for (const entry of fs68.readdirSync(dir, { withFileTypes: true })) {
210837
- const full = path73.join(dir, entry.name);
211327
+ for (const entry of fs69.readdirSync(dir, { withFileTypes: true })) {
211328
+ const full = path74.join(dir, entry.name);
210838
211329
  if (entry.isDirectory()) visit(full);
210839
211330
  else if (entry.isFile() && entry.name.endsWith(".tc")) {
210840
211331
  try {
210841
- fileNodes.push(parserOhm.parseTcFile(full, fs68.readFileSync(full, "utf-8")));
211332
+ fileNodes.push(parserOhm.parseTcFile(full, fs69.readFileSync(full, "utf-8")));
210842
211333
  } catch {
210843
211334
  parseErrors += 1;
210844
211335
  }
@@ -210865,7 +211356,7 @@ async function runContractsList(options = {}) {
210865
211356
  mt(`Contracts \u2014 ${artifacts.length} ${scope}artifact${artifacts.length === 1 ? "" : "s"}`);
210866
211357
  for (const a of artifacts) {
210867
211358
  const conf = a.confidence ? `[${a.confidence}] ` : "";
210868
- const loc = a.origin ? a.origin.lines[0] >= 0 ? `${a.origin.source}:${a.origin.lines[0]}` : a.origin.source : `${path73.relative(repoRoot5, a.declarationLoc.filePath)}:${a.declarationLoc.lineStart}`;
211359
+ const loc = a.origin ? a.origin.lines[0] >= 0 ? `${a.origin.source}:${a.origin.lines[0]}` : a.origin.source : `${path74.relative(repoRoot5, a.declarationLoc.filePath)}:${a.declarationLoc.lineStart}`;
210869
211360
  console.log(` ${conf}${a.ref.type}:${a.ref.identity} ${loc}`);
210870
211361
  }
210871
211362
  if (parseErrors > 0) {
@@ -210877,8 +211368,8 @@ async function runContractsList(options = {}) {
210877
211368
  }
210878
211369
  async function runContractsValidate(options = {}) {
210879
211370
  const repoRoot5 = options.cwd ?? process.cwd();
210880
- const contractsDir = path73.join(repoRoot5, ".truecourse", "contracts");
210881
- if (!fs68.existsSync(contractsDir)) {
211371
+ const contractsDir = path74.join(repoRoot5, ".truecourse", "contracts");
211372
+ if (!fs69.existsSync(contractsDir)) {
210882
211373
  O2.error("No .truecourse/contracts/ directory found.");
210883
211374
  process.exit(1);
210884
211375
  }
@@ -210886,14 +211377,14 @@ async function runContractsValidate(options = {}) {
210886
211377
  const fileNodes = [];
210887
211378
  const issues = [];
210888
211379
  const visit = (dir) => {
210889
- for (const entry of fs68.readdirSync(dir, { withFileTypes: true })) {
210890
- const full = path73.join(dir, entry.name);
211380
+ for (const entry of fs69.readdirSync(dir, { withFileTypes: true })) {
211381
+ const full = path74.join(dir, entry.name);
210891
211382
  if (entry.isDirectory()) visit(full);
210892
211383
  else if (entry.isFile() && entry.name.endsWith(".tc")) {
210893
211384
  try {
210894
- fileNodes.push(parserOhm.parseTcFile(full, fs68.readFileSync(full, "utf-8")));
211385
+ fileNodes.push(parserOhm.parseTcFile(full, fs69.readFileSync(full, "utf-8")));
210895
211386
  } catch (e) {
210896
- issues.push(`${path73.relative(repoRoot5, full)}: parse error: ${e instanceof Error ? e.message : e}`);
211387
+ issues.push(`${path74.relative(repoRoot5, full)}: parse error: ${e instanceof Error ? e.message : e}`);
210897
211388
  }
210898
211389
  }
210899
211390
  }
@@ -210901,11 +211392,11 @@ async function runContractsValidate(options = {}) {
210901
211392
  visit(contractsDir);
210902
211393
  const resolution = resolver.resolve(fileNodes);
210903
211394
  for (const err of resolution.errors) {
210904
- issues.push(`${path73.relative(repoRoot5, err.filePath)}:${err.line} ${err.message}`);
211395
+ issues.push(`${path74.relative(repoRoot5, err.filePath)}:${err.line} ${err.message}`);
210905
211396
  }
210906
211397
  const trulyUnresolved = resolution.unresolvedRefs.filter((u2) => u2.ref.type !== "Unknown");
210907
211398
  for (const u2 of trulyUnresolved) {
210908
- issues.push(`${path73.relative(repoRoot5, u2.usedAt.filePath)}:${u2.usedAt.lineStart} unresolved ${u2.ref.type}:${u2.ref.identity}`);
211399
+ issues.push(`${path74.relative(repoRoot5, u2.usedAt.filePath)}:${u2.usedAt.lineStart} unresolved ${u2.ref.type}:${u2.ref.identity}`);
210909
211400
  }
210910
211401
  if (issues.length === 0) {
210911
211402
  O2.success(`Validated ${resolution.index.size} artifact${resolution.index.size === 1 ? "" : "s"} \u2014 no issues.`);
@@ -210919,7 +211410,7 @@ async function runContractsValidate(options = {}) {
210919
211410
 
210920
211411
  // tools/cli/src/commands/spec.ts
210921
211412
  init_dist4();
210922
- import path74 from "node:path";
211413
+ import path75 from "node:path";
210923
211414
  init_dist5();
210924
211415
  init_progress();
210925
211416
  init_registry();
@@ -210970,17 +211461,18 @@ async function runSpecScan(opts = {}) {
210970
211461
  O2.warn("Manual includes outside spec.include (never discovered \u2014 widen the scope to pick them up):");
210971
211462
  for (const inc of s.outOfScopeManualIncludes) O2.message(` \u2022 ${inc}`);
210972
211463
  }
210973
- if (s.openOverlaps.length > 0) {
211464
+ const open = openConflicts(curate2.corpus, curate2.decisions);
211465
+ if (open.length > 0) {
210974
211466
  O2.message("");
210975
- O2.message("Open overlaps (areas where two docs may disagree \u2014 resolve with a relation):");
210976
- for (const o of s.openOverlaps.slice(0, 10)) {
211467
+ O2.message("Open overlaps (two docs may disagree \u2014 pick a side or dismiss with `spec conflicts resolve`):");
211468
+ for (const o of open.slice(0, 10)) {
210977
211469
  O2.message(` \u2022 ${o.area}: ${o.a} \u2194 ${o.b}`);
210978
211470
  }
210979
- if (s.openOverlaps.length > 10) {
210980
- O2.message(` \u2026 (+${s.openOverlaps.length - 10} more)`);
211471
+ if (open.length > 10) {
211472
+ O2.message(` \u2026 (+${open.length - 10} more)`);
210981
211473
  }
210982
211474
  }
210983
- const openCount = s.openOverlaps.length;
211475
+ const openCount = open.length;
210984
211476
  gt(
210985
211477
  openCount === 0 ? "Corpus written to .truecourse/specs/corpus.json. Run `truecourse guard generate`." : `Corpus written to .truecourse/specs/corpus.json. ${openCount} conflict${openCount === 1 ? "" : "s"} to resolve (\`truecourse spec conflicts list\`), then \`truecourse guard generate\`.`
210986
211478
  );
@@ -211012,6 +211504,14 @@ async function runSpecStatus(opts = {}) {
211012
211504
  const ov = area.overlaps.length ? ` \xB7 ${area.overlaps.length} overlap${area.overlaps.length === 1 ? "" : "s"}` : "";
211013
211505
  O2.message(` ${area.id.padEnd(30)} ${area.docRefs.length} doc${area.docRefs.length === 1 ? "" : "s"}${ov}`);
211014
211506
  }
211507
+ const orphaned = orphanedConflictResolutions(corpus, decisions);
211508
+ if (orphaned.length > 0) {
211509
+ O2.message("");
211510
+ O2.warn(
211511
+ `${orphaned.length} orphaned conflict resolution${orphaned.length === 1 ? "" : "s"} (no longer match a flagged dispute \u2014 review with \`spec conflicts list\`):`
211512
+ );
211513
+ for (const o of orphaned.slice(0, 10)) O2.message(` \u2022 ${o.docA} \u2194 ${o.docB} (${o.verdict})`);
211514
+ }
211015
211515
  gt(
211016
211516
  open === 0 ? "No open overlaps \u2014 run `truecourse guard generate`." : "Open overlaps \u2014 see `truecourse spec conflicts list`."
211017
211517
  );
@@ -211039,7 +211539,7 @@ async function runVerify(opts = {}) {
211039
211539
  O2.message("");
211040
211540
  O2.message("Drifts:");
211041
211541
  for (const d3 of verify2.drifts.slice(0, 20)) {
211042
- const loc = d3.filePath ? ` ${path74.relative(root2, d3.filePath)}:${d3.lineStart ?? "?"}` : "";
211542
+ const loc = d3.filePath ? ` ${path75.relative(root2, d3.filePath)}:${d3.lineStart ?? "?"}` : "";
211043
211543
  O2.message(` [${d3.severity}] ${d3.obligationKey}${loc}`);
211044
211544
  O2.message(` \u2192 ${d3.message}`);
211045
211545
  }
@@ -211073,7 +211573,7 @@ async function runVerifyDiff(opts) {
211073
211573
  O2.message("");
211074
211574
  O2.message(`${label}:`);
211075
211575
  for (const d3 of drifts.slice(0, 20)) {
211076
- const loc = d3.filePath ? ` ${path74.relative(root2, d3.filePath)}:${d3.lineStart ?? "?"}` : "";
211576
+ const loc = d3.filePath ? ` ${path75.relative(root2, d3.filePath)}:${d3.lineStart ?? "?"}` : "";
211077
211577
  O2.message(` [${d3.severity}] ${d3.obligationKey}${loc}`);
211078
211578
  }
211079
211579
  if (drifts.length > 20) O2.message(` \u2026 (+${drifts.length - 20} more)`);
@@ -211128,8 +211628,8 @@ async function runInfer(opts = {}) {
211128
211628
 
211129
211629
  // tools/cli/src/commands/spec-conflicts.ts
211130
211630
  init_dist4();
211131
- import fs69 from "node:fs";
211132
- import path75 from "node:path";
211631
+ import fs70 from "node:fs";
211632
+ import path76 from "node:path";
211133
211633
  init_dist5();
211134
211634
  var root = (opts) => opts.cwd ?? process.cwd();
211135
211635
  var base = (ref) => ref.split("/").pop() ?? ref;
@@ -211141,25 +211641,47 @@ function loadCorpusOrExit(repoRoot5) {
211141
211641
  }
211142
211642
  return corpus;
211143
211643
  }
211644
+ function resolvedLabel(c2) {
211645
+ if (c2.resolution) {
211646
+ if (c2.resolution.verdict === "dismissed") return "dismissed (not a real conflict)";
211647
+ const winner = c2.resolution.verdict === "a" ? c2.resolution.docA : c2.resolution.docB;
211648
+ return `${base(winner)} is right (loser\u2019s claim suppressed at generate)`;
211649
+ }
211650
+ if (c2.excludedRef) return `${base(c2.excludedRef)} excluded`;
211651
+ return "resolved";
211652
+ }
211144
211653
  async function runSpecConflictsList(opts = {}) {
211145
211654
  const repoRoot5 = root(opts);
211146
211655
  const corpus = loadCorpusOrExit(repoRoot5);
211147
- const conflicts2 = buildCorpusConflicts(corpus, readCorpusDecisions(repoRoot5));
211656
+ const decisions = readCorpusDecisions(repoRoot5);
211657
+ const conflicts2 = buildCorpusConflicts(corpus, decisions);
211148
211658
  const open = conflicts2.filter((c2) => !c2.resolved);
211149
- const resolved = conflicts2.length - open.length;
211150
- mt("Overlaps (areas where docs may disagree)");
211151
- for (const c2 of open) {
211152
- O2.warn(`${c2.area}`);
211153
- O2.message(` ${base(c2.a)} \u2194 ${base(c2.b)}${c2.note ? ` \xB7 ${c2.note}` : ""}`);
211154
- O2.message(` resolve: truecourse spec conflicts resolve ${c2.area} --older ${c2.a} --newer ${c2.b} --precedence`);
211659
+ const orphaned = orphanedConflictResolutions(corpus, decisions);
211660
+ mt("Overlaps (where two docs\u2019 sections may disagree)");
211661
+ conflicts2.forEach((c2, i) => {
211662
+ const n = i + 1;
211663
+ if (c2.resolved) {
211664
+ O2.step(`${n}. ${c2.area} \xB7 ${base(c2.a)} \u2194 ${base(c2.b)} \u2014 resolved: ${resolvedLabel(c2)}`);
211665
+ } else {
211666
+ O2.warn(`${n}. ${c2.area} \xB7 ${base(c2.a)} \u2194 ${base(c2.b)}${c2.note ? ` \xB7 ${c2.note}` : ""}`);
211667
+ O2.message(` pick a side: truecourse spec conflicts resolve ${n} --right ${c2.a} (or --right ${c2.b}, or --dismiss)`);
211668
+ }
211669
+ });
211670
+ if (conflicts2.length === 0) O2.step("No overlaps flagged.");
211671
+ if (orphaned.length > 0) {
211672
+ O2.warn(
211673
+ `${orphaned.length} orphaned resolution${orphaned.length === 1 ? "" : "s"} \u2014 recorded but no longer match a flagged conflict (the docs changed):`
211674
+ );
211675
+ for (const o of orphaned) O2.message(` ${base(o.docA)} \u2194 ${base(o.docB)} (${o.verdict})`);
211155
211676
  }
211156
- if (open.length === 0) O2.step("No open overlaps.");
211157
- gt(`${open.length} open \xB7 ${resolved} resolved. Inspect with \`spec conflicts show <area>\`.`);
211677
+ gt(
211678
+ `${open.length} open \xB7 ${conflicts2.length - open.length} resolved${orphaned.length ? ` \xB7 ${orphaned.length} orphaned` : ""}. Inspect with \`spec conflicts show <area>\`.`
211679
+ );
211158
211680
  }
211159
211681
  function excerpt(repoRoot5, ref, note, max = 20) {
211160
211682
  let text4;
211161
211683
  try {
211162
- text4 = fs69.readFileSync(path75.join(repoRoot5, ref), "utf-8");
211684
+ text4 = fs70.readFileSync(path76.join(repoRoot5, ref), "utf-8");
211163
211685
  } catch {
211164
211686
  return ` (could not read ${ref})`;
211165
211687
  }
@@ -211183,47 +211705,76 @@ async function runSpecConflictsShow(area, opts = {}) {
211183
211705
  for (const ov of a.overlaps) {
211184
211706
  const [da, db] = ov.docs;
211185
211707
  const c2 = conflicts2.find(
211186
- (x) => x.area === area && (x.a === da && x.b === db || x.a === db && x.b === da)
211708
+ (x) => (x.areas.includes(area) || x.area === area) && (x.a === da && x.b === db || x.a === db && x.b === da)
211187
211709
  );
211188
211710
  O2.warn(`${base(da)} \u2194 ${base(db)}${ov.note ? ` \xB7 ${ov.note}` : ""}`);
211189
- if (c2?.relation) O2.message(` resolved \u2192 ${c2.relation.type} (${c2.relation.older} \u21D2 ${c2.relation.newer})`);
211190
- else if (c2?.excludedRef) O2.message(` resolved \u2192 ${c2.excludedRef} excluded`);
211191
- else O2.message(" open");
211711
+ O2.message(c2 && c2.resolved ? ` resolved \u2192 ${resolvedLabel(c2)}` : " open");
211192
211712
  O2.message(` ${da}:`);
211193
211713
  O2.message(excerpt(repoRoot5, da, ov.note));
211194
211714
  O2.message(` ${db}:`);
211195
211715
  O2.message(excerpt(repoRoot5, db, ov.note));
211196
211716
  }
211197
- gt("resolve with `spec conflicts resolve <area> --older P --newer P --replace|--precedence|--keep-both`.");
211717
+ gt("resolve with `spec conflicts resolve <n|area> --right <docPath>` (pick a side) or `--dismiss`.");
211718
+ }
211719
+ function pickConflict(target, conflicts2, right) {
211720
+ if (/^\d+$/.test(target)) {
211721
+ const idx = Number(target) - 1;
211722
+ if (idx < 0 || idx >= conflicts2.length) {
211723
+ return { error: `No conflict #${target}. Run \`spec conflicts list\` (${conflicts2.length} listed).` };
211724
+ }
211725
+ return conflicts2[idx];
211726
+ }
211727
+ let inArea = conflicts2.filter((c2) => c2.areas.includes(target) || c2.area === target);
211728
+ if (inArea.length === 0) return { error: `No conflicts in area ${target}. List them with \`spec conflicts list\`.` };
211729
+ if (right) inArea = inArea.filter((c2) => c2.a === right || c2.b === right);
211730
+ if (inArea.length === 0) return { error: `No conflict in ${target} involves ${right}.` };
211731
+ if (inArea.length > 1) {
211732
+ return { error: `Area ${target} has ${inArea.length} conflicts \u2014 address one by its number (\`spec conflicts list\`).` };
211733
+ }
211734
+ return inArea[0];
211735
+ }
211736
+ function buildResolution(c2, verdict, note) {
211737
+ const secOf = (doc) => (c2.sections ?? []).find((s) => s.doc === doc);
211738
+ return {
211739
+ docA: c2.a,
211740
+ anchorA: secOf(c2.a)?.heading ?? null,
211741
+ quoteA: secOf(c2.a)?.quote,
211742
+ docB: c2.b,
211743
+ anchorB: secOf(c2.b)?.heading ?? null,
211744
+ quoteB: secOf(c2.b)?.quote,
211745
+ verdict,
211746
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
211747
+ note
211748
+ };
211198
211749
  }
211199
- async function runSpecConflictsResolve(area, opts) {
211750
+ async function runSpecConflictsResolve(target, opts) {
211200
211751
  const repoRoot5 = root(opts);
211201
- if (!opts.older || !opts.newer) return fail("resolve needs --older <path> and --newer <path>");
211202
- if (opts.older === opts.newer) return fail("--older and --newer must be different docs");
211203
211752
  const corpus = loadCorpusOrExit(repoRoot5);
211204
- const a = corpus.areas.find((x) => x.id === area);
211205
- if (!a) return fail(`No such area: ${area}.`);
211206
- const known = new Set(a.docRefs);
211207
- for (const ref of [opts.older, opts.newer]) {
211208
- if (!known.has(ref)) return fail(`${ref} is not a doc in area ${area}. Docs: ${a.docRefs.join(", ")}`);
211753
+ const decisions = readCorpusDecisions(repoRoot5);
211754
+ if (!opts.right && !opts.dismiss) {
211755
+ return fail("Pass --right <docPath> (pick a side) or --dismiss. Doc-level relations live in `spec chains add` and never resolve a conflict.");
211756
+ }
211757
+ if (opts.right && opts.dismiss) return fail("Pass either --right <docPath> or --dismiss, not both.");
211758
+ const conflicts2 = buildCorpusConflicts(corpus, decisions);
211759
+ const picked = pickConflict(target, conflicts2, opts.right);
211760
+ if ("error" in picked) return fail(picked.error);
211761
+ let verdict;
211762
+ if (opts.dismiss) {
211763
+ verdict = "dismissed";
211764
+ } else {
211765
+ if (opts.right !== picked.a && opts.right !== picked.b) {
211766
+ return fail(`--right must be one of the disputing docs: ${picked.a} or ${picked.b}.`);
211767
+ }
211768
+ verdict = opts.right === picked.a ? "a" : "b";
211769
+ }
211770
+ await addConflictResolution(repoRoot5, buildResolution(picked, verdict, opts.note));
211771
+ if (verdict === "dismissed") {
211772
+ gt(`Dismissed: ${base(picked.a)} \u2194 ${base(picked.b)} is not a real conflict.`);
211773
+ } else {
211774
+ const winner = verdict === "a" ? picked.a : picked.b;
211775
+ const loser = verdict === "a" ? picked.b : picked.a;
211776
+ gt(`Recorded: ${base(winner)} is right. ${base(loser)}\u2019s disputed claim is suppressed at \`truecourse guard generate\`.`);
211209
211777
  }
211210
- const conflict = buildCorpusConflicts(corpus, readCorpusDecisions(repoRoot5)).find(
211211
- (c2) => c2.a === opts.older && c2.b === opts.newer || c2.a === opts.newer && c2.b === opts.older
211212
- );
211213
- const scope = conflict && conflict.areas.length > 1 ? void 0 : area;
211214
- await addRelation(repoRoot5, {
211215
- type: opts.type,
211216
- older: opts.older,
211217
- newer: opts.newer,
211218
- scope,
211219
- detectedFrom: "manual",
211220
- note: opts.note
211221
- });
211222
- const s = fe();
211223
- s.start("Re-scanning to apply the relation");
211224
- await curateInProcess(repoRoot5, {});
211225
- s.stop("Re-scanned");
211226
- gt(`Recorded ${opts.type}: ${opts.older} \u21D2 ${opts.newer} (scope ${scope ?? "all areas"}).`);
211227
211778
  }
211228
211779
  function fail(msg) {
211229
211780
  pt(msg);
@@ -211392,7 +211943,7 @@ function fail3(msg) {
211392
211943
 
211393
211944
  // tools/cli/src/commands/drifts.ts
211394
211945
  init_dist4();
211395
- import path76 from "node:path";
211946
+ import path77 from "node:path";
211396
211947
  var DRIFT_SEVERITIES = [
211397
211948
  "critical",
211398
211949
  "high",
@@ -211429,7 +211980,7 @@ async function runDriftsList(opts = {}) {
211429
211980
  O2.message("");
211430
211981
  O2.message("Drifts:");
211431
211982
  for (const d3 of page) {
211432
- const loc = d3.filePath ? ` ${path76.relative(root2, d3.filePath)}:${d3.lineStart ?? "?"}` : "";
211983
+ const loc = d3.filePath ? ` ${path77.relative(root2, d3.filePath)}:${d3.lineStart ?? "?"}` : "";
211433
211984
  O2.message(` [${d3.severity}] ${d3.obligationKey}${loc}`);
211434
211985
  O2.message(` \u2192 ${d3.message}`);
211435
211986
  }
@@ -211460,7 +212011,7 @@ function parseDriftSeverityFlag(raw) {
211460
212011
 
211461
212012
  // tools/cli/src/commands/guard.ts
211462
212013
  init_dist4();
211463
- import path77 from "node:path";
212014
+ import path78 from "node:path";
211464
212015
  init_progress();
211465
212016
 
211466
212017
  // packages/core/dist/commands/guard-in-process.js
@@ -211905,7 +212456,7 @@ async function runGuardGenerate(opts = {}) {
211905
212456
  return;
211906
212457
  }
211907
212458
  const report4 = readGuardResult(repoRoot5) ?? { ...guard, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
211908
- printGuardGenerateSummary(report4, path77.relative(repoRoot5, guardResultPath(repoRoot5)));
212459
+ printGuardGenerateSummary(report4, path78.relative(repoRoot5, guardResultPath(repoRoot5)));
211909
212460
  if (guard.written.length === 0 && guard.birthFindings.length === 0 && guard.errors.length === 0) {
211910
212461
  gt("No scenarios written.");
211911
212462
  return;
@@ -212113,7 +212664,7 @@ function printLoadErrors(loadErrors) {
212113
212664
 
212114
212665
  // tools/cli/src/commands/config.ts
212115
212666
  init_dist4();
212116
- import path78 from "node:path";
212667
+ import path79 from "node:path";
212117
212668
  var STAGE_LABEL = {
212118
212669
  "spec.relevance": "Spec \xB7 doc relevance",
212119
212670
  "spec.areaTag": "Spec \xB7 area tag",
@@ -212144,7 +212695,7 @@ async function runConfigLlmShow(options = {}) {
212144
212695
  const repoRoot5 = options.cwd ?? process.cwd();
212145
212696
  const { stages, fallbackModel } = describeStageResolutions(repoRoot5);
212146
212697
  mt("LLM model resolution");
212147
- O2.info(`repoRoot ${path78.relative(process.cwd(), repoRoot5) || "."}`);
212698
+ O2.info(`repoRoot ${path79.relative(process.cwd(), repoRoot5) || "."}`);
212148
212699
  O2.info(`fallback ${fallbackModel ?? "(not configured)"}`);
212149
212700
  for (const stage of stages) {
212150
212701
  const label = STAGE_LABEL[stage.stageId];
@@ -212160,8 +212711,8 @@ async function runConfigLlmShow(options = {}) {
212160
212711
 
212161
212712
  // tools/cli/src/commands/hooks.ts
212162
212713
  import { execSync as execSync4 } from "node:child_process";
212163
- import fs70 from "node:fs";
212164
- import path79 from "node:path";
212714
+ import fs71 from "node:fs";
212715
+ import path80 from "node:path";
212165
212716
  init_dist4();
212166
212717
  init_paths();
212167
212718
  init_registry();
@@ -212195,17 +212746,17 @@ pre-commit:
212195
212746
  function findGitDir(from) {
212196
212747
  let dir = from;
212197
212748
  while (true) {
212198
- const gitPath = path79.join(dir, ".git");
212199
- if (fs70.existsSync(gitPath)) {
212200
- const stat = fs70.statSync(gitPath);
212749
+ const gitPath = path80.join(dir, ".git");
212750
+ if (fs71.existsSync(gitPath)) {
212751
+ const stat = fs71.statSync(gitPath);
212201
212752
  if (stat.isDirectory()) return gitPath;
212202
212753
  if (stat.isFile()) {
212203
- const content = fs70.readFileSync(gitPath, "utf-8").trim();
212754
+ const content = fs71.readFileSync(gitPath, "utf-8").trim();
212204
212755
  const match4 = content.match(/^gitdir:\s*(.+)$/);
212205
- if (match4) return path79.resolve(dir, match4[1]);
212756
+ if (match4) return path80.resolve(dir, match4[1]);
212206
212757
  }
212207
212758
  }
212208
- const parent = path79.dirname(dir);
212759
+ const parent = path80.dirname(dir);
212209
212760
  if (parent === dir) return null;
212210
212761
  dir = parent;
212211
212762
  }
@@ -212213,18 +212764,18 @@ function findGitDir(from) {
212213
212764
  function findProjectRoot(from) {
212214
212765
  let dir = from;
212215
212766
  while (true) {
212216
- if (fs70.existsSync(path79.join(dir, ".git"))) return dir;
212217
- const parent = path79.dirname(dir);
212767
+ if (fs71.existsSync(path80.join(dir, ".git"))) return dir;
212768
+ const parent = path80.dirname(dir);
212218
212769
  if (parent === dir) return null;
212219
212770
  dir = parent;
212220
212771
  }
212221
212772
  }
212222
212773
  function loadConfig(projectRoot) {
212223
- const configPath = path79.join(projectRoot, ".truecourse", "hooks.yaml");
212224
- if (!fs70.existsSync(configPath)) return null;
212774
+ const configPath = path80.join(projectRoot, ".truecourse", "hooks.yaml");
212775
+ if (!fs71.existsSync(configPath)) return null;
212225
212776
  let parsed;
212226
212777
  try {
212227
- const raw = fs70.readFileSync(configPath, "utf-8");
212778
+ const raw = fs71.readFileSync(configPath, "utf-8");
212228
212779
  parsed = jsYaml.load(raw) || {};
212229
212780
  } catch (err) {
212230
212781
  console.error(`Error parsing ${configPath}: ${err.message}`);
@@ -212275,11 +212826,11 @@ async function runHooksInstall() {
212275
212826
  } else {
212276
212827
  console.log(INSTALL_WARNING);
212277
212828
  }
212278
- const hooksDir = path79.join(gitDir, "hooks");
212279
- fs70.mkdirSync(hooksDir, { recursive: true });
212280
- const hookPath = path79.join(hooksDir, "pre-commit");
212281
- if (fs70.existsSync(hookPath)) {
212282
- const existing = fs70.readFileSync(hookPath, "utf-8");
212829
+ const hooksDir = path80.join(gitDir, "hooks");
212830
+ fs71.mkdirSync(hooksDir, { recursive: true });
212831
+ const hookPath = path80.join(hooksDir, "pre-commit");
212832
+ if (fs71.existsSync(hookPath)) {
212833
+ const existing = fs71.readFileSync(hookPath, "utf-8");
212283
212834
  if (!existing.includes(HOOK_IDENTIFIER)) {
212284
212835
  console.error(
212285
212836
  "Error: A pre-commit hook already exists and was not installed by TrueCourse."
@@ -212289,16 +212840,16 @@ async function runHooksInstall() {
212289
212840
  process.exit(1);
212290
212841
  }
212291
212842
  }
212292
- fs70.writeFileSync(hookPath, HOOK_SCRIPT, { mode: 493 });
212843
+ fs71.writeFileSync(hookPath, HOOK_SCRIPT, { mode: 493 });
212293
212844
  console.log("TrueCourse pre-commit hook installed.");
212294
212845
  console.log(` ${hookPath}`);
212295
212846
  const projectRoot = findProjectRoot(process.cwd());
212296
212847
  if (projectRoot) {
212297
- const cfgDir = path79.join(projectRoot, ".truecourse");
212298
- const cfgPath = path79.join(cfgDir, "hooks.yaml");
212299
- if (!fs70.existsSync(cfgPath)) {
212300
- fs70.mkdirSync(cfgDir, { recursive: true });
212301
- fs70.writeFileSync(cfgPath, HOOKS_YAML_TEMPLATE);
212848
+ const cfgDir = path80.join(projectRoot, ".truecourse");
212849
+ const cfgPath = path80.join(cfgDir, "hooks.yaml");
212850
+ if (!fs71.existsSync(cfgPath)) {
212851
+ fs71.mkdirSync(cfgDir, { recursive: true });
212852
+ fs71.writeFileSync(cfgPath, HOOKS_YAML_TEMPLATE);
212302
212853
  console.log(` ${cfgPath} (starter config \u2014 edit to customize, commit to share with the team)`);
212303
212854
  }
212304
212855
  }
@@ -212309,17 +212860,17 @@ function runHooksUninstall() {
212309
212860
  console.error("Error: Not a git repository.");
212310
212861
  process.exit(1);
212311
212862
  }
212312
- const hookPath = path79.join(gitDir, "hooks", "pre-commit");
212313
- if (!fs70.existsSync(hookPath)) {
212863
+ const hookPath = path80.join(gitDir, "hooks", "pre-commit");
212864
+ if (!fs71.existsSync(hookPath)) {
212314
212865
  console.log("No pre-commit hook installed.");
212315
212866
  return;
212316
212867
  }
212317
- const content = fs70.readFileSync(hookPath, "utf-8");
212868
+ const content = fs71.readFileSync(hookPath, "utf-8");
212318
212869
  if (!content.includes(HOOK_IDENTIFIER)) {
212319
212870
  console.error("Error: The pre-commit hook was not installed by TrueCourse. Leaving it in place.");
212320
212871
  process.exit(1);
212321
212872
  }
212322
- fs70.unlinkSync(hookPath);
212873
+ fs71.unlinkSync(hookPath);
212323
212874
  console.log("TrueCourse pre-commit hook removed.");
212324
212875
  }
212325
212876
  function runHooksStatus() {
@@ -212328,8 +212879,8 @@ function runHooksStatus() {
212328
212879
  console.error("Error: Not a git repository.");
212329
212880
  process.exit(1);
212330
212881
  }
212331
- const hookPath = path79.join(gitDir, "hooks", "pre-commit");
212332
- const installed = fs70.existsSync(hookPath) && fs70.readFileSync(hookPath, "utf-8").includes(HOOK_IDENTIFIER);
212882
+ const hookPath = path80.join(gitDir, "hooks", "pre-commit");
212883
+ const installed = fs71.existsSync(hookPath) && fs71.readFileSync(hookPath, "utf-8").includes(HOOK_IDENTIFIER);
212333
212884
  if (installed) {
212334
212885
  console.log("TrueCourse pre-commit hook: installed");
212335
212886
  console.log(` ${hookPath}`);
@@ -212438,7 +212989,7 @@ async function runHooksRun() {
212438
212989
 
212439
212990
  // tools/cli/src/index.ts
212440
212991
  var program2 = new Command();
212441
- program2.name("truecourse").version("0.7.0-next.7").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
212992
+ program2.name("truecourse").version("0.7.0-next.9").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
212442
212993
  function warnDiscontinued(command) {
212443
212994
  process.stderr.write(
212444
212995
  `\u26A0 \`${command}\` is discontinued in favor of \`truecourse guard\` \u2014 see the README. Planned removal: 0.8.
@@ -212519,19 +213070,18 @@ specCmd.command("status").description("Summary of docs, areas, relations, and op
212519
213070
  await runSpecStatus();
212520
213071
  });
212521
213072
  var conflictsCmd = specCmd.command("conflicts").description("Inspect and resolve flagged within-area doc overlaps (agent-friendly)");
212522
- conflictsCmd.command("list").description("List flagged overlaps still awaiting a relation").action(async () => {
213073
+ conflictsCmd.command("list").description("List flagged overlaps still awaiting a verdict").action(async () => {
212523
213074
  await runSpecConflictsList();
212524
213075
  });
212525
213076
  conflictsCmd.command("show <area>").description("Show an area's overlapping docs with prose excerpts").action(async (area) => {
212526
213077
  await runSpecConflictsShow(area);
212527
213078
  });
212528
- conflictsCmd.command("resolve <area>").description("Resolve an overlap by recording a doc\u2192doc relation").requiredOption("--older <path>", "Repo-relative path of the older / superseded doc").requiredOption("--newer <path>", "Repo-relative path of the newer / authoritative doc").option("--replace", "`newer` fully supersedes `older` (excluded from generate)").option("--precedence", "Both feed generate; `newer` wins where they overlap").option("--keep-both", "Both are current peers (combine)").option("--note <text>", "Optional rationale").action(async (area, opts) => {
212529
- const type2 = opts.replace ? "replace" : opts.precedence ? "precedence" : opts.keepBoth ? "keep-both" : void 0;
212530
- if (!type2) {
212531
- console.error("Pass one of --replace | --precedence | --keep-both");
212532
- process.exit(1);
212533
- }
212534
- await runSpecConflictsResolve(area, { older: opts.older, newer: opts.newer, type: type2, note: opts.note });
213079
+ conflictsCmd.command("resolve <n|area>").description("Resolve a flagged overlap: pick a side (--right) or dismiss it (--dismiss)").option("--right <path>", "Pick a side: this doc is right; the other side's disputed claim is suppressed at generate").option("--dismiss", "Not a real conflict \u2014 dismiss the detector false-positive").option("--note <text>", "Optional rationale").action(async (target, opts) => {
213080
+ await runSpecConflictsResolve(target, {
213081
+ right: opts.right,
213082
+ dismiss: opts.dismiss,
213083
+ note: opts.note
213084
+ });
212535
213085
  });
212536
213086
  var chainsCmd = specCmd.command("chains").description("Manage doc\u2192doc relations (supersession / precedence overrides)");
212537
213087
  chainsCmd.command("list").description("List effective relations (auto-detected + user-authored)").action(async () => {