opencode-codebase-index 0.22.4 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -496,7 +496,7 @@ var require_ignore = __commonJS({
496
496
  // path matching.
497
497
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
498
498
  // @returns {TestResult} true if a file is ignored
499
- test(path31, checkUnignored, mode) {
499
+ test(path33, checkUnignored, mode) {
500
500
  let ignored = false;
501
501
  let unignored = false;
502
502
  let matchedRule;
@@ -505,7 +505,7 @@ var require_ignore = __commonJS({
505
505
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
506
506
  return;
507
507
  }
508
- const matched = rule[mode].test(path31);
508
+ const matched = rule[mode].test(path33);
509
509
  if (!matched) {
510
510
  return;
511
511
  }
@@ -526,17 +526,17 @@ var require_ignore = __commonJS({
526
526
  var throwError = (message, Ctor) => {
527
527
  throw new Ctor(message);
528
528
  };
529
- var checkPath = (path31, originalPath, doThrow) => {
530
- if (!isString(path31)) {
529
+ var checkPath = (path33, originalPath, doThrow) => {
530
+ if (!isString(path33)) {
531
531
  return doThrow(
532
532
  `path must be a string, but got \`${originalPath}\``,
533
533
  TypeError
534
534
  );
535
535
  }
536
- if (!path31) {
536
+ if (!path33) {
537
537
  return doThrow(`path must not be empty`, TypeError);
538
538
  }
539
- if (checkPath.isNotRelative(path31)) {
539
+ if (checkPath.isNotRelative(path33)) {
540
540
  const r = "`path.relative()`d";
541
541
  return doThrow(
542
542
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -545,7 +545,7 @@ var require_ignore = __commonJS({
545
545
  }
546
546
  return true;
547
547
  };
548
- var isNotRelative = (path31) => REGEX_TEST_INVALID_PATH.test(path31);
548
+ var isNotRelative = (path33) => REGEX_TEST_INVALID_PATH.test(path33);
549
549
  checkPath.isNotRelative = isNotRelative;
550
550
  checkPath.convert = (p) => p;
551
551
  var Ignore2 = class {
@@ -575,19 +575,19 @@ var require_ignore = __commonJS({
575
575
  }
576
576
  // @returns {TestResult}
577
577
  _test(originalPath, cache, checkUnignored, slices) {
578
- const path31 = originalPath && checkPath.convert(originalPath);
578
+ const path33 = originalPath && checkPath.convert(originalPath);
579
579
  checkPath(
580
- path31,
580
+ path33,
581
581
  originalPath,
582
582
  this._strictPathCheck ? throwError : RETURN_FALSE
583
583
  );
584
- return this._t(path31, cache, checkUnignored, slices);
584
+ return this._t(path33, cache, checkUnignored, slices);
585
585
  }
586
- checkIgnore(path31) {
587
- if (!REGEX_TEST_TRAILING_SLASH.test(path31)) {
588
- return this.test(path31);
586
+ checkIgnore(path33) {
587
+ if (!REGEX_TEST_TRAILING_SLASH.test(path33)) {
588
+ return this.test(path33);
589
589
  }
590
- const slices = path31.split(SLASH2).filter(Boolean);
590
+ const slices = path33.split(SLASH2).filter(Boolean);
591
591
  slices.pop();
592
592
  if (slices.length) {
593
593
  const parent = this._t(
@@ -600,18 +600,18 @@ var require_ignore = __commonJS({
600
600
  return parent;
601
601
  }
602
602
  }
603
- return this._rules.test(path31, false, MODE_CHECK_IGNORE);
603
+ return this._rules.test(path33, false, MODE_CHECK_IGNORE);
604
604
  }
605
- _t(path31, cache, checkUnignored, slices) {
606
- if (path31 in cache) {
607
- return cache[path31];
605
+ _t(path33, cache, checkUnignored, slices) {
606
+ if (path33 in cache) {
607
+ return cache[path33];
608
608
  }
609
609
  if (!slices) {
610
- slices = path31.split(SLASH2).filter(Boolean);
610
+ slices = path33.split(SLASH2).filter(Boolean);
611
611
  }
612
612
  slices.pop();
613
613
  if (!slices.length) {
614
- return cache[path31] = this._rules.test(path31, checkUnignored, MODE_IGNORE);
614
+ return cache[path33] = this._rules.test(path33, checkUnignored, MODE_IGNORE);
615
615
  }
616
616
  const parent = this._t(
617
617
  slices.join(SLASH2) + SLASH2,
@@ -619,29 +619,29 @@ var require_ignore = __commonJS({
619
619
  checkUnignored,
620
620
  slices
621
621
  );
622
- return cache[path31] = parent.ignored ? parent : this._rules.test(path31, checkUnignored, MODE_IGNORE);
622
+ return cache[path33] = parent.ignored ? parent : this._rules.test(path33, checkUnignored, MODE_IGNORE);
623
623
  }
624
- ignores(path31) {
625
- return this._test(path31, this._ignoreCache, false).ignored;
624
+ ignores(path33) {
625
+ return this._test(path33, this._ignoreCache, false).ignored;
626
626
  }
627
627
  createFilter() {
628
- return (path31) => !this.ignores(path31);
628
+ return (path33) => !this.ignores(path33);
629
629
  }
630
630
  filter(paths) {
631
631
  return makeArray(paths).filter(this.createFilter());
632
632
  }
633
633
  // @returns {TestResult}
634
- test(path31) {
635
- return this._test(path31, this._testCache, true);
634
+ test(path33) {
635
+ return this._test(path33, this._testCache, true);
636
636
  }
637
637
  };
638
638
  var factory = (options) => new Ignore2(options);
639
- var isPathValid = (path31) => checkPath(path31 && checkPath.convert(path31), path31, RETURN_FALSE);
639
+ var isPathValid = (path33) => checkPath(path33 && checkPath.convert(path33), path33, RETURN_FALSE);
640
640
  var setupWindows = () => {
641
641
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
642
642
  checkPath.convert = makePosix;
643
643
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
644
- checkPath.isNotRelative = (path31) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path31) || isNotRelative(path31);
644
+ checkPath.isNotRelative = (path33) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path33) || isNotRelative(path33);
645
645
  };
646
646
  if (
647
647
  // Detect `process` so that it can run in browsers.
@@ -669,7 +669,7 @@ module.exports = __toCommonJS(cli_exports);
669
669
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
670
670
  var import_fs20 = require("fs");
671
671
  var os8 = __toESM(require("os"), 1);
672
- var path30 = __toESM(require("path"), 1);
672
+ var path32 = __toESM(require("path"), 1);
673
673
  var import_url = require("url");
674
674
 
675
675
  // src/config/constants.ts
@@ -1179,9 +1179,9 @@ var import_fs = require("fs");
1179
1179
  var path = __toESM(require("path"), 1);
1180
1180
 
1181
1181
  // src/eval/report-formatters.ts
1182
- function assertFiniteNumber(value, path31) {
1182
+ function assertFiniteNumber(value, path33) {
1183
1183
  if (typeof value !== "number" || Number.isNaN(value) || !Number.isFinite(value)) {
1184
- throw new Error(`${path31} must be a finite number`);
1184
+ throw new Error(`${path33} must be a finite number`);
1185
1185
  }
1186
1186
  return value;
1187
1187
  }
@@ -1453,7 +1453,7 @@ function pTimeout(promise, options) {
1453
1453
  } = options;
1454
1454
  let timer;
1455
1455
  let abortHandler;
1456
- const wrappedPromise = new Promise((resolve18, reject) => {
1456
+ const wrappedPromise = new Promise((resolve20, reject) => {
1457
1457
  if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
1458
1458
  throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
1459
1459
  }
@@ -1467,7 +1467,7 @@ function pTimeout(promise, options) {
1467
1467
  };
1468
1468
  signal.addEventListener("abort", abortHandler, { once: true });
1469
1469
  }
1470
- promise.then(resolve18, reject);
1470
+ promise.then(resolve20, reject);
1471
1471
  if (milliseconds === Number.POSITIVE_INFINITY) {
1472
1472
  return;
1473
1473
  }
@@ -1475,7 +1475,7 @@ function pTimeout(promise, options) {
1475
1475
  timer = customTimers.setTimeout.call(void 0, () => {
1476
1476
  if (fallback) {
1477
1477
  try {
1478
- resolve18(fallback());
1478
+ resolve20(fallback());
1479
1479
  } catch (error) {
1480
1480
  reject(error);
1481
1481
  }
@@ -1485,7 +1485,7 @@ function pTimeout(promise, options) {
1485
1485
  promise.cancel();
1486
1486
  }
1487
1487
  if (message === false) {
1488
- resolve18();
1488
+ resolve20();
1489
1489
  } else if (message instanceof Error) {
1490
1490
  reject(message);
1491
1491
  } else {
@@ -1887,7 +1887,7 @@ var PQueue = class extends import_index.default {
1887
1887
  // Assign unique ID if not provided
1888
1888
  id: options.id ?? (this.#idAssigner++).toString()
1889
1889
  };
1890
- return new Promise((resolve18, reject) => {
1890
+ return new Promise((resolve20, reject) => {
1891
1891
  const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
1892
1892
  let cleanupQueueAbortHandler = () => void 0;
1893
1893
  const run = async () => {
@@ -1927,7 +1927,7 @@ var PQueue = class extends import_index.default {
1927
1927
  })]);
1928
1928
  }
1929
1929
  const result = await operation;
1930
- resolve18(result);
1930
+ resolve20(result);
1931
1931
  this.emit("completed", result);
1932
1932
  } catch (error) {
1933
1933
  reject(error);
@@ -2115,13 +2115,13 @@ var PQueue = class extends import_index.default {
2115
2115
  });
2116
2116
  }
2117
2117
  async #onEvent(event, filter) {
2118
- return new Promise((resolve18) => {
2118
+ return new Promise((resolve20) => {
2119
2119
  const listener = () => {
2120
2120
  if (filter && !filter()) {
2121
2121
  return;
2122
2122
  }
2123
2123
  this.off(event, listener);
2124
- resolve18();
2124
+ resolve20();
2125
2125
  };
2126
2126
  this.on(event, listener);
2127
2127
  });
@@ -2407,7 +2407,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
2407
2407
  const finalDelay = Math.min(delayTime, remainingTime);
2408
2408
  options.signal?.throwIfAborted();
2409
2409
  if (finalDelay > 0) {
2410
- await new Promise((resolve18, reject) => {
2410
+ await new Promise((resolve20, reject) => {
2411
2411
  const onAbort = () => {
2412
2412
  clearTimeout(timeoutToken);
2413
2413
  options.signal?.removeEventListener("abort", onAbort);
@@ -2415,7 +2415,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
2415
2415
  };
2416
2416
  const timeoutToken = setTimeout(() => {
2417
2417
  options.signal?.removeEventListener("abort", onAbort);
2418
- resolve18();
2418
+ resolve20();
2419
2419
  }, finalDelay);
2420
2420
  if (options.unref) {
2421
2421
  timeoutToken.unref?.();
@@ -3221,85 +3221,6 @@ function createEmbeddingProvider(configuredProviderInfo) {
3221
3221
  }
3222
3222
  }
3223
3223
 
3224
- // src/rerank/index.ts
3225
- function createReranker(config) {
3226
- if (!config.enabled) {
3227
- return new NoOpReranker();
3228
- }
3229
- return new SiliconFlowReranker(config);
3230
- }
3231
- var NoOpReranker = class {
3232
- isAvailable() {
3233
- return false;
3234
- }
3235
- async rerank(_query, documents, _topN) {
3236
- return {
3237
- results: documents.map((_, index) => ({ index, relevanceScore: 0 }))
3238
- };
3239
- }
3240
- };
3241
- var SiliconFlowReranker = class {
3242
- config;
3243
- constructor(config) {
3244
- this.config = config;
3245
- }
3246
- isAvailable() {
3247
- return this.config.enabled && !!this.config.baseUrl && !!this.config.model;
3248
- }
3249
- async rerank(query, documents, topN) {
3250
- if (documents.length === 0) {
3251
- return { results: [] };
3252
- }
3253
- const headers = {
3254
- "Content-Type": "application/json"
3255
- };
3256
- if (this.config.apiKey) {
3257
- headers["Authorization"] = `Bearer ${this.config.apiKey}`;
3258
- }
3259
- const baseUrl = this.config.baseUrl;
3260
- if (!baseUrl) {
3261
- throw new Error("Reranker baseUrl is required. Configure reranker.baseUrl in your codebase-index.json.");
3262
- }
3263
- const timeoutMs = this.config.timeoutMs ?? 3e4;
3264
- const controller = new AbortController();
3265
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
3266
- try {
3267
- const response = await fetch(`${baseUrl}/rerank`, {
3268
- method: "POST",
3269
- headers,
3270
- body: JSON.stringify({
3271
- model: this.config.model,
3272
- query,
3273
- documents,
3274
- top_n: topN ?? this.config.topN ?? 20,
3275
- return_documents: false
3276
- }),
3277
- signal: controller.signal
3278
- });
3279
- clearTimeout(timeout);
3280
- if (!response.ok) {
3281
- const errorText = await response.text();
3282
- throw new Error(`Rerank API error: ${response.status} - ${errorText}`);
3283
- }
3284
- const data = await response.json();
3285
- return {
3286
- results: data.results.map((r) => ({
3287
- index: r.index,
3288
- relevanceScore: r.relevance_score,
3289
- document: r.document?.text
3290
- })),
3291
- tokensUsed: data.meta?.tokens?.input_tokens
3292
- };
3293
- } catch (error) {
3294
- clearTimeout(timeout);
3295
- if (error instanceof Error && error.name === "AbortError") {
3296
- throw new Error(`Rerank API request timed out after ${timeoutMs}ms`);
3297
- }
3298
- throw error;
3299
- }
3300
- }
3301
- };
3302
-
3303
3224
  // src/utils/files.ts
3304
3225
  var import_ignore = __toESM(require_ignore(), 1);
3305
3226
  var import_fs3 = require("fs");
@@ -3461,8 +3382,8 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3461
3382
  if (entry.isDirectory()) {
3462
3383
  subdirs.push({ fullPath, relativePath });
3463
3384
  } else if (entry.isFile()) {
3464
- const stat4 = await import_fs3.promises.stat(fullPath);
3465
- if (stat4.size > maxFileSize) {
3385
+ const stat5 = await import_fs3.promises.stat(fullPath);
3386
+ if (stat5.size > maxFileSize) {
3466
3387
  skipped.push({ path: relativePath, reason: "too_large" });
3467
3388
  continue;
3468
3389
  }
@@ -3480,7 +3401,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3480
3401
  }
3481
3402
  }
3482
3403
  if (matched) {
3483
- filesInDir.push({ path: fullPath, size: stat4.size });
3404
+ filesInDir.push({ path: fullPath, size: stat5.size });
3484
3405
  }
3485
3406
  }
3486
3407
  }
@@ -3537,8 +3458,8 @@ async function collectFiles(projectRoot, includePatterns, excludePatterns, maxFi
3537
3458
  }
3538
3459
  for (const resolvedKbRoot of normalizedRoots) {
3539
3460
  try {
3540
- const stat4 = await import_fs3.promises.stat(resolvedKbRoot);
3541
- if (!stat4.isDirectory()) {
3461
+ const stat5 = await import_fs3.promises.stat(resolvedKbRoot);
3462
+ if (!stat5.isDirectory()) {
3542
3463
  skipped.push({ path: resolvedKbRoot, reason: "excluded" });
3543
3464
  continue;
3544
3465
  }
@@ -4865,11 +4786,11 @@ function resolveGitDir(repoRoot) {
4865
4786
  return null;
4866
4787
  }
4867
4788
  try {
4868
- const stat4 = (0, import_fs5.statSync)(gitPath);
4869
- if (stat4.isDirectory()) {
4789
+ const stat5 = (0, import_fs5.statSync)(gitPath);
4790
+ if (stat5.isDirectory()) {
4870
4791
  return gitPath;
4871
4792
  }
4872
- if (stat4.isFile()) {
4793
+ if (stat5.isFile()) {
4873
4794
  const content = (0, import_fs5.readFileSync)(gitPath, "utf-8").trim();
4874
4795
  const match = content.match(/^gitdir:\s*(.+)$/);
4875
4796
  if (match) {
@@ -5374,8 +5295,8 @@ async function isWorktreeRegistered(projectRoot, worktreePath) {
5374
5295
  return false;
5375
5296
  }
5376
5297
  function isPathWithinRoot(filePath, rootPath) {
5377
- const relative12 = path9.relative(path9.resolve(rootPath), path9.resolve(filePath));
5378
- return relative12 === "" || !relative12.startsWith(`..${path9.sep}`) && relative12 !== ".." && !path9.isAbsolute(relative12);
5298
+ const relative14 = path9.relative(path9.resolve(rootPath), path9.resolve(filePath));
5299
+ return relative14 === "" || !relative14.startsWith(`..${path9.sep}`) && relative14 !== ".." && !path9.isAbsolute(relative14);
5379
5300
  }
5380
5301
  async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath) {
5381
5302
  if (await pathExists(worktreePath)) return false;
@@ -5933,11 +5854,11 @@ function normalizeFiles(rawFiles, projectRoot) {
5933
5854
  for (const raw of rawFiles) {
5934
5855
  if (raw.length === 0) continue;
5935
5856
  const absolute = path11.resolve(root, raw);
5936
- const relative12 = path11.relative(root, absolute);
5937
- if (path11.isAbsolute(raw) || relative12 === ".." || relative12.startsWith(`..${path11.sep}`) || path11.isAbsolute(relative12)) {
5857
+ const relative14 = path11.relative(root, absolute);
5858
+ if (path11.isAbsolute(raw) || relative14 === ".." || relative14.startsWith(`..${path11.sep}`) || path11.isAbsolute(relative14)) {
5938
5859
  throw new Error(`Changed file escapes the project root: ${JSON.stringify(raw)}`);
5939
5860
  }
5940
- const cleaned = relative12.startsWith(`.${path11.sep}`) ? relative12.slice(2) : relative12;
5861
+ const cleaned = relative14.startsWith(`.${path11.sep}`) ? relative14.slice(2) : relative14;
5941
5862
  if (!seen.has(cleaned)) {
5942
5863
  seen.add(cleaned);
5943
5864
  result.push(cleaned);
@@ -6274,7 +6195,7 @@ function analyzeQueryIntent(query) {
6274
6195
  }
6275
6196
  function isTestPath(filePath) {
6276
6197
  const normalized = normalizePath(filePath);
6277
- return /(?:^|\/)(?:test|tests|__tests__|spec|specs)(?:\/|$)/u.test(normalized) || /\.(?:test|spec)\.[^/]+$/u.test(normalized);
6198
+ return /(?:^|\/)(?:test|tests|__tests__|spec|specs)(?:\/|$)/u.test(normalized) || /(?:\.(?:test|spec)|_(?:test|spec))\.[^/]+$/u.test(normalized) || /(?:^|\/)(?:test|spec)_[^/]+\.[^/]+$/u.test(normalized);
6278
6199
  }
6279
6200
  function isFixturePath(filePath) {
6280
6201
  const normalized = normalizePath(filePath);
@@ -6681,7 +6602,8 @@ function rankHybridResults(query, semanticResults, keywordResults, options) {
6681
6602
  return cached;
6682
6603
  }
6683
6604
  }
6684
- const overfetchLimit = Math.max(options.limit * 4, options.limit);
6605
+ const overfetchFactor = prioritizeSourcePaths ? 12 : 4;
6606
+ const overfetchLimit = Math.max(options.limit * overfetchFactor, options.limit);
6685
6607
  const fused = options.fusionStrategy === "rrf" ? fuseResultsRrf(semanticResults, keywordResults, options.rrfK, overfetchLimit) : fuseResultsWeighted(semanticResults, keywordResults, options.hybridWeight, overfetchLimit);
6686
6608
  const rerankPoolLimit = Math.max(overfetchLimit, options.rerankTopN * 3, options.limit * 6);
6687
6609
  const rerankPool = fused.slice(0, rerankPoolLimit);
@@ -7067,6 +6989,29 @@ function extractPrimaryIdentifierQueryHint(query) {
7067
6989
  const best = codeTerms.find((term) => term.length >= 6);
7068
6990
  return best ?? null;
7069
6991
  }
6992
+ function pathSegmentsForAffinityMatch(filePath) {
6993
+ const normalizedPath3 = normalizeRankingText(filePath).replace(/\\/g, "/");
6994
+ const segments = normalizedPath3.split("/").filter((segment) => segment.length > 0);
6995
+ if (segments.length === 0) {
6996
+ return [];
6997
+ }
6998
+ const basename8 = segments[segments.length - 1] ?? "";
6999
+ const basenameWithoutExt = basename8.replace(/\.[^/.]+$/u, "");
7000
+ const normalizedSegments = segments.map((segment) => segment.toLowerCase());
7001
+ return Array.from(/* @__PURE__ */ new Set([
7002
+ ...normalizedSegments,
7003
+ basenameWithoutExt.toLowerCase()
7004
+ ]));
7005
+ }
7006
+ function hasModuleAffinity(filePath, exactIdentifierVariants) {
7007
+ const haystack = pathSegmentsForAffinityMatch(filePath);
7008
+ return exactIdentifierVariants.some((variant) => {
7009
+ if (!variant || variant.length < 2) {
7010
+ return false;
7011
+ }
7012
+ return haystack.includes(variant);
7013
+ });
7014
+ }
7070
7015
  var FILE_PATH_HINT_EXTENSIONS = [
7071
7016
  "ts",
7072
7017
  "tsx",
@@ -7142,10 +7087,13 @@ function buildDeterministicIdentifierPass(query, candidates, limit, prioritizeSo
7142
7087
  ).map((candidate) => {
7143
7088
  const nameLower = (candidate.metadata.name ?? "").toLowerCase();
7144
7089
  const pathLower = candidate.metadata.filePath.toLowerCase();
7145
- let maxMatch = 0;
7146
- const nameMatchesPrimary = primaryVariants.some(
7090
+ const exactIdentifierVariants = primaryVariants.filter((value) => value.length >= 2);
7091
+ const exactMatch = exactIdentifierVariants.some(
7147
7092
  (variant) => nameLower === variant || nameLower.replace(/[^a-z0-9]/g, "") === variant.replace(/[^a-z0-9]/g, "")
7148
7093
  );
7094
+ let maxMatch = 0;
7095
+ const nameMatchesPrimary = exactMatch;
7096
+ const pathAffinity = exactMatch ? hasModuleAffinity(candidate.metadata.filePath, exactIdentifierVariants) : false;
7149
7097
  const pathMatchesFileHint = filePathHint ? pathMatchesHint(candidate.metadata.filePath, filePathHint) : false;
7150
7098
  for (const hint of hints) {
7151
7099
  const variants = normalizeIdentifierVariants(hint);
@@ -7166,12 +7114,17 @@ function buildDeterministicIdentifierPass(query, candidates, limit, prioritizeSo
7166
7114
  candidate,
7167
7115
  maxMatch,
7168
7116
  pathMatchesFileHint,
7169
- nameMatchesPrimary
7117
+ nameMatchesPrimary,
7118
+ pathAffinity
7170
7119
  };
7171
7120
  }).filter((entry) => entry.maxMatch >= 0.7).sort((a, b) => {
7172
7121
  const aAnchored = a.pathMatchesFileHint && a.nameMatchesPrimary ? 1 : 0;
7173
7122
  const bAnchored = b.pathMatchesFileHint && b.nameMatchesPrimary ? 1 : 0;
7174
7123
  if (aAnchored !== bAnchored) return bAnchored - aAnchored;
7124
+ if (a.nameMatchesPrimary !== b.nameMatchesPrimary) {
7125
+ return b.nameMatchesPrimary ? 1 : -1;
7126
+ }
7127
+ if (a.pathAffinity !== b.pathAffinity) return b.pathAffinity ? 1 : -1;
7175
7128
  if (b.maxMatch !== a.maxMatch) return b.maxMatch - a.maxMatch;
7176
7129
  if (b.candidate.score !== a.candidate.score) return b.candidate.score - a.candidate.score;
7177
7130
  return a.candidate.id.localeCompare(b.candidate.id);
@@ -8552,7 +8505,6 @@ var Indexer = class _Indexer {
8552
8505
  database = null;
8553
8506
  provider = null;
8554
8507
  configuredProviderInfo = null;
8555
- reranker = null;
8556
8508
  fileHashCache = /* @__PURE__ */ new Map();
8557
8509
  fileHashCachePath = "";
8558
8510
  failedBatchesPath = "";
@@ -8712,7 +8664,6 @@ var Indexer = class _Indexer {
8712
8664
  this.database = null;
8713
8665
  this.provider = null;
8714
8666
  this.configuredProviderInfo = null;
8715
- this.reranker = null;
8716
8667
  this.indexCompatibility = null;
8717
8668
  this.initializationMode = "none";
8718
8669
  this.readIssues = [];
@@ -9442,7 +9393,7 @@ var Indexer = class _Indexer {
9442
9393
  await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
9443
9394
  const task = options.queue.add(async () => {
9444
9395
  if (options.rateLimitState.backoffMs > 0) {
9445
- await new Promise((resolve18) => setTimeout(resolve18, options.rateLimitState.backoffMs));
9396
+ await new Promise((resolve20) => setTimeout(resolve20, options.rateLimitState.backoffMs));
9446
9397
  }
9447
9398
  try {
9448
9399
  const embeddingResult = await pRetry(
@@ -10009,15 +9960,6 @@ var Indexer = class _Indexer {
10009
9960
  rerankerEnabled: this.config.reranker?.enabled ?? false
10010
9961
  });
10011
9962
  this.provider = createEmbeddingProvider(this.configuredProviderInfo);
10012
- if (this.config.reranker?.enabled) {
10013
- this.reranker = createReranker(this.config.reranker);
10014
- if (this.reranker.isAvailable()) {
10015
- this.logger.info("Reranker initialized", {
10016
- model: this.config.reranker.model,
10017
- baseUrl: this.config.reranker.baseUrl
10018
- });
10019
- }
10020
- }
10021
9963
  const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
10022
9964
  const storePath = path15.join(this.indexPath, "vectors");
10023
9965
  const vectorMetadataPath = `${storePath}.meta.json`;
@@ -11422,6 +11364,7 @@ var Indexer = class _Indexer {
11422
11364
  const filterByBranch = options?.filterByBranch ?? true;
11423
11365
  const sourceIntent = options?.definitionIntent === true || classifyQueryIntentRaw(query) === "source";
11424
11366
  const identifierHints = extractIdentifierHints(query);
11367
+ const candidateLimit = maxResults * (sourceIntent ? 12 : 4);
11425
11368
  this.logger.search("debug", "Starting search", {
11426
11369
  query,
11427
11370
  maxResults,
@@ -11458,7 +11401,7 @@ var Indexer = class _Indexer {
11458
11401
  const semanticCandidates = embedding ? this.searchSemanticCandidates(
11459
11402
  store,
11460
11403
  embedding,
11461
- maxResults * 4,
11404
+ candidateLimit,
11462
11405
  branchChunkIds,
11463
11406
  shouldPrefilterByBranch
11464
11407
  ) : [];
@@ -11466,7 +11409,7 @@ var Indexer = class _Indexer {
11466
11409
  const keywordStartTime = import_perf_hooks.performance.now();
11467
11410
  const keywordCandidates = await this.keywordSearch(
11468
11411
  query,
11469
- maxResults * 4,
11412
+ candidateLimit,
11470
11413
  store,
11471
11414
  invertedIndex,
11472
11415
  branchChunkIds,
@@ -12224,9 +12167,9 @@ var Indexer = class _Indexer {
12224
12167
  this.requireReadableComponents(readIssues, "database");
12225
12168
  let shortest = [];
12226
12169
  for (const branchKey of this.getBranchCatalogKeys()) {
12227
- const path31 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
12228
- if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
12229
- shortest = path31;
12170
+ const path33 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
12171
+ if (path33.length > 0 && (shortest.length === 0 || path33.length < shortest.length)) {
12172
+ shortest = path33;
12230
12173
  }
12231
12174
  }
12232
12175
  return shortest.map((hop) => this.resolveFilePathRecord(hop));
@@ -12274,13 +12217,13 @@ var Indexer = class _Indexer {
12274
12217
  }
12275
12218
  }
12276
12219
  if (!found) continue;
12277
- const path31 = [];
12220
+ const path33 = [];
12278
12221
  let currentSymbolId = toSymbolId;
12279
12222
  while (true) {
12280
12223
  const symbol = symbolsById.get(currentSymbolId);
12281
12224
  if (!symbol) break;
12282
12225
  const parent = parentBySymbolId.get(currentSymbolId);
12283
- path31.push({
12226
+ path33.push({
12284
12227
  symbolId: symbol.id,
12285
12228
  symbolName: symbol.name,
12286
12229
  filePath: symbol.filePath,
@@ -12290,9 +12233,9 @@ var Indexer = class _Indexer {
12290
12233
  if (!parent) break;
12291
12234
  currentSymbolId = parent.parentId;
12292
12235
  }
12293
- path31.reverse();
12294
- if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
12295
- shortest = path31;
12236
+ path33.reverse();
12237
+ if (path33.length > 0 && (shortest.length === 0 || path33.length < shortest.length)) {
12238
+ shortest = path33;
12296
12239
  }
12297
12240
  }
12298
12241
  return shortest.map((hop) => this.resolveFilePathRecord(hop));
@@ -12628,7 +12571,6 @@ var Indexer = class _Indexer {
12628
12571
  this.store = null;
12629
12572
  this.invertedIndex = null;
12630
12573
  this.provider = null;
12631
- this.reranker = null;
12632
12574
  this.configuredProviderInfo = null;
12633
12575
  this.indexCompatibility = null;
12634
12576
  this.initializationMode = "none";
@@ -12942,8 +12884,8 @@ function formatExactSearchHandoff(results) {
12942
12884
  }
12943
12885
  function formatContextEvidence(result, index) {
12944
12886
  const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
12945
- const path31 = compactEvidenceValue(result.filePath, 120);
12946
- return `[${index}] ${result.chunkType}${symbol} in ${path31}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
12887
+ const path33 = compactEvidenceValue(result.filePath, 120);
12888
+ return `[${index}] ${result.chunkType}${symbol} in ${path33}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
12947
12889
  }
12948
12890
  function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
12949
12891
  const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
@@ -13597,7 +13539,7 @@ function getErrorMessage4(error) {
13597
13539
  return error instanceof Error ? error.message : String(error);
13598
13540
  }
13599
13541
  function runCommand(file, args, options) {
13600
- return new Promise((resolve18, reject) => {
13542
+ return new Promise((resolve20, reject) => {
13601
13543
  childProcess.execFile(
13602
13544
  file,
13603
13545
  args,
@@ -13607,7 +13549,7 @@ function runCommand(file, args, options) {
13607
13549
  reject(error);
13608
13550
  return;
13609
13551
  }
13610
- resolve18(stdout);
13552
+ resolve20(stdout);
13611
13553
  }
13612
13554
  );
13613
13555
  });
@@ -13752,10 +13694,10 @@ function safeFailureMessage(error) {
13752
13694
  }
13753
13695
  function cancellableDelay(delayMs, signal) {
13754
13696
  if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
13755
- return new Promise((resolve18, reject) => {
13697
+ return new Promise((resolve20, reject) => {
13756
13698
  const timer = setTimeout(() => {
13757
13699
  signal.removeEventListener("abort", onAbort);
13758
- resolve18();
13700
+ resolve20();
13759
13701
  }, delayMs);
13760
13702
  timer.unref?.();
13761
13703
  const onAbort = () => {
@@ -13767,15 +13709,15 @@ function cancellableDelay(delayMs, signal) {
13767
13709
  }
13768
13710
  function withTimeout(promise, timeoutMs) {
13769
13711
  if (timeoutMs <= 0) return Promise.resolve(void 0);
13770
- return new Promise((resolve18) => {
13771
- const timer = setTimeout(() => resolve18(void 0), timeoutMs);
13712
+ return new Promise((resolve20) => {
13713
+ const timer = setTimeout(() => resolve20(void 0), timeoutMs);
13772
13714
  timer.unref?.();
13773
13715
  void promise.then((value) => {
13774
13716
  clearTimeout(timer);
13775
- resolve18(value);
13717
+ resolve20(value);
13776
13718
  }, () => {
13777
13719
  clearTimeout(timer);
13778
- resolve18(void 0);
13720
+ resolve20(void 0);
13779
13721
  });
13780
13722
  });
13781
13723
  }
@@ -14157,17 +14099,17 @@ var AutoIndexCoordinator = class {
14157
14099
  }
14158
14100
  }
14159
14101
  waitForBatteryRetry(delayMs) {
14160
- return new Promise((resolve18) => {
14102
+ return new Promise((resolve20) => {
14161
14103
  const timer = setTimeout(() => {
14162
14104
  if (this.batteryRetryTimer === timer) {
14163
14105
  this.batteryRetryTimer = null;
14164
14106
  this.resolveBatteryRetry = null;
14165
14107
  }
14166
- resolve18();
14108
+ resolve20();
14167
14109
  }, delayMs);
14168
14110
  timer.unref?.();
14169
14111
  this.batteryRetryTimer = timer;
14170
- this.resolveBatteryRetry = resolve18;
14112
+ this.resolveBatteryRetry = resolve20;
14171
14113
  });
14172
14114
  }
14173
14115
  cancelBatteryRetry() {
@@ -14175,9 +14117,9 @@ var AutoIndexCoordinator = class {
14175
14117
  clearTimeout(this.batteryRetryTimer);
14176
14118
  this.batteryRetryTimer = null;
14177
14119
  }
14178
- const resolve18 = this.resolveBatteryRetry;
14120
+ const resolve20 = this.resolveBatteryRetry;
14179
14121
  this.resolveBatteryRetry = null;
14180
- resolve18?.();
14122
+ resolve20?.();
14181
14123
  }
14182
14124
  finishBatteryCheck(batteryCheck) {
14183
14125
  if (this.batteryCheck !== batteryCheck) return;
@@ -14852,12 +14794,12 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth, fromFileP
14852
14794
  if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
14853
14795
  return { from: fromResolution, to: toResolution, path: [] };
14854
14796
  }
14855
- const path31 = await indexer.findCallPathBySymbolIds(
14797
+ const path33 = await indexer.findCallPathBySymbolIds(
14856
14798
  fromResolution.symbolId,
14857
14799
  toResolution.symbolId,
14858
14800
  maxDepth
14859
14801
  );
14860
- return { from: fromResolution, to: toResolution, path: path31 };
14802
+ return { from: fromResolution, to: toResolution, path: path33 };
14861
14803
  }
14862
14804
  async function runIndexCodebase(projectRoot, host, args, onProgress) {
14863
14805
  const root = getProjectRoot(projectRoot, host);
@@ -15482,7 +15424,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
15482
15424
  const directory = input.directory ?? void 0;
15483
15425
  const tokenBudget = input.tokenBudget ?? void 0;
15484
15426
  if (from && to) {
15485
- const path31 = await getCallGraphPath(
15427
+ const path33 = await getCallGraphPath(
15486
15428
  projectRoot,
15487
15429
  host,
15488
15430
  from,
@@ -15491,25 +15433,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
15491
15433
  fromFilePath,
15492
15434
  toFilePath
15493
15435
  );
15494
- const pathText = formatCallGraphPathResult(path31);
15495
- if (path31.path.length > 0) {
15436
+ const pathText = formatCallGraphPathResult(path33);
15437
+ if (path33.path.length > 0) {
15496
15438
  const fitted2 = fitTextToContextBudget(
15497
15439
  pathText,
15498
15440
  tokenBudget
15499
15441
  );
15500
15442
  return {
15501
15443
  text: fitted2.text,
15502
- details: fittedDetails("path", fitted2, path31.path.length)
15444
+ details: fittedDetails("path", fitted2, path33.path.length)
15503
15445
  };
15504
15446
  }
15505
- if (path31.from.status !== "resolved" || path31.to.status !== "resolved") {
15447
+ if (path33.from.status !== "resolved" || path33.to.status !== "resolved") {
15506
15448
  const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
15507
15449
  return {
15508
15450
  text: fitted2.text,
15509
15451
  details: fittedDetails("path", fitted2, 0)
15510
15452
  };
15511
15453
  }
15512
- const resolvedFrom = path31.from;
15454
+ const resolvedFrom = path33.from;
15513
15455
  const { callers } = await getCallGraphData(projectRoot, host, {
15514
15456
  name: to,
15515
15457
  direction: "callers",
@@ -15986,9 +15928,9 @@ function getRelevantEvidence(query) {
15986
15928
  });
15987
15929
  }
15988
15930
  if (query.expected.acceptableFiles) {
15989
- for (const path31 of query.expected.acceptableFiles) {
15931
+ for (const path33 of query.expected.acceptableFiles) {
15990
15932
  legacyEvidence.push({
15991
- path: path31,
15933
+ path: path33,
15992
15934
  ...query.expected.symbol !== void 0 ? { symbol: query.expected.symbol } : {},
15993
15935
  relevance: 1
15994
15936
  });
@@ -16485,68 +16427,68 @@ function isStringArray4(value) {
16485
16427
  function isNonEmptyString(value) {
16486
16428
  return typeof value === "string" && value.trim().length > 0;
16487
16429
  }
16488
- function asPositiveNumber(value, path31) {
16430
+ function asPositiveNumber(value, path33) {
16489
16431
  if (typeof value !== "number" || Number.isNaN(value) || value < 0) {
16490
- throw new Error(`${path31} must be a non-negative number`);
16432
+ throw new Error(`${path33} must be a non-negative number`);
16491
16433
  }
16492
16434
  return value;
16493
16435
  }
16494
- function parseQueryType(value, path31) {
16436
+ function parseQueryType(value, path33) {
16495
16437
  if (value === "definition" || value === "implementation-intent" || value === "similarity" || value === "keyword-heavy" || value === "conceptual") {
16496
16438
  return value;
16497
16439
  }
16498
16440
  throw new Error(
16499
- `${path31} must be one of: definition, implementation-intent, similarity, keyword-heavy, conceptual`
16441
+ `${path33} must be one of: definition, implementation-intent, similarity, keyword-heavy, conceptual`
16500
16442
  );
16501
16443
  }
16502
- function parseExpectedRoute(value, path31) {
16444
+ function parseExpectedRoute(value, path33) {
16503
16445
  if (value === void 0) return void 0;
16504
16446
  if (value === "search" || value === "definition") return value;
16505
- throw new Error(`${path31} must be one of: search, definition`);
16447
+ throw new Error(`${path33} must be one of: search, definition`);
16506
16448
  }
16507
- function parseExpectedOutcome(value, path31) {
16449
+ function parseExpectedOutcome(value, path33) {
16508
16450
  if (value === void 0) return void 0;
16509
16451
  if (value === "results" || value === "no-results") {
16510
16452
  return value;
16511
16453
  }
16512
- throw new Error(`${path31} must be one of: results, no-results`);
16454
+ throw new Error(`${path33} must be one of: results, no-results`);
16513
16455
  }
16514
- function parseRecoveryExpectation(value, path31) {
16456
+ function parseRecoveryExpectation(value, path33) {
16515
16457
  if (value === void 0) return void 0;
16516
16458
  if (value === "none" || value === "filter-relaxed") {
16517
16459
  return value;
16518
16460
  }
16519
- throw new Error(`${path31} must be one of: none, filter-relaxed`);
16461
+ throw new Error(`${path33} must be one of: none, filter-relaxed`);
16520
16462
  }
16521
- function parseQueryDifficulty(value, path31) {
16463
+ function parseQueryDifficulty(value, path33) {
16522
16464
  if (value === void 0) return void 0;
16523
16465
  if (value === "easy" || value === "medium" || value === "hard") {
16524
16466
  return value;
16525
16467
  }
16526
- throw new Error(`${path31} must be one of: easy, medium, hard`);
16468
+ throw new Error(`${path33} must be one of: easy, medium, hard`);
16527
16469
  }
16528
- function parseQueryTags(value, path31) {
16470
+ function parseQueryTags(value, path33) {
16529
16471
  if (value === void 0) return void 0;
16530
16472
  if (!isStringArray4(value) || value.some((tag) => tag.trim().length === 0)) {
16531
- throw new Error(`${path31} must be an array of non-empty strings`);
16473
+ throw new Error(`${path33} must be an array of non-empty strings`);
16532
16474
  }
16533
16475
  if (value.length > 16) {
16534
- throw new Error(`${path31} must contain at most 16 tags`);
16476
+ throw new Error(`${path33} must contain at most 16 tags`);
16535
16477
  }
16536
16478
  return value;
16537
16479
  }
16538
- function parseQueryArgs(value, path31) {
16480
+ function parseQueryArgs(value, path33) {
16539
16481
  if (value === void 0) return void 0;
16540
16482
  if (!isRecord3(value)) {
16541
- throw new Error(`${path31} must be an object`);
16542
- }
16543
- const symbol = parseStringOrUndefined(value.symbol, `${path31}.symbol`);
16544
- const filePath = parseStringOrUndefined(value.filePath, `${path31}.filePath`);
16545
- const fileType = parseStringOrUndefined(value.fileType, `${path31}.fileType`);
16546
- const directory = parseStringOrUndefined(value.directory, `${path31}.directory`);
16547
- const callerLimit = parsePositiveIntegerOrUndefined(value.callerLimit, `${path31}.callerLimit`);
16548
- const calleeLimit = parsePositiveIntegerOrUndefined(value.calleeLimit, `${path31}.calleeLimit`);
16549
- const tokenBudget = parsePositiveIntegerOrUndefined(value.tokenBudget, `${path31}.tokenBudget`);
16483
+ throw new Error(`${path33} must be an object`);
16484
+ }
16485
+ const symbol = parseStringOrUndefined(value.symbol, `${path33}.symbol`);
16486
+ const filePath = parseStringOrUndefined(value.filePath, `${path33}.filePath`);
16487
+ const fileType = parseStringOrUndefined(value.fileType, `${path33}.fileType`);
16488
+ const directory = parseStringOrUndefined(value.directory, `${path33}.directory`);
16489
+ const callerLimit = parsePositiveIntegerOrUndefined(value.callerLimit, `${path33}.callerLimit`);
16490
+ const calleeLimit = parsePositiveIntegerOrUndefined(value.calleeLimit, `${path33}.calleeLimit`);
16491
+ const tokenBudget = parsePositiveIntegerOrUndefined(value.tokenBudget, `${path33}.tokenBudget`);
16550
16492
  return {
16551
16493
  ...symbol !== void 0 ? { symbol } : {},
16552
16494
  ...filePath !== void 0 ? { filePath } : {},
@@ -16557,50 +16499,50 @@ function parseQueryArgs(value, path31) {
16557
16499
  ...tokenBudget !== void 0 ? { tokenBudget } : {}
16558
16500
  };
16559
16501
  }
16560
- function parsePositiveIntegerOrUndefined(value, path31) {
16502
+ function parsePositiveIntegerOrUndefined(value, path33) {
16561
16503
  if (value === void 0 || value === null) return void 0;
16562
16504
  if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
16563
- throw new Error(`${path31} must be a positive integer`);
16505
+ throw new Error(`${path33} must be a positive integer`);
16564
16506
  }
16565
16507
  return value;
16566
16508
  }
16567
16509
  var SEMVER_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
16568
- function parseSemanticVersion(value, path31) {
16510
+ function parseSemanticVersion(value, path33) {
16569
16511
  if (!isNonEmptyString(value)) {
16570
- throw new Error(`${path31} must be a non-empty string`);
16512
+ throw new Error(`${path33} must be a non-empty string`);
16571
16513
  }
16572
16514
  if (!SEMVER_VERSION_PATTERN.test(value)) {
16573
- throw new Error(`${path31} must be a valid semantic version (MAJOR.MINOR.PATCH)`);
16515
+ throw new Error(`${path33} must be a valid semantic version (MAJOR.MINOR.PATCH)`);
16574
16516
  }
16575
16517
  return value;
16576
16518
  }
16577
- function parseRetrievalMode(value, path31) {
16519
+ function parseRetrievalMode(value, path33) {
16578
16520
  if (value === void 0 || value === "search") return "search";
16579
16521
  if (value === "context" || value === "edit-context") return value;
16580
- throw new Error(`${path31} must be one of: search, context, edit-context`);
16522
+ throw new Error(`${path33} must be one of: search, context, edit-context`);
16581
16523
  }
16582
- function parseStringOrUndefined(value, path31) {
16524
+ function parseStringOrUndefined(value, path33) {
16583
16525
  if (value === void 0 || value === null) return void 0;
16584
16526
  if (!isNonEmptyString(value)) {
16585
- throw new Error(`${path31} must be a non-empty string`);
16527
+ throw new Error(`${path33} must be a non-empty string`);
16586
16528
  }
16587
16529
  return value;
16588
16530
  }
16589
- function parseGradedEvidence(value, path31) {
16531
+ function parseGradedEvidence(value, path33) {
16590
16532
  if (value === void 0) return [];
16591
16533
  if (!Array.isArray(value)) {
16592
- throw new Error(`${path31} must be an array`);
16534
+ throw new Error(`${path33} must be an array`);
16593
16535
  }
16594
16536
  return value.map((entry, index) => {
16595
16537
  if (!isRecord3(entry)) {
16596
- throw new Error(`${path31}[${index}] must be an object`);
16538
+ throw new Error(`${path33}[${index}] must be an object`);
16597
16539
  }
16598
- const evidencePath = parseStringOrUndefined(entry.path, `${path31}[${index}].path`);
16540
+ const evidencePath = parseStringOrUndefined(entry.path, `${path33}[${index}].path`);
16599
16541
  if (evidencePath === void 0) {
16600
- throw new Error(`${path31}[${index}].path is required`);
16542
+ throw new Error(`${path33}[${index}].path is required`);
16601
16543
  }
16602
- const symbol = parseStringOrUndefined(entry.symbol, `${path31}[${index}].symbol`);
16603
- const relevance = parseEvidenceRelevance(entry.relevance, `${path31}[${index}].relevance`);
16544
+ const symbol = parseStringOrUndefined(entry.symbol, `${path33}[${index}].symbol`);
16545
+ const relevance = parseEvidenceRelevance(entry.relevance, `${path33}[${index}].relevance`);
16604
16546
  return {
16605
16547
  path: evidencePath,
16606
16548
  ...symbol !== void 0 ? { symbol } : {},
@@ -16608,27 +16550,27 @@ function parseGradedEvidence(value, path31) {
16608
16550
  };
16609
16551
  });
16610
16552
  }
16611
- function parseEvidenceRelevance(value, path31) {
16553
+ function parseEvidenceRelevance(value, path33) {
16612
16554
  if (value === void 0) {
16613
- throw new Error(`${path31} is required`);
16555
+ throw new Error(`${path33} is required`);
16614
16556
  }
16615
16557
  if (value !== 1 && value !== 2 && value !== 3) {
16616
- throw new Error(`${path31} must be 1, 2, or 3`);
16558
+ throw new Error(`${path33} must be 1, 2, or 3`);
16617
16559
  }
16618
16560
  return value;
16619
16561
  }
16620
- function parseExpectedGraphNeighbor(value, path31) {
16562
+ function parseExpectedGraphNeighbor(value, path33) {
16621
16563
  if (value === void 0) return void 0;
16622
16564
  if (!isRecord3(value)) {
16623
- throw new Error(`${path31} must be an object`);
16565
+ throw new Error(`${path33} must be an object`);
16624
16566
  }
16625
16567
  if (value.direction !== "caller" && value.direction !== "callee") {
16626
- throw new Error(`${path31}.direction must be one of: caller, callee`);
16568
+ throw new Error(`${path33}.direction must be one of: caller, callee`);
16627
16569
  }
16628
- const filePath = parseStringOrUndefined(value.filePath, `${path31}.filePath`);
16629
- const symbol = parseStringOrUndefined(value.symbol, `${path31}.symbol`);
16570
+ const filePath = parseStringOrUndefined(value.filePath, `${path33}.filePath`);
16571
+ const symbol = parseStringOrUndefined(value.symbol, `${path33}.symbol`);
16630
16572
  if (filePath === void 0 && symbol === void 0) {
16631
- throw new Error(`${path31} must include filePath or symbol`);
16573
+ throw new Error(`${path33} must include filePath or symbol`);
16632
16574
  }
16633
16575
  return {
16634
16576
  direction: value.direction,
@@ -16636,9 +16578,9 @@ function parseExpectedGraphNeighbor(value, path31) {
16636
16578
  ...symbol !== void 0 ? { symbol } : {}
16637
16579
  };
16638
16580
  }
16639
- function parseExpected(input, path31) {
16581
+ function parseExpected(input, path33) {
16640
16582
  if (!isRecord3(input)) {
16641
- throw new Error(`${path31} must be an object`);
16583
+ throw new Error(`${path33} must be an object`);
16642
16584
  }
16643
16585
  const filePathRaw = input.filePath;
16644
16586
  const acceptableFilesRaw = input.acceptableFiles;
@@ -16649,29 +16591,29 @@ function parseExpected(input, path31) {
16649
16591
  const recoveryExpectationRaw = input.recoveryExpectation;
16650
16592
  const gradedEvidenceRaw = input.gradedEvidence;
16651
16593
  const graphNeighborRaw = input.graphNeighbor;
16652
- const filePath = parseStringOrUndefined(filePathRaw, `${path31}.filePath`);
16594
+ const filePath = parseStringOrUndefined(filePathRaw, `${path33}.filePath`);
16653
16595
  const acceptableFiles = isStringArray4(acceptableFilesRaw) ? acceptableFilesRaw : void 0;
16654
- const gradedEvidence = parseGradedEvidence(gradedEvidenceRaw, `${path31}.gradedEvidence`);
16655
- const graphNeighbor = parseExpectedGraphNeighbor(graphNeighborRaw, `${path31}.graphNeighbor`);
16656
- const expectedOutcome = parseExpectedOutcome(expectedOutcomeRaw, `${path31}.expectedOutcome`);
16596
+ const gradedEvidence = parseGradedEvidence(gradedEvidenceRaw, `${path33}.gradedEvidence`);
16597
+ const graphNeighbor = parseExpectedGraphNeighbor(graphNeighborRaw, `${path33}.graphNeighbor`);
16598
+ const expectedOutcome = parseExpectedOutcome(expectedOutcomeRaw, `${path33}.expectedOutcome`);
16657
16599
  if (expectedOutcome !== "no-results" && !filePath && (!acceptableFiles || acceptableFiles.length === 0) && gradedEvidence.length === 0) {
16658
16600
  throw new Error(
16659
- `${path31} must include expected.filePath, expected.acceptableFiles, or expected.gradedEvidence`
16601
+ `${path33} must include expected.filePath, expected.acceptableFiles, or expected.gradedEvidence`
16660
16602
  );
16661
16603
  }
16662
16604
  if (acceptableFilesRaw !== void 0 && !isStringArray4(acceptableFilesRaw)) {
16663
- throw new Error(`${path31}.acceptableFiles must be an array of strings`);
16605
+ throw new Error(`${path33}.acceptableFiles must be an array of strings`);
16664
16606
  }
16665
16607
  if (symbolRaw !== void 0 && typeof symbolRaw !== "string") {
16666
- throw new Error(`${path31}.symbol must be a string when provided`);
16608
+ throw new Error(`${path33}.symbol must be a string when provided`);
16667
16609
  }
16668
16610
  if (branchRaw !== void 0 && typeof branchRaw !== "string") {
16669
- throw new Error(`${path31}.branch must be a string when provided`);
16611
+ throw new Error(`${path33}.branch must be a string when provided`);
16670
16612
  }
16671
- const expectedRoute = parseExpectedRoute(expectedRouteRaw, `${path31}.expectedRoute`);
16613
+ const expectedRoute = parseExpectedRoute(expectedRouteRaw, `${path33}.expectedRoute`);
16672
16614
  const recoveryExpectation = parseRecoveryExpectation(
16673
16615
  recoveryExpectationRaw,
16674
- `${path31}.recoveryExpectation`
16616
+ `${path33}.recoveryExpectation`
16675
16617
  );
16676
16618
  return {
16677
16619
  filePath,
@@ -16685,13 +16627,13 @@ function parseExpected(input, path31) {
16685
16627
  ...graphNeighbor !== void 0 ? { graphNeighbor } : {}
16686
16628
  };
16687
16629
  }
16688
- function parseQueryLanguage(value, path31) {
16689
- return parseStringOrUndefined(value, path31);
16630
+ function parseQueryLanguage(value, path33) {
16631
+ return parseStringOrUndefined(value, path33);
16690
16632
  }
16691
16633
  function parseQuery(input, index) {
16692
- const path31 = `queries[${index}]`;
16634
+ const path33 = `queries[${index}]`;
16693
16635
  if (!isRecord3(input)) {
16694
- throw new Error(`${path31} must be an object`);
16636
+ throw new Error(`${path33} must be an object`);
16695
16637
  }
16696
16638
  const id = input.id;
16697
16639
  const query = input.query;
@@ -16703,21 +16645,21 @@ function parseQuery(input, index) {
16703
16645
  const tags = input.tags;
16704
16646
  const args = input.args;
16705
16647
  if (typeof id !== "string" || id.trim().length === 0) {
16706
- throw new Error(`${path31}.id must be a non-empty string`);
16648
+ throw new Error(`${path33}.id must be a non-empty string`);
16707
16649
  }
16708
16650
  if (typeof query !== "string" || query.trim().length === 0) {
16709
- throw new Error(`${path31}.query must be a non-empty string`);
16651
+ throw new Error(`${path33}.query must be a non-empty string`);
16710
16652
  }
16711
16653
  return {
16712
16654
  id,
16713
16655
  query,
16714
- queryType: parseQueryType(queryType, `${path31}.queryType`),
16715
- retrievalMode: parseRetrievalMode(retrievalMode, `${path31}.retrievalMode`),
16716
- language: parseQueryLanguage(language, `${path31}.language`),
16717
- difficulty: parseQueryDifficulty(difficulty, `${path31}.difficulty`),
16718
- args: parseQueryArgs(args, `${path31}.args`),
16719
- tags: parseQueryTags(tags, `${path31}.tags`),
16720
- expected: parseExpected(expected, `${path31}.expected`)
16656
+ queryType: parseQueryType(queryType, `${path33}.queryType`),
16657
+ retrievalMode: parseRetrievalMode(retrievalMode, `${path33}.retrievalMode`),
16658
+ language: parseQueryLanguage(language, `${path33}.language`),
16659
+ difficulty: parseQueryDifficulty(difficulty, `${path33}.difficulty`),
16660
+ args: parseQueryArgs(args, `${path33}.args`),
16661
+ tags: parseQueryTags(tags, `${path33}.tags`),
16662
+ expected: parseExpected(expected, `${path33}.expected`)
16721
16663
  };
16722
16664
  }
16723
16665
  function parseGoldenDataset(raw, sourceLabel) {
@@ -17684,7 +17626,7 @@ async function executeCallGraph(projectRoot, host, args) {
17684
17626
  return { text: formatCallGraphResult(await getCallGraphData(projectRoot, host, args)) };
17685
17627
  }
17686
17628
  async function executeCallGraphPath(projectRoot, host, args) {
17687
- const path31 = await getCallGraphPath(
17629
+ const path33 = await getCallGraphPath(
17688
17630
  projectRoot,
17689
17631
  host,
17690
17632
  args.from,
@@ -17693,7 +17635,7 @@ async function executeCallGraphPath(projectRoot, host, args) {
17693
17635
  args.fromFilePath,
17694
17636
  args.toFilePath
17695
17637
  );
17696
- return { text: formatCallGraphPathResult(path31) };
17638
+ return { text: formatCallGraphPathResult(path33) };
17697
17639
  }
17698
17640
  async function executeCodeCommunities(projectRoot, host, args) {
17699
17641
  const result = await getCodeCommunities(projectRoot, host, args);
@@ -18272,7 +18214,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
18272
18214
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
18273
18215
  const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
18274
18216
  if (wantBigintFsStats) {
18275
- this._stat = (path31) => statMethod(path31, { bigint: true });
18217
+ this._stat = (path33) => statMethod(path33, { bigint: true });
18276
18218
  } else {
18277
18219
  this._stat = statMethod;
18278
18220
  }
@@ -18297,8 +18239,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
18297
18239
  const par = this.parent;
18298
18240
  const fil = par && par.files;
18299
18241
  if (fil && fil.length > 0) {
18300
- const { path: path31, depth } = par;
18301
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path31));
18242
+ const { path: path33, depth } = par;
18243
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path33));
18302
18244
  const awaited = await Promise.all(slice);
18303
18245
  for (const entry of awaited) {
18304
18246
  if (!entry)
@@ -18338,20 +18280,20 @@ var ReaddirpStream = class extends import_node_stream.Readable {
18338
18280
  this.reading = false;
18339
18281
  }
18340
18282
  }
18341
- async _exploreDir(path31, depth) {
18283
+ async _exploreDir(path33, depth) {
18342
18284
  let files;
18343
18285
  try {
18344
- files = await (0, import_promises.readdir)(path31, this._rdOptions);
18286
+ files = await (0, import_promises.readdir)(path33, this._rdOptions);
18345
18287
  } catch (error) {
18346
18288
  this._onError(error);
18347
18289
  }
18348
- return { files, depth, path: path31 };
18290
+ return { files, depth, path: path33 };
18349
18291
  }
18350
- async _formatEntry(dirent, path31) {
18292
+ async _formatEntry(dirent, path33) {
18351
18293
  let entry;
18352
18294
  const basename8 = this._isDirent ? dirent.name : dirent;
18353
18295
  try {
18354
- const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path31, basename8));
18296
+ const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path33, basename8));
18355
18297
  entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename8 };
18356
18298
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
18357
18299
  } catch (err) {
@@ -18751,16 +18693,16 @@ var delFromSet = (main, prop, item) => {
18751
18693
  };
18752
18694
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
18753
18695
  var FsWatchInstances = /* @__PURE__ */ new Map();
18754
- function createFsWatchInstance(path31, options, listener, errHandler, emitRaw) {
18696
+ function createFsWatchInstance(path33, options, listener, errHandler, emitRaw) {
18755
18697
  const handleEvent = (rawEvent, evPath) => {
18756
- listener(path31);
18757
- emitRaw(rawEvent, evPath, { watchedPath: path31 });
18758
- if (evPath && path31 !== evPath) {
18759
- fsWatchBroadcast(sp.resolve(path31, evPath), KEY_LISTENERS, sp.join(path31, evPath));
18698
+ listener(path33);
18699
+ emitRaw(rawEvent, evPath, { watchedPath: path33 });
18700
+ if (evPath && path33 !== evPath) {
18701
+ fsWatchBroadcast(sp.resolve(path33, evPath), KEY_LISTENERS, sp.join(path33, evPath));
18760
18702
  }
18761
18703
  };
18762
18704
  try {
18763
- return (0, import_node_fs.watch)(path31, {
18705
+ return (0, import_node_fs.watch)(path33, {
18764
18706
  persistent: options.persistent
18765
18707
  }, handleEvent);
18766
18708
  } catch (error) {
@@ -18776,12 +18718,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
18776
18718
  listener(val1, val2, val3);
18777
18719
  });
18778
18720
  };
18779
- var setFsWatchListener = (path31, fullPath, options, handlers) => {
18721
+ var setFsWatchListener = (path33, fullPath, options, handlers) => {
18780
18722
  const { listener, errHandler, rawEmitter } = handlers;
18781
18723
  let cont = FsWatchInstances.get(fullPath);
18782
18724
  let watcher;
18783
18725
  if (!options.persistent) {
18784
- watcher = createFsWatchInstance(path31, options, listener, errHandler, rawEmitter);
18726
+ watcher = createFsWatchInstance(path33, options, listener, errHandler, rawEmitter);
18785
18727
  if (!watcher)
18786
18728
  return;
18787
18729
  return watcher.close.bind(watcher);
@@ -18792,7 +18734,7 @@ var setFsWatchListener = (path31, fullPath, options, handlers) => {
18792
18734
  addAndConvert(cont, KEY_RAW, rawEmitter);
18793
18735
  } else {
18794
18736
  watcher = createFsWatchInstance(
18795
- path31,
18737
+ path33,
18796
18738
  options,
18797
18739
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
18798
18740
  errHandler,
@@ -18807,7 +18749,7 @@ var setFsWatchListener = (path31, fullPath, options, handlers) => {
18807
18749
  cont.watcherUnusable = true;
18808
18750
  if (isWindows && error.code === "EPERM") {
18809
18751
  try {
18810
- const fd = await (0, import_promises2.open)(path31, "r");
18752
+ const fd = await (0, import_promises2.open)(path33, "r");
18811
18753
  await fd.close();
18812
18754
  broadcastErr(error);
18813
18755
  } catch (err) {
@@ -18838,7 +18780,7 @@ var setFsWatchListener = (path31, fullPath, options, handlers) => {
18838
18780
  };
18839
18781
  };
18840
18782
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
18841
- var setFsWatchFileListener = (path31, fullPath, options, handlers) => {
18783
+ var setFsWatchFileListener = (path33, fullPath, options, handlers) => {
18842
18784
  const { listener, rawEmitter } = handlers;
18843
18785
  let cont = FsWatchFileInstances.get(fullPath);
18844
18786
  const copts = cont && cont.options;
@@ -18860,7 +18802,7 @@ var setFsWatchFileListener = (path31, fullPath, options, handlers) => {
18860
18802
  });
18861
18803
  const currmtime = curr.mtimeMs;
18862
18804
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
18863
- foreach(cont.listeners, (listener2) => listener2(path31, curr));
18805
+ foreach(cont.listeners, (listener2) => listener2(path33, curr));
18864
18806
  }
18865
18807
  })
18866
18808
  };
@@ -18890,13 +18832,13 @@ var NodeFsHandler = class {
18890
18832
  * @param listener on fs change
18891
18833
  * @returns closer for the watcher instance
18892
18834
  */
18893
- _watchWithNodeFs(path31, listener) {
18835
+ _watchWithNodeFs(path33, listener) {
18894
18836
  const opts = this.fsw.options;
18895
- const directory = sp.dirname(path31);
18896
- const basename8 = sp.basename(path31);
18837
+ const directory = sp.dirname(path33);
18838
+ const basename8 = sp.basename(path33);
18897
18839
  const parent = this.fsw._getWatchedDir(directory);
18898
18840
  parent.add(basename8);
18899
- const absolutePath = sp.resolve(path31);
18841
+ const absolutePath = sp.resolve(path33);
18900
18842
  const options = {
18901
18843
  persistent: opts.persistent
18902
18844
  };
@@ -18906,12 +18848,12 @@ var NodeFsHandler = class {
18906
18848
  if (opts.usePolling) {
18907
18849
  const enableBin = opts.interval !== opts.binaryInterval;
18908
18850
  options.interval = enableBin && isBinaryPath(basename8) ? opts.binaryInterval : opts.interval;
18909
- closer = setFsWatchFileListener(path31, absolutePath, options, {
18851
+ closer = setFsWatchFileListener(path33, absolutePath, options, {
18910
18852
  listener,
18911
18853
  rawEmitter: this.fsw._emitRaw
18912
18854
  });
18913
18855
  } else {
18914
- closer = setFsWatchListener(path31, absolutePath, options, {
18856
+ closer = setFsWatchListener(path33, absolutePath, options, {
18915
18857
  listener,
18916
18858
  errHandler: this._boundHandleError,
18917
18859
  rawEmitter: this.fsw._emitRaw
@@ -18933,7 +18875,7 @@ var NodeFsHandler = class {
18933
18875
  let prevStats = stats;
18934
18876
  if (parent.has(basename8))
18935
18877
  return;
18936
- const listener = async (path31, newStats) => {
18878
+ const listener = async (path33, newStats) => {
18937
18879
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
18938
18880
  return;
18939
18881
  if (!newStats || newStats.mtimeMs === 0) {
@@ -18947,11 +18889,11 @@ var NodeFsHandler = class {
18947
18889
  this.fsw._emit(EV.CHANGE, file, newStats2);
18948
18890
  }
18949
18891
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
18950
- this.fsw._closeFile(path31);
18892
+ this.fsw._closeFile(path33);
18951
18893
  prevStats = newStats2;
18952
18894
  const closer2 = this._watchWithNodeFs(file, listener);
18953
18895
  if (closer2)
18954
- this.fsw._addPathCloser(path31, closer2);
18896
+ this.fsw._addPathCloser(path33, closer2);
18955
18897
  } else {
18956
18898
  prevStats = newStats2;
18957
18899
  }
@@ -18983,7 +18925,7 @@ var NodeFsHandler = class {
18983
18925
  * @param item basename of this item
18984
18926
  * @returns true if no more processing is needed for this entry.
18985
18927
  */
18986
- async _handleSymlink(entry, directory, path31, item) {
18928
+ async _handleSymlink(entry, directory, path33, item) {
18987
18929
  if (this.fsw.closed) {
18988
18930
  return;
18989
18931
  }
@@ -18993,7 +18935,7 @@ var NodeFsHandler = class {
18993
18935
  this.fsw._incrReadyCount();
18994
18936
  let linkPath;
18995
18937
  try {
18996
- linkPath = await (0, import_promises2.realpath)(path31);
18938
+ linkPath = await (0, import_promises2.realpath)(path33);
18997
18939
  } catch (e) {
18998
18940
  this.fsw._emitReady();
18999
18941
  return true;
@@ -19003,12 +18945,12 @@ var NodeFsHandler = class {
19003
18945
  if (dir.has(item)) {
19004
18946
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
19005
18947
  this.fsw._symlinkPaths.set(full, linkPath);
19006
- this.fsw._emit(EV.CHANGE, path31, entry.stats);
18948
+ this.fsw._emit(EV.CHANGE, path33, entry.stats);
19007
18949
  }
19008
18950
  } else {
19009
18951
  dir.add(item);
19010
18952
  this.fsw._symlinkPaths.set(full, linkPath);
19011
- this.fsw._emit(EV.ADD, path31, entry.stats);
18953
+ this.fsw._emit(EV.ADD, path33, entry.stats);
19012
18954
  }
19013
18955
  this.fsw._emitReady();
19014
18956
  return true;
@@ -19038,9 +18980,9 @@ var NodeFsHandler = class {
19038
18980
  return;
19039
18981
  }
19040
18982
  const item = entry.path;
19041
- let path31 = sp.join(directory, item);
18983
+ let path33 = sp.join(directory, item);
19042
18984
  current.add(item);
19043
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path31, item)) {
18985
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path33, item)) {
19044
18986
  return;
19045
18987
  }
19046
18988
  if (this.fsw.closed) {
@@ -19049,11 +18991,11 @@ var NodeFsHandler = class {
19049
18991
  }
19050
18992
  if (item === target || !target && !previous.has(item)) {
19051
18993
  this.fsw._incrReadyCount();
19052
- path31 = sp.join(dir, sp.relative(dir, path31));
19053
- this._addToNodeFs(path31, initialAdd, wh, depth + 1);
18994
+ path33 = sp.join(dir, sp.relative(dir, path33));
18995
+ this._addToNodeFs(path33, initialAdd, wh, depth + 1);
19054
18996
  }
19055
18997
  }).on(EV.ERROR, this._boundHandleError);
19056
- return new Promise((resolve18, reject) => {
18998
+ return new Promise((resolve20, reject) => {
19057
18999
  if (!stream)
19058
19000
  return reject();
19059
19001
  stream.once(STR_END, () => {
@@ -19062,7 +19004,7 @@ var NodeFsHandler = class {
19062
19004
  return;
19063
19005
  }
19064
19006
  const wasThrottled = throttler ? throttler.clear() : false;
19065
- resolve18(void 0);
19007
+ resolve20(void 0);
19066
19008
  previous.getChildren().filter((item) => {
19067
19009
  return item !== directory && !current.has(item);
19068
19010
  }).forEach((item) => {
@@ -19119,13 +19061,13 @@ var NodeFsHandler = class {
19119
19061
  * @param depth Child path actually targeted for watch
19120
19062
  * @param target Child path actually targeted for watch
19121
19063
  */
19122
- async _addToNodeFs(path31, initialAdd, priorWh, depth, target) {
19064
+ async _addToNodeFs(path33, initialAdd, priorWh, depth, target) {
19123
19065
  const ready = this.fsw._emitReady;
19124
- if (this.fsw._isIgnored(path31) || this.fsw.closed) {
19066
+ if (this.fsw._isIgnored(path33) || this.fsw.closed) {
19125
19067
  ready();
19126
19068
  return false;
19127
19069
  }
19128
- const wh = this.fsw._getWatchHelpers(path31);
19070
+ const wh = this.fsw._getWatchHelpers(path33);
19129
19071
  if (priorWh) {
19130
19072
  wh.filterPath = (entry) => priorWh.filterPath(entry);
19131
19073
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -19141,8 +19083,8 @@ var NodeFsHandler = class {
19141
19083
  const follow = this.fsw.options.followSymlinks;
19142
19084
  let closer;
19143
19085
  if (stats.isDirectory()) {
19144
- const absPath = sp.resolve(path31);
19145
- const targetPath = follow ? await (0, import_promises2.realpath)(path31) : path31;
19086
+ const absPath = sp.resolve(path33);
19087
+ const targetPath = follow ? await (0, import_promises2.realpath)(path33) : path33;
19146
19088
  if (this.fsw.closed)
19147
19089
  return;
19148
19090
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -19152,29 +19094,29 @@ var NodeFsHandler = class {
19152
19094
  this.fsw._symlinkPaths.set(absPath, targetPath);
19153
19095
  }
19154
19096
  } else if (stats.isSymbolicLink()) {
19155
- const targetPath = follow ? await (0, import_promises2.realpath)(path31) : path31;
19097
+ const targetPath = follow ? await (0, import_promises2.realpath)(path33) : path33;
19156
19098
  if (this.fsw.closed)
19157
19099
  return;
19158
19100
  const parent = sp.dirname(wh.watchPath);
19159
19101
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
19160
19102
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
19161
- closer = await this._handleDir(parent, stats, initialAdd, depth, path31, wh, targetPath);
19103
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path33, wh, targetPath);
19162
19104
  if (this.fsw.closed)
19163
19105
  return;
19164
19106
  if (targetPath !== void 0) {
19165
- this.fsw._symlinkPaths.set(sp.resolve(path31), targetPath);
19107
+ this.fsw._symlinkPaths.set(sp.resolve(path33), targetPath);
19166
19108
  }
19167
19109
  } else {
19168
19110
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
19169
19111
  }
19170
19112
  ready();
19171
19113
  if (closer)
19172
- this.fsw._addPathCloser(path31, closer);
19114
+ this.fsw._addPathCloser(path33, closer);
19173
19115
  return false;
19174
19116
  } catch (error) {
19175
19117
  if (this.fsw._handleError(error)) {
19176
19118
  ready();
19177
- return path31;
19119
+ return path33;
19178
19120
  }
19179
19121
  }
19180
19122
  }
@@ -19206,35 +19148,35 @@ function createPattern(matcher) {
19206
19148
  if (matcher.path === string)
19207
19149
  return true;
19208
19150
  if (matcher.recursive) {
19209
- const relative12 = sp2.relative(matcher.path, string);
19210
- if (!relative12) {
19151
+ const relative14 = sp2.relative(matcher.path, string);
19152
+ if (!relative14) {
19211
19153
  return false;
19212
19154
  }
19213
- return !relative12.startsWith("..") && !sp2.isAbsolute(relative12);
19155
+ return !relative14.startsWith("..") && !sp2.isAbsolute(relative14);
19214
19156
  }
19215
19157
  return false;
19216
19158
  };
19217
19159
  }
19218
19160
  return () => false;
19219
19161
  }
19220
- function normalizePath3(path31) {
19221
- if (typeof path31 !== "string")
19162
+ function normalizePath3(path33) {
19163
+ if (typeof path33 !== "string")
19222
19164
  throw new Error("string expected");
19223
- path31 = sp2.normalize(path31);
19224
- path31 = path31.replace(/\\/g, "/");
19165
+ path33 = sp2.normalize(path33);
19166
+ path33 = path33.replace(/\\/g, "/");
19225
19167
  let prepend = false;
19226
- if (path31.startsWith("//"))
19168
+ if (path33.startsWith("//"))
19227
19169
  prepend = true;
19228
- path31 = path31.replace(DOUBLE_SLASH_RE, "/");
19170
+ path33 = path33.replace(DOUBLE_SLASH_RE, "/");
19229
19171
  if (prepend)
19230
- path31 = "/" + path31;
19231
- return path31;
19172
+ path33 = "/" + path33;
19173
+ return path33;
19232
19174
  }
19233
19175
  function matchPatterns(patterns, testString, stats) {
19234
- const path31 = normalizePath3(testString);
19176
+ const path33 = normalizePath3(testString);
19235
19177
  for (let index = 0; index < patterns.length; index++) {
19236
19178
  const pattern = patterns[index];
19237
- if (pattern(path31, stats)) {
19179
+ if (pattern(path33, stats)) {
19238
19180
  return true;
19239
19181
  }
19240
19182
  }
@@ -19272,19 +19214,19 @@ var toUnix = (string) => {
19272
19214
  }
19273
19215
  return str;
19274
19216
  };
19275
- var normalizePathToUnix = (path31) => toUnix(sp2.normalize(toUnix(path31)));
19276
- var normalizeIgnored = (cwd = "") => (path31) => {
19277
- if (typeof path31 === "string") {
19278
- return normalizePathToUnix(sp2.isAbsolute(path31) ? path31 : sp2.join(cwd, path31));
19217
+ var normalizePathToUnix = (path33) => toUnix(sp2.normalize(toUnix(path33)));
19218
+ var normalizeIgnored = (cwd = "") => (path33) => {
19219
+ if (typeof path33 === "string") {
19220
+ return normalizePathToUnix(sp2.isAbsolute(path33) ? path33 : sp2.join(cwd, path33));
19279
19221
  } else {
19280
- return path31;
19222
+ return path33;
19281
19223
  }
19282
19224
  };
19283
- var getAbsolutePath = (path31, cwd) => {
19284
- if (sp2.isAbsolute(path31)) {
19285
- return path31;
19225
+ var getAbsolutePath = (path33, cwd) => {
19226
+ if (sp2.isAbsolute(path33)) {
19227
+ return path33;
19286
19228
  }
19287
- return sp2.join(cwd, path31);
19229
+ return sp2.join(cwd, path33);
19288
19230
  };
19289
19231
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
19290
19232
  var DirEntry = class {
@@ -19349,10 +19291,10 @@ var WatchHelper = class {
19349
19291
  dirParts;
19350
19292
  followSymlinks;
19351
19293
  statMethod;
19352
- constructor(path31, follow, fsw) {
19294
+ constructor(path33, follow, fsw) {
19353
19295
  this.fsw = fsw;
19354
- const watchPath = path31;
19355
- this.path = path31 = path31.replace(REPLACER_RE, "");
19296
+ const watchPath = path33;
19297
+ this.path = path33 = path33.replace(REPLACER_RE, "");
19356
19298
  this.watchPath = watchPath;
19357
19299
  this.fullWatchPath = sp2.resolve(watchPath);
19358
19300
  this.dirParts = [];
@@ -19492,20 +19434,20 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19492
19434
  this._closePromise = void 0;
19493
19435
  let paths = unifyPaths(paths_);
19494
19436
  if (cwd) {
19495
- paths = paths.map((path31) => {
19496
- const absPath = getAbsolutePath(path31, cwd);
19437
+ paths = paths.map((path33) => {
19438
+ const absPath = getAbsolutePath(path33, cwd);
19497
19439
  return absPath;
19498
19440
  });
19499
19441
  }
19500
- paths.forEach((path31) => {
19501
- this._removeIgnoredPath(path31);
19442
+ paths.forEach((path33) => {
19443
+ this._removeIgnoredPath(path33);
19502
19444
  });
19503
19445
  this._userIgnored = void 0;
19504
19446
  if (!this._readyCount)
19505
19447
  this._readyCount = 0;
19506
19448
  this._readyCount += paths.length;
19507
- Promise.all(paths.map(async (path31) => {
19508
- const res = await this._nodeFsHandler._addToNodeFs(path31, !_internal, void 0, 0, _origAdd);
19449
+ Promise.all(paths.map(async (path33) => {
19450
+ const res = await this._nodeFsHandler._addToNodeFs(path33, !_internal, void 0, 0, _origAdd);
19509
19451
  if (res)
19510
19452
  this._emitReady();
19511
19453
  return res;
@@ -19527,17 +19469,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19527
19469
  return this;
19528
19470
  const paths = unifyPaths(paths_);
19529
19471
  const { cwd } = this.options;
19530
- paths.forEach((path31) => {
19531
- if (!sp2.isAbsolute(path31) && !this._closers.has(path31)) {
19472
+ paths.forEach((path33) => {
19473
+ if (!sp2.isAbsolute(path33) && !this._closers.has(path33)) {
19532
19474
  if (cwd)
19533
- path31 = sp2.join(cwd, path31);
19534
- path31 = sp2.resolve(path31);
19475
+ path33 = sp2.join(cwd, path33);
19476
+ path33 = sp2.resolve(path33);
19535
19477
  }
19536
- this._closePath(path31);
19537
- this._addIgnoredPath(path31);
19538
- if (this._watched.has(path31)) {
19478
+ this._closePath(path33);
19479
+ this._addIgnoredPath(path33);
19480
+ if (this._watched.has(path33)) {
19539
19481
  this._addIgnoredPath({
19540
- path: path31,
19482
+ path: path33,
19541
19483
  recursive: true
19542
19484
  });
19543
19485
  }
@@ -19601,38 +19543,38 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19601
19543
  * @param stats arguments to be passed with event
19602
19544
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
19603
19545
  */
19604
- async _emit(event, path31, stats) {
19546
+ async _emit(event, path33, stats) {
19605
19547
  if (this.closed)
19606
19548
  return;
19607
19549
  const opts = this.options;
19608
19550
  if (isWindows)
19609
- path31 = sp2.normalize(path31);
19551
+ path33 = sp2.normalize(path33);
19610
19552
  if (opts.cwd)
19611
- path31 = sp2.relative(opts.cwd, path31);
19612
- const args = [path31];
19553
+ path33 = sp2.relative(opts.cwd, path33);
19554
+ const args = [path33];
19613
19555
  if (stats != null)
19614
19556
  args.push(stats);
19615
19557
  const awf = opts.awaitWriteFinish;
19616
19558
  let pw;
19617
- if (awf && (pw = this._pendingWrites.get(path31))) {
19559
+ if (awf && (pw = this._pendingWrites.get(path33))) {
19618
19560
  pw.lastChange = /* @__PURE__ */ new Date();
19619
19561
  return this;
19620
19562
  }
19621
19563
  if (opts.atomic) {
19622
19564
  if (event === EVENTS.UNLINK) {
19623
- this._pendingUnlinks.set(path31, [event, ...args]);
19565
+ this._pendingUnlinks.set(path33, [event, ...args]);
19624
19566
  setTimeout(() => {
19625
- this._pendingUnlinks.forEach((entry, path32) => {
19567
+ this._pendingUnlinks.forEach((entry, path34) => {
19626
19568
  this.emit(...entry);
19627
19569
  this.emit(EVENTS.ALL, ...entry);
19628
- this._pendingUnlinks.delete(path32);
19570
+ this._pendingUnlinks.delete(path34);
19629
19571
  });
19630
19572
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
19631
19573
  return this;
19632
19574
  }
19633
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path31)) {
19575
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path33)) {
19634
19576
  event = EVENTS.CHANGE;
19635
- this._pendingUnlinks.delete(path31);
19577
+ this._pendingUnlinks.delete(path33);
19636
19578
  }
19637
19579
  }
19638
19580
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -19650,16 +19592,16 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19650
19592
  this.emitWithAll(event, args);
19651
19593
  }
19652
19594
  };
19653
- this._awaitWriteFinish(path31, awf.stabilityThreshold, event, awfEmit);
19595
+ this._awaitWriteFinish(path33, awf.stabilityThreshold, event, awfEmit);
19654
19596
  return this;
19655
19597
  }
19656
19598
  if (event === EVENTS.CHANGE) {
19657
- const isThrottled = !this._throttle(EVENTS.CHANGE, path31, 50);
19599
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path33, 50);
19658
19600
  if (isThrottled)
19659
19601
  return this;
19660
19602
  }
19661
19603
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
19662
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path31) : path31;
19604
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path33) : path33;
19663
19605
  let stats2;
19664
19606
  try {
19665
19607
  stats2 = await (0, import_promises3.stat)(fullPath);
@@ -19690,23 +19632,23 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19690
19632
  * @param timeout duration of time to suppress duplicate actions
19691
19633
  * @returns tracking object or false if action should be suppressed
19692
19634
  */
19693
- _throttle(actionType, path31, timeout) {
19635
+ _throttle(actionType, path33, timeout) {
19694
19636
  if (!this._throttled.has(actionType)) {
19695
19637
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
19696
19638
  }
19697
19639
  const action = this._throttled.get(actionType);
19698
19640
  if (!action)
19699
19641
  throw new Error("invalid throttle");
19700
- const actionPath = action.get(path31);
19642
+ const actionPath = action.get(path33);
19701
19643
  if (actionPath) {
19702
19644
  actionPath.count++;
19703
19645
  return false;
19704
19646
  }
19705
19647
  let timeoutObject;
19706
19648
  const clear = () => {
19707
- const item = action.get(path31);
19649
+ const item = action.get(path33);
19708
19650
  const count = item ? item.count : 0;
19709
- action.delete(path31);
19651
+ action.delete(path33);
19710
19652
  clearTimeout(timeoutObject);
19711
19653
  if (item)
19712
19654
  clearTimeout(item.timeoutObject);
@@ -19714,7 +19656,7 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19714
19656
  };
19715
19657
  timeoutObject = setTimeout(clear, timeout);
19716
19658
  const thr = { timeoutObject, clear, count: 0 };
19717
- action.set(path31, thr);
19659
+ action.set(path33, thr);
19718
19660
  return thr;
19719
19661
  }
19720
19662
  _incrReadyCount() {
@@ -19728,44 +19670,44 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19728
19670
  * @param event
19729
19671
  * @param awfEmit Callback to be called when ready for event to be emitted.
19730
19672
  */
19731
- _awaitWriteFinish(path31, threshold, event, awfEmit) {
19673
+ _awaitWriteFinish(path33, threshold, event, awfEmit) {
19732
19674
  const awf = this.options.awaitWriteFinish;
19733
19675
  if (typeof awf !== "object")
19734
19676
  return;
19735
19677
  const pollInterval = awf.pollInterval;
19736
19678
  let timeoutHandler;
19737
- let fullPath = path31;
19738
- if (this.options.cwd && !sp2.isAbsolute(path31)) {
19739
- fullPath = sp2.join(this.options.cwd, path31);
19679
+ let fullPath = path33;
19680
+ if (this.options.cwd && !sp2.isAbsolute(path33)) {
19681
+ fullPath = sp2.join(this.options.cwd, path33);
19740
19682
  }
19741
19683
  const now2 = /* @__PURE__ */ new Date();
19742
19684
  const writes = this._pendingWrites;
19743
19685
  function awaitWriteFinishFn(prevStat) {
19744
19686
  (0, import_node_fs2.stat)(fullPath, (err, curStat) => {
19745
- if (err || !writes.has(path31)) {
19687
+ if (err || !writes.has(path33)) {
19746
19688
  if (err && err.code !== "ENOENT")
19747
19689
  awfEmit(err);
19748
19690
  return;
19749
19691
  }
19750
19692
  const now3 = Number(/* @__PURE__ */ new Date());
19751
19693
  if (prevStat && curStat.size !== prevStat.size) {
19752
- writes.get(path31).lastChange = now3;
19694
+ writes.get(path33).lastChange = now3;
19753
19695
  }
19754
- const pw = writes.get(path31);
19696
+ const pw = writes.get(path33);
19755
19697
  const df = now3 - pw.lastChange;
19756
19698
  if (df >= threshold) {
19757
- writes.delete(path31);
19699
+ writes.delete(path33);
19758
19700
  awfEmit(void 0, curStat);
19759
19701
  } else {
19760
19702
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
19761
19703
  }
19762
19704
  });
19763
19705
  }
19764
- if (!writes.has(path31)) {
19765
- writes.set(path31, {
19706
+ if (!writes.has(path33)) {
19707
+ writes.set(path33, {
19766
19708
  lastChange: now2,
19767
19709
  cancelWait: () => {
19768
- writes.delete(path31);
19710
+ writes.delete(path33);
19769
19711
  clearTimeout(timeoutHandler);
19770
19712
  return event;
19771
19713
  }
@@ -19776,8 +19718,8 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19776
19718
  /**
19777
19719
  * Determines whether user has asked to ignore this path.
19778
19720
  */
19779
- _isIgnored(path31, stats) {
19780
- if (this.options.atomic && DOT_RE.test(path31))
19721
+ _isIgnored(path33, stats) {
19722
+ if (this.options.atomic && DOT_RE.test(path33))
19781
19723
  return true;
19782
19724
  if (!this._userIgnored) {
19783
19725
  const { cwd } = this.options;
@@ -19787,17 +19729,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19787
19729
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
19788
19730
  this._userIgnored = anymatch(list, void 0);
19789
19731
  }
19790
- return this._userIgnored(path31, stats);
19732
+ return this._userIgnored(path33, stats);
19791
19733
  }
19792
- _isntIgnored(path31, stat4) {
19793
- return !this._isIgnored(path31, stat4);
19734
+ _isntIgnored(path33, stat5) {
19735
+ return !this._isIgnored(path33, stat5);
19794
19736
  }
19795
19737
  /**
19796
19738
  * Provides a set of common helpers and properties relating to symlink handling.
19797
19739
  * @param path file or directory pattern being watched
19798
19740
  */
19799
- _getWatchHelpers(path31) {
19800
- return new WatchHelper(path31, this.options.followSymlinks, this);
19741
+ _getWatchHelpers(path33) {
19742
+ return new WatchHelper(path33, this.options.followSymlinks, this);
19801
19743
  }
19802
19744
  // Directory helpers
19803
19745
  // -----------------
@@ -19829,63 +19771,63 @@ var FSWatcher = class extends import_node_events.EventEmitter {
19829
19771
  * @param item base path of item/directory
19830
19772
  */
19831
19773
  _remove(directory, item, isDirectory) {
19832
- const path31 = sp2.join(directory, item);
19833
- const fullPath = sp2.resolve(path31);
19834
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path31) || this._watched.has(fullPath);
19835
- if (!this._throttle("remove", path31, 100))
19774
+ const path33 = sp2.join(directory, item);
19775
+ const fullPath = sp2.resolve(path33);
19776
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path33) || this._watched.has(fullPath);
19777
+ if (!this._throttle("remove", path33, 100))
19836
19778
  return;
19837
19779
  if (!isDirectory && this._watched.size === 1) {
19838
19780
  this.add(directory, item, true);
19839
19781
  }
19840
- const wp = this._getWatchedDir(path31);
19782
+ const wp = this._getWatchedDir(path33);
19841
19783
  const nestedDirectoryChildren = wp.getChildren();
19842
- nestedDirectoryChildren.forEach((nested) => this._remove(path31, nested));
19784
+ nestedDirectoryChildren.forEach((nested) => this._remove(path33, nested));
19843
19785
  const parent = this._getWatchedDir(directory);
19844
19786
  const wasTracked = parent.has(item);
19845
19787
  parent.remove(item);
19846
19788
  if (this._symlinkPaths.has(fullPath)) {
19847
19789
  this._symlinkPaths.delete(fullPath);
19848
19790
  }
19849
- let relPath = path31;
19791
+ let relPath = path33;
19850
19792
  if (this.options.cwd)
19851
- relPath = sp2.relative(this.options.cwd, path31);
19793
+ relPath = sp2.relative(this.options.cwd, path33);
19852
19794
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
19853
19795
  const event = this._pendingWrites.get(relPath).cancelWait();
19854
19796
  if (event === EVENTS.ADD)
19855
19797
  return;
19856
19798
  }
19857
- this._watched.delete(path31);
19799
+ this._watched.delete(path33);
19858
19800
  this._watched.delete(fullPath);
19859
19801
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
19860
- if (wasTracked && !this._isIgnored(path31))
19861
- this._emit(eventName, path31);
19862
- this._closePath(path31);
19802
+ if (wasTracked && !this._isIgnored(path33))
19803
+ this._emit(eventName, path33);
19804
+ this._closePath(path33);
19863
19805
  }
19864
19806
  /**
19865
19807
  * Closes all watchers for a path
19866
19808
  */
19867
- _closePath(path31) {
19868
- this._closeFile(path31);
19869
- const dir = sp2.dirname(path31);
19870
- this._getWatchedDir(dir).remove(sp2.basename(path31));
19809
+ _closePath(path33) {
19810
+ this._closeFile(path33);
19811
+ const dir = sp2.dirname(path33);
19812
+ this._getWatchedDir(dir).remove(sp2.basename(path33));
19871
19813
  }
19872
19814
  /**
19873
19815
  * Closes only file-specific watchers
19874
19816
  */
19875
- _closeFile(path31) {
19876
- const closers = this._closers.get(path31);
19817
+ _closeFile(path33) {
19818
+ const closers = this._closers.get(path33);
19877
19819
  if (!closers)
19878
19820
  return;
19879
19821
  closers.forEach((closer) => closer());
19880
- this._closers.delete(path31);
19822
+ this._closers.delete(path33);
19881
19823
  }
19882
- _addPathCloser(path31, closer) {
19824
+ _addPathCloser(path33, closer) {
19883
19825
  if (!closer)
19884
19826
  return;
19885
- let list = this._closers.get(path31);
19827
+ let list = this._closers.get(path33);
19886
19828
  if (!list) {
19887
19829
  list = [];
19888
- this._closers.set(path31, list);
19830
+ this._closers.set(path33, list);
19889
19831
  }
19890
19832
  list.push(closer);
19891
19833
  }
@@ -19915,12 +19857,291 @@ function watch(paths, options = {}) {
19915
19857
  var chokidar_default = { watch, FSWatcher };
19916
19858
 
19917
19859
  // src/watcher/file-watcher.ts
19860
+ var path28 = __toESM(require("path"), 1);
19861
+
19862
+ // src/watcher/native-recursive-watcher.ts
19863
+ var import_node_fs3 = require("fs");
19918
19864
  var path26 = __toESM(require("path"), 1);
19865
+ var NativeRecursiveWatcher = class {
19866
+ constructor(root, onChange, options = {}) {
19867
+ this.root = root;
19868
+ this.onChange = onChange;
19869
+ this.watchFactory = options.watchFactory ?? this.defaultWatchFactory;
19870
+ this.onError = options.onError;
19871
+ }
19872
+ root;
19873
+ onChange;
19874
+ watcher = null;
19875
+ listenerToken = 0;
19876
+ watchFactory;
19877
+ onError;
19878
+ start() {
19879
+ if (this.watcher) return;
19880
+ const token = ++this.listenerToken;
19881
+ const listener = (_eventType, filename) => {
19882
+ if (this.watcher === null || this.listenerToken !== token) return;
19883
+ const absolutePath = this.toAbsolutePath(filename);
19884
+ const nextResult = this.onChange(absolutePath);
19885
+ if (nextResult instanceof Promise) {
19886
+ void nextResult.catch((error) => {
19887
+ console.error("[codebase-index] Error handling native watcher event:", error);
19888
+ });
19889
+ }
19890
+ };
19891
+ const watcher = this.watchFactory(this.root, listener, {
19892
+ persistent: true,
19893
+ recursive: true
19894
+ });
19895
+ watcher.on?.("error", (error) => {
19896
+ if (this.watcher === watcher && this.listenerToken === token) {
19897
+ this.onError?.(error);
19898
+ }
19899
+ });
19900
+ this.watcher = watcher;
19901
+ }
19902
+ async stop() {
19903
+ const watcher = this.watcher;
19904
+ this.watcher = null;
19905
+ this.listenerToken += 1;
19906
+ if (!watcher) return;
19907
+ await watcher.close();
19908
+ }
19909
+ toAbsolutePath(filename) {
19910
+ if (filename == null) return null;
19911
+ const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
19912
+ const absolutePath = path26.resolve(this.root, normalizedFilename);
19913
+ const relativePath = path26.relative(this.root, absolutePath);
19914
+ const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path26.sep}`) || path26.isAbsolute(relativePath);
19915
+ return outsideRoot ? null : absolutePath;
19916
+ }
19917
+ defaultWatchFactory = (root, listener, options) => (0, import_node_fs3.watch)(root, options, listener);
19918
+ };
19919
+
19920
+ // src/watcher/snapshot.ts
19921
+ var fsPromises4 = __toESM(require("fs/promises"), 1);
19922
+ var path27 = __toESM(require("path"), 1);
19923
+ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
19924
+ const normalizedProjectRoot = path27.resolve(projectRoot);
19925
+ const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
19926
+ const includePatterns = [...config.include, ...config.additionalInclude ?? []];
19927
+ const maxDepth = config.indexing?.maxDepth ?? -1;
19928
+ const snapshot = /* @__PURE__ */ new Map();
19929
+ const unreadablePrefixes = /* @__PURE__ */ new Set();
19930
+ const includeFile = async (filePath) => {
19931
+ const normalizedPath3 = path27.resolve(filePath);
19932
+ if (!shouldIncludeFile(normalizedPath3, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
19933
+ const stat5 = await readStatIfFile(normalizedPath3, unreadablePrefixes);
19934
+ if (stat5) snapshot.set(normalizedPath3, { size: stat5.size, mtimeMs: stat5.mtimeMs });
19935
+ };
19936
+ const walk = async (directoryPath, depth) => {
19937
+ let entries;
19938
+ try {
19939
+ entries = await fsPromises4.readdir(directoryPath, { withFileTypes: true });
19940
+ } catch (error) {
19941
+ if (isMissingFsError(error)) return;
19942
+ if (isPermissionFsError(error)) {
19943
+ unreadablePrefixes.add(path27.resolve(directoryPath));
19944
+ return;
19945
+ }
19946
+ throw error;
19947
+ }
19948
+ for (const entry of entries) {
19949
+ const fullPath = path27.join(directoryPath, entry.name);
19950
+ const relativePath = path27.relative(normalizedProjectRoot, fullPath);
19951
+ if (entry.isDirectory()) {
19952
+ if (hasFilteredPathSegment(relativePath, path27.sep) || isRestrictedDirectory(relativePath, path27.sep)) continue;
19953
+ if (ignoreFilter.ignores(relativePath)) continue;
19954
+ if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
19955
+ } else if (entry.isFile()) {
19956
+ await includeFile(fullPath);
19957
+ }
19958
+ }
19959
+ };
19960
+ await walk(normalizedProjectRoot, 0);
19961
+ await includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths);
19962
+ return { entries: snapshot, unreadablePrefixes };
19963
+ }
19964
+ async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, targetPath) {
19965
+ const normalizedProjectRoot = path27.resolve(projectRoot);
19966
+ const normalizedTargetPath = path27.resolve(targetPath);
19967
+ if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
19968
+ return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
19969
+ }
19970
+ const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
19971
+ const includePatterns = [...config.include, ...config.additionalInclude ?? []];
19972
+ const maxDepth = config.indexing?.maxDepth ?? -1;
19973
+ const explicitConfigPaths = new Set(configPaths.map((configPath) => path27.resolve(configPath)));
19974
+ const snapshot = /* @__PURE__ */ new Map();
19975
+ const unreadablePrefixes = /* @__PURE__ */ new Set();
19976
+ const includeFile = async (filePath) => {
19977
+ const normalizedPath3 = path27.resolve(filePath);
19978
+ if (!explicitConfigPaths.has(normalizedPath3) && !shouldIncludeFile(
19979
+ normalizedPath3,
19980
+ normalizedProjectRoot,
19981
+ includePatterns,
19982
+ config.exclude,
19983
+ ignoreFilter
19984
+ )) return;
19985
+ const stat5 = await readStatIfFile(normalizedPath3, unreadablePrefixes);
19986
+ if (stat5) snapshot.set(normalizedPath3, { size: stat5.size, mtimeMs: stat5.mtimeMs });
19987
+ };
19988
+ const walk = async (directoryPath, depth) => {
19989
+ let entries;
19990
+ try {
19991
+ entries = await fsPromises4.readdir(directoryPath, { withFileTypes: true });
19992
+ } catch (error) {
19993
+ if (isMissingFsError(error)) return;
19994
+ if (isPermissionFsError(error)) {
19995
+ unreadablePrefixes.add(path27.resolve(directoryPath));
19996
+ return;
19997
+ }
19998
+ throw error;
19999
+ }
20000
+ for (const entry of entries) {
20001
+ const fullPath = path27.join(directoryPath, entry.name);
20002
+ const relativePath = path27.relative(normalizedProjectRoot, fullPath);
20003
+ if (entry.isDirectory()) {
20004
+ if (hasFilteredPathSegment(relativePath, path27.sep) || isRestrictedDirectory(relativePath, path27.sep)) continue;
20005
+ if (ignoreFilter.ignores(relativePath)) continue;
20006
+ if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
20007
+ } else if (entry.isFile()) {
20008
+ await includeFile(fullPath);
20009
+ }
20010
+ }
20011
+ };
20012
+ const targetStat = await readStatIfFile(normalizedTargetPath, unreadablePrefixes);
20013
+ if (targetStat) await includeFile(normalizedTargetPath);
20014
+ else await walk(normalizedTargetPath, 0);
20015
+ await includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, configPaths, normalizedTargetPath);
20016
+ return { entries: snapshot, unreadablePrefixes };
20017
+ }
20018
+ function completeFileSnapshot(previous, scan) {
20019
+ const completed = new Map(scan.entries);
20020
+ for (const unreadablePrefix of scan.unreadablePrefixes) {
20021
+ for (const [entryPath, entry] of previous) {
20022
+ if (isWithinPath(unreadablePrefix, entryPath) && !completed.has(entryPath)) completed.set(entryPath, entry);
20023
+ }
20024
+ }
20025
+ return completed;
20026
+ }
20027
+ async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
20028
+ for (const configPath of [...new Set(configPaths.map((value) => path27.resolve(value)))]) {
20029
+ if (snapshot.has(configPath)) continue;
20030
+ const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
20031
+ if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
20032
+ }
20033
+ }
20034
+ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, configPaths, targetPath) {
20035
+ await includeExplicitConfigPaths(
20036
+ snapshot,
20037
+ unreadablePrefixes,
20038
+ configPaths.filter((configPath) => isWithinPath(targetPath, path27.resolve(configPath)))
20039
+ );
20040
+ }
20041
+ function isWithinPath(parentPath, childPath) {
20042
+ const relativePath = path27.relative(parentPath, childPath);
20043
+ return relativePath === "" || !relativePath.startsWith(`..${path27.sep}`) && relativePath !== ".." && !path27.isAbsolute(relativePath);
20044
+ }
20045
+ async function readStatIfFile(filePath, unreadablePrefixes) {
20046
+ try {
20047
+ const stat5 = await fsPromises4.stat(filePath);
20048
+ return stat5.isFile() ? stat5 : null;
20049
+ } catch (error) {
20050
+ if (isMissingFsError(error)) return null;
20051
+ if (isPermissionFsError(error)) {
20052
+ unreadablePrefixes.add(path27.resolve(filePath));
20053
+ return null;
20054
+ }
20055
+ throw error;
20056
+ }
20057
+ }
20058
+ function isMissingFsError(error) {
20059
+ return error instanceof Error && ["ENOENT", "ENOTDIR"].includes(error.code ?? "");
20060
+ }
20061
+ function isPermissionFsError(error) {
20062
+ return error instanceof Error && ["EACCES", "EPERM"].includes(error.code ?? "");
20063
+ }
20064
+ var diffTypeOrder = { add: 0, change: 1, unlink: 2 };
20065
+ function diffFileSnapshots(previous, current, forcedChanges = /* @__PURE__ */ new Set()) {
20066
+ const changes = [];
20067
+ for (const [filePath, previousEntry] of previous) {
20068
+ const currentEntry = current.get(filePath);
20069
+ if (!currentEntry) changes.push({ type: "unlink", path: filePath });
20070
+ else if (forcedChanges.has(filePath) || currentEntry.size !== previousEntry.size || currentEntry.mtimeMs !== previousEntry.mtimeMs) {
20071
+ changes.push({ type: "change", path: filePath });
20072
+ }
20073
+ }
20074
+ for (const [filePath] of current) {
20075
+ if (!previous.has(filePath)) changes.push({ type: "add", path: filePath });
20076
+ }
20077
+ return changes.sort((left, right) => left.path.localeCompare(right.path) || diffTypeOrder[left.type] - diffTypeOrder[right.type]);
20078
+ }
20079
+
20080
+ // src/watcher/snapshot-reconciler.ts
20081
+ var FileSnapshotReconciler = class {
20082
+ constructor(projectRoot, config, configPaths) {
20083
+ this.projectRoot = projectRoot;
20084
+ this.config = config;
20085
+ this.configPaths = configPaths;
20086
+ }
20087
+ projectRoot;
20088
+ config;
20089
+ configPaths;
20090
+ snapshot = null;
20091
+ reconciliationTail = Promise.resolve();
20092
+ async initialize() {
20093
+ this.snapshot = (await buildFileSnapshotScan(this.projectRoot, this.config, this.configPaths)).entries;
20094
+ }
20095
+ async reconcile(invalidations = []) {
20096
+ if (this.snapshot === null) {
20097
+ throw new Error("FileSnapshotReconciler is not initialized. Call initialize() before reconcile().");
20098
+ }
20099
+ const reconciliation = this.reconciliationTail.then(async () => {
20100
+ const previousSnapshot = this.snapshot;
20101
+ if (previousSnapshot === null) {
20102
+ throw new Error("FileSnapshotReconciler is not initialized. Call initialize() before reconcile().");
20103
+ }
20104
+ const normalizedInvalidations = invalidations.map((invalidation) => typeof invalidation === "string" || invalidation === null ? { path: invalidation, forceChange: false } : { path: invalidation.path, forceChange: invalidation.forceChange === true });
20105
+ const scopedPaths = normalizedInvalidations.map((invalidation) => invalidation.path).filter((filePath) => filePath !== null);
20106
+ const scan = scopedPaths.length === 0 || scopedPaths.length !== normalizedInvalidations.length ? await buildFileSnapshotScan(this.projectRoot, this.config, this.configPaths) : await this.reconcilePaths(previousSnapshot, scopedPaths);
20107
+ const nextSnapshot = completeFileSnapshot(previousSnapshot, scan);
20108
+ const forcedChanges = new Set(normalizedInvalidations.filter((invalidation) => invalidation.path !== null && invalidation.forceChange).map((invalidation) => invalidation.path));
20109
+ const changes = diffFileSnapshots(previousSnapshot, nextSnapshot, forcedChanges);
20110
+ this.snapshot = nextSnapshot;
20111
+ return changes;
20112
+ });
20113
+ this.reconciliationTail = reconciliation.then(() => void 0, () => void 0);
20114
+ return reconciliation;
20115
+ }
20116
+ async reconcilePaths(previousSnapshot, invalidatedPaths) {
20117
+ const scopes = this.getScopes(invalidatedPaths);
20118
+ const entries = new Map(previousSnapshot);
20119
+ const unreadablePrefixes = /* @__PURE__ */ new Set();
20120
+ for (const scope of scopes) {
20121
+ for (const previousPath of entries.keys()) {
20122
+ if (isWithinPath(scope, previousPath)) entries.delete(previousPath);
20123
+ }
20124
+ const scopedScan = await buildFileSnapshotForPathScan(this.projectRoot, this.config, this.configPaths, scope);
20125
+ for (const [filePath, entry] of scopedScan.entries) entries.set(filePath, entry);
20126
+ for (const unreadablePrefix of scopedScan.unreadablePrefixes) unreadablePrefixes.add(unreadablePrefix);
20127
+ }
20128
+ return { entries, unreadablePrefixes };
20129
+ }
20130
+ getScopes(invalidatedPaths) {
20131
+ const uniquePaths = [...new Set(invalidatedPaths)].sort((left, right) => left.length - right.length);
20132
+ return uniquePaths.filter((candidate, index) => !uniquePaths.slice(0, index).some(
20133
+ (ancestor) => isWithinPath(ancestor, candidate)
20134
+ ));
20135
+ }
20136
+ };
20137
+
20138
+ // src/watcher/file-watcher.ts
19919
20139
  var FileWatcher = class {
19920
20140
  watcher = null;
19921
20141
  projectRoot;
19922
20142
  config;
19923
20143
  configPath;
20144
+ backend;
19924
20145
  projectConfigPaths;
19925
20146
  pendingChanges = /* @__PURE__ */ new Map();
19926
20147
  debounceTimer = null;
@@ -19930,44 +20151,74 @@ var FileWatcher = class {
19930
20151
  resolveReady = null;
19931
20152
  pollingFallbackAttempted = false;
19932
20153
  pendingClose = null;
20154
+ startupReadySignals = 1;
20155
+ nativeWatcher = null;
20156
+ nativeReconciler = null;
20157
+ nativeSetupGeneration = 0;
20158
+ nativeStarting = false;
20159
+ nativeInitializing = false;
20160
+ nativeReconcileTimer = null;
20161
+ nativeInvalidatedPaths = /* @__PURE__ */ new Map();
20162
+ configPathStates = /* @__PURE__ */ new Map();
19933
20163
  constructor(projectRoot, config, host, options = {}) {
19934
20164
  this.projectRoot = projectRoot;
19935
20165
  this.config = config;
20166
+ this.backend = options.backend ?? "auto";
19936
20167
  this.configPath = options.configPath;
19937
20168
  this.projectConfigPaths = options.configPath ? [options.configPath] : getProjectConfigCandidatePaths(projectRoot, host);
19938
20169
  }
19939
20170
  start(handler) {
19940
- if (this.watcher) {
20171
+ if (this.watcher || this.nativeWatcher || this.nativeStarting) {
19941
20172
  return;
19942
20173
  }
19943
20174
  this.onChanges = handler;
19944
20175
  this.pollingFallbackAttempted = false;
19945
20176
  this.resetReady();
20177
+ if (this.shouldUseNativeWatcher()) {
20178
+ if (this.hasExternalConfigWatchTarget()) {
20179
+ this.setStartupReadySignals(2);
20180
+ this.startExternalConfigWatcher();
20181
+ }
20182
+ this.nativeStarting = true;
20183
+ void this.createNativeWatcher();
20184
+ return;
20185
+ }
19946
20186
  this.createWatcher();
19947
20187
  }
19948
20188
  resetReady() {
19949
- this.readyPromise = new Promise((resolve18) => {
19950
- this.resolveReady = resolve18;
20189
+ this.readyPromise = new Promise((resolve20) => {
20190
+ this.resolveReady = resolve20;
19951
20191
  });
20192
+ this.startupReadySignals = 1;
19952
20193
  }
19953
- createWatcher(usePolling = false) {
19954
- const ignoreFilter = createIgnoreFilter(this.projectRoot);
19955
- let watchTargets = this.projectRoot;
19956
- if (this.configPath) {
19957
- watchTargets = [this.projectRoot, this.configPath];
19958
- } else {
19959
- const externalConfigTargets = this.projectConfigPaths.filter((projectConfigPath) => {
19960
- const relativeConfigPath = path26.relative(this.projectRoot, projectConfigPath);
19961
- return this.isOutsideProjectPath(relativeConfigPath);
19962
- }).map((projectConfigPath) => (0, import_fs19.existsSync)(projectConfigPath) ? projectConfigPath : this.getNearestExistingDirectory(path26.dirname(projectConfigPath)));
19963
- const uniqueExternalConfigTargets = [...new Set(externalConfigTargets)];
19964
- if (uniqueExternalConfigTargets.length > 0) {
19965
- watchTargets = [this.projectRoot, ...uniqueExternalConfigTargets];
19966
- }
20194
+ setStartupReadySignals(expectedSignals) {
20195
+ if (!this.readyPromise) {
20196
+ return;
19967
20197
  }
20198
+ this.startupReadySignals = Math.max(0, expectedSignals);
20199
+ }
20200
+ reportStartupReadySignal() {
20201
+ if (!this.readyPromise || !this.resolveReady) {
20202
+ return;
20203
+ }
20204
+ if (this.startupReadySignals <= 0) {
20205
+ return;
20206
+ }
20207
+ this.startupReadySignals -= 1;
20208
+ if (this.startupReadySignals !== 0) {
20209
+ return;
20210
+ }
20211
+ this.resolveReady();
20212
+ this.resolveReady = null;
20213
+ }
20214
+ createWatcher(watchTargets, usePolling = false, reportsStartupReady = true) {
20215
+ let reportedStartupReady = false;
20216
+ this.configPathStates = this.getConfigPathStates();
20217
+ const ignoreFilter = createIgnoreFilter(this.projectRoot);
20218
+ const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
19968
20219
  const watcherOptions = {
19969
20220
  ignored: (filePath) => {
19970
- const relativePath = path26.relative(this.projectRoot, filePath);
20221
+ const relativePath = path28.relative(this.projectRoot, filePath);
19971
20222
  if (!relativePath) return false;
19972
20223
  if (this.isProjectConfigPathOrAncestor(relativePath)) {
19973
20224
  return false;
@@ -19975,10 +20226,10 @@ var FileWatcher = class {
19975
20226
  if (this.isOutsideProjectPath(relativePath)) {
19976
20227
  return true;
19977
20228
  }
19978
- if (hasFilteredPathSegment(relativePath, path26.sep)) {
20229
+ if (hasFilteredPathSegment(relativePath, path28.sep)) {
19979
20230
  return true;
19980
20231
  }
19981
- if (isRestrictedDirectory(relativePath, path26.sep)) {
20232
+ if (isRestrictedDirectory(relativePath, path28.sep)) {
19982
20233
  return true;
19983
20234
  }
19984
20235
  if (ignoreFilter.ignores(relativePath)) {
@@ -20011,10 +20262,13 @@ var FileWatcher = class {
20011
20262
  watcher = new FSWatcher(watcherOptions);
20012
20263
  }
20013
20264
  this.watcher = watcher;
20014
- watcher.once("ready", () => {
20265
+ watcher.on("ready", () => {
20015
20266
  if (this.watcher !== watcher) return;
20016
- this.resolveReady?.();
20017
- this.resolveReady = null;
20267
+ this.reconcileConfigPathStates();
20268
+ if (reportsStartupReady) {
20269
+ this.reportStartupReadySignal();
20270
+ reportedStartupReady = true;
20271
+ }
20018
20272
  });
20019
20273
  watcher.on("error", (error) => {
20020
20274
  const err = error instanceof Error ? error : null;
@@ -20028,10 +20282,13 @@ var FileWatcher = class {
20028
20282
  console.error("[codebase-index] Failed to close exhausted file watcher:", closeError);
20029
20283
  });
20030
20284
  if (this.onChanges) {
20285
+ const replacementReportsStartupReady = reportsStartupReady || reportedStartupReady;
20031
20286
  if (!this.resolveReady) {
20032
20287
  this.resetReady();
20288
+ } else if (reportedStartupReady) {
20289
+ this.startupReadySignals += 1;
20033
20290
  }
20034
- this.createWatcher(true);
20291
+ this.createWatcher(resolvedWatchTargets, true, replacementReportsStartupReady);
20035
20292
  } else {
20036
20293
  this.watcher = null;
20037
20294
  }
@@ -20042,13 +20299,166 @@ var FileWatcher = class {
20042
20299
  watcher.on("add", (filePath) => this.handleChange(watcher, "add", filePath));
20043
20300
  watcher.on("change", (filePath) => this.handleChange(watcher, "change", filePath));
20044
20301
  watcher.on("unlink", (filePath) => this.handleChange(watcher, "unlink", filePath));
20045
- watcher.add(watchTargets);
20302
+ watcher.add(resolvedWatchTargets);
20303
+ }
20304
+ shouldUseNativeWatcher() {
20305
+ if (this.backend === "chokidar") {
20306
+ return false;
20307
+ }
20308
+ return true;
20309
+ }
20310
+ getFullChokidarWatchTargets() {
20311
+ if (this.configPath) {
20312
+ return [this.projectRoot, this.configPath];
20313
+ }
20314
+ const externalConfigTargets = this.getExternalConfigWatchTargets();
20315
+ if (externalConfigTargets.length === 0) {
20316
+ return this.projectRoot;
20317
+ }
20318
+ return [this.projectRoot, ...externalConfigTargets];
20319
+ }
20320
+ getExternalConfigWatchTargets() {
20321
+ return [...new Set(
20322
+ this.projectConfigPaths.filter((projectConfigPath) => {
20323
+ const relativeConfigPath = path28.relative(this.projectRoot, projectConfigPath);
20324
+ return this.isOutsideProjectPath(relativeConfigPath);
20325
+ }).map((projectConfigPath) => {
20326
+ if ((0, import_fs19.existsSync)(projectConfigPath)) {
20327
+ return projectConfigPath;
20328
+ }
20329
+ return this.getNearestExistingDirectory(path28.dirname(projectConfigPath));
20330
+ })
20331
+ )];
20332
+ }
20333
+ hasExternalConfigWatchTarget() {
20334
+ return this.getExternalConfigWatchTargets().length > 0;
20335
+ }
20336
+ startExternalConfigWatcher(usePolling = false) {
20337
+ const externalTargets = this.getExternalConfigWatchTargets();
20338
+ if (externalTargets.length === 0) {
20339
+ return;
20340
+ }
20341
+ this.createWatcher(externalTargets, usePolling);
20342
+ }
20343
+ async createNativeWatcher() {
20344
+ const generation = ++this.nativeSetupGeneration;
20345
+ const reconciler = new FileSnapshotReconciler(this.projectRoot, this.config, this.projectConfigPaths);
20346
+ const watcher = new NativeRecursiveWatcher(
20347
+ this.projectRoot,
20348
+ (filePath) => this.scheduleNativeReconciliation(generation, filePath),
20349
+ { onError: (error) => void this.fallbackFromNativeWatcher(generation, error) }
20350
+ );
20351
+ this.nativeReconciler = reconciler;
20352
+ this.nativeWatcher = watcher;
20353
+ this.nativeInitializing = true;
20354
+ try {
20355
+ watcher.start();
20356
+ if (!this.isCurrentNativeSetup(generation)) {
20357
+ await watcher.stop();
20358
+ return;
20359
+ }
20360
+ await reconciler.initialize();
20361
+ if (!this.isCurrentNativeSetup(generation) || this.nativeWatcher !== watcher) {
20362
+ await watcher.stop();
20363
+ return;
20364
+ }
20365
+ this.nativeStarting = false;
20366
+ this.nativeInitializing = false;
20367
+ await this.reconcileNativeWatcherWithPendingInvalidations(generation);
20368
+ this.reportStartupReadySignal();
20369
+ } catch (error) {
20370
+ if (!this.isCurrentNativeSetup(generation)) return;
20371
+ this.nativeInitializing = false;
20372
+ if (this.nativeWatcher) {
20373
+ await this.fallbackFromNativeWatcher(generation, error);
20374
+ return;
20375
+ }
20376
+ this.nativeStarting = false;
20377
+ const externalWatcher = this.watcher;
20378
+ this.watcher = null;
20379
+ this.nativeReconciler = null;
20380
+ await externalWatcher?.close();
20381
+ console.warn("[codebase-index] Native recursive watcher unavailable; using Chokidar fallback.", error);
20382
+ this.setStartupReadySignals(1);
20383
+ this.createWatcher();
20384
+ }
20385
+ }
20386
+ isCurrentNativeSetup(generation) {
20387
+ return this.nativeSetupGeneration === generation && this.onChanges !== null;
20388
+ }
20389
+ scheduleNativeReconciliation(generation, filePath) {
20390
+ if (!this.isCurrentNativeSetup(generation)) return;
20391
+ const requiresFullReconciliation = filePath === path28.join(this.projectRoot, ".gitignore");
20392
+ const invalidatedPath = requiresFullReconciliation ? null : filePath;
20393
+ this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
20394
+ if (this.nativeReconcileTimer) {
20395
+ clearTimeout(this.nativeReconcileTimer);
20396
+ }
20397
+ this.nativeReconcileTimer = setTimeout(() => {
20398
+ this.nativeReconcileTimer = null;
20399
+ void this.reconcileNativeWatcherFromQueue(generation);
20400
+ }, 100);
20401
+ }
20402
+ reconcileNativeWatcherFromQueue(generation) {
20403
+ if (!this.isCurrentNativeSetup(generation) || this.nativeInitializing) return;
20404
+ const invalidatedPaths = this.popNativeInvalidations();
20405
+ if (invalidatedPaths.length === 0) return;
20406
+ void this.reconcileNativeWatcher(generation, invalidatedPaths);
20407
+ }
20408
+ async reconcileNativeWatcher(generation, invalidatedPaths) {
20409
+ if (!this.isCurrentNativeSetup(generation) || !this.nativeReconciler) return;
20410
+ try {
20411
+ const reconciler = this.nativeReconciler;
20412
+ const changes = await reconciler.reconcile(invalidatedPaths);
20413
+ if (!this.isCurrentNativeSetup(generation) || this.nativeReconciler !== reconciler) return;
20414
+ this.recordChanges(changes);
20415
+ } catch (error) {
20416
+ await this.fallbackFromNativeWatcher(generation, error);
20417
+ }
20418
+ }
20419
+ async reconcileNativeWatcherWithPendingInvalidations(generation) {
20420
+ const invalidatedPaths = this.popNativeInvalidations();
20421
+ if (invalidatedPaths.length === 0) return;
20422
+ await this.reconcileNativeWatcher(generation, invalidatedPaths);
20423
+ }
20424
+ popNativeInvalidations() {
20425
+ if (this.nativeInvalidatedPaths.size === 0) return [];
20426
+ const invalidations = [...this.nativeInvalidatedPaths].map(([invalidatedPath, forceChange]) => ({
20427
+ path: invalidatedPath,
20428
+ forceChange
20429
+ }));
20430
+ this.nativeInvalidatedPaths.clear();
20431
+ return invalidations;
20432
+ }
20433
+ async fallbackFromNativeWatcher(generation, error) {
20434
+ if (!this.isCurrentNativeSetup(generation)) return;
20435
+ const watcher = this.nativeWatcher;
20436
+ const externalWatcher = this.watcher;
20437
+ this.nativeWatcher = null;
20438
+ this.watcher = null;
20439
+ this.nativeReconciler = null;
20440
+ this.nativeStarting = false;
20441
+ this.nativeInitializing = false;
20442
+ this.nativeSetupGeneration += 1;
20443
+ if (this.nativeReconcileTimer) {
20444
+ clearTimeout(this.nativeReconcileTimer);
20445
+ this.nativeReconcileTimer = null;
20446
+ }
20447
+ this.nativeInvalidatedPaths.clear();
20448
+ this.setStartupReadySignals(1);
20449
+ console.warn("[codebase-index] Native recursive watcher failed; using Chokidar fallback.", error);
20450
+ await watcher?.stop();
20451
+ await externalWatcher?.close();
20452
+ if (this.onChanges) {
20453
+ this.createWatcher();
20454
+ }
20046
20455
  }
20047
20456
  handleChange(watcher, type, filePath) {
20048
20457
  if (this.watcher !== watcher) {
20049
20458
  return;
20050
20459
  }
20051
20460
  if (this.isProjectConfigPath(filePath)) {
20461
+ this.updateConfigPathState(filePath);
20052
20462
  this.pendingChanges.set(filePath, type);
20053
20463
  this.scheduleFlush();
20054
20464
  return;
@@ -20063,27 +20473,33 @@ var FileWatcher = class {
20063
20473
  )) {
20064
20474
  return;
20065
20475
  }
20066
- this.pendingChanges.set(filePath, type);
20476
+ this.recordChanges([{ path: filePath, type }]);
20477
+ }
20478
+ recordChanges(changes) {
20479
+ if (changes.length === 0) return;
20480
+ for (const change of changes) {
20481
+ this.pendingChanges.set(change.path, change.type);
20482
+ }
20067
20483
  this.scheduleFlush();
20068
20484
  }
20069
20485
  isProjectConfigPath(filePath) {
20070
- const relativePath = path26.relative(this.projectRoot, filePath);
20071
- const normalizedRelativePath = path26.normalize(relativePath);
20486
+ const relativePath = path28.relative(this.projectRoot, filePath);
20487
+ const normalizedRelativePath = path28.normalize(relativePath);
20072
20488
  return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
20073
20489
  }
20074
20490
  isProjectConfigPathOrAncestor(relativePath) {
20075
- const normalizedRelativePath = path26.normalize(relativePath);
20491
+ const normalizedRelativePath = path28.normalize(relativePath);
20076
20492
  return this.getProjectConfigRelativePaths().some(
20077
- (configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path26.sep}`)
20493
+ (configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path28.sep}`)
20078
20494
  );
20079
20495
  }
20080
20496
  isOutsideProjectPath(relativePath) {
20081
- return relativePath === ".." || relativePath.startsWith(`..${path26.sep}`) || path26.isAbsolute(relativePath);
20497
+ return relativePath === ".." || relativePath.startsWith(`..${path28.sep}`) || path28.isAbsolute(relativePath);
20082
20498
  }
20083
20499
  getNearestExistingDirectory(directoryPath) {
20084
20500
  let candidate = directoryPath;
20085
20501
  while (!(0, import_fs19.existsSync)(candidate)) {
20086
- const parent = path26.dirname(candidate);
20502
+ const parent = path28.dirname(candidate);
20087
20503
  if (parent === candidate) break;
20088
20504
  candidate = parent;
20089
20505
  }
@@ -20091,9 +20507,51 @@ var FileWatcher = class {
20091
20507
  }
20092
20508
  getProjectConfigRelativePaths() {
20093
20509
  return this.projectConfigPaths.map(
20094
- (configPath) => path26.normalize(path26.relative(this.projectRoot, configPath))
20510
+ (configPath) => path28.normalize(path28.relative(this.projectRoot, configPath))
20095
20511
  );
20096
20512
  }
20513
+ getConfigPathStates() {
20514
+ const states = /* @__PURE__ */ new Map();
20515
+ for (const configPath of this.projectConfigPaths) {
20516
+ const state = this.getConfigPathState(configPath);
20517
+ if (state) states.set(configPath, state);
20518
+ }
20519
+ return states;
20520
+ }
20521
+ getConfigPathState(configPath) {
20522
+ try {
20523
+ const stats = (0, import_fs19.statSync)(configPath);
20524
+ return stats.isFile() ? { mtimeMs: stats.mtimeMs, size: stats.size } : void 0;
20525
+ } catch (error) {
20526
+ void error;
20527
+ return void 0;
20528
+ }
20529
+ }
20530
+ updateConfigPathState(configPath) {
20531
+ const state = this.getConfigPathState(configPath);
20532
+ if (state) {
20533
+ this.configPathStates.set(configPath, state);
20534
+ } else {
20535
+ this.configPathStates.delete(configPath);
20536
+ }
20537
+ }
20538
+ reconcileConfigPathStates() {
20539
+ const nextStates = this.getConfigPathStates();
20540
+ const changes = [];
20541
+ for (const configPath of this.projectConfigPaths) {
20542
+ const previous = this.configPathStates.get(configPath);
20543
+ const next = nextStates.get(configPath);
20544
+ if (!previous && next) {
20545
+ changes.push({ path: configPath, type: "add" });
20546
+ } else if (previous && !next) {
20547
+ changes.push({ path: configPath, type: "unlink" });
20548
+ } else if (previous && next && (previous.size !== next.size || previous.mtimeMs !== next.mtimeMs)) {
20549
+ changes.push({ path: configPath, type: "change" });
20550
+ }
20551
+ }
20552
+ this.configPathStates = nextStates;
20553
+ this.recordChanges(changes);
20554
+ }
20097
20555
  scheduleFlush() {
20098
20556
  if (this.debounceTimer) {
20099
20557
  clearTimeout(this.debounceTimer);
@@ -20107,7 +20565,7 @@ var FileWatcher = class {
20107
20565
  return;
20108
20566
  }
20109
20567
  const changes = Array.from(this.pendingChanges.entries()).map(
20110
- ([path31, type]) => ({ path: path31, type })
20568
+ ([path33, type]) => ({ path: path33, type })
20111
20569
  );
20112
20570
  this.pendingChanges.clear();
20113
20571
  try {
@@ -20121,20 +20579,31 @@ var FileWatcher = class {
20121
20579
  clearTimeout(this.debounceTimer);
20122
20580
  this.debounceTimer = null;
20123
20581
  }
20582
+ if (this.nativeReconcileTimer) {
20583
+ clearTimeout(this.nativeReconcileTimer);
20584
+ this.nativeReconcileTimer = null;
20585
+ }
20586
+ this.nativeInvalidatedPaths.clear();
20124
20587
  const watcher = this.watcher;
20588
+ const nativeWatcher = this.nativeWatcher;
20125
20589
  const pendingClose = this.pendingClose;
20126
20590
  const resolveReady = this.resolveReady;
20127
20591
  this.watcher = null;
20592
+ this.nativeWatcher = null;
20593
+ this.nativeReconciler = null;
20594
+ this.nativeStarting = false;
20595
+ this.nativeInitializing = false;
20596
+ this.nativeSetupGeneration += 1;
20128
20597
  this.pendingClose = null;
20129
20598
  this.resolveReady = null;
20130
20599
  this.readyPromise = null;
20131
20600
  this.pendingChanges.clear();
20132
20601
  this.onChanges = null;
20133
- await Promise.all([watcher?.close(), pendingClose]);
20602
+ await Promise.all([watcher?.close(), nativeWatcher?.stop(), pendingClose]);
20134
20603
  resolveReady?.();
20135
20604
  }
20136
20605
  isRunning() {
20137
- return this.watcher !== null;
20606
+ return this.watcher !== null || this.nativeWatcher !== null || this.nativeStarting;
20138
20607
  }
20139
20608
  async waitUntilReady() {
20140
20609
  await (this.readyPromise ?? Promise.resolve());
@@ -20142,7 +20611,7 @@ var FileWatcher = class {
20142
20611
  };
20143
20612
 
20144
20613
  // src/watcher/git-head-watcher.ts
20145
- var path27 = __toESM(require("path"), 1);
20614
+ var path29 = __toESM(require("path"), 1);
20146
20615
  var GitHeadWatcher = class {
20147
20616
  watcher = null;
20148
20617
  projectRoot;
@@ -20164,13 +20633,13 @@ var GitHeadWatcher = class {
20164
20633
  this.readyPromise = Promise.resolve();
20165
20634
  return;
20166
20635
  }
20167
- this.readyPromise = new Promise((resolve18) => {
20168
- this.resolveReady = resolve18;
20636
+ this.readyPromise = new Promise((resolve20) => {
20637
+ this.resolveReady = resolve20;
20169
20638
  });
20170
20639
  this.onBranchChange = handler;
20171
20640
  this.currentBranch = getCurrentBranch(this.projectRoot);
20172
20641
  const headPath = getHeadPath(this.projectRoot);
20173
- const refsPath = path27.join(this.projectRoot, ".git", "refs", "heads");
20642
+ const refsPath = path29.join(this.projectRoot, ".git", "refs", "heads");
20174
20643
  this.watcher = chokidar_default.watch([headPath, refsPath], {
20175
20644
  persistent: true,
20176
20645
  ignoreInitial: true,
@@ -20306,7 +20775,7 @@ function getConfigPaths(projectRoot, host, options) {
20306
20775
 
20307
20776
  // src/tools/visualize/activity.ts
20308
20777
  var import_child_process5 = require("child_process");
20309
- var path28 = __toESM(require("path"), 1);
20778
+ var path30 = __toESM(require("path"), 1);
20310
20779
  function attachRecentActivity(data, projectRoot) {
20311
20780
  const activity = readGitActivity(projectRoot);
20312
20781
  const changes = activity.size > 0 ? buildGitChanges(data, activity, projectRoot) : buildGraphChanges(data);
@@ -20468,7 +20937,7 @@ function normalizePath4(filePath) {
20468
20937
  return filePath.replace(/\\/g, "/");
20469
20938
  }
20470
20939
  function toGitRelativePath(projectRoot, filePath) {
20471
- const relativePath = path28.isAbsolute(filePath) ? path28.relative(projectRoot, filePath) : filePath;
20940
+ const relativePath = path30.isAbsolute(filePath) ? path30.relative(projectRoot, filePath) : filePath;
20472
20941
  return normalizePath4(relativePath);
20473
20942
  }
20474
20943
 
@@ -20726,7 +21195,7 @@ render();
20726
21195
  }
20727
21196
 
20728
21197
  // src/tools/visualize/transform.ts
20729
- var path29 = __toESM(require("path"), 1);
21198
+ var path31 = __toESM(require("path"), 1);
20730
21199
 
20731
21200
  // src/tools/visualize/modules.ts
20732
21201
  var MAX_MODULES = 18;
@@ -20859,8 +21328,8 @@ function compactModules(prefixToNodes) {
20859
21328
  function deriveModules(nodes) {
20860
21329
  const initial = /* @__PURE__ */ new Map();
20861
21330
  for (const node of nodes) {
20862
- const relative12 = stripToProjectRelative(node.filePath);
20863
- const prefix = modulePrefixFromRelativePath(relative12);
21331
+ const relative14 = stripToProjectRelative(node.filePath);
21332
+ const prefix = modulePrefixFromRelativePath(relative14);
20864
21333
  if (!initial.has(prefix)) initial.set(prefix, []);
20865
21334
  initial.get(prefix)?.push(node);
20866
21335
  }
@@ -20986,7 +21455,7 @@ function transformForVisualization(symbols, edges, options = {}) {
20986
21455
  filePath: s.filePath,
20987
21456
  kind: s.kind,
20988
21457
  line: s.startLine,
20989
- directory: path29.dirname(s.filePath),
21458
+ directory: path31.dirname(s.filePath),
20990
21459
  moduleId: "",
20991
21460
  moduleLabel: ""
20992
21461
  }));
@@ -21014,9 +21483,9 @@ function parseArgs(argv) {
21014
21483
  let host = "opencode";
21015
21484
  for (let i = 2; i < argv.length; i++) {
21016
21485
  if (argv[i] === "--project" && argv[i + 1]) {
21017
- project = path30.resolve(argv[++i]);
21486
+ project = path32.resolve(argv[++i]);
21018
21487
  } else if (argv[i] === "--config" && argv[i + 1]) {
21019
- config = path30.resolve(argv[++i]);
21488
+ config = path32.resolve(argv[++i]);
21020
21489
  } else if (argv[i] === "--host" && argv[i + 1]) {
21021
21490
  host = parseHostMode(argv[++i]);
21022
21491
  } else if (argv[i] === "--host") {
@@ -21043,7 +21512,7 @@ function parseIndexArgs(argv, cwd) {
21043
21512
  if (!arg.startsWith("--project=")) {
21044
21513
  i += 1;
21045
21514
  }
21046
- project = path30.resolve(cwd, value);
21515
+ project = path32.resolve(cwd, value);
21047
21516
  continue;
21048
21517
  }
21049
21518
  if (arg === "--config" || arg.startsWith("--config=")) {
@@ -21054,7 +21523,7 @@ function parseIndexArgs(argv, cwd) {
21054
21523
  if (!arg.startsWith("--config=")) {
21055
21524
  i += 1;
21056
21525
  }
21057
- config = path30.resolve(cwd, value);
21526
+ config = path32.resolve(cwd, value);
21058
21527
  continue;
21059
21528
  }
21060
21529
  if (arg === "--host" || arg.startsWith("--host=")) {
@@ -21120,7 +21589,7 @@ function parseVisualizeArgs(argv, cwd) {
21120
21589
  for (let i = 0; i < argv.length; i++) {
21121
21590
  const arg = argv[i];
21122
21591
  if (arg === "--project" && argv[i + 1]) {
21123
- project = path30.resolve(argv[++i]);
21592
+ project = path32.resolve(argv[++i]);
21124
21593
  } else if (arg === "--max" && argv[i + 1]) {
21125
21594
  maxNodes = Number(argv[++i]);
21126
21595
  } else if (arg.startsWith("--max=") || arg.startsWith("max=")) {
@@ -21157,7 +21626,7 @@ async function handleVisualizeCommand(argv, cwd) {
21157
21626
  console.error("No connected symbols found. Retry with: npm run visualize -- orphans");
21158
21627
  return 1;
21159
21628
  }
21160
- const outputPath = path30.join(os8.tmpdir(), `call-graph-${Date.now()}.html`);
21629
+ const outputPath = path32.join(os8.tmpdir(), `call-graph-${Date.now()}.html`);
21161
21630
  (0, import_fs20.writeFileSync)(outputPath, generateVisualizationHtml(vizData), "utf-8");
21162
21631
  console.log(`Temporal call graph visualization generated: ${outputPath}`);
21163
21632
  console.log(`Nodes: ${vizData.nodes.length} | Edges: ${vizData.edges.length}`);
@@ -21189,8 +21658,60 @@ async function runMcpCli(argv) {
21189
21658
  const config = parseConfig(rawConfig);
21190
21659
  const server = createMcpServer(args.project, config, args.host);
21191
21660
  const transport = new import_stdio.StdioServerTransport();
21192
- await server.connect(transport);
21193
21661
  let watcher = null;
21662
+ let shutdownPromise;
21663
+ const onServerClose = server.server.onclose;
21664
+ const shutdown = () => {
21665
+ if (shutdownPromise) return shutdownPromise;
21666
+ process.stdin.removeListener("end", requestShutdown);
21667
+ process.stdin.removeListener("close", requestShutdown);
21668
+ process.removeListener("SIGHUP", requestShutdown);
21669
+ process.removeListener("SIGINT", requestShutdown);
21670
+ process.removeListener("SIGTERM", requestShutdown);
21671
+ server.server.onclose = onServerClose;
21672
+ shutdownPromise = (async () => {
21673
+ let exitCode = 0;
21674
+ try {
21675
+ await watcher?.stop();
21676
+ } catch (error) {
21677
+ exitCode = 1;
21678
+ console.error("Failed to stop MCP file watcher cleanly:", error);
21679
+ }
21680
+ try {
21681
+ await stopAutoIndex(args.project, args.host);
21682
+ } catch (error) {
21683
+ exitCode = 1;
21684
+ console.error("Failed to stop automatic indexing cleanly:", error);
21685
+ }
21686
+ try {
21687
+ await server.close();
21688
+ } catch (error) {
21689
+ exitCode = 1;
21690
+ console.error("Failed to close MCP server cleanly:", error);
21691
+ }
21692
+ process.exit(exitCode);
21693
+ })();
21694
+ return shutdownPromise;
21695
+ };
21696
+ const requestShutdown = () => {
21697
+ void shutdown();
21698
+ };
21699
+ server.server.onclose = () => {
21700
+ try {
21701
+ onServerClose?.();
21702
+ } finally {
21703
+ requestShutdown();
21704
+ }
21705
+ };
21706
+ process.stdin.once("end", requestShutdown);
21707
+ process.stdin.once("close", requestShutdown);
21708
+ process.once("SIGINT", requestShutdown);
21709
+ if (process.platform !== "win32") {
21710
+ process.once("SIGHUP", requestShutdown);
21711
+ process.once("SIGTERM", requestShutdown);
21712
+ }
21713
+ await server.connect(transport);
21714
+ if (shutdownPromise) return;
21194
21715
  const isHomeDir = isHomeDirectory(args.project);
21195
21716
  const isValidProject = !isHomeDir && (!config.indexing.requireProjectMarker || hasProjectMarker(args.project));
21196
21717
  if (config.indexing.watchFiles && isValidProject) {
@@ -21202,26 +21723,6 @@ async function runMcpCli(argv) {
21202
21723
  args.config ? { configPath: args.config } : {}
21203
21724
  );
21204
21725
  }
21205
- let shuttingDown = false;
21206
- const shutdown = async () => {
21207
- if (shuttingDown) return;
21208
- shuttingDown = true;
21209
- try {
21210
- await watcher?.stop();
21211
- await stopAutoIndex(args.project, args.host);
21212
- await server.close();
21213
- process.exit(0);
21214
- } catch (error) {
21215
- console.error("Failed to stop MCP server cleanly:", error);
21216
- process.exit(1);
21217
- }
21218
- };
21219
- process.on("SIGINT", () => {
21220
- void shutdown();
21221
- });
21222
- process.on("SIGTERM", () => {
21223
- void shutdown();
21224
- });
21225
21726
  }
21226
21727
  function printIndexProgress(onProgress, title, metadata) {
21227
21728
  const details = Object.entries(metadata).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${isSensitiveKey(key) ? "[REDACTED]" : String(value)}`).join(" ");